There is a long tradition of making the GPU accessible by inventing a friendlier language for it, and most of the attempts fail in the same place: they produce a toy that cannot express a real scene. GSS — GPU Style Sheets — takes a stranger route. It does not invent a language. It reuses one that several million people already know, and applies it to geometry.
@scene {
torus#ring;
sphere#ball;
}
#ring {
translate: 0 1.2 0;
rotate-x: 70deg;
radius: 1.1;
thickness: 0.14;
color: #e8e6e1;
}
#ball {
translate: 0 1.2 0;
radius: 0.55;
color: #ff5a36;
material: jelly(0.6);
animation: float 2s ease-in-out alternate;
}
@keyframes float {
from { translate: 0 1.2 0; }
to { translate: 0 1.5 0; }
}
That is a complete scene. Declare shapes in @scene, style them with selectors, and the compiler turns the whole sheet into one raymarched shader. In the project’s own words: “No Three.js, no meshes.”
Why the cascade is the actual idea
Anyone can map CSS property names onto 3D transforms. The part worth paying attention to is that GSS implements the parts of CSS that are hard: classes, ids, combinators, :hover, :has(), :nth-child() and nesting.
A scene graph is a tree of objects with inherited properties and local overrides. That is exactly what the cascade is for. Describing a scene as a stylesheet means you get specificity, inheritance and state-based restyling for free, as language features rather than as engine API calls. :hover on a torus is a meaningful thing to want, and in an imperative renderer it is an event listener, a raycast and a material swap.
Because everything compiles to a single shader, there are no meshes to allocate and no draw calls to batch — the scene is signed-distance geometry evaluated per pixel. That is also the constraint, and the honest limit of the approach: raymarching an SDF scene is wonderful for the shapes it supports and simply cannot represent an imported character model.
What is in the box
| Area | Coverage |
|---|---|
| Shapes | cube, sphere, torus, cylinder, cone, capsule, path, prism, lathe and more |
| Materials | matte(), metal(), glass(), jelly(), emissive(), iridescent(), textures |
| Motion | @keyframes, transition, scroll-driven animations, offset-path |
| Values | calc(), var(), @property, random(), CSS colour functions |
| Effects | gradients, noise, masks, blur, bloom, grain |
| Scene | floor, background, lights, fog, shadows, orbit camera |
| Responsive | @media, light-dark(), if() |
@property and calc() are the entries that signal this is not a thin skin. Registered custom properties with types are what make CSS variables animatable, and supporting them means the compiler has a real value system rather than string substitution.
Three ways in
A script tag with no build step, npm, or compiled at build time through Vite:
npm install gss-lang@0.0.6
import { mount } from "gss-lang";
mount(canvas, "@scene { sphere; }");
The Vite path compiles .gss files ahead of time:
// vite.config.ts
import gss from "gss-lang/vite";
export default { plugins: [gss()] };
// main.ts
import { mount } from "gss-lang/runtime";
import logo from "./logo.gss";
mount(canvas, logo);
There is also a <gss-scene> custom element for dropping a scene into any page.
The playground is the honest part
The playground does something most new shader languages avoid: it shows the generated GLSL and WGSL, with errors reported under the line that caused them, and exports to Shadertoy.
Exposing the compiler output is a meaningful choice. It means the abstraction is inspectable — you can find out what a jelly(0.6) material actually costs, and you can leave. A DSL that hides its output asks for trust it has not earned yet; one that prints the shader is telling you it expects to be audited.
There is also a VS Code extension with highlighting, formatting and snippets:
code --install-extension lukyvj.gss-language
Where it actually is
v0.0.6, released 9 October 2026. The repository was created on 29 September and has moved fast — 0.0.1 through 0.0.6 shipped to npm between 1 and 9 October. It currently has 102 stars, five forks and no open issues, under Apache 2.0.
The project’s own status note is one line and you should believe it: “0.0.6, early: the syntax may still change.”
So this is not a thing to put in production. It is a thing to spend an evening in, and an unusually good argument-by-demonstration that the language we use for layout was always a language for describing hierarchies of styled objects — and that nothing about that required the objects to be flat.
Sources
- GSS — GPU Style Sheets on GitHub
- gss-lang.dev
- GSS playground
- gss-lang on npm
- Getting started — GSS docs