A 124-second 4K film of a Formula 1 car, shot as one unbroken camera take with zero cuts — in which every polygon, every material and every sound is generated by code in this repository.
resolution 3840 x 2160
frame rate 24 fps
frames 2,978 (124.0833 s)
cuts 0
samples 512
grade AgX, look None, exposure -3.628
renderer Blender 5.2.0 LTS / Cycles / OptiX
render 3 rented RTX 5090s, 2026-08-09 -> 08-13, $132.57
triangles 17,707,774,735 evaluated per frame (52.7 trillion across the film)
138,073,595 unique, resident once -- instanced 128x
Those two triangle figures are different quantities and are not interchangeable;
docs/SCALE.md defines all four of them, gives the source line
for every number in this file, and records the one measurement disagreement that
is still open.
The camera starts inside a showroom, flies through a wall as it is breached, out onto an access road, and away around a 3,675 m circuit — as a single continuous path through one continuous world. There is no cut to hide a transition behind, which is the constraint that produced most of what is in here.
This is the second hard rule after the single take, and it is meant literally:
- no downloaded or purchased 3D models — the car, the circuit, the grandstands, the barriers, the crowd, the debris are all built by Python here
- no HDRIs — the sky is a node graph in
world/build_sky.py - no photographic textures — every material is a procedural node graph
- no sample libraries — the audio is synthesised from physical models in
audio/; the engine note is a mode series, not a recording - no AI-generated images, video, audio or geometry anywhere in the pipeline
What that produced, by the numbers: a 3,675 m circuit; a vegetation library
of 33.62 M base-library triangles over 1,432 unique meshes, placing
27,969 woody objects (24,646 woodland + 3,299 hedgerow + 24 avenue) alongside
38,847 shrubs and ~4.86 M ground-cover instances; ~45 individually-gated item
modules; a crowd; and a soundtrack — all from scripts in this tree. Every one of
those numbers has an entry behind it in docs/DEFECT-LOG-R2.md, usually because
someone got it wrong first.
(Those are the shipped world's figures, measured from
render/world/assembly/r2/assembly15_build.json. This paragraph previously read
"33.26 M … 26,641 trees", which was assembly5-era — the same superseded-terrain
chain docs/SCALE.md §9 is about. docs/README.md:173 still
quotes the old pair while describing a historical document; that instance is left
as written.)
The only thing carried in from the previous round is a 2.4 MB build recipe
under round1_source/ (see its PROVENANCE.md) — deliberately the recipe and
not the 288 MB artefact it produces.
| if you have | read |
|---|---|
| five minutes, and no interest in films | docs/BROKEN-INSTRUMENTS.md — twenty-six cases of a check that passed while the thing it guarded was broken. Written for a reader who knows nothing about this project. |
| ten minutes | docs/READING-LIST.md — sixty entries out of ~1,300, each with a line on why it is worth opening. There is a ten-minute list at the top. |
| an afternoon | docs/README.md — how the engineering log is organised, which documents are live and which are historical, and a glossary. |
| to know how big this thing is | docs/SCALE.md — the film in measured triangles: the four definitions, the four census layers, the per-module breakdown, the render settings and the GPU bill. Every figure with its source line. |
| to find one specific thing | docs/INDEX.md — every file in docs/, one line each. |
| twenty seconds and a terminal | Run something, below. |
Not the film. docs/BROKEN-INSTRUMENTS.md — a catalogue of this project's
own checks that reported success while the thing they guarded was broken. One
failure, found twenty-six times, in subsystems that share no code and were
written weeks apart:
A guard, gate, metric or report returned the same answer whether the defect it existed to catch was present or absent.
Three of the cases, to show the shape:
- A limiter reported 0.124 dB of gain reduction while removing about 22 dB (§IV.1). The measurement was taken correctly and then overwritten by the code's own arithmetic four lines later. The project read −0.124, declared the limiter innocent, and went looking elsewhere.
- A quality gate whose best possible score was silence (§II.1). Every gate in the audio suite was relative — ratios, spans, correlations — so digital silence scored perfectly on all of them. A tuning loop walked downhill towards a better score and arrived: the delivered passage measured 26.4 dB SPL with 0 of 29 third-octave bands above the threshold of hearing. It was caught by a listener, not by an instrument.
- A gate suite that passed a two-second block of audio tiled 16.5 times
(§I.1). Eight gates, all green,
ALL_PASS = True, on 33 seconds of literal loop. Three of the eight never opened the file.
The document is grouped by mechanism rather than by subsystem, because the mechanism is the transferable part, and it ends with a Corrections section retracting two claims that had circulated in this project as folklore and did not survive being checked against their sources.
Most repositories do not ship this. This one leads with it: an append-only log of ~1,300 numbered entries that records what was tried, what was measured, and what turned out to be wrong — including entries that retract their own author's published findings, and one that retracts a retraction.
Nothing here needs the film, the render farm or the 545 GB of gitignored
artefacts. There are 45 item modules under world/items/, and 27 of them carry
a selftest — which is the interesting part, because it builds the geometry,
measures it, and prints what it measured rather than a green tick.
blender -b -noaudio -P world/items/armco_post.py -- --selftestAbout 20 seconds on a laptop, no GPU required. It builds 3,236 crash-barrier posts and then argues with them:
3236 distinct post specifications over 3236 posts; 0 exact duplicates
naive [tangent, normal, up]: 1685 of 3236 records are LEFT-handed (det = -1)
`_world_frame`: det min 1.000000 max 1.000000; 0 left-handed
LOD0: 69547 tris/post edge p10 0.687 mm = 0.99 px
SELFTEST PASSED
Twenty-seven of the 45 item modules carry --selftest. All 27 were run on
2026-08-18 and the results are in docs/QUICKSTART.md,
untidied: 20 pass, 5 fail, and 2 are neither. The failures are the useful
rows — each is a disagreement with a manifest or another module, stated in
metres or in slots, which is more informative than a pass. And one module runs
its selftest, exits 0, and prints nothing at all: no checks ran. That is this
repository's founding defect, found live while writing the page that describes
it.
The world is assembled, not modelled. Each module owns a slice of the scene and knows nothing about the others except through a contract:
world/world_contract.py |
ownership rules — who is allowed to create what |
world/build_terrain.py, build_surface.py |
ground, sward, asphalt and its relief |
world/build_architecture.py, build_barriers.py |
showroom, pit buildings, armco, catch fence |
world/build_dressing.py, build_nearband.py |
scatter and the detail band nearest camera |
world/build_sky.py, showroom_lighting.py, film_exposure.py |
light and grade |
world/items/ |
~45 individually-gated item modules (trees, masts, seating, …) |
world/build_items.py |
places items, and refuses to run on any item lacking an accepted gate verdict |
sim/ |
the breach: fracture, debris, ride pose, contact |
audio/ |
engine, chain, glass and master — synthesised, never sampled |
Assembly runs every module into one scene and saves a single .blend:
blender -b -noaudio -P render/world/assembly/r2/assemble.py -- --out assembly.blendrender/world/assembly/r2/SHIPPING.md records which assembly is the shipping
world and why it was promoted. That file matters more than it looks: the film
build appends the car and props onto a prebuilt world and does not rebuild it,
so a landed change to a world module reaches no frame until assemble.py is run
again. The staleness warning it prints is not a refusal.
Never straight to 4K. docs/RENDER-LADDER.md sets out
the rule and the reason: stills and sequences catch different defect
classes. A 4K still shows you a material reading as plastic; only a sequence
shows flicker, popping shadows, sim jitter, camera-path kinks, speed-ramp
stutter, or a seam where two machines rendered adjacent ranges. So work climbs
the ladder — 720p and 1080p sequences, stripped to frames and inspected — and 4K
is the last rung, not the first.
The master itself was not rendered locally, and could not have been:
| full 4K master | three rented RTX 5090s, launched 2026-08-09 ~04:30Z, 2,978/2,978 frames on disk 2026-08-13 05:45Z — about 97 h wall clock against a projection of ~84 h — for $132.57 against a $150 ceiling |
| one 4K frame | minutes, not seconds; a local 8 GB card cannot hold one in a single pass |
| rung 1 (1280×720, 64 spp) | cheap enough to iterate on, and explicitly not able to adjudicate a delivery-spec question |
| an item selftest | ~20–60 s, CPU only |
Frame ranges were dispatched to the rented GPUs by the broker in the companion
repository, vast-render — it rents instances on vast.ai,
ships the assembled .blend, renders ranges, fetches frames, verifies them and
tears the fleet down. If you intend to reproduce the film rather than read about
it, you need that repository and a funded vast.ai account.
docs/MASTER-RUNBOOK.md is the record of the run —
what had to be true, what it cost, and what was checked at each retirement.
Nothing here makes a 4K master cheap. This repository does not include the rendered frames or the delivered master; both are far too large and are regenerable from what is here.
The recurring failure this project kept finding is not a bad render. It is a check that passes without having measured anything. Several things follow from that, and they are the actual engineering content of the repository:
- Gate verdicts are records, not artefacts.
render/items/*/gate.jsonis the verdict of the run that accepted the geometry that shipped. Re-running the gate cannot restore it; it can only produce a different verdict with the same filename. That is why 33 of them are tracked here while everything else underrender/is ignored. - A gate must be able to fail. The battery under
render/world/assembly/r2/ships control scenes alongside the probes, so a probe that would pass anything is caught by a control it should have rejected. - Measuring the film against itself proves nothing. Several gates passed worlds that were days behind their own generators, because every one of them measured the built scene rather than the sources it came from.
- A convention is not a rule. The 11.25 GB delivery master sat untracked with
nothing but "never
git add -A" protecting it, until an ignore rule replaced the convention.
tools/ holds ~250 single-purpose probes and A/B rigs written for individual
defects. They are kept rather than deleted because the measurement is the
evidence for the fix.
docs/DEFECT-LOG-R2.md is the largest thing in this
repository and the reason it is worth publishing. 67,640 lines, 1,316 entry
headings, 1,295 distinct numbered entries (R2-001 … R2-4255), written as the
work happened. (Measured 2026-08-18; the log is append-only and grows.)
It is not a changelog. Each entry records what was believed, what was measured, and what the measurement turned out to mean — including the many cases where the first diagnosis was wrong and the entry says so. The genuinely instructive entries are the ones where a fix that was verified turned out not to be in the shipped output at all, where a gate was found to have never run on the world that renders, and where a resource limit was found wearing the costume of a verdict about the work.
Do not start at line 1. Start with docs/READING-LIST.md.
The commit history reads the same way, and deliberately: commit subjects state the finding, not the file that changed.
Related documents: docs/MASTER-PLAN.md (the plan),
docs/THE-BRIEF-ROUND2.md (the original brief and
its laws), docs/MASTER-RUNBOOK.md (the master
render), watch/INDEX.md (what was reviewed and what was concluded).
- Blender 5.2.0 LTS. Not "5.x" — the project pins this version and the broker installs exactly it on rented instances, because a scene must be rendered by the build that assembled it.
- Python 3.14 for the standalone tools in
tools/. Scripts run inside Blender use Blender's own interpreter, not this one. numpy,scipy,soundfilefor the audio modules, in whichever interpreter runs them. There is norequirements.txtand no packaging; nothing here is installable as a package and everything is run as a script.- An NVIDIA GPU for Cycles/OptiX if you want pictures. Selftests and the audio synthesis do not need one.
ffmpegfor encoding, if you want a video rather than frames.
Stated plainly rather than discovered later:
- Paths assume the repository sits at
~/f1-round2. 135 Python files and 64 shell scripts used to carry the author's absolute home directory. They now useos.path.expanduser("~/f1-round2/…")in Python and$HOME/f1-round2/…in shell, so a clone into~/f1-round2runs unchanged and a clone anywhere else does not. There is still no configuration layer; there is now a convention, and it is one line to see:grep -rn 'expanduser("~/f1-round2' tools/. Records underdocs/,render/andaudio/out/quote the same paths repo-relative, which is what you want when reading a verdict. - The rendered outputs are not here.
render/,work/,world/bakes andwatch/are gitignored — several hundred gigabytes of blends, frames, caches and the delivered master. The repository is source and reasoning only. - Some tooling is not committed. A number of one-off probes under
tools/,sim/andworld/items/, and tendocs/STAGING-*.mdfiles, exist on the authoring machine and are not in the repository. Of the entry IDs in those staging files, all but one (R2-1661) were already merged intodocs/DEFECT-LOG-R2.md, so the loss is one entry rather than ten files' worth — measured, not assumed. - Some selftests fail here. See
docs/QUICKSTART.mdfor which, and why that is left visible rather than tidied away.
The .gitignore is heavily commented and those comments are load-bearing —
read them before simplifying anything. The short version is in its header:
version control was added on 2026-08-03 after an edit truncated a 1,655-line
reference document to 538 lines with no backup and no way to recover it. The
lost sections are still lost.
So the rule is: track the source and the reasoning; do not track the
artefacts. Everything large and regenerable is ignored. Where real,
hand-written source turned out to be sitting inside an ignored directory — the
gate battery in render/, the film bar's two measurement probes in work/,
the item gate verdicts — it is re-included one directory at a time, and each of
those blocks carries the incident that motivated it.
See CONTRIBUTING.md. The short version: the append-only log
is the house style, corrections are appended rather than applied in place, and
a change that fixes a defect should say how the fix was measured.
There is one thing to do before your first commit — set a noreply git identity:
git config user.email 'ID+username@users.noreply.github.com'
git config user.name 'Your Name'This is local configuration only, and it changes nothing already committed. The
existing history carries personal addresses on most of its ~640 commits
(git rev-list --count HEAD).
Rewriting it is a live option and is the owner's decision: measured against this
repository's object store, the documentation cites 83 distinct commit SHAs in
218 places, all of which a rewrite would de-reference. (An earlier figure of
"~4,100 SHAs" circulated in this repository and was wrong — 4,100 is the scale of
the R2-NNNN entry-ID citations, which a history rewrite does not touch at
all. The correction is recorded in
docs/PUBLICATION-AUDIT.md §6.)
Before publishing, re-run tools/publication/sanitise_docs.py. Its README says
why "once, and then trusted" is not good enough for a corpus that is still
moving.
Three kinds of work live here and they are licensed differently.
LICENSE is the authority; this is the summary.
| Code | GPL-3.0-or-later — world/, tools/, sim/, audio/, render/, anim/, telemetry/, work/, round1_source/, and every .py / .sh / build-input .json wherever it sits |
| Documentation | CC BY-SA 4.0 — docs/, README.md, round2_inventory.md, watch/*.md, and the .md files beside the modules they describe. Full text in LICENSE-DOCS. |
| The film and its audio | all rights reserved, not licensed for reuse — watch/*.mov, watch/*.mp4, the rendered frames, the masters under audio/out/. They are gitignored and are not published with this repository. |
Why GPL and not something permissive. Not a preference. Blender is GPL, and
the Blender Foundation's stated position is that publicly distributed scripts
using the bpy API are derivative works of Blender and must be GPL-compatible.
Nearly everything here is bpy code. Worth being precise about the strength of
the claim: this is the Foundation's stated interpretation, not settled case law —
it is adopted because it is the conservative reading, and because being wrong in
the other direction is the more expensive mistake.
Why the film is called out separately. So that nobody infers a grant from silence. A licence file that covered "everything in the repository" would be read, wrongly, as covering the film if a copy ever travelled alongside it. Renders you make by running this code are yours.
Individual source files do not carry per-file licence headers. LICENSE
section 1 names the covered directories and file types explicitly, and is the
authority for any file that does not say otherwise.
The owner can change any of this before publishing. These licences were applied so the repository would not go public in the no-licence, therefore all-rights-reserved default that makes public code unusable. After the first public copy the position is asymmetric: future versions can be relicensed, copies already released cannot be recalled.