From 987f19e0516f9c48f1786549b4c2ff2e5fc0bf62 Mon Sep 17 00:00:00 2001 From: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Date: Sat, 26 Sep 2026 21:51:32 -0400 Subject: [PATCH] feat(examples): add gn-sim-fountain Witness the Simulation Zone frame contract: stepped frames land on the closed-form ballistic arc, an unbaked frame_set(N) jump runs one step, and calculate_to_frame is PASS_THROUGH headless. Only a bake gives random access. Identical on 4.5, 5.1 and 5.2. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> --- .cursor-plugin/plugin.json | 1 + AGENTS.md | 4 +- CLAUDE.md | 6 +- README.md | 25 +- ROADMAP.md | 5 +- docs/gallery/assets/gn-sim-fountain-hero.webp | Bin 0 -> 56000 bytes .../gn-sim-fountain-contact-sheet.webp | Bin 0 -> 55190 bytes docs/gallery/gn-sim-fountain/index.html | 1008 +++++++++++++++++ docs/gallery/index.html | 15 +- docs/new-example-prompt.md | 2 +- examples/gallery.json | 12 + examples/gn-sim-fountain/README.md | 109 ++ examples/gn-sim-fountain/gn_sim_fountain.py | 657 +++++++++++ examples/gn-sim-fountain/preview.webp | Bin 0 -> 51988 bytes tests/smoke/catalog.json | 1 + 15 files changed, 1832 insertions(+), 13 deletions(-) create mode 100644 docs/gallery/assets/gn-sim-fountain-hero.webp create mode 100644 docs/gallery/contact-sheets/gn-sim-fountain-contact-sheet.webp create mode 100644 docs/gallery/gn-sim-fountain/index.html create mode 100644 examples/gn-sim-fountain/README.md create mode 100644 examples/gn-sim-fountain/gn_sim_fountain.py create mode 100644 examples/gn-sim-fountain/preview.webp diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index dd5ab8b6..d8d67591 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -102,6 +102,7 @@ "examples/gn-instance-grid", "examples/gn-modifier-inputs", "examples/gn-sdf-remesh", + "examples/gn-sim-fountain", "examples/gn-socket-rename", "examples/gn-zone-iterate", "examples/gp-lineart-contour", diff --git a/AGENTS.md b/AGENTS.md index abd6ad9f..932613b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker classifies it as a `cursor-plugin`. This is content the AI loads when the user asks Blender questions or works on Blender add-ons in Cursor or Claude Code. -The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 59 +The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 60 examples, and 26 showcase pieces (counts are CI-enforced against README.md) and the manifest). The full inventory tables and per-item purposes live in `CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`; @@ -36,7 +36,7 @@ Blender-Developer-Tools/ rules/.mdc # 9 rule files templates// # 3 starter templates snippets/.py # 27 standalone Python snippets - examples// # 59 runnable smoke-gated examples (+ gallery.json) + examples// # 60 runnable smoke-gated examples (+ gallery.json) examples/gallery_framing.py # shared Layer 1 framing measurement (render path only) showcase// # budget-conformance props (sibling of examples/) showcase/gallery.json # this tree's gallery index; merged into docs/gallery/ diff --git a/CLAUDE.md b/CLAUDE.md index 806d916a..872a397b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,7 +21,7 @@ skills//SKILL.md - AI workflow definitions, 16 total rules/.mdc - Anti-pattern rules, 9 total templates// - Starter projects, 3 total snippets/.py - Standalone code patterns, 27 total -examples// - Runnable smoke-gated examples, 59 total (+ gallery.json) +examples// - Runnable smoke-gated examples, 60 total (+ gallery.json) showcase// - Budget-conformance props, 36 pieces (sibling of examples/; see showcase/README.md) scripts/build_gallery.py - Regenerates docs/gallery/ from examples/gallery.json + showcase/gallery.json scripts/site/ - Vendored landing-page build (Jinja2) @@ -104,12 +104,12 @@ v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namesp AI asset pipeline track: `decimate_to_budget.py`, `convex_hull_collider.py`, `lod_chain.py` (helper duplicated, not imported), `gltf_draco_export.py`, `export_preset_unity.py`, `export_preset_godot.py`, `export_preset_unreal.py`, `setup_bake_target_image.py`, `bake_normal_high_to_low.py`, `save_baked_image.py`. -## Examples (59) +## Examples (60) Runnable scripts at `examples//`, each asserting a real API contract with deterministic checks (exit non-zero on failure) and optionally rendering a still via `--output`. All of them run headless on Blender 5.2 LTS and 4.5 LTS in `blender-smoke.yml` (5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch); -**51 of the 59 ship a render in the site gallery** at `docs/gallery/`. The other +**52 of the 60 ship a render in the site gallery** at `docs/gallery/`. The other eight are **check-only**: they carry no `--output` path, no gallery entry, and no hero asset. The criterion is whether the contract is expressible in pixels. An example is check-only when its witness is a data or state fact that no scene diff --git a/README.md b/README.md index 8768cd0d..4eb3398d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@

- 16 skills  •  9 rules  •  3 templates  •  27 snippets  •  59 examples  •  36 showcase pieces + 16 skills  •  9 rules  •  3 templates  •  27 snippets  •  60 examples  •  36 showcase pieces

@@ -37,7 +37,7 @@ ## Overview -This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, 59 examples, and 36 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable. +This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, 60 examples, and 36 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable. The content is consumed by AI coding agents reading these files directly from a checkout — **there is no MCP server in this repository, and none is required**. Cursor applies `rules/*.mdc` automatically wherever their scope globs match and takes skills by name in chat; Claude Code reads `skills/` and `rules/` from the project workspace, or from this repo kept as a referenced checkout. Any agent that can read files in a workspace can use it the same way. There is no build step for the content — edit the Markdown and Python files directly. @@ -75,7 +75,7 @@ blender --background --python examples/bmesh-gear/bmesh_gear.py -- ## Falsifiers -Every one of the 59 examples carries a **falsifier**: a flag that changes the +Every one of the 60 examples carries a **falsifier**: a flag that changes the input so a real assertion fails. It never disables the assertion, skips the check, or short-circuits to an error — it feeds the script something the contract says must not pass, and the same check that guards the happy path @@ -556,7 +556,7 @@ exits 0 on all three. `--assume-present` is red only on 5.2.

-Geometry Nodes — 6 examples +Geometry Nodes — 7 examples @@ -617,6 +617,23 @@ evaluated cubes against closed forms — Repeat `8×(1+N)` with X-centers at nodes exist. Unpaired evaluates empty; For Each's main Geometry socket is a passthrough. + + + + + diff --git a/ROADMAP.md b/ROADMAP.md index 8f51d315..4a5b3c2f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -176,7 +176,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo - **Flagship showcase: pirate sloop** — lofted hull from stations, deck planking, mast, boom, gaff, shrouds and ratlines to chainplates, cannon ports: hull mirror-symmetric to the keel plane, every shroud terminating on its chainplate and masthead within a band, ratlines horizontal and evenly spaced - **Flagship showcase: full chess set on a board** — 32 lathe-turned pieces (king to pawn, two woods) on an inlaid board: every piece centred on its square's computed centre, base seated on the board, lathe profiles revolved exactly (radii match profile closed form), 64 squares alternating by (file + rank) parity - **Flagship showcase: modular dungeon kit** — floor, wall, corner, arch, stair and pillar tiles on a 2 m grid composed into a room: every open-edge boundary vert on the grid, zero gap/overlap at every joint, stair riser × count equal to one storey height, per-tile budgets plus a composed-room budget -- **Flagship example: GN simulation-zone ballistic fountain** — a Simulation Zone integrating particles under gravity: positions at frame N match the closed-form ballistic arc (p₀ + v₀t − ½gt²) per particle, determinism across re-bakes, and the 4.x vs 5.x bake/cache API paths documented; `--no-cache-reset` falsifier +- ~~**Flagship example: GN simulation-zone ballistic fountain**~~ **SHIPPED** as `examples/gn-sim-fountain/` — 20 jets integrated by the exact constant-g update land on p₀ + v₀t − ½gt² every stepped frame; an unbaked `frame_set(N)` jump runs one step, `calculate_to_frame` is PASS_THROUGH headless, only a bake gives random access. The 4.x vs 5.x divergence the entry anticipated does not exist: zone and bake operators measured identical on 4.5.11, 5.1.2 and 5.2.1. Falsifiers `--unpair` / `--euler` / `--prebake-trap` / `--calc-to-frame` replace the proposed `--no-cache-reset`, which had no failing check to target - **Flagship example: GN procedural building generator** — one node tree with floor count, bay count and roof type as modifier inputs driving storeys, windows (instanced), cornices and a pitched or flat roof: window instance count = floors × bays × faces closed-form, storey heights exact, three buildings from the same tree side by side - **Flagship example: GN road along a curve** — a Bezier path swept into a road with kerbs, lane markings and lamp posts instanced at equal arc-length spacing aligned to the tangent: post count = floor(length / spacing) + 1, every post perpendicular to the curve tangent within a band - **Flagship example: L-system tree via GN repeat zone** — branching generated by a Repeat Zone: branch/leaf counts closed-form in the iteration depth, each child branch attached to its parent's tip, total height the closed-form series sum @@ -184,6 +184,9 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo - **Flagship example: channel-packed ORM bake** — Cycles-bake AO, roughness and metallic of a prop into R/G/B of one Non-Color image: each channel matches its independently baked single-channel reference within a stated tolerance, and sRGB tagging is the falsifier - **Flagship example: Cryptomatte ID witness** — a multi-object scene rendered with Cryptomatte passes to multilayer EXR: decoded object IDs (MurmurHash3 of the names) cover exactly each object's coverage mask, re-read with the stdlib-only EXR reader - **Flagship example: walk cycle with planted feet** — slotted-action walk cycle on a leg rig with IK and NLA strip blending: planted-foot world position constant during each contact phase (foot slide below a band), stride length × cycles equals root travel, 4.5 vs 5.x channelbag paths +- Simulation-zone cache interpolation witness — frames between two cached simulation frames read as a linear interpolation of the endpoints (measured: steps 1.27 at frame 4 between cached 1 and 12), not a simulated state; assert the interpolant closed form and that a bake removes it (found authoring `gn-sim-fountain`) +- Operator PASS_THROUGH trap snippet — an operator whose poll fails headless (`simulation_nodes_cache_calculate_to_frame`) logs "Invalid operator call" and returns `{'PASS_THROUGH'}` without raising; check the returned set, never assume a non-raising `bpy.ops` call ran (found authoring `gn-sim-fountain`) +- Simulation-zone substeps witness — a Repeat Zone inside the Simulation Zone splitting Delta Time into k substeps: explicit Euler error shrinks exactly by 1/k against the closed-form arc, the exact update is invariant in k - ~~Small modular kit showcase on recognizable geometry (`modular-kit-snap` contract)~~ **SHIPPED** as `showcase/fence-kit/` — tiling post-and-rail section (AABB X is the tile width; does not re-witness the snap contract); `--skip-decimate` exits 9 on the LOD1 ratio band - ~~Custom ID-property delete witness~~ **SHIPPED** as `examples/cross-version-property-delete/` — IDs built via `bpy.data.objects.new` (not `active_object`); `property_unset` is TypeError and leaves the key; `del` removes it on 4.5 LTS and 5.x diff --git a/docs/gallery/assets/gn-sim-fountain-hero.webp b/docs/gallery/assets/gn-sim-fountain-hero.webp new file mode 100644 index 0000000000000000000000000000000000000000..cc2d7e9221aaa82beeebe61550489664f8813692 GIT binary patch literal 56000 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 VJC7594V1TfLXdzDmbg;5008GPS-t=O literal 0 HcmV?d00001 diff --git a/docs/gallery/contact-sheets/gn-sim-fountain-contact-sheet.webp b/docs/gallery/contact-sheets/gn-sim-fountain-contact-sheet.webp new file mode 100644 index 0000000000000000000000000000000000000000..a63e187cdc6fdca81a2ea8cae58152e245704674 GIT binary patch literal 55190 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 + + + + + gn-sim-fountain — Examples — Blender Developer Tools + + + + + + + + + + + + + + + + + + + + + + + + +
+

