HarperZ9/studio-engineExplainer, built from commit 24cd0f4All repository explainers

studio-engine

Generate replayable shaders, sound and motion, each with a receipt.

What it does for you

Generated art usually ends as pixels nobody can inspect. studio-engine keeps the whole recipe: the shader, a sound graph, a motion timeline, the criteria it was judged against, every refinement step and a receipt. You can re-render it, steer it over a local HTTP API, or render PNG frames with no GPU. It runs on the Python standard library alone.

Source: README.md at 24cd0f4 (version 0.3.0)

Watch

No concept film fits this tool closely yet. The walkthrough below covers it in text, with real commands and output.

Video walkthrough: coming with the next release.

How it works, one step at a time

Scroll, or use the step buttons. Every line is output from studio-engine at commit 24cd0f4, from python -m studio_engine --render-frames 7 gyroid and from the engine called in Python with an empty novelty corpus.

  1. 01

    A seed and a generator

    Pick the gyroid with seed 7. The seed drives a fixed integer hash, so it sets the starting parameters and a six-colour palette in OKLCh. The gyroid starts at frequency 8.88 and z 0.66.

    Source: studio_engine/engine.py, run

  2. 02

    Score, then refine the weakest axis

    Each step samples the field on a 20 by 20 grid and scores four axes: clean frequency, contrast, complexity and novelty. Cohesion is their harmonic mean. Refinement moves one parameter at a time toward higher cohesion. The frequency jumps to 10, a whole number, then z rises to 0.95, and cohesion climbs from 0.7983 to 0.8922.

    Source: studio_engine/criteria.py, studio_engine/engine.py

  3. 03

    Short of the target, and an outside check

    Convergence needs cohesion of 0.9 with every axis at or above the floor. At 0.8922 the run stops as best effort, unconverged. A separate structural-fitness check from coherence-membrane then measures a deviation of 0.108 against a tolerance of 0.4 and verifies the world. Without that package installed, this line reads unverifiable.

    Source: studio_engine/certify.py

  4. 04

    One expression, three outputs

    The field sin(10u)cos(10v) + sin(10v)cos(10t) + sin(10t)cos(10u) is held as a frozen tree. It is emitted as the GLSL field() body, parsed back, and required to evaluate equal to the original within 1e-6. Swept over t it gives a timeline with a period of 0.628 seconds whose loop has no jump. Sonified, it becomes a six-harmonic additive sine synth at 373.7 Hz.

    Source: studio_engine/strand/glsl.py, studio_engine/temporal.py, studio_engine/strand/webaudio.py

  5. 05

    Frames, and a tampered program

    --render-frames rasterizes eight PNG frames across the loop period and writes a manifest binding each frame's SHA-256 to the expression hash. Before drawing, the rasterizer rebuilds the expression from the shipped tree and re-hashes it. Pick a program in the panel: changing one constant from 10 to 11 makes the hash disagree, and the render is refused.

    Source: studio_engine/raster_renderer.py

  6. 06

    Same input, same world, for a fixed corpus

    Novelty is measured against a corpus of everything made before, and the corpus grows with every run. With the corpus cleared, seed 7 gives world 1e1312cf579e9deb every time. Run it again without clearing and the new gyroid is a near copy of the last one: novelty falls to 0.08 and the result changes.

    Source: studio_engine/corpus.py; README.md, "Why it matters"

Walkthrough

Install it, run it once, then use the main feature. Each command below is real, and so is its output.

  1. Get it

    Clone it. Python 3.10 or newer, no install step.

    $ git clone https://github.com/HarperZ9/studio-engine && cd studio-engine
  2. First run: a world with frames

    Generate the gyroid at seed 7 and render PNG frames with no GPU.

    $ python -m studio_engine --render-frames 7 gyroid
    world 1e1312cf579e9deb | 'Gyroid #7'
      steps=8 converged=False final_score=0.8922
      render=glsl-fragment expr_sha=528f4a81a82a6ea2
      timeline period=0.628319 continuity=verified
      rendered 8 PNG frame(s) -> studio-out/frames-7/ (+ frames.json)
  3. Open the chamber

    Start the API, then open handoff/reference-chamber.html to see the shader and hear the synth.

    $ python -m studio_engine.server 8777

Output from studio-engine at 24cd0f4 with Python 3.12 on Windows. The unittest suite reported 195 tests passing. Ids depend on the novelty corpus, which the CLI keeps at studio_engine/_corpus.json.

What it does not do

Source: README.md at 24cd0f4, "Scope and maturity" and "Why it matters"

Check what stuck

Answer each one in your head before you open it.

Why does a second run of seed 7 give a different world?

Novelty is scored against a corpus that grew with the first run.

What does the rasterizer check before drawing a frame?

It rebuilds the expression from the shipped tree, re-hashes it, and refuses on a mismatch.

What happens to the GLSL before it ships?

It is parsed back and must evaluate equal to the original expression within 1e-6.