Prism
I want to talk about an idea.
Every shader you have ever admired was a graph before it was a file. A smooth blob is a smooth-union of two distance functions. A tunnel is a distance function with a domain repeat applied to the coordinates. A landscape is a layered noise field thresholded against a plane. A good glitch pass is a feedback loop and a colour warp and a scanline wobble, each of which is a function of the pixel’s position. Every single one of those things is small operations composed together.
The graph exists in the author’s head. They know which pieces are being combined. They know that the smooth union is a smooth union, and they know which two shapes are feeding into it, and they know what k does. And then they sit down, open a text editor, and spend the next two hours translating the graph in their head into a WGSL file.
I have watched hundreds of shader tutorials. They all start the same way. “Open a text editor. Paste this smin function. Paste this SDF primitive. Now write a map(p) that combines them.” Every creative coder I know has a private folder of .glsl snippets they copy-paste into new projects. Every Shadertoy you have ever scrolled past is one person’s graph, typed out linearly, one character at a time, in a language that the GPU happens to speak.
Prism is the answer to a question I have been asking myself for years. If the thing you actually want is a composed shader, and the thing in your head is already a graph, why is there a text editor in the middle?
The idea
Prism is visual shader composition. You build a graph of shader operations the same way you build any other graph in Lux: drag a primitive, drag a combiner, drag a modifier, wire them up. The terminal node of the graph is where the pixels come out. At runtime, Lux walks the graph, generates a complete WGSL shader from it, compiles that shader, and draws it. No text editor. No intermediate source file you have to look at. No step where you switch from “thinking in shapes” to “thinking in code.”
That is the entire idea, and it sounds small until you have tried to use it.
A SdfCircle node becomes a function. An SdfBox2D node becomes another function. An SdfSmoothUnion node becomes a third function that calls the first two. Move the circle and the shader regenerates. Change the smoothing factor and the shader regenerates. Wire a fourth primitive into the union and the shader regenerates to include it. The feedback loop between “I want to try something” and “I see the result on screen” collapses to one drag or one slider move, every time. No compile errors from a missing semicolon. No “wait, did I import that function.” No text at all.
The shader is as fast as a hand-written one because it is a hand-written one, just written by a walker that walks a graph instead of a human who walks a keyboard. Behind the scenes, the generated WGSL goes through the same cache and the same compile path as any other shader in Lux. Steady state is zero compilation. Editing state is a recompile per change, which takes low milliseconds on any GPU made this decade.
Why this matters
Writing shaders as text is one of the great filters of creative coding. Not because the math is hard (the math is mostly copy-paste from a small set of canonical functions anyone can learn), but because the tooling is hostile. You need to know the language. You need to know the conventions. You need to know where your shader is running and which constants the engine provides. You need a feedback loop that involves saving the file, recompiling, and checking whether the pixels moved.
The people who push through this filter are the people who love shaders enough to tolerate the tooling. There are maybe a few thousand of them in the world. Every one of them is sitting on a private library of techniques, none of which are discoverable, because the artifacts they produce are .glsl files on their hard drive and not something anyone else can pick up.
Prism says: the people who love the outputs don’t have to love the text editor. The shader lives in the same editor you already use for everything else. Your graph is the artifact. Someone else can open your project file, look at your SdfSmoothUnion node, see what goes into it, and take it apart to learn how it works. The technique is visible. The technique is editable. The technique is composable with every other node in Lux.
And if you already love shaders and you love the text editor: Prism doesn’t take that away. You can still drop a PixelShader node and write hand-authored WGSL into it. The graph primitives you build in Prism are, under the hood, the same WGSL functions. Eventually, when the plugin system lands, authoring a new primitive will mean writing a function and wrapping it as a node, and every Prism graph in the world can use it the same way. The graph and the code are going to meet in the middle.
This is the feature I wanted to build when I started Lux. It is the reason I started Lux. The ten months before this post were spent building the pieces that would let me build this one honestly: a node graph, a GPU pipeline, a shader cache, a compute system, a module registry, an IR for fragments, a way to turn the IR into real WGSL. Every phase before Phase 9 was, secretly, a Prism prerequisite.
What it changes
There is a specific kind of experimentation that only works when the feedback loop is fast. Try a thing, look at the result, adjust, try again. Ten iterations in the time it takes to think “what if I did this instead.” Shader work at its best looks like this. Shader work as most people experience it does not, because the feedback loop has a text editor in it, and a text editor makes every iteration take thirty seconds instead of two.
Prism collapses the iteration cost. A slider move is an iteration. A new node is an iteration. A rewire is an iteration. Ten iterations is ten seconds, not ten minutes. At that pace, you are not debugging your shader, you are playing with it. And the difference between debugging and playing is the entire difference between the kind of shaders people make in a day and the kind of shaders people make in a year.
It also changes what “sharing a shader” means. A Shadertoy is a file full of code. A Prism graph is a subgraph you can copy and paste into anyone else’s project, with every input visible on the inspector, with every sub-node available for someone to detach and reuse. You do not have to read the shader to take it apart. You look at the graph, and the graph is the explanation.
I do not know how much of creative coding will shift toward this model. I suspect more than people think. The gap between “I have an idea” and “I can see it” is the thing that kills most creative projects, and every tool that closes that gap by even a little tends to get adopted faster than anyone predicted.
What Prism doesn’t do
One honest note, because I don’t want to oversell.
Prism does not invent primitives for you. Someone still has to write the WGSL function that defines what a SdfCircle looks like, or what a CurlNoise produces, or how SdfSmoothUnion blends its inputs. That’s a one-time cost paid by whoever adds the primitive to the library, and once it’s added every user composes with it for free. Lux ships with the common ones and will keep adding more. A public plugin API is on the roadmap but not shipped yet, which means for now the primitives library grows by pull request, not by third-party drop-in. When the plugin API does land, Prism is already designed for it: the fragment IR is stable, the stitcher is a pure function, and everything a plugin would need to register a new primitive already exists as internal API.
Prism also does not decide what kind of shader you’re building. A raymarched SDF is one kind of shader. A post-processing filter is another. A procedural texture generator is a third. Each one wants a different terminal node and a different generation strategy. Today Prism does 2D SDFs. The 3D raymarcher is next, then the noise library, then volumetrics, then the integration with the 3D depth buffer so raymarched scenes and rasterized meshes occlude each other correctly. Each of those is a new stitcher on top of the same IR and the same module system. None of them change the core idea.
The core idea is the same in every case. The graph is the shader. Everything else is how that idea gets implemented for a specific output.
Why I’m building it
Every time I sit down to write a shader, the part I enjoy is the thinking. What shapes do I want. How do they combine. What does the edge look like. How does the noise change the surface. That part is creative and playful and fast. The part I don’t enjoy is everything between that thought and the pixels on screen: the text editor, the semicolons, the re-compile, the dance of remembering which function lives in which file, the copy-paste of smin for the hundredth time. I want that middle step to disappear. I want the gap between “I have an idea” and “I can see it” to be as close to zero as I can make it.
Prism is me trying to build that for myself. If it turns out other people want the same thing, that would make me very happy. If it turns out only I want it, then I’ve built a tool I love to use, and that’s already a good enough reason to have built it.
That’s the point of the whole project, honestly. Not “disrupt creative coding.” Not “own a category.” Just: make the thing I wish existed, put it out there, and see if anyone else feels the same way.
Spreads are the idea at the core of Lux on the CPU side. Prism is the idea at the core of Lux on the GPU side. Everything else in the codebase exists to make those two ideas feel effortless.
Next post will start getting into what comes after the first SDF release and what Prism looks like once the 3D raymarcher lands. This one was the idea by itself.