Skip to content

feat(wild): playable-world kernel + BotW-style meadow on scene3d - #265

Closed
doodlewind wants to merge 1 commit into
mainfrom
charmed-zucchini
Closed

feat(wild): playable-world kernel + BotW-style meadow on scene3d#265
doodlewind wants to merge 1 commit into
mainfrom
charmed-zucchini

Conversation

@doodlewind

Copy link
Copy Markdown
Collaborator

A proof of concept for systemic open-world gameplay on the PocketJS stack, distilled from the engine architecture documented by Breath of the Wild research (the zeldaret/botw decompilation and the GDC 2017 chemistry-engine talk) — rebuilt from first principles on the PocketJS determinism contract, as infrastructure meant to scale.

blaze

Flint → the grass catches → the fire walks tuft-to-tuft up the trail → the orchard tree ignites and shakes its apples loose. None of this chain is scripted; it falls out of three chemistry rules.

The wild kernel (apps/wild/wild/, design record: docs/WILD.md)

  • Everything is an actor: one data record, one state record. ActorDef composes behavior from optional fields (body, fuel, cook, life, spHit, tags) — BotW's actor param file stack reduced to one literal. A def never contains code.
  • Chemistry is three rules over one quantity (heat). Elements change materials; elements change elements (water kills fire, wind stretches it); materials never change materials — that's physics. No rule names a def, which is why carrying a burning branch to a meadow just works.
  • Damage is a typed event carrying a physical kind + element + tag bonus (BotW SpHitTag: the axe is a chop weapon with ×3 vs tree-tagged actors, not "the tree tool").
  • Destruction is actor substitution: standing tree → felled trunk → 3 firewood logs; burned-out grass → scorch; apple + sustained heat → baked apple (IsBurnOutBorn, generalized).
  • The world is a pure fold (state[n+1] = F(state[n], input[n])): fixed 1/60 pipeline, one seeded rng, typed events out, nothing feeds back.

tests/wild.test.ts pins every tuning number — the flint/kindling/timber heat ladder, the grass chain reaching the orchard, cooking, water-beats-fire, four-chops-fell-a-tree, apples rolling downhill and settling, and the layout invariant that a lit campfire cannot torch the meadow by itself. tests/wild-sim.test.ts runs the bundle end-to-end in the sim host (renderless s3): byte-identical reruns, and the same journey ends on the same world hash at 60 Hz and 20 Hz.

The scene3d desktop surface (ported from feat/playset)

The kernel needed a 3D presentation path on main, so this PR also lands the research branch's scene3d surface for desktop, verbatim where possible:

  • engine/pocket3d/crates/pocket-scene3d (wgpu store/renderer/batcher + the s3 mount);
  • PROP.scene3d = 160 / DRAW_OP.sceneQuad = 9 in the spec (append-only; bun run gen + drift guard green), SCENE_QUAD emission in engine/core/draw.rs, graceful skips in the software raster, damage tracker, pocket-ui-wgpu walker, PSP GE / Vita / Symbian / ESP32-P4 consumers;
  • uihost composites bound scenes under the ui layer, and grows --hold plus a level-triggered --script "frame:mask[:analog]" for reproducible headless captures (all screenshots here are commands in apps/wild/README.md).

Cross-check: the branch's own rally bundle rendered through the ported host matches its committed reference at RMSE 0.16/255; all pre-existing web goldens are byte-identical; bun run test is green across all 13 stages.

A new display.scene3d capability id gates admission — no stock target ships a 3D core yet, so wild stays off every launcher registry (registry.generated.ts unchanged) and bun pocket check --target psp rejects it with capability.unavailable, as intended.

The meadow

vista campfire
timber blaze

Every mesh is a cached primitive or the terrain heightfield — no model files. One seeded height function serves both the kernel and the baked heightfield, so the drawn meadow and the simulated meadow cannot disagree. The BotW register comes from banded vertex colors, one warm sun + two-tone hemisphere ambient, thick linear fog matched to the sky horizon, and pooled billboard fire/smoke whose jitter is a stateless hash of (actor id, tick).

bun tools/build.ts wild-main
cd engine && cargo run -p uihost --release -- --app wild-main --scale 2

Scaling paths

Content scales as def rows; new elements (electricity, ice) are enum space + rule entries, not new systems. The kernel is exactly the guest-side half of the Pocket Voxel split, so a PSP path is the branch's GE scene3d core plus (if needed) a native ps-style hot loop — the def table doesn't change. The verb surface (queueHit / heatBurst / pickUp / throwHeld / detach + the event stream) is what a future wild runtime spec would pin.

🤖 Generated with Claude Code

Two halves that make systemic open-world gameplay run on the PocketJS
stack:

scene3d desktop surface (ported from feat/playset): the pocket-scene3d
wgpu crate, PROP.scene3d / DRAW_OP.sceneQuad spec codes, SCENE_QUAD
emission in the core with graceful skips in every other DrawList
consumer, scene_quads()/UiSurface::set_prop plumbing, and the uihost
graft that composites bound scenes under the ui layer — plus --hold and
a level-triggered --script "frame:mask[:analog]" for headless captures.
Cross-checked by rendering the research branch's rally bundle: RMSE
0.16/255 against its committed reference; existing goldens
byte-identical.

apps/wild: a deterministic playable-world kernel distilled from BotW
engine research (zeldaret/botw, the GDC 2017 chemistry talk) — actors
as data records, three chemistry rules over one heat quantity, typed
damage with SpHitTag bonuses, destruction as actor substitution — and a
meadow POC on it: trees chop into trunks into firewood, apples detach,
roll downhill and bake beside fires, flint lights campfires, grass fire
chains tuft-to-tuft into the orchard, the pond extinguishes. docs/WILD.md
is the design record; tests/wild.test.ts pins every tuning number
(the flint/kindling/timber heat ladder, the campfire-does-not-torch-
the-meadow layout invariant), tests/wild-sim.test.ts proves
byte-identical reruns and hz-invariant world trajectories; a new
display.scene3d capability gates admission (no stock target ships a 3D
core yet, so launcher registries are unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@doodlewind doodlewind closed this Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant