Autonomous Generative Studio - A-GEN

A local agent-driven evolutionary studio in which model agents propose bounded mutations to a seeded, frame-driven particle painting and a human selects which versions survive. Part artwork, part technical documentation of an evolvable image system.

2026

AI Agents · Evolutionary Systems · Generative Systems · three.js · Playwright

Year
2026
Role
Concept, system design, development
Tools
AI Agents, Evolutionary Systems, Generative Systems, three.js, Playwright

Updated 4 October 2026


Graph view: six code-exploratory siblings of one parent, each rendered at 500 frames, one dotted exploration edge above them, with the inspector open
Input A seeded, frame-driven particle painting — tens of thousands of particles wandering Perlin and curl noise fields and depositing pigment on an accumulation buffer — driven by config.json and fixed at seed 42 and 2048 × 2048
Perception The studio, never the model, reads back what actually changed: the config resolved against known bounds, diffs computed against the real parent snapshot, no-op submissions rejected, and every attempt kept with its validation result, token usage and timing
Generative System / Model A Pi RPC harness — one coordinator plans a round, then independent worker agents propose bounded mutations (parameter shifts, focused code changes, open explorations) inside isolated working copies with six allowlisted tools
Behavior Deterministic and append-only: validated submissions are frozen into content-addressed blobs as immutable versions, candidates render a fixed frame count from the seed in a sandboxed Chromium, failures stay visible with their reasons, and no round ever starts without a confirmed human selection
Output An evolving lineage of technical images — sealed versions with their renders, diffs, provenance and live preview — plus a documentation export built from the committed record

A-GEN_01 · Evolutionary Studio · Technical Documentation

Technical images under human selection

A local agent driven studio in which a seeded, frame-driven particle painting is evolved by model agents and a human breeder.

Part I — The artistic concept

An evolutionary studio for technical images

1 · The apparatus and its program

A_GEN_01 is a particle painting. Tens of thousands of particles wander a field built from two noise functions — Perlin and curl — and deposit pigment on an accumulation buffer, frame after frame, until the painting is finished. Nothing in the picture is drawn by hand. Every mark is a consequence of a program: a seeded random generator, a fixed noise implementation, a configuration that names the field scales, the particle lives, the color cycle.

Vilém Flusser called images like this technical images: images produced by apparatuses rather than by hands. For Flusser, a photograph is not a window onto the world but a projection of a concept onto the world — the camera realizes possibilities that were latent in its program. A_GEN_01 makes that latency explicit. Its program is literally readable: config.json is the parameter surface of the apparatus, the code is its fixed part, and the seed is the throw of the dice that starts it. Where a photographer walks the world looking for scenes, this apparatus walks its own possibility space. Every seed, every field scale, every lifespan is an address in a landscape of possible paintings that exists before anyone looks at it.

2 · The artist as selector

An apparatus contains more possibilities than any player can visit. Flusser’s player is the one who probes the program, hunting for the improbable — for states the program contains but rarely shows. In this studio the exploration is shared. Model agents propose mutations — parameter shifts, focused code changes, open explorations — inside hard bounds. But they never judge. No fitness function ranks the children. The only aesthetic act in the system is selection: the artist looks at renders and chooses which versions survive as parents.

This puts the studio in an old lineage. Richard Dawkins’ biomorphs showed that a blind mutation walk becomes directed the moment an eye picks a branch. Karl Sims evolved virtual creatures by jury; William Latham grew sculptures by hand-picking mutations. In all of these, evolution is not automatic — it is a dialogue between a generator that can only enumerate and a selector that can only choose. The computer explores; the artist is the fitness function. The studio enforces this in code: an unselected version is not rejected, it simply waits; and nothing evolves without a new, confirmed human request. The machine proposes, the human disposes — and the proposing is bounded so that the disposing stays meaningful.

3 · Breeding: every child descends from both parents

One source produces variants of itself. But when the artist selects a second source, the pair is bred: every candidate of that round is then a hybrid of both parents, not a share of each. This is the rule that makes the crossing a real cross and not a collage.

Two kinds of hybrid exist, and the difference matters. A parameter hybrid is computed by the studio itself: the two genomes cross field by field, each field taken from one parent or the other. No model is called, no judgment is involved — the cross is arithmetic, and the provenance records exactly which field came from which parent. A code hybrid is synthesised by one worker that is given both sources, one of them read-only: two programs enter, one program leaves, and the child must carry the character of both. In both cases the parents are recorded, the inherited fields are listed, and a hybrid remains one seeded artwork — two sources can only be bred when they share one seed and one resolution, because the child replays from a single seed at frame zero.

Crossing is never automatic. It happens only where the artist selected two sources, the way a breeder chooses a pairing for traits already seen. The offspring is a descendant of both — a new point in the program’s possibility space that neither parent could reach alone.

The hybrid is therefore not just a visual mixture. It is a relation between two programs. One source contributes a way of moving, coloring, or accumulating; the other changes the field in which those behaviors become visible. The child is a new operation on the same seeded material, and its difference from each parent can be inspected rather than guessed from the image alone.

4 · The lineage as artwork

The studio’s real output is not any single painting. It is a lineage of technical images: a family tree in which every edge is a recorded decision and every card keeps its render, prompt, diff and failures. The graph is not a diagram placed around the artwork after the fact. It is a second surface of the work. It shows how visual form becomes history.

This is close to Gilbert Simondon’s idea that a technical object is understood through its becoming, not only through its finished shape. Each version carries traces of the conditions that produced it: the parent or parents, the selected render, the worker assignment, the actual diff, and the point at which the artist accepted or passed over it. The object is not isolated from its history. Its history is part of what it is.

The interface gives that history a readable form. Graph makes relations visible. Compare makes differences visible. Inspector makes causes visible. Together they turn an otherwise hidden program into a space the artist can inhabit and question.

Graph view: a selected sealed version with its hybrid lineage and the inspector open
Fig. 1 — The lineage, visible. A sealed code-exploratory version is selected as a parent (blue card) and its hybrids are grouped beneath it: siblings sharing a parent set sit together, solid edges for parameter mutations, dashed for focused code mutations, dotted for explorations. Every card is a real render or an honest state — queued, in progress, failed — never a placeholder pretending to be work.

5 · Determinism and the improbable

Every version is frozen: source, configuration, ordered textures, seed — hashed and kept. A render is a fixed number of frames computed from that frozen state, not a duration; a replay walks from frame zero to the recorded frame. The image is therefore a calculation that can, in principle, be repeated — the projection surface is documented along with the projected image.

The archive also keeps what did not survive. Failed versions sit in the graph beside the sealed ones, each stating its reason; a rejected submission and its repair remain inspectable as evidence. Flusser worried that technical images would become a memoryless flow. This studio’s answer is an append-only memory in which the improbable path through the program — including its dead ends — stays visible. The project is close to Sol LeWitt’s idea that a concept can become a machine that makes the art, but it keeps the machine open to human interruption. The program proposes; the artist chooses; the archive remembers both actions.

Part II — Technical documentation

How the studio works

1 · Three parts

System overview: browser, studio service, workers and render sandbox
Fig. 2 — Three parts. The browser only speaks to the studio service; the service owns all state. Workers never see the browser, and the render sandbox never sees the studio's data beyond the frozen bytes of one candidate.

2 · The artwork and its contract

The artwork is the existing three.js port of the Processing sketch A_GEN_01.pde. It is bit-exact against Processing at seed 42. The studio does not rewrite it; it drives it and mutates copies of it. Three rules make that safe:

  • Seeded. One number (seed 42, inherited by every version unless the artist changes it explicitly) drives a 48-bit LCG and the noise functions. Same seed, same bytes, same painting.
  • Frame-driven. The simulation advances by calling step() and drawing once per frame. No wall-clock time enters the artistic state, so a render is defined by a frame count, not by a duration.
  • Config-driven. Everything that changes the look lives in config.json. The studio imports those bytes, hashes them, and treats them as the genome.

3 · The genome

The genome is the config: six fixed sections plus a free custom namespace that code workers may add to. The studio knows which fields can change pixels and within which ranges — fields marked inactive exist in the config but do not move pixels today (for example canvas.background, which the renderer ignores). Parameter workers may only edit active fields.

SectionFieldsNotes
runseed · frames · width · height · speedseed and resolution are locked unless the artist changes them
particlesamount · maxParticles · strokeWeight · opacity · speed · noiseOffsetamount is capped by maxParticles
flowfieldperlinNoiseScale · curlNoiseScale · curlMixthe two noise fields and their mix
lifebaseLifespan · lifespanJitter · finalColorInfluence · initialColorInfluenceparticle lifetime and color blend over life
sequencetimer · amtTex · zoomAmounttexture swap cadence and zoom
canvasbackground · cap · hudbackground inactive today; hud is a DOM overlay, never captured
customdata onlycode workers may extend; the studio keeps it, warns on unknown fields

4 · One round

A round is one confirmed request from the browser. It is frozen before anything runs: parents, the exact renders the artist saw, the verbatim prompt, the model, the mutation mix, the frame count and the budgets. An idempotency key makes retries safe — a refresh cannot start a second round or spend twice.

The seven stages of a round, from selection to comparison, with the human feedback loop
Fig. 3 — One round. The request is frozen before work starts; workers get their own copies; validation and freezing produce immutable versions; rendering uses only frozen bytes. The loop back to stage 1 is human — the studio never starts a round by itself.
A running round of six hybrid candidates with one sealed sibling open in the inspector
Fig. 4 — The same round, running. Six hybrids of one pair (2 parameter, 2 focused, 2 exploratory) work in parallel — two queued, four in progress — each in its own workspace. The inspector holds a sealed sibling's hypothesis and provenance while the others work, and the bar shows the mutation mix, which must total the candidate count.
DefaultValueNote
candidates3 (max 9)mix must total the candidate count
mutation mix2 parameter · 1 code focusedcode exploratory replaces focused for open directions
parents1–2two sources are bred, see §5
frames100 (options 100 / 200 / 500)an exact frame count beats a duration
watchdog75 sexternal, for stuck frames and stuck workers
worker turns8 by mode (more for code exploration)a turn is one model round-trip
repair attempts1the failure reason is quoted back to the worker
models366 available via Pichosen in the UI per round; never silently substituted

5 · Breeding two sources

With one selected parent, the candidate count is divided across that parent: each candidate is a variant of it. With two selected parents, the studio breeds the pair instead — every candidate of the round is a hybrid of both. Two sources must share one seed and one resolution, because a hybrid is one seeded artwork, not a collage of two.

Breeding: two sources converge into one hybrid child, via a studio-computed parameter cross or a worker-synthesised code hybrid
Fig. 5 — Breeding. The graph draws two arrows converging on every hybrid; the inspector lists both parents and which fields were inherited from the second source.

The two kinds of hybrid differ in an important way. The parameter hybrid is mechanical — the studio performs the cross itself, so the result is exactly the arithmetic and nothing else; no model is called and no taste is involved. The code hybrid is a synthesis: a worker reads both programs and writes one that keeps the seeded, frame-driven contract while carrying both parents’ character. In both cases the artist chose the pair, and the record shows the cross field by field or the actual source diff.

6 · The worker sandbox

Each candidate gets an isolated working copy of its parent’s frozen bytes. A worker agent never sees the studio, the browser, the network, or another worker’s copy. It has six tools and nothing else — no shell, no filesystem outside its copy, no package installation. Completion requires a structured submission, never an assistant message.

ToolWhat it may do
list_artworksee the files of its working copy
read_artworkread allowed paths (its own editable files plus the read-only second source)
patch_artwork / replace_in_artworkedit config.json, src/a-gen.js, src/renderer.js — and, for code work, add bounded helper modules under src/
validate_artworkpre-check its own work against the seal-time rules
submit_candidatesubmit hypothesis, intended changes, and the edited files — once

Enforcement lives in the extension, not in the model: resolved-path containment (traversal, UNC paths and symlinks are rejected), mutation-mode allowlists, a 256 KiB source quota, at most 12 files, 64 KiB tool results, and static import checks (only three may be imported; the parser is a real ES-module parser, nothing is executed). Parameter workers cannot edit JavaScript at all — the freeze compares file hashes.

7 · Validation, freezing, repair

When a worker submits, the studio — never the model — decides what happens. The config is resolved against known bounds (a field outside its range is an error; the legacy numeric canvas.hud written by an earlier validator version is resolved back to its boolean). Diffs are computed against the actual parent snapshot, so a model’s summary is never trusted as the diff. A submission that changes nothing is rejected as a no-op. A valid submission is frozen: the source files, the canonical config, and the ordered textures become content-addressed blobs, and a sealed version is created — immutable forever.

A rejected submission gets one repair attempt: a new session in the same workspace, with the failure reason quoted back. The rejected submission file is removed first, so the repair is a real worker turn rather than a replay of the rejected bytes. Every attempt — initial, repair, failed — stays in the record with its validation result, token usage, and timing. Failed candidates remain visible in the graph, each card stating its reason. A restart marks unfinished rounds as interrupted instead of guessing.

8 · Rendering

Rendering uses only frozen bytes. A fresh, sandboxed Chromium opens on a separate ephemeral origin and loads a trusted runner that was itself frozen into the version snapshot. The runner starts the simulation, waits for an explicit ready handshake, and steps the artwork frame by frame while the controller counts frames — the controller owns time limits and success decisions, not the artwork’s own frame counter. When the requested frame count is reached, the final visible canvas is captured at native size (no UI chrome), the PNG dimensions are verified, and the image plus a derived thumbnail are archived together with a recipe.

  • Never fewer particles, never lower resolution, never reduced quality to finish faster.
  • The wall clock is only a safety ceiling (5 s per frame, 75 s stall watchdog).
  • The recipe records source hash, config, asset hashes, seed, frame count, runner hash, Chromium revision, and the runtime identity — so a replay is honest about what it can and cannot promise.
  • Additional renders of the same source belong to the same version and restart from the seed.
Compare view: two sealed versions side by side with frames and seconds
Fig. 6 — Frames, not durations. Two sealed versions of one seed at native resolution, each shown with the frames actually completed and the seconds it took. Unequal runs are presented as unequal rather than normalized into a fair-looking comparison, which is why a render is defined by frames and the wall clock is only a safety ceiling.

9 · The archive

The immutable record: version, blob store, event journal, attempts, renders
Fig. 7 — The immutable record. Everything large is stored once, by hash; everything that happened is journaled; every attempt keeps its evidence. A documentation export is an offline ZIP built from this state — versions, event journal, frozen source, original PNGs.

Runtime data lives outside the repository, under %LOCALAPPDATA%\a-gen\projects\<project-id>\: archive.sqlite, the blob store, private agent sessions, disposable job directories, and exports. The browser’s state and the agents’ chat history are not the experiment database — the server’s records are.

10 · The interface

The browser is a working archive, not a chat. Three views carry the work. The Graph is the lineage: cards with real renders (or a hatched placeholder and an honest state), thin arrows for parentage — solid for parameter mutations, dashed for focused code mutations, dotted for explorations, faint dashes for the same-round braces. Siblings that share a parent set are grouped and centered under their parents, with a wider gap between families. Compare places two versions side by side at equal size with frames and seconds shown. The Inspector holds the summary, the config delta, the source diff, and the full provenance of one version. The bar at the bottom carries the selection, the verbatim direction, the model, and the mutation mix.

With exactly one version selected, the Inspector offers View: the studio serves that version’s frozen source from an origin of its own and the artwork plays there — not as a render, but as the artist watching the frozen code run. Watching is not work: it writes no render, event or provenance row, and the frame count in the window is measured against the length that was last recorded for that version.

The live preview window: a version's artwork playing, with its frame count and duration, over the Graph view
Fig. 8 — Live preview. One version selected in the Graph, its frozen source playing in a window of its own: a separate ephemeral origin (a different port, no CORS, framable only by this studio window), the recorded seed, and the artwork stepping its own frames with the duration per frame shown. The footer counts frames against the last recorded render and states plainly that viewing adds nothing to the record.

11 · Safety rules

  • The studio and its API are loopback-only; the browser never receives a shell or a raw agent channel.
  • Model output is untrusted input at every boundary — submissions are parsed, not executed.
  • Artwork code runs only in an isolated origin of its own — the sandboxed render Chromium, or the preview origin the studio serves to the artist’s window; never in Node.
  • Worker tools are allowlisted by path and mode; quotas are finite; credentials stay server-side.
  • Cancellation is confirmed only after owned processes have actually stopped.
  • Failures stay visible; completed siblings are preserved; nothing is silently retried or deleted.

A-GEN_01 — human-directed evolution of a seeded noise-field painting

Documentation compiled 2026-09-14 from the running system and the repository. This page and the screenshots next to it are part of the experiment record; images are kept exactly as captured.