gn-sim-fountain

+

A Simulation Zone only advances one step per consecutive frame_set. A direct jump to frame N runs a single step, and only a bake gives random access to the stepped state.

+
+
+ +

Rendered headless by the example itself — click to zoom.

+
witnesses 24 stepped frames match p0 + v0 t - g t^2/2 within 6.6e-7 m. An unbaked jump 1->25 runs one step and sits 1.68-2.42 m off the arc; calculate_to_frame returns PASS_THROUGH headless; after a bake, random-access frames match within 5.6e-7 m.
+
+
blender --background --python examples/gn-sim-fountain/gn_sim_fountain.py --
+ +
+
+

A two-tier stone fountain whose twenty jets are integrated by a Simulation Zone, witnessing the geometry-nodes-python frame contract: a Simulation Zone only advances when the scene steps one frame at a time. The evaluated state at frame N is not a function of N. AI code that calls scene.frame_set(N) and reads positions gets a silently wrong answer.

+

Each droplet is a point with a vel attribute. Per step the zone applies the constant-gravity update that is exact for any dt:

+
p += v*dt - 0.5*g*dt^2 * z
+v -= g*dt * z
+

so at frame f every point must lie on the closed-form ballistic arc p0 + v0*t - 0.5*g*t^2*z and carry v0 - g*t*z, with t = (f - frame_start) / fps. The check recomputes both from the launch data (8 crown jets thrown up and out, 12 rim jets arcing inward; g = 9.81, 24 fps, 24 steps = 1.0 s).

+

Measured behavior

+

Identical on 4.5.11 LTS, 5.1.2 and 5.2.1 LTS. The Simulation Zone and its cache/bake operators have not diverged across the three, so there is no version branch; the probes that established this are the checks below.

+
+GN simulation fountain: a two-tier sandstone fountain whose twenty jets are strings of cyan droplet beads, each bead a stepped Simulation Zone position threaded on its thin closed-form ballistic arc + + +### [gn-sim-fountain](examples/gn-sim-fountain/) + +A Simulation Zone integrates twenty jets under gravity with the exact +constant-g update, and every stepped frame lands on `p0 + v0 t - g t^2/2` +(worst 6.6e-7 m). Two silent traps, identical on 4.5, 5.1 and 5.2: a direct +`frame_set(N)` jump runs one step, not N; and `calculate_to_frame` returns +`PASS_THROUGH` headless and leaves interpolated frames. Only a bake gives +random access. +
Call sequenceWhat the zone does
frame_set(frame_start)body runs once with Delta Time 0 — state reset to the input
frame_set(f) then frame_set(f + 1)one step, dt = 1/fps
frame_set(start) then frame_set(N), no cacheone step, dt = 1/fps: frame N shows the frame-2 state
simulation_nodes_cache_calculate_to_frame(selected=True) headlesspoll fails: logs Invalid operator call, returns {'PASS_THROUGH'}, does not raise; frames between the two cached endpoints then read as a linear interpolation of them
simulation_nodes_cache_bake(selected=True) under temp_overridebakes frame_start..frame_end (PACKED, in memory, no directory); any frame_set order then reads the exact per-frame state
+

Two silent traps, then. The jump is 1.68–2.42 m off the true frame-25 arc here. The tempting cache operator "succeeds" without raising and leaves interpolated garbage between cached frames (2.42 m / 9.40 m/s off).

+

Tolerance. TOL = 1e-4 m and m/s. The state is float32 accumulated over 24 steps; the measured worst case is 6.6e-7 m and 1.4e-6 m/s, so the band is ~150× the observed error and ~2000× below the smallest broken case (Euler, 0.204 m). The trap must also clear TRAP_GAP_FLOOR = 0.25 m from the true arc, so a rounding difference can never pass as the trap.

+

What failure each check would catch:

+
  • exit 3 — the zone is unpaired or drops points: pair_with_output not called evaluates to 0 points (--unpair)
  • exit 4 — the integrator is not the exact constant-gravity update: naive p += v*dt drifts by g*dt*t/2, 0.2044 m at t = 1 s (--euler)
  • exit 5 — a direct frame jump did not reproduce the one-step trap — e.g. because a bake was already present (--prebake-trap). This is what keeps the trap claim above honest on every version CI runs
  • exit 6 — random-access reads after a cache fill miss the arc, or the fill operator did not return FINISHED: calculate_to_frame headless (--calc-to-frame)
+

The render is the proof. Every droplet bead in the still is a recorded simulated position from the stepped run (check 4). The thin line each string of beads is threaded on is the closed-form arc, drawn from the launch data, not from the simulation. A drifting integrator would pull the late beads off their line — by 0.20 m at the pool for --euler, as check 4 measures (that flag exits before rendering, so this is computed, not a rendered still).

+

Run

+
blender --background --python gn_sim_fountain.py --
+blender --background --python gn_sim_fountain.py -- --output fountain.png
+

The --output render path measures framing via examples/gallery_framing.py (exit 10 on violation).

+

Falsifiers

+

Each breaks one thing and exits the code of the check it targets, on all three versions.

+
FlagBreaksTarget checkExit
--unpairSimulation Input never paired with its Outputzone evaluates one point per jet3
--eulerdrops the -0.5*g*dt^2 position termstepped frames on the closed-form arc4
--prebake-trapbakes before the direct jumpunbaked jump runs exactly one step5
--calc-to-framefills the cache with calculate_to_frame, not a bakebaked random access on the arc6
+

Exit codes

+

Per-script sequential checks. 10 is the shared framing helper.

+
CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Point count or frame-start state off the launch data
4Stepped frames off the closed-form arc (position or velocity)
5Direct jump did not reproduce the one-step trap
6After the cache fill, random-access frames off the arc (or fill not FINISHED)
10Gallery framing violation
12--output produced no file
+

The blender-smoke workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the needs-5.1 PR label, or manual dispatch). Smoke does not pass --output or any falsifier.

+ +
+

Source

+
+ examples/gn-sim-fountain/gn_sim_fountain.py + View on GitHub → +
+
"""Geometry Nodes Simulation Zone ballistic fountain — a runnable example.
+
+Witnesses the Simulation Zone frame contract from
+``skills/geometry-nodes-python``. A zone integrates state only when the
+scene advances one frame at a time; the evaluated result at frame N is not a
+function of N. AI code that sets ``scene.frame_set(N)`` and reads positions
+gets a silently wrong answer.
+
+Each jet's droplet is a point carrying a ``vel`` attribute. Per step the zone
+applies the constant-gravity update that is exact for any ``dt``::
+
+    p += v*dt - 0.5*g*dt^2 * z
+    v -= g*dt * z
+
+so at frame f every point must sit on the closed-form ballistic arc
+``p0 + v0*t - 0.5*g*t^2*z`` with ``t = (f - frame_start) / fps``, and carry
+``v0 - g*t*z``. The check recomputes both from the launch data.
+
+Measured identically on 4.5.11 LTS, 5.1.2 and 5.2.1 LTS (the API has not
+diverged across the three):
+
+* At ``frame_start`` the zone body runs once with Delta Time 0 (state reset).
+* Each consecutive ``frame_set(f + 1)`` runs one step with dt = 1/fps.
+* A forward jump ``frame_set(start)`` -> ``frame_set(N)`` with no cache runs
+  exactly ONE step with dt = 1/fps. Frame N shows the frame-2 state.
+* ``bpy.ops.object.simulation_nodes_cache_calculate_to_frame`` fails its poll
+  headless: it logs "Invalid operator call", returns ``{'PASS_THROUGH'}``
+  without raising, and frames between the two cached endpoints then read as
+  a linear interpolation of them — a second silent wrong answer.
+* ``bpy.ops.object.simulation_nodes_cache_bake(selected=True)`` under
+  ``temp_override`` bakes the frame range (PACKED, in memory, no directory)
+  and random-access ``frame_set`` then returns the exact per-frame state.
+
+By default it runs only the correctness check (no render) — the CI smoke
+check. Pass --output to also render a still:
+
+    blender --background --python gn_sim_fountain.py --
+    blender --background --python gn_sim_fountain.py -- --euler          # exit 4
+    blender --background --python gn_sim_fountain.py -- --output f.png
+"""
+import bpy, bmesh, sys, os, math, argparse
+from mathutils import Vector, Matrix
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
+sys.dont_write_bytecode = True  # keep examples/__pycache__ out of the repo tree
+import gallery_framing
+
+G = 9.81
+FPS = 24
+FRAME_START = 1
+STEPS = 24                       # 1.0 s of flight, frame 1 -> frame 25
+FRAME_END = FRAME_START + STEPS
+# float32 state accumulated over STEPS updates: measured worst 2e-6 m (see README)
+TOL = 1e-4
+# the jump trap must be unmistakable, not a rounding difference
+TRAP_GAP_FLOOR = 0.25
+# random-access order for the baked read: backwards, forwards, repeats
+SCRAMBLED = (FRAME_END, 7, FRAME_START + 1, 19, 12, FRAME_END, 3)
+
+# Jets: (count, launch radius, launch height, radial speed, vertical speed).
+# The crown throws up and out; the rim jets arc inward.
+CROWN = (8, 0.09, 1.52, 0.80, 3.55)
+RIM = (12, 1.52, 0.50, -1.30, 2.95)
+WATER_Z = 0.36                  # render only: droplets below the water are hidden
+
+
+def jets():
+    """Launch positions and velocities, crown first then rim."""
+    out = []
+    for count, radius, height, v_r, v_z in (CROWN, RIM):
+        phase = 0.0 if count == CROWN[0] else math.pi / count
+        for i in range(count):
+            a = phase + 2 * math.pi * i / count
+            d = Vector((math.cos(a), math.sin(a), 0.0))
+            out.append((d * radius + Vector((0.0, 0.0, height)), d * v_r + Vector((0.0, 0.0, v_z))))
+    return out
+
+
+def closed_form(p0, v0, t):
+    return (p0 + v0 * t + Vector((0.0, 0.0, -0.5 * G * t * t)),
+            v0 + Vector((0.0, 0.0, -G * t)))
+
+
+def build_tree(pair=True, euler=False):
+    tree = bpy.data.node_groups.new("BallisticSim", "GeometryNodeTree")
+    tree.interface.new_socket(name="Geometry", in_out="INPUT", socket_type="NodeSocketGeometry")
+    tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry")
+    nodes, links = tree.nodes, tree.links
+    gi = nodes.new("NodeGroupInput")
+    go = nodes.new("NodeGroupOutput")
+    sin = nodes.new("GeometryNodeSimulationInput")
+    sout = nodes.new("GeometryNodeSimulationOutput")
+    if not pair:
+        # Unpaired Simulation Input has no Geometry socket. Leave the output
+        # empty so evaluation cannot silently pass the emitter through.
+        return tree
+    if not sin.pair_with_output(sout):
+        raise RuntimeError("SimulationInput.pair_with_output failed")
+
+    pos = nodes.new("GeometryNodeInputPosition")
+    vel = nodes.new("GeometryNodeInputNamedAttribute")
+    vel.data_type = "FLOAT_VECTOR"
+    vel.inputs["Name"].default_value = "vel"
+    dt = sin.outputs["Delta Time"]
+
+    # p + v*dt (- 0.5*g*dt^2 on z unless --euler)
+    v_dt = nodes.new("ShaderNodeVectorMath")
+    v_dt.operation = "SCALE"
+    links.new(vel.outputs["Attribute"], v_dt.inputs[0])
+    links.new(dt, v_dt.inputs["Scale"])
+    new_pos = nodes.new("ShaderNodeVectorMath")
+    new_pos.operation = "ADD"
+    links.new(pos.outputs["Position"], new_pos.inputs[0])
+    links.new(v_dt.outputs["Vector"], new_pos.inputs[1])
+    pos_out = new_pos.outputs["Vector"]
+    if not euler:
+        dt2 = nodes.new("ShaderNodeMath")
+        dt2.operation = "MULTIPLY"
+        links.new(dt, dt2.inputs[0])
+        links.new(dt, dt2.inputs[1])
+        half_g = nodes.new("ShaderNodeMath")
+        half_g.operation = "MULTIPLY"
+        half_g.inputs[1].default_value = -0.5 * G
+        links.new(dt2.outputs["Value"], half_g.inputs[0])
+        drop = nodes.new("ShaderNodeCombineXYZ")
+        links.new(half_g.outputs["Value"], drop.inputs["Z"])
+        with_drop = nodes.new("ShaderNodeVectorMath")
+        with_drop.operation = "ADD"
+        links.new(pos_out, with_drop.inputs[0])
+        links.new(drop.outputs["Vector"], with_drop.inputs[1])
+        pos_out = with_drop.outputs["Vector"]
+
+    # v - g*dt on z
+    g_dt = nodes.new("ShaderNodeMath")
+    g_dt.operation = "MULTIPLY"
+    g_dt.inputs[1].default_value = -G
+    links.new(dt, g_dt.inputs[0])
+    dv = nodes.new("ShaderNodeCombineXYZ")
+    links.new(g_dt.outputs["Value"], dv.inputs["Z"])
+    new_vel = nodes.new("ShaderNodeVectorMath")
+    new_vel.operation = "ADD"
+    links.new(vel.outputs["Attribute"], new_vel.inputs[0])
+    links.new(dv.outputs["Vector"], new_vel.inputs[1])
+
+    # Set Position first: its field reads the old vel. Storing vel first would
+    # make the position update read the new one.
+    setp = nodes.new("GeometryNodeSetPosition")
+    links.new(sin.outputs["Geometry"], setp.inputs["Geometry"])
+    links.new(pos_out, setp.inputs["Position"])
+    store = nodes.new("GeometryNodeStoreNamedAttribute")
+    store.data_type = "FLOAT_VECTOR"
+    store.domain = "POINT"
+    store.inputs["Name"].default_value = "vel"
+    links.new(setp.outputs["Geometry"], store.inputs["Geometry"])
+    links.new(new_vel.outputs["Vector"], store.inputs["Value"])
+
+    links.new(gi.outputs["Geometry"], sin.inputs["Geometry"])
+    links.new(store.outputs["Geometry"], sout.inputs["Geometry"])
+    links.new(sout.outputs["Geometry"], go.inputs["Geometry"])
+    return tree
+
+
+def build(pair=True, euler=False):
+    bpy.ops.wm.read_factory_settings(use_empty=True)
+    sc = bpy.context.scene
+    sc.render.fps = FPS
+    sc.render.fps_base = 1.0
+    sc.frame_start = FRAME_START
+    sc.frame_end = FRAME_END
+
+    launch = jets()
+    me = bpy.data.meshes.new("Nozzles")
+    me.vertices.add(len(launch))
+    me.vertices.foreach_set("co", [c for p, _ in launch for c in p])
+    attr = me.attributes.new("vel", "FLOAT_VECTOR", "POINT")
+    attr.data.foreach_set("vector", [c for _, v in launch for c in v])
+    ob = bpy.data.objects.new("Droplets", me)
+    sc.collection.objects.link(ob)
+    mod = ob.modifiers.new("Ballistic", "NODES")
+    mod.node_group = build_tree(pair=pair, euler=euler)
+    return ob, launch
+
+
+def read_state(ob):
+    """Evaluated (positions, velocities) of the simulated points."""
+    dg = bpy.context.evaluated_depsgraph_get()
+    ev = ob.evaluated_get(dg)
+    me = ev.to_mesh()
+    try:
+        n = len(me.vertices)
+        co = [0.0] * (3 * n)
+        me.vertices.foreach_get("co", co)
+        vel = [0.0] * (3 * n)
+        a = me.attributes.get("vel")
+        if a is not None and a.domain == "POINT" and n:
+            a.data.foreach_get("vector", vel)
+    finally:
+        ev.to_mesh_clear()
+    pts = [Vector(co[i:i + 3]) for i in range(0, 3 * n, 3)]
+    vels = [Vector(vel[i:i + 3]) for i in range(0, 3 * n, 3)]
+    return pts, vels
+
+
+def worst_error(state, launch, t):
+    pts, vels = state
+    wp = wv = 0.0
+    for (p0, v0), p, v in zip(launch, pts, vels):
+        ep, ev = closed_form(p0, v0, t)
+        wp = max(wp, (p - ep).length)
+        wv = max(wv, (v - ev).length)
+    return wp, wv
+
+
+def t_of(frame):
+    return (frame - FRAME_START) / FPS
+
+
+def select_override(ob):
+    return bpy.context.temp_override(
+        active_object=ob, object=ob, selected_objects=[ob], selected_editable_objects=[ob],
+    )
+
+
+def fill_cache(ob, use_calc_to_frame=False):
+    """Bake the simulation range so any frame reads the stepped state."""
+    sc = bpy.context.scene
+    with select_override(ob):
+        if use_calc_to_frame:
+            # The tempting operator. Its poll fails headless; it returns
+            # PASS_THROUGH without raising and computes nothing.
+            sc.frame_set(FRAME_END)
+            return bpy.ops.object.simulation_nodes_cache_calculate_to_frame(selected=True)
+        return bpy.ops.object.simulation_nodes_cache_bake(selected=True)
+
+
+def delete_cache(ob):
+    with select_override(ob):
+        bpy.ops.object.simulation_nodes_cache_delete(selected=True)
+
+
+def check(ob, launch, prebake_trap=False, calc_to_frame=False):
+    sc = bpy.context.scene
+    n = len(launch)
+
+    # 3 — the paired zone evaluates one point per jet, at rest on the nozzles
+    sc.frame_set(FRAME_START)
+    state = read_state(ob)
+    if len(state[0]) != n:
+        print(f"ERROR: zone evaluated {len(state[0])} points at frame_start, expected {n} "
+              f"(one per jet); an unpaired zone outputs nothing", file=sys.stderr)
+        return 3
+    wp, wv = worst_error(state, launch, 0.0)
+    if wp > TOL or wv > TOL:
+        print(f"ERROR: frame_start state off the launch data by {wp:.2e} m, {wv:.2e} m/s",
+              file=sys.stderr)
+        return 3
+    print(f"frame_start: {n} points on the nozzles (err {wp:.1e} m)")
+
+    # 4 — stepping one frame at a time lands on the closed-form arc every frame
+    trail = [state[0]]
+    worst_p = worst_v = 0.0
+    for f in range(FRAME_START + 1, FRAME_END + 1):
+        sc.frame_set(f)
+        state = read_state(ob)
+        if len(state[0]) != n:
+            print(f"ERROR: frame {f} evaluated {len(state[0])} points, expected {n}", file=sys.stderr)
+            return 4
+        wp, wv = worst_error(state, launch, t_of(f))
+        worst_p, worst_v = max(worst_p, wp), max(worst_v, wv)
+        trail.append(state[0])
+    if worst_p > TOL or worst_v > TOL:
+        print(f"ERROR: stepped frames {FRAME_START}..{FRAME_END} miss p0 + v0 t - g t^2/2 by up to "
+              f"{worst_p:.4f} m and v0 - g t by {worst_v:.4f} m/s (tol {TOL})", file=sys.stderr)
+        return 4
+    print(f"stepped {STEPS} frames: worst position err {worst_p:.2e} m, "
+          f"velocity err {worst_v:.2e} m/s (tol {TOL})")
+
+    # 5 — the trap: a direct jump with no cache runs exactly one step
+    delete_cache(ob)
+    sc.frame_set(FRAME_START)
+    if prebake_trap:
+        fill_cache(ob)
+    sc.frame_set(FRAME_END)
+    state = read_state(ob)
+    one_step_p, _ = worst_error(state, launch, 1.0 / FPS)
+    true_p, _ = worst_error(state, launch, t_of(FRAME_END))
+    gap = min((p - closed_form(p0, v0, t_of(FRAME_END))[0]).length
+              for (p0, v0), p in zip(launch, state[0])) if state[0] else 0.0
+    label = "prebaked" if prebake_trap else "unbaked"
+    print(f"jump {FRAME_START}->{FRAME_END} {label}: off the one-step state by {one_step_p:.2e} m, "
+          f"off the frame-{FRAME_END} arc by {gap:.3f}..{true_p:.3f} m")
+    if one_step_p > TOL or gap < TRAP_GAP_FLOOR:
+        print(f"ERROR: jump did not reproduce the one-step trap (one-step err {one_step_p:.2e} m, "
+              f"min gap to the true arc {gap:.4f} m < {TRAP_GAP_FLOOR})", file=sys.stderr)
+        return 5
+
+    # 6 — the remedy: bake, then any frame in any order reads the stepped state
+    delete_cache(ob)
+    sc.frame_set(FRAME_START)
+    result = fill_cache(ob, use_calc_to_frame=calc_to_frame)
+    print(f"cache fill -> {sorted(result)}")
+    worst_p = worst_v = 0.0
+    for f in SCRAMBLED:
+        sc.frame_set(f)
+        wp, wv = worst_error(read_state(ob), launch, t_of(f))
+        worst_p, worst_v = max(worst_p, wp), max(worst_v, wv)
+    if result != {"FINISHED"} or worst_p > TOL or worst_v > TOL:
+        print(f"ERROR: after cache fill {sorted(result)}, frames {list(SCRAMBLED)} miss the arc by "
+              f"up to {worst_p:.4f} m / {worst_v:.4f} m/s (tol {TOL})", file=sys.stderr)
+        return 6
+    print(f"baked random access {list(SCRAMBLED)}: worst err {worst_p:.2e} m, {worst_v:.2e} m/s")
+    return 0, trail
+
+
+def main():
+    argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
+    p = argparse.ArgumentParser()
+    p.add_argument("--output", default=None)
+    p.add_argument("--engine", default="eevee", choices=("eevee", "cycles"))
+    p.add_argument("--unpair", action="store_true",
+                   help="falsification: Simulation Input never paired with its Output (exit 3)")
+    p.add_argument("--euler", action="store_true",
+                   help="falsification: naive p += v*dt drops the g*dt^2/2 term (exit 4)")
+    p.add_argument("--prebake-trap", action="store_true",
+                   help="falsification: bake before the jump, so the trap cannot show (exit 5)")
+    p.add_argument("--calc-to-frame", action="store_true",
+                   help="falsification: fill the cache with calculate_to_frame, not bake (exit 6)")
+    args = p.parse_args(argv)
+
+    ob, launch = build(pair=not args.unpair, euler=args.euler)
+    result = check(ob, launch, prebake_trap=args.prebake_trap, calc_to_frame=args.calc_to_frame)
+    if isinstance(result, int):
+        return result
+    _, trail = result
+
+    if args.output:
+        rcode = render_still(ob, launch, trail, os.path.abspath(args.output), args.engine)
+        if rcode:
+            return rcode
+        print(f"rendered still {args.output}")
+
+    print("gn-sim-fountain OK")
+    return 0
+
+
+# ---------------------------------------------------------------- render only
+# (r, z) lathe profiles, outside in. Nothing below is read by the check.
+BASIN_PROFILE = [
+    (0.0, 0.0), (2.04, 0.0), (2.04, 0.06), (1.99, 0.085), (1.93, 0.09), (1.91, 0.12),
+    (1.94, 0.15), (1.95, 0.19), (1.92, 0.22), (1.87, 0.23), (1.85, 0.27), (1.84, 0.44),
+    (1.88, 0.47), (1.90, 0.52), (1.87, 0.57), (1.78, 0.59), (1.67, 0.58), (1.61, 0.55),
+    (1.59, 0.50), (1.58, 0.16), (0.0, 0.16),
+]
+PEDESTAL_PROFILE = [
+    (0.0, 0.16), (0.46, 0.16), (0.46, 0.30), (0.40, 0.34), (0.30, 0.40), (0.22, 0.52),
+    (0.18, 0.70), (0.17, 0.95), (0.21, 1.03), (0.24, 1.08), (0.20, 1.12), (0.36, 1.18),
+    (0.56, 1.25), (0.66, 1.30), (0.68, 1.35), (0.64, 1.38), (0.58, 1.37), (0.20, 1.29),
+    (0.0, 1.28),
+]
+SPIRE_PROFILE = [
+    (0.0, 1.28), (0.10, 1.28), (0.10, 1.31), (0.06, 1.36), (0.05, 1.44), (0.075, 1.47),
+    (0.075, 1.50), (0.045, 1.53), (0.0, 1.535),
+]
+BOWL_WATER = (0.60, 1.33)        # radius, height of the upper bowl's water
+DROP_R = 0.030
+ARC_R = 0.0055
+
+
+def lathe(name, profile, steps=96):
+    me = bpy.data.meshes.new(name)
+    bm = bmesh.new()
+    try:
+        verts = [bm.verts.new((r, 0.0, z)) for r, z in profile]
+        edges = [bm.edges.new((a, b)) for a, b in zip(verts, verts[1:])]
+        bmesh.ops.spin(bm, geom=verts + edges, cent=(0.0, 0.0, 0.0), axis=(0.0, 0.0, 1.0),
+                       angle=2 * math.pi, steps=steps, use_merge=True)
+        bmesh.ops.remove_doubles(bm, verts=sorted(bm.verts, key=lambda v: v.index), dist=1e-5)
+        bmesh.ops.recalc_face_normals(bm, faces=list(bm.faces))
+        bm.to_mesh(me)
+    finally:
+        bm.free()
+    me.shade_smooth()
+    ob = bpy.data.objects.new(name, me)
+    bpy.context.scene.collection.objects.link(ob)
+    return ob
+
+
+def disc(name, radius, z, segments=96):
+    me = bpy.data.meshes.new(name)
+    bm = bmesh.new()
+    try:
+        bmesh.ops.create_circle(bm, cap_ends=True, segments=segments, radius=radius)
+        bmesh.ops.translate(bm, verts=list(bm.verts), vec=(0.0, 0.0, z))
+        bm.to_mesh(me)
+    finally:
+        bm.free()
+    ob = bpy.data.objects.new(name, me)
+    bpy.context.scene.collection.objects.link(ob)
+    return ob
+
+
+def droplet_mesh(name, points):
+    """One icosphere per simulated droplet position above the water."""
+    me = bpy.data.meshes.new(name)
+    bm = bmesh.new()
+    try:
+        for p in points:
+            bmesh.ops.create_icosphere(bm, subdivisions=2, radius=DROP_R,
+                                       matrix=Matrix.Translation(p))
+        bm.to_mesh(me)
+    finally:
+        bm.free()
+    me.shade_smooth()
+    ob = bpy.data.objects.new(name, me)
+    bpy.context.scene.collection.objects.link(ob)
+    return ob
+
+
+def arc_curves(name, launch):
+    """The closed-form arcs, drawn from the launch data, not from the sim."""
+    cu = bpy.data.curves.new(name, "CURVE")
+    cu.dimensions = "3D"
+    cu.bevel_depth = ARC_R
+    cu.bevel_resolution = 2
+    for p0, v0 in launch:
+        pts = []
+        t = 0.0
+        while True:
+            p, _ = closed_form(p0, v0, t)
+            if p.z < WATER_Z:
+                break
+            pts.append(p)
+            t += 0.01
+        sp = cu.splines.new("POLY")
+        sp.points.add(len(pts) - 1)
+        sp.points.foreach_set("co", [c for p in pts for c in (p.x, p.y, p.z, 1.0)])
+    ob = bpy.data.objects.new(name, cu)
+    bpy.context.scene.collection.objects.link(ob)
+    return ob
+
+
+def nozzles(name, launch):
+    """Bronze spouts at each rim jet, pointing along its launch velocity."""
+    me = bpy.data.meshes.new(name)
+    bm = bmesh.new()
+    try:
+        for p0, v0 in launch[CROWN[0]:]:
+            d = v0.normalized()
+            rot = d.to_track_quat("Z", "Y").to_matrix().to_4x4()
+            m = Matrix.Translation(p0 - d * 0.075) @ rot
+            bmesh.ops.create_cone(bm, cap_ends=True, segments=16, radius1=0.034,
+                                  radius2=0.020, depth=0.15, matrix=m)
+        bm.to_mesh(me)
+    finally:
+        bm.free()
+    me.shade_smooth()
+    ob = bpy.data.objects.new(name, me)
+    bpy.context.scene.collection.objects.link(ob)
+    return ob
+
+
+def material(name, color, roughness, metallic=0.0, emission=None, strength=0.0,
+             noise_tint=None, bump=0.0, joints=0):
+    mat = bpy.data.materials.new(name)
+    mat.use_nodes = True
+    nt = mat.node_tree
+    bsdf = nt.nodes["Principled BSDF"]
+    bsdf.inputs["Base Color"].default_value = color
+    bsdf.inputs["Roughness"].default_value = roughness
+    bsdf.inputs["Metallic"].default_value = metallic
+    if emission is not None:
+        bsdf.inputs["Emission Color"].default_value = emission
+        bsdf.inputs["Emission Strength"].default_value = strength
+    if noise_tint is not None:
+        # dressed-stone variation: low-frequency tint plus a fine tooling bump
+        noise = nt.nodes.new("ShaderNodeTexNoise")
+        noise.inputs["Scale"].default_value = 4.5
+        noise.inputs["Detail"].default_value = 6.0
+        ramp = nt.nodes.new("ShaderNodeValToRGB")
+        ramp.color_ramp.elements[0].color = noise_tint
+        ramp.color_ramp.elements[1].color = color
+        ramp.color_ramp.elements[0].position = 0.35
+        ramp.color_ramp.elements[1].position = 0.70
+        nt.links.new(noise.outputs["Fac"], ramp.inputs["Fac"])
+        nt.links.new(ramp.outputs["Color"], bsdf.inputs["Base Color"])
+        height = None
+        if bump:
+            fine = nt.nodes.new("ShaderNodeTexNoise")
+            fine.inputs["Scale"].default_value = 60.0
+            height = fine.outputs["Fac"]
+        if joints:
+            # radial block joints: angle about Z, JOINTS blocks per turn, a thin
+            # mortar line where the block fraction wraps
+            coord = nt.nodes.new("ShaderNodeTexCoord")
+            xyz = nt.nodes.new("ShaderNodeSeparateXYZ")
+            nt.links.new(coord.outputs["Object"], xyz.inputs["Vector"])
+            ang = nt.nodes.new("ShaderNodeMath")
+            ang.operation = "ARCTAN2"
+            nt.links.new(xyz.outputs["Y"], ang.inputs[0])
+            nt.links.new(xyz.outputs["X"], ang.inputs[1])
+            per = nt.nodes.new("ShaderNodeMath")
+            per.operation = "MULTIPLY"
+            per.inputs[1].default_value = joints / (2 * math.pi)
+            nt.links.new(ang.outputs["Value"], per.inputs[0])
+            frac = nt.nodes.new("ShaderNodeMath")
+            frac.operation = "PINGPONG"          # 0 at a joint, 0.5 mid-block
+            frac.inputs[1].default_value = 0.5
+            nt.links.new(per.outputs["Value"], frac.inputs[0])
+            line = nt.nodes.new("ShaderNodeMath")
+            line.operation = "LESS_THAN"
+            line.inputs[1].default_value = 0.022
+            nt.links.new(frac.outputs["Value"], line.inputs[0])
+            mortar = nt.nodes.new("ShaderNodeMix")
+            mortar.data_type = "RGBA"
+            mortar.inputs["B"].default_value = (0.16, 0.10, 0.06, 1.0)
+            nt.links.new(line.outputs["Value"], mortar.inputs["Factor"])
+            nt.links.new(ramp.outputs["Color"], mortar.inputs["A"])
+            nt.links.new(mortar.outputs["Result"], bsdf.inputs["Base Color"])
+            if height is not None:
+                recess = nt.nodes.new("ShaderNodeMath")
+                recess.operation = "MULTIPLY_ADD"
+                recess.inputs[1].default_value = -0.6
+                nt.links.new(line.outputs["Value"], recess.inputs[0])
+                nt.links.new(height, recess.inputs[2])
+                height = recess.outputs["Value"]
+        if height is not None:
+            bmp = nt.nodes.new("ShaderNodeBump")
+            bmp.inputs["Strength"].default_value = bump
+            nt.links.new(height, bmp.inputs["Height"])
+            nt.links.new(bmp.outputs["Normal"], bsdf.inputs["Normal"])
+    return mat
+
+
+def eevee_engine_id():
+    return "BLENDER_EEVEE" if bpy.app.version >= (5, 0, 0) else "BLENDER_EEVEE_NEXT"
+
+
+def render_still(ob, launch, trail, path, engine):
+    scene = bpy.context.scene
+    scene.frame_set(FRAME_START)
+    ob.hide_render = True        # the live points; the still shows the recorded trail
+
+    stone = material("Sandstone", (0.70, 0.46, 0.27, 1.0), 0.8,
+                     noise_tint=(0.47, 0.29, 0.16, 1.0), bump=0.22, joints=28)
+    turned = material("TurnedStone", (0.70, 0.46, 0.27, 1.0), 0.72,
+                      noise_tint=(0.47, 0.29, 0.16, 1.0), bump=0.15)
+    bronze = material("Bronze", (0.62, 0.36, 0.15, 1.0), 0.34, metallic=0.9)
+    water = material("Pool", (0.02, 0.16, 0.20, 1.0), 0.32)
+    # a mirror-flat pool reflects the rim light as a pale sheet over the water
+    water.node_tree.nodes["Principled BSDF"].inputs["Specular IOR Level"].default_value = 0.25
+    drop = material("Droplet", (0.45, 0.82, 1.0, 1.0), 0.12,
+                    emission=(0.35, 0.78, 1.0, 1.0), strength=0.9)
+    arc = material("Arc", (0.8, 0.92, 1.0, 1.0), 0.3,
+                   emission=(0.7, 0.88, 1.0, 1.0), strength=0.35)
+
+    basin = lathe("Basin", BASIN_PROFILE)
+    pedestal = lathe("Pedestal", PEDESTAL_PROFILE)
+    basin.data.materials.append(stone)
+    pedestal.data.materials.append(turned)
+    spire = lathe("Spire", SPIRE_PROFILE, steps=48)
+    spire.data.materials.append(bronze)
+    spouts = nozzles("Spouts", launch)
+    spouts.data.materials.append(bronze)
+    pool = disc("Pool", 1.585, WATER_Z)
+    bowl = disc("BowlPool", BOWL_WATER[0], BOWL_WATER[1])
+    for o in (pool, bowl):
+        o.data.materials.append(water)
+    above = [p for frame in trail for p in frame if p.z > WATER_Z + DROP_R * 0.5]
+    drops = droplet_mesh("DropletTrail", above)
+    drops.data.materials.append(drop)
+    arcs = arc_curves("Arcs", launch)
+    arcs.data.materials.append(arc)
+
+    floor_me = bpy.data.meshes.new("Floor")
+    bm = bmesh.new()
+    try:
+        bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=30.0)
+        bm.to_mesh(floor_me)
+    finally:
+        bm.free()
+    studio = material("Studio", (0.03, 0.032, 0.037, 1.0), 0.7)
+    floor_me.materials.append(studio)
+    floor = bpy.data.objects.new("Floor", floor_me)
+    scene.collection.objects.link(floor)
+    wall = bpy.data.objects.new("Wall", floor_me.copy())
+    wall.location = (0.0, 8.0, 0.0)
+    wall.rotation_euler = (math.pi / 2, 0.0, 0.0)
+    scene.collection.objects.link(wall)
+
+    world = bpy.data.worlds.new("World")
+    world.use_nodes = True
+    world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.02, 0.021, 0.025, 1.0)
+    scene.world = world
+
+    def light(name, loc, energy, size, col, rot):
+        ld = bpy.data.lights.new(name, "AREA")
+        ld.energy = energy
+        ld.size = size
+        ld.color = col
+        lo = bpy.data.objects.new(name, ld)
+        lo.location = loc
+        lo.rotation_euler = tuple(math.radians(a) for a in rot)
+        scene.collection.objects.link(lo)
+
+    light("Key", (-4.0, -5.0, 6.0), 560.0, 5.0, (1.0, 0.96, 0.9), (46, 0, -35))
+    light("Fill", (5.0, -3.5, 3.0), 70.0, 9.0, (0.75, 0.85, 1.0), (62, 0, 50))
+    light("Wedge", (1.2, 5.2, 3.6), 420.0, 6.0, (1.0, 0.76, 0.5), (100, 0, 10))
+    light("Rim", (-1.8, 4.6, 5.6), 240.0, 4.0, (0.6, 0.78, 1.0), (42, 0, 180))
+
+    aim = bpy.data.objects.new("Aim", None)
+    aim.location = (0.0, 0.0, 0.74)
+    scene.collection.objects.link(aim)
+    cam_data = bpy.data.cameras.new("Cam")
+    cam_data.lens = 50.0
+    cam = bpy.data.objects.new("Cam", cam_data)
+    cam.location = (4.0, -7.95, 4.75)
+    scene.collection.objects.link(cam)
+    scene.camera = cam
+    track = cam.constraints.new("TRACK_TO")
+    track.target = aim
+    track.track_axis = "TRACK_NEGATIVE_Z"
+    track.up_axis = "UP_Y"
+
+    scene.render.engine = "CYCLES" if engine == "cycles" else eevee_engine_id()
+    if engine == "cycles":
+        scene.cycles.samples = 64
+    else:
+        try:
+            scene.eevee.taa_render_samples = 64
+        except AttributeError:
+            pass
+    scene.render.resolution_x = 1280
+    scene.render.resolution_y = 720
+    scene.render.image_settings.file_format = "PNG"
+    scene.render.filepath = path
+    # Standard, not AgX: AgX washes the droplet cyan and lifts the stage to grey
+    scene.view_settings.view_transform = "Standard"
+
+    hero = [basin, pedestal, spire, spouts, drops, arcs]
+    fcode = gallery_framing.check_framing(
+        scene, cam, hero=hero, elements=hero, stage=[floor, wall],
+    )
+    if fcode:
+        return fcode
+    bpy.ops.render.render(write_still=True)
+    if not (os.path.exists(path) and os.path.getsize(path) > 0):
+        print("ERROR: render produced no file", file=sys.stderr)
+        return 12
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as exc:
+        print(f"ERROR: {type(exc).__name__}: {exc}", file=sys.stderr)
+        sys.exit(1)
+
+
+ + + + A two-tier sandstone fountain in a dark studio whose twenty jets are strings of glowing cyan droplet beads, each string threaded on a thin line tracing its ballistic arc into the pool. + +
+
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
+
+ + + diff --git a/docs/gallery/index.html b/docs/gallery/index.html index 1000bf02..8166a1b3 100644 --- a/docs/gallery/index.html +++ b/docs/gallery/index.html @@ -291,7 +291,7 @@

