There is a small feature in RISE now that took a redesign of the renderer’s entire editing model to make possible, and a few days to build once it was. Right-click any property row in the inspector (a sphere’s radius, a material’s roughness) and choose “Reveal in Scene File”. The scene text editor scrolls to the exact byte run that defines that value and highlights it; not the line, the bytes. Then go the other way: right-click anywhere in the scene text, choose “Select in Inspector”, and the entity that owns that text lights up in the outliner with its properties laid out beside it.
As parlor tricks go it is modest. Nobody gasps. But it is the visible corner of the largest architectural change in RISE’s twenty-five years, and that change is the reason I can now build scenes in the renderer with an AI agent as a genuine partner rather than a very fast typist. This is the first essay in a series about that build. It starts where the build had to start: with the language the human, the GUI, and the agent all agree to speak.
Three dialects
RISE has always had a scene language. I hand-wrote the original ASCII parser back in the renderer’s research days; plain text was the easiest, most cross-platform way to feed scenes to a codebase that had to build everywhere, and in research code, easiest and portable wins. You declare a geometry chunk, a painter, a material, an object that binds them, and the renderer assembles a world. The format grew a descriptor system that defines every chunk’s parameters, and for most of the renderer’s life that text was how I talked to it. The GUIs came later, and they spoke something else entirely.
The GUI’s native tongue (now built in the AI era) was a live, mutable, in-memory scene. Edits were commands that mutated it. Undo was reconstructed from inverse edits. The file on disk was a lossy dump you produced when you remembered to save. Which means the system was really speaking three dialects at once: the text on disk, the object graph in memory, and the widgets on screen, with translation layers between all of them and no authority on what the scene actually was.
When it came to using AI agents to build scenes, they gravitated straight to the file. Text is an agent’s native medium; it can read a scene the way it reads a program, diff it, and propose a change as a patch. The agent and I had converged on the same dialect. The GUI was the odd one out, but my human brain likes working with a GUI.
Plenty of tools live comfortably with a human-facing GUI and a machine-facing format that drift politely apart, and I could have left it there; what forced the issue was a long stretch of unglamorous work that kept teaching the same lesson.
The translation tax
Before any of the redesign, I spent weeks using the agent to harden the GUI’s editor and transaction subsystem, the machinery for apply, undo, redo, and round-trip save, with review rounds that kept finding more. By the end the count stood at roughly two dozen correctness bugs: a transaction baseline that never captured quite every field, edit handling duplicated across five separate code walks so a fix in one missed the others, an undo that landed on the wrong camera, invalidation logic that a dozen call sites each had to remember independently.
Individually each bug was ordinary. Collectively they had one anatomy. Nearly every failure came from two or more mutable representations of the scene that had to be kept in agreement, and the consistency problem was unbounded; you could always find one more field the baseline forgot, one more walk the fix missed. We were paying a translation tax between dialects, and the tax was not going down with effort. Careful syncing does not reduce this class of bug. Removing the second representation dissolves it.
One canonical document
So the pivot. The attribution here matters, because the idea and its sharpening came from different minds. The product thesis was mine: RISE should be agent-forward by design, the 3D package for nerds, where the agent is a first-class user of the tool rather than a feature bolted onto it, the scene file is canonical, and the UI is a live view of it that never diverges. The sharpening was the agent’s. “The scene file is canonical” is a slogan until you commit to what canonical means, and the agent’s formulation was the one that held. The canonical object is the scene document, a lossless concrete syntax tree; comments and whitespace survive parsing, so it round-trips byte for byte. The text is its serialization. The file on disk is the last serialization you deliberately persisted. The rendered scene is its evaluation. And the GUI and the agent are two clients of the same edit boundary.
Compilers are not my field; my roots are in light transport, not language tooling, so before committing I did the reading on syntax trees and on how compilers and IDEs keep lossless source representations, and came out knowing considerably more about that world than I went in. The agent supplied the direction; validating it was mine to do.
The two-clients clause is the one carrying the weight. When you drag a slider in the inspector, the GUI performs a structured edit on the document, exactly as the agent does when it proposes a change in chat; at the edit boundary they are peers. Document undo stops being a reconstruction from inverse edits and becomes restoration of a previous immutable version, which shares structure with the new one, an edit path-copying only the handful of nodes on its spine. Session state, what camera you are looking through, where the animation is scrubbed to, still needs its own careful handling, and later essays will show us learning that. But the architecture removes the need to synchronize independent mutable representations of the document itself, which is where the translation tax lived.
There was a satisfying discovery when we audited the codebase against this design: RISE had been trying to become this for years. A proto syntax tree had been built for round-trip save and then thrown away, the derivation pipeline was already incremental, and the descriptor system was already the schema for parsing and highlighting, ready to also drive the UI and validate agent edits. Even the old GUI roadmap declared “text is the source of truth” while the implementation did the opposite, which I choose to read as aspiration rather than irony. The redesign was less a rewrite than the completion of a trend the code was already on.
Canonical, it turns out, does not mean automatically persisted. The editor now mirrors the live document; every GUI edit, agent edit, and undo appears as text within half a second, so you are always looking at the document, not a copy. But saving stayed deliberate: an auto-save experiment lasted one day, until it wrote camera-navigation residue from merely looking around into two scenes and the golden tests caught it. Exploring a scene is not editing it. Meanwhile agent proposals became reviewable in the one format we both fully trust, a diff against the document, read the way I would read a pull request; and the GUI’s “Add Sphere” menu turned out to be the agent’s validated chunk-insertion primitive with a different caller.
Closing the loop
Which brings us back to the parlor trick, because traceability is where the language claim gets tested, and where review’s job was to protect one user-facing invariant.
The forward direction fell out of a single decision: the address a UI element uses to reveal itself is the same address it uses to edit itself. The reveal resolver reuses the edit path’s lookup verbatim, then asks the document for the byte range of one parameter. Reveal and edit can never disagree about where a value lives, because there is only one resolution path for both.
The reverse direction (text cursor to UI element) looked symmetrical and was not. The question sounds trivial: given the chunk under the cursor, which UI category owns it? The first cut was a hand-written suffix table; _material means Material, _light means Light. A reviewer (another agent; the review loop in this project is agents adversarially reviewing agents, with me as the court of appeal) checked it against all 158 registered chunk parsers and found the drift every hand-maintained list accumulates: csg_object is an object, expression_function2d is a painter, neither matches a suffix, so the reverse direction silently failed on entities the forward direction resolved fine.
The obvious fix was to delegate to the parser registry, which already declares a category for every chunk. Drift-proof by construction, except it drifted the other way: the registry’s category is a parsing classification, not a statement about what is selectable. scene_options is filed under Camera for parsing purposes, so clicking inside a scene options block now selected the scene’s camera; an actively wrong answer, worse than the honest “I don’t know” the suffix table gave. One attempt trusted a naming convention to be a taxonomy; the next trusted a taxonomy to answer a question it was never built for.
The fix that held was not a better taxonomy but a self-check. Whatever entity the reverse direction computes, forward-resolve it and demand you land back on the chunk you started from; if you do not, the address is not real, and the answer is no answer. No blocklist, no curated exceptions. The feature’s founding equation, revealable equals editable, promoted from design principle to runtime guard: the reverse mapping is valid exactly when forward-of-reverse is the identity.
One last detail about where the project’s values landed. Reveal offsets resolve against the live serialization of the document, which matches the editor buffer only while it is clean; one keystroke of a hand edit and they are stale. The first “Select in Inspector” shipped always-enabled and silently did nothing in exactly that state, and a reviewer escalated on principle: an enabled affordance is a promise, and one that fails in the common case is a lie the user has to debug. It now disables itself, with a reason. Disabled with a reason beats enabled with silence, in menus as elsewhere.
Two kinds of machines
There is a deeper reason the answer is one language with three faces, rather than retiring the GUI and living in text (the ascetic option an agent-forward pitch might imply). Humans and agents are efficient at different things. I can skim a stretch of scene text and tell whether it looks right, and I can do it with a render of the same object sitting in the corner of my eye, text and pixels checked against each other in a single glance; validation, for a human, is naturally multimodal and essentially free. Editing is where the asymmetry gets extreme, because there humans are remarkable parallel multimodal machines: eyes on the render, hand on the trackpad, dragging a slider in real time until the roughness just looks right, a feedback loop no text field can match. The agent is the mirror image. It is at its best reading and writing text and values, and it is nowhere near as efficient a multimodal machine; asking it to nudge a slider is asking it to work in translation. Each kind of machine should edit in the medium where it is strongest, and that only works without reintroducing the three-dialect problem if every medium is bound to the same canonical document, correctness included: a slider drag, a typed value, and an agent patch must be the same operation, validated the same way, undone the same way.
Why this is the foundation
It would be fair to ask why a hobby renderer needs any of this rigor, and the answer is that none of it was for the renderer. It was for the partnership. In an earlier essay, “What Will Be Tuesday?”, I argued that AI products are stochastic at their core and earn trust by changing the promise they make to the user. RISE is my attempt to build a whole tool around a stochastic core on purpose: the agent at the center is probabilistic, and for that matter so is the renderer, which converges on an image rather than computing one. You do not make a stochastic partner trustworthy by making it deterministic; you make everything around it deterministic and inspectable. The canonical document is that contract: whatever the agent proposes is a diff against a document whose meaning is exact, validated like any other edit, and undoable.
What RISE suggests as a broader pattern is that the agent question is downstream of the state question. Coding agents are formidable in software because software already has a canonical textual representation with mature tooling around it; RISE borrowed that machinery (a lossless syntax tree, pure derivation, structured edits, addresses that round-trip; compiler and IDE technology, decades old) and pointed it at a renderer, the way OpenSCAD made text the model for CAD. A canonical, addressable representation does not make a tool agent-native for free; twenty-five years of architecture and a long cutover say otherwise. What it does is remove the most expensive translation boundary and let the agent surface stay thin: essentially one mutating verb, validated by the same descriptors that drive the UI, instead of hundreds of bespoke mutation calls with their own documentation, their own validation, and their own bugs.
So the question your own product’s agent story hinges on is probably not which model to call. It is whether there is a single representation of your system’s state that a human, a UI, and an agent can all read, address, and edit without translation. Get that wrong and every capability becomes a translation and consistency problem, and no amount of careful syncing will settle the bill.
Next in this series: how the design survived six rounds of adversarial review before a line of engine code, and why it came out smaller each time.