Excel meets JSON, but a graph, and it’s projected.

The forest and the code under it are two drawings of the same thing, and each knows about the other. Drag the slider and the forest grows; hold Ctrl and click a tree to select the code that drew it. Then peel off what each library draws, a layer at a time, down to what’s stored.

What it is

Progred is a pre-alpha programming environment. Your program is a document, and everything you see, including the code, is a projection of it drawn by some library. Working in it feels more like a spreadsheet than a text file: change a value, and whatever depends on it updates. It’s a minimal prototype that demonstrates the ideas below, not a finished product.

Like a JSON object, a record maps keys to values. But a key isn’t a string: it’s an identity with a name attached as a label, so renaming a key never breaks anything that uses it. A value can also be a cell, which has its own identity, and the same cell can sit in any number of places; that’s what makes a document a graph. There are no built-in strings or numbers either, just records, lists, blobs of raw bytes, and cells. Whoever owns a key decides what it means and how it’s drawn: a 60f64 is an eight-byte blob under the f64 library’s key, and a function is a record that a language such as Grap knows how to run.

Progred is public early to get feedback. Share on Zulip what clicks, what doesn’t, and where you get lost.

Chat about it on Zulip Try the editor Start the tutorial GitHub

The ideas

The data

Structure, not text

A Progred document is built from four things: records, lists, blobs, and cells. Records map keys to values and lists keep them in order; blobs, runs of raw bytes, are the leaves; a cell is a value with its own identity, and the same cell can sit in any number of places, which makes a document a graph rather than a tree. Nothing is parsed, and there’s no source text to keep in sync. The .gid files in the repository are a temporary text bridge for Git and tools.

Identity, not names

Every key and every reference is a random 128-bit identity. A name is a fact stored about a cell, {name: "x"}, which projections draw as a label. So renaming never breaks a reference, two different things can wear the same name, and a call files its arguments under its parameters’ identities.

Libraries give data its meaning

Text is a blob under the text library’s utf8 key, and a 64-bit float is an eight-byte blob under the f64 library’s key; the little f64 beside a number names that library. Other libraries read numbers their own way (f32, u64, and Fidget, whose arithmetic builds 3D shapes), and each has its own +. The tag on an operator records whose arithmetic you chose.

Projections and language

Everything you see is a projection

Libraries contribute projections: functions from a value to a drawing, each free to decline a value it doesn’t recognize. They’re tried in order, and the first that recognizes a value draws it; data no library understands falls back to the base projection, which shows what’s stored, instead of disappearing. You can edit through any projection: code, a number you scrub, a color picker, or a slider.

Grap, a language made of the same data

As Lisp is list processing and its programs are lists, Grap is graph processing and its programs are part of the graph. Functions and calls are ordinary records. Functions that libraries implement receive their arguments unevaluated, so do, all, for each, and match are library functions, not built-in keywords. quote is one too: it returns its argument as data, filling each ` hole, which is how a program builds a shape. Unfinished programs still run: a missing argument or a mismatched value becomes an absent, a value that says what’s wrong, which the rest of the program can pass along or recover from. Fuel bounds every evaluation.

Output linked to source

A drawing remembers the call that drew each shape. Hold Ctrl and click a tree to select the code that drew it; hover a call and its shapes light up. Controls like the forest’s slider are requested by ordinary Grap code, and their values feed the drawing.

Projections are programs

A projection is an ordinary function, so a document can declare its own libraries with projections written in Grap. Each library names the keys it owns, and every record carrying one is drawn by its projection, a fraction stacked over a rule or an angle as a dial, while the parts it shows stay editable.

Fractions stacked over rules and angles drawn as dials, beside the key each library owns.

The workspace is part of the document

Panes are an ordinary record in the document, panes: {left: […], right: […]}. Opening or moving a pane edits that record, so the layout saves and undoes with everything else.

Underneath

Small constructs, composed

A composition stays an ordinary input to further composition: partial projections combine into a partial projection, and completion providers into a completion provider. Richer behavior lives in compositions rather than in special cases of the primitives.

Puri: pure widget descriptions

Progred’s interface is built with Puri, a widget library that keeps no widget tree and mints no identities. A description takes caller-owned state and, from its settled geometry, produces drawing and input handlers. Drawing is a final-tagless language: Vello interprets it natively, Canvas2D in the browser, and a recorder turns frames into data for tests and for pictures like the ones on this page.

Final-encoded trees

Grap programs build hierarchies by emitting groups and leaves through scoped builders. Whoever runs the program chooses the representation, a retained tree or a stream of emissions, and each emission keeps a link to the call that made it.

Incremental, cancellable work

Expensive views run as explicit, dependency-tracked computations that can be cancelled in the background and refined progressively. The CAM preview draws a mesh first while implicit rendering refines behind it.

What it does today

Progred is pre-alpha: enough to show these ideas working together, with rough edges and missing pieces a finished environment wouldn’t have. CAD/CAM is the demanding example it’s being pushed on right now, because it needs expensive live views, parameters you can scrub, and output you can trace back to code. It’s an example, not the point.

A tree drawing beside the editable program that draws it.
A recreation of the tree from Bret Victor’s Inventing on Principle, beside its editable program. The original demo and the inspiration for this loop are his.
CAM playback beside its Grap program: a partially cut cube, upcoming toolpaths, and a playback slider.
CAM playback beside its Grap program: toolpaths cutting a cube, with a slider through the cut.

Progred is a native app, developed and tested on macOS; a Linux build exists but hasn’t been tested recently. This site runs the same editor compiled to WebAssembly. Build the native app from source.

What isn’t there yet

Where to start

Start with the tutorial. It’s best on a laptop, and when you’re done, share on Zulip what made it click and where you got lost.

How the forest was madeGrow the forest above from a single dot, one idea at a time, take it apart down to what’s stored, and end with a forest of your own.

Share how it went

Who’s building it

Progred is Jake Brownson’s project (@jakebrownson on X). The idea dates to 2013 and the name to 2014, and it has gone through TypeScript, Swift, egui, and Haskell prototypes to today’s Rust implementation on the Linebender stack. The source is on GitHub.

Come talk about it

Early feedback matters most at this stage, and the conversation happens on Zulip. Questions, ideas, criticism, and where you got stuck in the tutorial are all welcome.

Join the Progred Zulip Try the editor GitHub