Examples and Showcase

autocomplete="off" spellcheck="false" aria-label="Search examples and showcase pieces" /> - 51 examples, 36 showcase pieces + 52 examples, 36 showcase pieces
@@ -880,6 +880,17 @@

gn-zone-iterate

View example gn-zone-iterate
+
+ +
+

gn-sim-fountain

+

A Simulation Zone only advances one step per consecutive frame_set. A direct jump to frame N runs a single step, and only a bake gives random access to the stepped state.

+

witnesses 24 stepped frames match p0 + v0 t - g t^2/2 within 6.6e-7 m. An unbaked jump 1->25 runs one step and sits 1.68-2.42 m off the arc; calculate_to_frame returns PASS_THROUGH headless; after a bake, random-access frames match within 5.6e-7 m.

+ View example gn-sim-fountain +
+

book-trolley

var tagsToggle = document.getElementById('tagsToggle'); var toTop = document.getElementById('toTop'); var total = cards.length; - var COUNT_LABEL = '51 examples, 36 showcase pieces'; + var COUNT_LABEL = '52 examples, 36 showcase pieces'; var LS_KEY = 'bdt-gallery-density'; var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; diff --git a/docs/new-example-prompt.md b/docs/new-example-prompt.md index a9b715ee..ce249e3c 100644 --- a/docs/new-example-prompt.md +++ b/docs/new-example-prompt.md @@ -59,7 +59,7 @@ metadata — so the render would be identical whether the API held or broke. The "redesign the scene until failure would be visible" instruction above is the test: attempt it first, and only when it cannot succeed in principle does the example become check-only. The exception is for contracts that are invisible, not for -renders that are hard. Eight of the 59 examples currently qualify, and `CLAUDE.md` +renders that are hard. Eight of the 60 examples currently qualify, and `CLAUDE.md` carries the same rule. A check-only example is otherwise a full example: it still asserts a real contract, still exits non-zero on failure, still carries a falsifier, and still takes a `tests/smoke/catalog.json` row so it runs on every PR. diff --git a/examples/gallery.json b/examples/gallery.json index 0ac35ed6..e0f3f0b8 100644 --- a/examples/gallery.json +++ b/examples/gallery.json @@ -666,6 +666,18 @@ "geometry-nodes" ] }, + { + "name": "gn-sim-fountain", + "dir": "examples/gn-sim-fountain", + "teaches": "A Simulation Zone only advances one step per consecutive frame_set. A direct jump to frame N runs a single step, and only a bake gives random access to the stepped state.", + "alt": "A two-tier sandstone fountain in a dark studio whose twenty jets are strings of glowing cyan droplet beads, each string threaded on a thin line tracing its ballistic arc into the pool.", + "witnessesFix": "24 stepped frames match p0 + v0 t - g t^2/2 within 6.6e-7 m. An unbaked jump 1->25 runs one step and sits 1.68-2.42 m off the arc; calculate_to_frame returns PASS_THROUGH headless; after a bake, random-access frames match within 5.6e-7 m.", + "hero": "docs/gallery/assets/gn-sim-fountain-hero.webp", + "preview": "examples/gn-sim-fountain/preview.webp", + "tags": [ + "geometry-nodes" + ] + }, { "name": "bake-normal-high-to-low", "dir": "examples/bake-normal-high-to-low", diff --git a/examples/gn-sim-fountain/README.md b/examples/gn-sim-fountain/README.md new file mode 100644 index 00000000..5b3f2b9a --- /dev/null +++ b/examples/gn-sim-fountain/README.md @@ -0,0 +1,109 @@ +# Geometry Nodes simulation-zone ballistic fountain + +A two-tier stone fountain whose twenty jets are integrated by a Simulation +Zone, witnessing the +[`geometry-nodes-python`](../../skills/geometry-nodes-python/SKILL.md) +frame contract: **a Simulation Zone only advances when the scene steps one +frame at a time.** The evaluated state at frame N is not a function of N. +AI code that calls `scene.frame_set(N)` and reads positions gets a silently +wrong answer. + +Each droplet is a point with a `vel` attribute. Per step the zone applies the +constant-gravity update that is exact for any `dt`: + +``` +p += v*dt - 0.5*g*dt^2 * z +v -= g*dt * z +``` + +so at frame `f` every point must lie on the closed-form ballistic arc +`p0 + v0*t - 0.5*g*t^2*z` and carry `v0 - g*t*z`, with +`t = (f - frame_start) / fps`. The check recomputes both from the launch data +(8 crown jets thrown up and out, 12 rim jets arcing inward; `g = 9.81`, +24 fps, 24 steps = 1.0 s). + +## Measured behavior + +Identical on 4.5.11 LTS, 5.1.2 and 5.2.1 LTS. The Simulation Zone and its +cache/bake operators have **not** diverged across the three, so there is no +version branch; the probes that established this are the checks below. + +| Call sequence | What the zone does | +| --- | --- | +| `frame_set(frame_start)` | body runs once with Delta Time 0 — state reset to the input | +| `frame_set(f)` then `frame_set(f + 1)` | one step, `dt = 1/fps` | +| `frame_set(start)` then `frame_set(N)`, no cache | **one** step, `dt = 1/fps`: frame N shows the frame-2 state | +| `simulation_nodes_cache_calculate_to_frame(selected=True)` headless | poll fails: logs `Invalid operator call`, returns `{'PASS_THROUGH'}`, **does not raise**; frames between the two cached endpoints then read as a linear interpolation of them | +| `simulation_nodes_cache_bake(selected=True)` under `temp_override` | bakes `frame_start..frame_end` (`PACKED`, in memory, no directory); any `frame_set` order then reads the exact per-frame state | + +Two silent traps, then. The jump is 1.68–2.42 m off the true frame-25 arc +here. The tempting cache operator "succeeds" without raising and leaves +interpolated garbage between cached frames (2.42 m / 9.40 m/s off). + +**Tolerance.** `TOL = 1e-4` m and m/s. The state is float32 accumulated over +24 steps; the measured worst case is 6.6e-7 m and 1.4e-6 m/s, so the band is +~150× the observed error and ~2000× below the smallest broken case (Euler, +0.204 m). The trap must also clear `TRAP_GAP_FLOOR = 0.25` m from the true +arc, so a rounding difference can never pass as the trap. + +**What failure each check would catch:** + +- exit 3 — the zone is unpaired or drops points: `pair_with_output` not + called evaluates to 0 points (`--unpair`) +- exit 4 — the integrator is not the exact constant-gravity update: naive + `p += v*dt` drifts by `g*dt*t/2`, 0.2044 m at t = 1 s (`--euler`) +- exit 5 — a direct frame jump did **not** reproduce the one-step trap — e.g. + because a bake was already present (`--prebake-trap`). This is what keeps + the trap claim above honest on every version CI runs +- exit 6 — random-access reads after a cache fill miss the arc, or the fill + operator did not return `FINISHED`: `calculate_to_frame` headless + (`--calc-to-frame`) + +**The render is the proof.** Every droplet bead in the still is a recorded +simulated position from the stepped run (check 4). The thin line each string +of beads is threaded on is the closed-form arc, drawn from the launch data, +not from the simulation. A drifting integrator would pull the late beads off +their line — by 0.20 m at the pool for `--euler`, as check 4 measures (that +flag exits before rendering, so this is computed, not a rendered still). + +## Run + +```bash +blender --background --python gn_sim_fountain.py -- +blender --background --python gn_sim_fountain.py -- --output fountain.png +``` + +The `--output` render path measures framing via `examples/gallery_framing.py` +(exit 10 on violation). + +## Falsifiers + +Each breaks one thing and exits the code of the check it targets, on all +three versions. + +| Flag | Breaks | Target check | Exit | +| --- | --- | --- | --- | +| `--unpair` | Simulation Input never paired with its Output | zone evaluates one point per jet | 3 | +| `--euler` | drops the `-0.5*g*dt^2` position term | stepped frames on the closed-form arc | 4 | +| `--prebake-trap` | bakes before the direct jump | unbaked jump runs exactly one step | 5 | +| `--calc-to-frame` | fills the cache with `calculate_to_frame`, not a bake | baked random access on the arc | 6 | + +## Exit codes + +Per-script sequential checks. `10` is the shared framing helper. + +| Code | Meaning | +| --- | --- | +| 0 | Success | +| 1 | Uncaught exception (FATAL wrapper) | +| 2 | argparse / usage | +| 3 | Point count or frame-start state off the launch data | +| 4 | Stepped frames off the closed-form arc (position or velocity) | +| 5 | Direct jump did not reproduce the one-step trap | +| 6 | After the cache fill, random-access frames off the arc (or fill not `FINISHED`) | +| 10 | Gallery framing violation | +| 12 | `--output` produced no file | + +The `blender-smoke` workflow runs the check on Blender 5.2 LTS and 4.5 LTS +(5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch). +Smoke does not pass `--output` or any falsifier. diff --git a/examples/gn-sim-fountain/gn_sim_fountain.py b/examples/gn-sim-fountain/gn_sim_fountain.py new file mode 100644 index 00000000..0d44c08e --- /dev/null +++ b/examples/gn-sim-fountain/gn_sim_fountain.py @@ -0,0 +1,657 @@ +"""Geometry Nodes Simulation Zone ballistic fountain — a runnable example. + +Witnesses the Simulation Zone frame contract from +``skills/geometry-nodes-python``. A zone integrates state only when the +scene advances one frame at a time; the evaluated result at frame N is not a +function of N. AI code that sets ``scene.frame_set(N)`` and reads positions +gets a silently wrong answer. + +Each jet's droplet is a point carrying a ``vel`` attribute. Per step the zone +applies the constant-gravity update that is exact for any ``dt``:: + + p += v*dt - 0.5*g*dt^2 * z + v -= g*dt * z + +so at frame f every point must sit on the closed-form ballistic arc +``p0 + v0*t - 0.5*g*t^2*z`` with ``t = (f - frame_start) / fps``, and carry +``v0 - g*t*z``. The check recomputes both from the launch data. + +Measured identically on 4.5.11 LTS, 5.1.2 and 5.2.1 LTS (the API has not +diverged across the three): + +* At ``frame_start`` the zone body runs once with Delta Time 0 (state reset). +* Each consecutive ``frame_set(f + 1)`` runs one step with dt = 1/fps. +* A forward jump ``frame_set(start)`` -> ``frame_set(N)`` with no cache runs + exactly ONE step with dt = 1/fps. Frame N shows the frame-2 state. +* ``bpy.ops.object.simulation_nodes_cache_calculate_to_frame`` fails its poll + headless: it logs "Invalid operator call", returns ``{'PASS_THROUGH'}`` + without raising, and frames between the two cached endpoints then read as + a linear interpolation of them — a second silent wrong answer. +* ``bpy.ops.object.simulation_nodes_cache_bake(selected=True)`` under + ``temp_override`` bakes the frame range (PACKED, in memory, no directory) + and random-access ``frame_set`` then returns the exact per-frame state. + +By default it runs only the correctness check (no render) — the CI smoke +check. Pass --output to also render a still: + + blender --background --python gn_sim_fountain.py -- + blender --background --python gn_sim_fountain.py -- --euler # exit 4 + blender --background --python gn_sim_fountain.py -- --output f.png +""" +import bpy, bmesh, sys, os, math, argparse +from mathutils import Vector, Matrix + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) +sys.dont_write_bytecode = True # keep examples/__pycache__ out of the repo tree +import gallery_framing + +G = 9.81 +FPS = 24 +FRAME_START = 1 +STEPS = 24 # 1.0 s of flight, frame 1 -> frame 25 +FRAME_END = FRAME_START + STEPS +# float32 state accumulated over STEPS updates: measured worst 2e-6 m (see README) +TOL = 1e-4 +# the jump trap must be unmistakable, not a rounding difference +TRAP_GAP_FLOOR = 0.25 +# random-access order for the baked read: backwards, forwards, repeats +SCRAMBLED = (FRAME_END, 7, FRAME_START + 1, 19, 12, FRAME_END, 3) + +# Jets: (count, launch radius, launch height, radial speed, vertical speed). +# The crown throws up and out; the rim jets arc inward. +CROWN = (8, 0.09, 1.52, 0.80, 3.55) +RIM = (12, 1.52, 0.50, -1.30, 2.95) +WATER_Z = 0.36 # render only: droplets below the water are hidden + + +def jets(): + """Launch positions and velocities, crown first then rim.""" + out = [] + for count, radius, height, v_r, v_z in (CROWN, RIM): + phase = 0.0 if count == CROWN[0] else math.pi / count + for i in range(count): + a = phase + 2 * math.pi * i / count + d = Vector((math.cos(a), math.sin(a), 0.0)) + out.append((d * radius + Vector((0.0, 0.0, height)), d * v_r + Vector((0.0, 0.0, v_z)))) + return out + + +def closed_form(p0, v0, t): + return (p0 + v0 * t + Vector((0.0, 0.0, -0.5 * G * t * t)), + v0 + Vector((0.0, 0.0, -G * t))) + + +def build_tree(pair=True, euler=False): + tree = bpy.data.node_groups.new("BallisticSim", "GeometryNodeTree") + tree.interface.new_socket(name="Geometry", in_out="INPUT", socket_type="NodeSocketGeometry") + tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry") + nodes, links = tree.nodes, tree.links + gi = nodes.new("NodeGroupInput") + go = nodes.new("NodeGroupOutput") + sin = nodes.new("GeometryNodeSimulationInput") + sout = nodes.new("GeometryNodeSimulationOutput") + if not pair: + # Unpaired Simulation Input has no Geometry socket. Leave the output + # empty so evaluation cannot silently pass the emitter through. + return tree + if not sin.pair_with_output(sout): + raise RuntimeError("SimulationInput.pair_with_output failed") + + pos = nodes.new("GeometryNodeInputPosition") + vel = nodes.new("GeometryNodeInputNamedAttribute") + vel.data_type = "FLOAT_VECTOR" + vel.inputs["Name"].default_value = "vel" + dt = sin.outputs["Delta Time"] + + # p + v*dt (- 0.5*g*dt^2 on z unless --euler) + v_dt = nodes.new("ShaderNodeVectorMath") + v_dt.operation = "SCALE" + links.new(vel.outputs["Attribute"], v_dt.inputs[0]) + links.new(dt, v_dt.inputs["Scale"]) + new_pos = nodes.new("ShaderNodeVectorMath") + new_pos.operation = "ADD" + links.new(pos.outputs["Position"], new_pos.inputs[0]) + links.new(v_dt.outputs["Vector"], new_pos.inputs[1]) + pos_out = new_pos.outputs["Vector"] + if not euler: + dt2 = nodes.new("ShaderNodeMath") + dt2.operation = "MULTIPLY" + links.new(dt, dt2.inputs[0]) + links.new(dt, dt2.inputs[1]) + half_g = nodes.new("ShaderNodeMath") + half_g.operation = "MULTIPLY" + half_g.inputs[1].default_value = -0.5 * G + links.new(dt2.outputs["Value"], half_g.inputs[0]) + drop = nodes.new("ShaderNodeCombineXYZ") + links.new(half_g.outputs["Value"], drop.inputs["Z"]) + with_drop = nodes.new("ShaderNodeVectorMath") + with_drop.operation = "ADD" + links.new(pos_out, with_drop.inputs[0]) + links.new(drop.outputs["Vector"], with_drop.inputs[1]) + pos_out = with_drop.outputs["Vector"] + + # v - g*dt on z + g_dt = nodes.new("ShaderNodeMath") + g_dt.operation = "MULTIPLY" + g_dt.inputs[1].default_value = -G + links.new(dt, g_dt.inputs[0]) + dv = nodes.new("ShaderNodeCombineXYZ") + links.new(g_dt.outputs["Value"], dv.inputs["Z"]) + new_vel = nodes.new("ShaderNodeVectorMath") + new_vel.operation = "ADD" + links.new(vel.outputs["Attribute"], new_vel.inputs[0]) + links.new(dv.outputs["Vector"], new_vel.inputs[1]) + + # Set Position first: its field reads the old vel. Storing vel first would + # make the position update read the new one. + setp = nodes.new("GeometryNodeSetPosition") + links.new(sin.outputs["Geometry"], setp.inputs["Geometry"]) + links.new(pos_out, setp.inputs["Position"]) + store = nodes.new("GeometryNodeStoreNamedAttribute") + store.data_type = "FLOAT_VECTOR" + store.domain = "POINT" + store.inputs["Name"].default_value = "vel" + links.new(setp.outputs["Geometry"], store.inputs["Geometry"]) + links.new(new_vel.outputs["Vector"], store.inputs["Value"]) + + links.new(gi.outputs["Geometry"], sin.inputs["Geometry"]) + links.new(store.outputs["Geometry"], sout.inputs["Geometry"]) + links.new(sout.outputs["Geometry"], go.inputs["Geometry"]) + return tree + + +def build(pair=True, euler=False): + bpy.ops.wm.read_factory_settings(use_empty=True) + sc = bpy.context.scene + sc.render.fps = FPS + sc.render.fps_base = 1.0 + sc.frame_start = FRAME_START + sc.frame_end = FRAME_END + + launch = jets() + me = bpy.data.meshes.new("Nozzles") + me.vertices.add(len(launch)) + me.vertices.foreach_set("co", [c for p, _ in launch for c in p]) + attr = me.attributes.new("vel", "FLOAT_VECTOR", "POINT") + attr.data.foreach_set("vector", [c for _, v in launch for c in v]) + ob = bpy.data.objects.new("Droplets", me) + sc.collection.objects.link(ob) + mod = ob.modifiers.new("Ballistic", "NODES") + mod.node_group = build_tree(pair=pair, euler=euler) + return ob, launch + + +def read_state(ob): + """Evaluated (positions, velocities) of the simulated points.""" + dg = bpy.context.evaluated_depsgraph_get() + ev = ob.evaluated_get(dg) + me = ev.to_mesh() + try: + n = len(me.vertices) + co = [0.0] * (3 * n) + me.vertices.foreach_get("co", co) + vel = [0.0] * (3 * n) + a = me.attributes.get("vel") + if a is not None and a.domain == "POINT" and n: + a.data.foreach_get("vector", vel) + finally: + ev.to_mesh_clear() + pts = [Vector(co[i:i + 3]) for i in range(0, 3 * n, 3)] + vels = [Vector(vel[i:i + 3]) for i in range(0, 3 * n, 3)] + return pts, vels + + +def worst_error(state, launch, t): + pts, vels = state + wp = wv = 0.0 + for (p0, v0), p, v in zip(launch, pts, vels): + ep, ev = closed_form(p0, v0, t) + wp = max(wp, (p - ep).length) + wv = max(wv, (v - ev).length) + return wp, wv + + +def t_of(frame): + return (frame - FRAME_START) / FPS + + +def select_override(ob): + return bpy.context.temp_override( + active_object=ob, object=ob, selected_objects=[ob], selected_editable_objects=[ob], + ) + + +def fill_cache(ob, use_calc_to_frame=False): + """Bake the simulation range so any frame reads the stepped state.""" + sc = bpy.context.scene + with select_override(ob): + if use_calc_to_frame: + # The tempting operator. Its poll fails headless; it returns + # PASS_THROUGH without raising and computes nothing. + sc.frame_set(FRAME_END) + return bpy.ops.object.simulation_nodes_cache_calculate_to_frame(selected=True) + return bpy.ops.object.simulation_nodes_cache_bake(selected=True) + + +def delete_cache(ob): + with select_override(ob): + bpy.ops.object.simulation_nodes_cache_delete(selected=True) + + +def check(ob, launch, prebake_trap=False, calc_to_frame=False): + sc = bpy.context.scene + n = len(launch) + + # 3 — the paired zone evaluates one point per jet, at rest on the nozzles + sc.frame_set(FRAME_START) + state = read_state(ob) + if len(state[0]) != n: + print(f"ERROR: zone evaluated {len(state[0])} points at frame_start, expected {n} " + f"(one per jet); an unpaired zone outputs nothing", file=sys.stderr) + return 3 + wp, wv = worst_error(state, launch, 0.0) + if wp > TOL or wv > TOL: + print(f"ERROR: frame_start state off the launch data by {wp:.2e} m, {wv:.2e} m/s", + file=sys.stderr) + return 3 + print(f"frame_start: {n} points on the nozzles (err {wp:.1e} m)") + + # 4 — stepping one frame at a time lands on the closed-form arc every frame + trail = [state[0]] + worst_p = worst_v = 0.0 + for f in range(FRAME_START + 1, FRAME_END + 1): + sc.frame_set(f) + state = read_state(ob) + if len(state[0]) != n: + print(f"ERROR: frame {f} evaluated {len(state[0])} points, expected {n}", file=sys.stderr) + return 4 + wp, wv = worst_error(state, launch, t_of(f)) + worst_p, worst_v = max(worst_p, wp), max(worst_v, wv) + trail.append(state[0]) + if worst_p > TOL or worst_v > TOL: + print(f"ERROR: stepped frames {FRAME_START}..{FRAME_END} miss p0 + v0 t - g t^2/2 by up to " + f"{worst_p:.4f} m and v0 - g t by {worst_v:.4f} m/s (tol {TOL})", file=sys.stderr) + return 4 + print(f"stepped {STEPS} frames: worst position err {worst_p:.2e} m, " + f"velocity err {worst_v:.2e} m/s (tol {TOL})") + + # 5 — the trap: a direct jump with no cache runs exactly one step + delete_cache(ob) + sc.frame_set(FRAME_START) + if prebake_trap: + fill_cache(ob) + sc.frame_set(FRAME_END) + state = read_state(ob) + one_step_p, _ = worst_error(state, launch, 1.0 / FPS) + true_p, _ = worst_error(state, launch, t_of(FRAME_END)) + gap = min((p - closed_form(p0, v0, t_of(FRAME_END))[0]).length + for (p0, v0), p in zip(launch, state[0])) if state[0] else 0.0 + label = "prebaked" if prebake_trap else "unbaked" + print(f"jump {FRAME_START}->{FRAME_END} {label}: off the one-step state by {one_step_p:.2e} m, " + f"off the frame-{FRAME_END} arc by {gap:.3f}..{true_p:.3f} m") + if one_step_p > TOL or gap < TRAP_GAP_FLOOR: + print(f"ERROR: jump did not reproduce the one-step trap (one-step err {one_step_p:.2e} m, " + f"min gap to the true arc {gap:.4f} m < {TRAP_GAP_FLOOR})", file=sys.stderr) + return 5 + + # 6 — the remedy: bake, then any frame in any order reads the stepped state + delete_cache(ob) + sc.frame_set(FRAME_START) + result = fill_cache(ob, use_calc_to_frame=calc_to_frame) + print(f"cache fill -> {sorted(result)}") + worst_p = worst_v = 0.0 + for f in SCRAMBLED: + sc.frame_set(f) + wp, wv = worst_error(read_state(ob), launch, t_of(f)) + worst_p, worst_v = max(worst_p, wp), max(worst_v, wv) + if result != {"FINISHED"} or worst_p > TOL or worst_v > TOL: + print(f"ERROR: after cache fill {sorted(result)}, frames {list(SCRAMBLED)} miss the arc by " + f"up to {worst_p:.4f} m / {worst_v:.4f} m/s (tol {TOL})", file=sys.stderr) + return 6 + print(f"baked random access {list(SCRAMBLED)}: worst err {worst_p:.2e} m, {worst_v:.2e} m/s") + return 0, trail + + +def main(): + argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] + p = argparse.ArgumentParser() + p.add_argument("--output", default=None) + p.add_argument("--engine", default="eevee", choices=("eevee", "cycles")) + p.add_argument("--unpair", action="store_true", + help="falsification: Simulation Input never paired with its Output (exit 3)") + p.add_argument("--euler", action="store_true", + help="falsification: naive p += v*dt drops the g*dt^2/2 term (exit 4)") + p.add_argument("--prebake-trap", action="store_true", + help="falsification: bake before the jump, so the trap cannot show (exit 5)") + p.add_argument("--calc-to-frame", action="store_true", + help="falsification: fill the cache with calculate_to_frame, not bake (exit 6)") + args = p.parse_args(argv) + + ob, launch = build(pair=not args.unpair, euler=args.euler) + result = check(ob, launch, prebake_trap=args.prebake_trap, calc_to_frame=args.calc_to_frame) + if isinstance(result, int): + return result + _, trail = result + + if args.output: + rcode = render_still(ob, launch, trail, os.path.abspath(args.output), args.engine) + if rcode: + return rcode + print(f"rendered still {args.output}") + + print("gn-sim-fountain OK") + return 0 + + +# ---------------------------------------------------------------- render only +# (r, z) lathe profiles, outside in. Nothing below is read by the check. +BASIN_PROFILE = [ + (0.0, 0.0), (2.04, 0.0), (2.04, 0.06), (1.99, 0.085), (1.93, 0.09), (1.91, 0.12), + (1.94, 0.15), (1.95, 0.19), (1.92, 0.22), (1.87, 0.23), (1.85, 0.27), (1.84, 0.44), + (1.88, 0.47), (1.90, 0.52), (1.87, 0.57), (1.78, 0.59), (1.67, 0.58), (1.61, 0.55), + (1.59, 0.50), (1.58, 0.16), (0.0, 0.16), +] +PEDESTAL_PROFILE = [ + (0.0, 0.16), (0.46, 0.16), (0.46, 0.30), (0.40, 0.34), (0.30, 0.40), (0.22, 0.52), + (0.18, 0.70), (0.17, 0.95), (0.21, 1.03), (0.24, 1.08), (0.20, 1.12), (0.36, 1.18), + (0.56, 1.25), (0.66, 1.30), (0.68, 1.35), (0.64, 1.38), (0.58, 1.37), (0.20, 1.29), + (0.0, 1.28), +] +SPIRE_PROFILE = [ + (0.0, 1.28), (0.10, 1.28), (0.10, 1.31), (0.06, 1.36), (0.05, 1.44), (0.075, 1.47), + (0.075, 1.50), (0.045, 1.53), (0.0, 1.535), +] +BOWL_WATER = (0.60, 1.33) # radius, height of the upper bowl's water +DROP_R = 0.030 +ARC_R = 0.0055 + + +def lathe(name, profile, steps=96): + me = bpy.data.meshes.new(name) + bm = bmesh.new() + try: + verts = [bm.verts.new((r, 0.0, z)) for r, z in profile] + edges = [bm.edges.new((a, b)) for a, b in zip(verts, verts[1:])] + bmesh.ops.spin(bm, geom=verts + edges, cent=(0.0, 0.0, 0.0), axis=(0.0, 0.0, 1.0), + angle=2 * math.pi, steps=steps, use_merge=True) + bmesh.ops.remove_doubles(bm, verts=sorted(bm.verts, key=lambda v: v.index), dist=1e-5) + bmesh.ops.recalc_face_normals(bm, faces=list(bm.faces)) + bm.to_mesh(me) + finally: + bm.free() + me.shade_smooth() + ob = bpy.data.objects.new(name, me) + bpy.context.scene.collection.objects.link(ob) + return ob + + +def disc(name, radius, z, segments=96): + me = bpy.data.meshes.new(name) + bm = bmesh.new() + try: + bmesh.ops.create_circle(bm, cap_ends=True, segments=segments, radius=radius) + bmesh.ops.translate(bm, verts=list(bm.verts), vec=(0.0, 0.0, z)) + bm.to_mesh(me) + finally: + bm.free() + ob = bpy.data.objects.new(name, me) + bpy.context.scene.collection.objects.link(ob) + return ob + + +def droplet_mesh(name, points): + """One icosphere per simulated droplet position above the water.""" + me = bpy.data.meshes.new(name) + bm = bmesh.new() + try: + for p in points: + bmesh.ops.create_icosphere(bm, subdivisions=2, radius=DROP_R, + matrix=Matrix.Translation(p)) + bm.to_mesh(me) + finally: + bm.free() + me.shade_smooth() + ob = bpy.data.objects.new(name, me) + bpy.context.scene.collection.objects.link(ob) + return ob + + +def arc_curves(name, launch): + """The closed-form arcs, drawn from the launch data, not from the sim.""" + cu = bpy.data.curves.new(name, "CURVE") + cu.dimensions = "3D" + cu.bevel_depth = ARC_R + cu.bevel_resolution = 2 + for p0, v0 in launch: + pts = [] + t = 0.0 + while True: + p, _ = closed_form(p0, v0, t) + if p.z < WATER_Z: + break + pts.append(p) + t += 0.01 + sp = cu.splines.new("POLY") + sp.points.add(len(pts) - 1) + sp.points.foreach_set("co", [c for p in pts for c in (p.x, p.y, p.z, 1.0)]) + ob = bpy.data.objects.new(name, cu) + bpy.context.scene.collection.objects.link(ob) + return ob + + +def nozzles(name, launch): + """Bronze spouts at each rim jet, pointing along its launch velocity.""" + me = bpy.data.meshes.new(name) + bm = bmesh.new() + try: + for p0, v0 in launch[CROWN[0]:]: + d = v0.normalized() + rot = d.to_track_quat("Z", "Y").to_matrix().to_4x4() + m = Matrix.Translation(p0 - d * 0.075) @ rot + bmesh.ops.create_cone(bm, cap_ends=True, segments=16, radius1=0.034, + radius2=0.020, depth=0.15, matrix=m) + bm.to_mesh(me) + finally: + bm.free() + me.shade_smooth() + ob = bpy.data.objects.new(name, me) + bpy.context.scene.collection.objects.link(ob) + return ob + + +def material(name, color, roughness, metallic=0.0, emission=None, strength=0.0, + noise_tint=None, bump=0.0, joints=0): + mat = bpy.data.materials.new(name) + mat.use_nodes = True + nt = mat.node_tree + bsdf = nt.nodes["Principled BSDF"] + bsdf.inputs["Base Color"].default_value = color + bsdf.inputs["Roughness"].default_value = roughness + bsdf.inputs["Metallic"].default_value = metallic + if emission is not None: + bsdf.inputs["Emission Color"].default_value = emission + bsdf.inputs["Emission Strength"].default_value = strength + if noise_tint is not None: + # dressed-stone variation: low-frequency tint plus a fine tooling bump + noise = nt.nodes.new("ShaderNodeTexNoise") + noise.inputs["Scale"].default_value = 4.5 + noise.inputs["Detail"].default_value = 6.0 + ramp = nt.nodes.new("ShaderNodeValToRGB") + ramp.color_ramp.elements[0].color = noise_tint + ramp.color_ramp.elements[1].color = color + ramp.color_ramp.elements[0].position = 0.35 + ramp.color_ramp.elements[1].position = 0.70 + nt.links.new(noise.outputs["Fac"], ramp.inputs["Fac"]) + nt.links.new(ramp.outputs["Color"], bsdf.inputs["Base Color"]) + height = None + if bump: + fine = nt.nodes.new("ShaderNodeTexNoise") + fine.inputs["Scale"].default_value = 60.0 + height = fine.outputs["Fac"] + if joints: + # radial block joints: angle about Z, JOINTS blocks per turn, a thin + # mortar line where the block fraction wraps + coord = nt.nodes.new("ShaderNodeTexCoord") + xyz = nt.nodes.new("ShaderNodeSeparateXYZ") + nt.links.new(coord.outputs["Object"], xyz.inputs["Vector"]) + ang = nt.nodes.new("ShaderNodeMath") + ang.operation = "ARCTAN2" + nt.links.new(xyz.outputs["Y"], ang.inputs[0]) + nt.links.new(xyz.outputs["X"], ang.inputs[1]) + per = nt.nodes.new("ShaderNodeMath") + per.operation = "MULTIPLY" + per.inputs[1].default_value = joints / (2 * math.pi) + nt.links.new(ang.outputs["Value"], per.inputs[0]) + frac = nt.nodes.new("ShaderNodeMath") + frac.operation = "PINGPONG" # 0 at a joint, 0.5 mid-block + frac.inputs[1].default_value = 0.5 + nt.links.new(per.outputs["Value"], frac.inputs[0]) + line = nt.nodes.new("ShaderNodeMath") + line.operation = "LESS_THAN" + line.inputs[1].default_value = 0.022 + nt.links.new(frac.outputs["Value"], line.inputs[0]) + mortar = nt.nodes.new("ShaderNodeMix") + mortar.data_type = "RGBA" + mortar.inputs["B"].default_value = (0.16, 0.10, 0.06, 1.0) + nt.links.new(line.outputs["Value"], mortar.inputs["Factor"]) + nt.links.new(ramp.outputs["Color"], mortar.inputs["A"]) + nt.links.new(mortar.outputs["Result"], bsdf.inputs["Base Color"]) + if height is not None: + recess = nt.nodes.new("ShaderNodeMath") + recess.operation = "MULTIPLY_ADD" + recess.inputs[1].default_value = -0.6 + nt.links.new(line.outputs["Value"], recess.inputs[0]) + nt.links.new(height, recess.inputs[2]) + height = recess.outputs["Value"] + if height is not None: + bmp = nt.nodes.new("ShaderNodeBump") + bmp.inputs["Strength"].default_value = bump + nt.links.new(height, bmp.inputs["Height"]) + nt.links.new(bmp.outputs["Normal"], bsdf.inputs["Normal"]) + return mat + + +def eevee_engine_id(): + return "BLENDER_EEVEE" if bpy.app.version >= (5, 0, 0) else "BLENDER_EEVEE_NEXT" + + +def render_still(ob, launch, trail, path, engine): + scene = bpy.context.scene + scene.frame_set(FRAME_START) + ob.hide_render = True # the live points; the still shows the recorded trail + + stone = material("Sandstone", (0.70, 0.46, 0.27, 1.0), 0.8, + noise_tint=(0.47, 0.29, 0.16, 1.0), bump=0.22, joints=28) + turned = material("TurnedStone", (0.70, 0.46, 0.27, 1.0), 0.72, + noise_tint=(0.47, 0.29, 0.16, 1.0), bump=0.15) + bronze = material("Bronze", (0.62, 0.36, 0.15, 1.0), 0.34, metallic=0.9) + water = material("Pool", (0.02, 0.16, 0.20, 1.0), 0.32) + # a mirror-flat pool reflects the rim light as a pale sheet over the water + water.node_tree.nodes["Principled BSDF"].inputs["Specular IOR Level"].default_value = 0.25 + drop = material("Droplet", (0.45, 0.82, 1.0, 1.0), 0.12, + emission=(0.35, 0.78, 1.0, 1.0), strength=0.9) + arc = material("Arc", (0.8, 0.92, 1.0, 1.0), 0.3, + emission=(0.7, 0.88, 1.0, 1.0), strength=0.35) + + basin = lathe("Basin", BASIN_PROFILE) + pedestal = lathe("Pedestal", PEDESTAL_PROFILE) + basin.data.materials.append(stone) + pedestal.data.materials.append(turned) + spire = lathe("Spire", SPIRE_PROFILE, steps=48) + spire.data.materials.append(bronze) + spouts = nozzles("Spouts", launch) + spouts.data.materials.append(bronze) + pool = disc("Pool", 1.585, WATER_Z) + bowl = disc("BowlPool", BOWL_WATER[0], BOWL_WATER[1]) + for o in (pool, bowl): + o.data.materials.append(water) + above = [p for frame in trail for p in frame if p.z > WATER_Z + DROP_R * 0.5] + drops = droplet_mesh("DropletTrail", above) + drops.data.materials.append(drop) + arcs = arc_curves("Arcs", launch) + arcs.data.materials.append(arc) + + floor_me = bpy.data.meshes.new("Floor") + bm = bmesh.new() + try: + bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=30.0) + bm.to_mesh(floor_me) + finally: + bm.free() + studio = material("Studio", (0.03, 0.032, 0.037, 1.0), 0.7) + floor_me.materials.append(studio) + floor = bpy.data.objects.new("Floor", floor_me) + scene.collection.objects.link(floor) + wall = bpy.data.objects.new("Wall", floor_me.copy()) + wall.location = (0.0, 8.0, 0.0) + wall.rotation_euler = (math.pi / 2, 0.0, 0.0) + scene.collection.objects.link(wall) + + world = bpy.data.worlds.new("World") + world.use_nodes = True + world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.02, 0.021, 0.025, 1.0) + scene.world = world + + def light(name, loc, energy, size, col, rot): + ld = bpy.data.lights.new(name, "AREA") + ld.energy = energy + ld.size = size + ld.color = col + lo = bpy.data.objects.new(name, ld) + lo.location = loc + lo.rotation_euler = tuple(math.radians(a) for a in rot) + scene.collection.objects.link(lo) + + light("Key", (-4.0, -5.0, 6.0), 560.0, 5.0, (1.0, 0.96, 0.9), (46, 0, -35)) + light("Fill", (5.0, -3.5, 3.0), 70.0, 9.0, (0.75, 0.85, 1.0), (62, 0, 50)) + light("Wedge", (1.2, 5.2, 3.6), 420.0, 6.0, (1.0, 0.76, 0.5), (100, 0, 10)) + light("Rim", (-1.8, 4.6, 5.6), 240.0, 4.0, (0.6, 0.78, 1.0), (42, 0, 180)) + + aim = bpy.data.objects.new("Aim", None) + aim.location = (0.0, 0.0, 0.74) + scene.collection.objects.link(aim) + cam_data = bpy.data.cameras.new("Cam") + cam_data.lens = 50.0 + cam = bpy.data.objects.new("Cam", cam_data) + cam.location = (4.0, -7.95, 4.75) + scene.collection.objects.link(cam) + scene.camera = cam + track = cam.constraints.new("TRACK_TO") + track.target = aim + track.track_axis = "TRACK_NEGATIVE_Z" + track.up_axis = "UP_Y" + + scene.render.engine = "CYCLES" if engine == "cycles" else eevee_engine_id() + if engine == "cycles": + scene.cycles.samples = 64 + else: + try: + scene.eevee.taa_render_samples = 64 + except AttributeError: + pass + scene.render.resolution_x = 1280 + scene.render.resolution_y = 720 + scene.render.image_settings.file_format = "PNG" + scene.render.filepath = path + # Standard, not AgX: AgX washes the droplet cyan and lifts the stage to grey + scene.view_settings.view_transform = "Standard" + + hero = [basin, pedestal, spire, spouts, drops, arcs] + fcode = gallery_framing.check_framing( + scene, cam, hero=hero, elements=hero, stage=[floor, wall], + ) + if fcode: + return fcode + bpy.ops.render.render(write_still=True) + if not (os.path.exists(path) and os.path.getsize(path) > 0): + print("ERROR: render produced no file", file=sys.stderr) + return 12 + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + print(f"ERROR: {type(exc).__name__}: {exc}", file=sys.stderr) + sys.exit(1) diff --git a/examples/gn-sim-fountain/preview.webp b/examples/gn-sim-fountain/preview.webp new file mode 100644 index 0000000000000000000000000000000000000000..a9ce695a0e8181ff826d0d2c8fc5aedf53b84fd2 GIT binary patch literal 51988 zcmV(tKB<|AJiU!I<>TLpe)s%$?jN@= z9`^_B55j)F{}J;?`)~W+Q2WpOpW1Iw-fsV&{x9;E<=_0D{2%H))c%YAx&Alz|L7O> zKmKR-Q(%6Z)6>AO9ZM zzxDtB`p$-|_@Bu?g8qU2WAelM$EyF5eLMKC??2{$+JAii>Hd%IoAaOSx`RK&^eg!n z-v7=2cKyWv5Bsb1Z~X7{pOId>{&W22{9p0^y59lckpDmb8U6qE`}`m7m)9TPe$e^V z@PF-pXnl#jy!yZVU-5swf9yRqzsdgp>wnkp_uu0`dOm=^nEy=wY5o8AxBMsn|Fl2i zf8+9G{3rYW+dqIW=%3&J@qd#4S^K;6+x_SMzxE&PzjJ-tewF^C|3~^?fY0Zj+kfVN zkpEBr$NcC2|Ns6_Jt04KfB%c&rS_48S>XTp!8RNmjH{wqew&wLw=Zj@-ZZJ`9y2$~ zT7G7S{o!|df8G~-jK^2zIC0c5Ddey796U1(44;(*kbwAH0uB^+@?=mPco`-?y|7Sha%oNfw;gpR8XdH27AhzUyKffegG6e#CO< zvqZdjy89#yM0Dyo8*g;lx=Q08Ab?c=+Jz>Gp6n3viRC&7c|wTHo+Y^DOKd?bjqhE(#$xM zZK^Y{|5_S03Bdm~tJaG_NHcSHqybeuzl;HMPzG)otaX{}az@M9RHh;yu zyaa)WpS+>YO~09BO~|{Uuk=RPS&c#~N6>L)Ni_2%<}TUBlit{1CL1S*Egu+yQZ_f}_PU%pi5DyqMNkJ;ly zbq9Nl^{qjiF~U=joxu8$a)}WN%Qe-4z(Rnxpm}gJ3bde4>g1rwJ^)v;X)OE`w!GZM zro9$^H|`D*SzW8wTZgO_iTAUKLKLi7@(`(D3`$y;=Y2Fu0s+n2l@&QP5*Mnkscp?# znB(u+ZQRHmbIvcf&p zvWLPNb{7UM3(b!H_(`;Iu#fB`67cgmG+SFBzxP4=QGe_q9lIr?y$8C9e7szT+PqfC zpyNG)(`}ll)3YYh$>0f!I+5zUL5UufnX3mIc}29LRpH(lg8EfL{ghwlt<1yRtt=Es zXJ!X+tPq*8>egit;n8p`aYR+J&;y+#tgJ5Bz?Nu?jko~*CEhM?chfV*9{x=>iVnWW0%g_fnPQnous4BNsOJK2dv9#?4E&(F%hR_Re`)US)9k z-~-IbqP`1$�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