@almadar/std 16.203.0 → 16.205.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/behaviors/lolo/ui/game/atoms/std-choice-gate.lolo +1 -1
  2. package/behaviors/lolo/ui/game/atoms/std-fx-narrative.lolo +1 -1
  3. package/behaviors/lolo/ui/game/atoms/std-fx-particles.lolo +1 -1
  4. package/behaviors/lolo/ui/game/atoms/std-gate-lock.lolo +1 -1
  5. package/behaviors/lolo/ui/game/atoms/std-lives.lolo +1 -1
  6. package/behaviors/lolo/ui/game/atoms/std-loop-lock.lolo +1 -1
  7. package/behaviors/lolo/ui/game/atoms/std-objective-flow.lolo +1 -1
  8. package/behaviors/lolo/ui/game/atoms/std-pad-lock.lolo +1 -1
  9. package/behaviors/lolo/ui/game/atoms/std-patrol-hazard.lolo +1 -1
  10. package/behaviors/lolo/ui/game/atoms/std-pickup.lolo +1 -1
  11. package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +1 -1
  12. package/behaviors/lolo/ui/game/atoms/std-tutorial-overlay.lolo +1 -1
  13. package/behaviors/lolo/ui/game/atoms/std-velocity-gate.lolo +1 -1
  14. package/behaviors/lolo/ui/game/organisms/std-platformer-puzzle.lolo +302 -0
  15. package/behaviors/registry/ui/game/atoms/std-choice-gate.orb +82 -2
  16. package/behaviors/registry/ui/game/atoms/std-fx-narrative.orb +1 -1
  17. package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +82 -2
  18. package/behaviors/registry/ui/game/atoms/std-gate-lock.orb +48 -2
  19. package/behaviors/registry/ui/game/atoms/std-lives.orb +26 -2
  20. package/behaviors/registry/ui/game/atoms/std-loop-lock.orb +56 -2
  21. package/behaviors/registry/ui/game/atoms/std-objective-flow.orb +1 -1
  22. package/behaviors/registry/ui/game/atoms/std-pad-lock.orb +30 -2
  23. package/behaviors/registry/ui/game/atoms/std-patrol-hazard.orb +63 -2
  24. package/behaviors/registry/ui/game/atoms/std-pickup.orb +1 -1
  25. package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +1 -1
  26. package/behaviors/registry/ui/game/atoms/std-tutorial-overlay.orb +24 -2
  27. package/behaviors/registry/ui/game/atoms/std-velocity-gate.orb +75 -2
  28. package/behaviors/registry/ui/game/organisms/std-platformer-puzzle.orb +2063 -0
  29. package/dist/behaviors/exports-reader.js +1235 -0
  30. package/dist/behaviors/functions/index.d.ts +115 -14
  31. package/dist/behaviors/functions/index.js +1232 -1
  32. package/dist/behaviors/index.d.ts +1 -1
  33. package/dist/behaviors/index.js +1236 -1
  34. package/dist/behaviors/query.js +1235 -0
  35. package/dist/behaviors-embeddings.hash.json +3 -3
  36. package/dist/behaviors-embeddings.json +29 -25
  37. package/dist/behaviors-registry.json +1805 -17
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.js +1236 -1
  40. package/dist/knob-embeddings.hash.json +3 -3
  41. package/dist/knob-embeddings.json +1 -1
  42. package/dist/registry/factory-signatures.json +1 -1
  43. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  app std-choice-gate "1.0.0"
2
- "Headless choice-gate mechanic for side-view boards: a gate of N labeled option platforms where progress stops until the player commits to an answer. Listens BODY_MOVED and judges a gate when the player stands grounded on one of its option platforms (|dx| <= reachX of the option center, |dy| <= reachY of the gate's option plane — the pad-lock touch pattern): the correct option stamps the gate solved + chosen on the shared entity and emits CHOICE_CORRECT once (a solved gate never judges again, so the path stays open); a wrong option emits CHOICE_WRONG carrying the gate id, the chosen optionId, and the option's world position, so the board can bounce the player back and float the gate's hint (the board owns the bounce — the atom only reports). RESTART unsolves every gate. Renders nothing; boards draw the option platforms and labels from the shared entity (the render authority)."
2
+ "Headless choice-gate mechanic for side-view boards: a gate of N labeled option platforms where progress stops until the player commits to an answer. Listens BODY_MOVED and judges a gate when the player stands grounded on one of its option platforms (|dx| <= reachX of the option center, |dy| <= reachY of the gate's option plane — the pad-lock touch pattern): the correct option stamps the gate solved + chosen on the shared entity and emits CHOICE_CORRECT once (a solved gate never judges again, so the path stays open); a wrong option emits CHOICE_WRONG carrying the gate id, the chosen optionId, and the option's world position, so the board can bounce the player back and float the gate's hint (the board owns the bounce — the atom only reports). RESTART unsolves every gate. Renders nothing; boards draw the option platforms and labels from the shared entity (the render authority). Corresponds to the design-sheet field(s): challenge, agency."
3
3
  orbital ChoiceGateOrbital {
4
4
  type ChoiceOption = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-fx-narrative "1.0.0"
2
- "Headless pedagogy→fx translator for game boards and learning shells: turns high-level narrative events into big transient screen-space or world-space text effects consumed by std-fx-particles / fx-overlay. Levels emit NARRATE { text, style } and get a correctly styled, centered (or positioned) floating text burst without hand-rolling particle structs. Tutorials emit TUTORIAL_SHOW and the atom forwards SHOW to a composed std-tutorial-overlay trait. Renders nothing; centralizes the FX vocabulary so every level's teaching text looks and behaves the same."
2
+ "Headless pedagogy→fx translator for game boards and learning shells: turns high-level narrative events into big transient screen-space or world-space text effects consumed by std-fx-particles / fx-overlay. Levels emit NARRATE { text, style } and get a correctly styled, centered (or positioned) floating text burst without hand-rolling particle structs. Tutorials emit TUTORIAL_SHOW and the atom forwards SHOW to a composed std-tutorial-overlay trait. Renders nothing; centralizes the FX vocabulary so every level's teaching text looks and behaves the same. Corresponds to the design-sheet field(s): feedback."
3
3
 
4
4
  orbital FxNarrativeOrbital {
5
5
  type NarrativeCue = {
@@ -1,5 +1,5 @@
1
1
  app std-fx-particles "1.1.0"
2
- "Headless transient-fx mechanic serving BOTH game boards and learning shells: appends spawned particles on BURST — stamping maxTtl (fade envelope) and bornAt (epoch ms, smooth render interpolation) when absent — decays each entry's ttl every tick, drops the dead ones, and clears on RESTART. Name-blind mechanism: the effect-kind vocabulary is consumer-declared (FxPreset tables at the render call sites). Composed onto a [runtime, shared] entity; renders nothing — the board/shell owns the single render authority (draw-fx-layer for space \"world\", fx-overlay for space \"screen\")."
2
+ "Headless transient-fx mechanic serving BOTH game boards and learning shells: appends spawned particles on BURST — stamping maxTtl (fade envelope) and bornAt (epoch ms, smooth render interpolation) when absent — decays each entry's ttl every tick, drops the dead ones, and clears on RESTART. Name-blind mechanism: the effect-kind vocabulary is consumer-declared (FxPreset tables at the render call sites). Composed onto a [runtime, shared] entity; renders nothing — the board/shell owns the single render authority (draw-fx-layer for space \"world\", fx-overlay for space \"screen\"). Corresponds to the design-sheet field(s): feedback, rewards."
3
3
  orbital FxParticlesOrbital {
4
4
  type Fx = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-gate-lock "1.0.0"
2
- "Headless collectible-gate mechanic: doors that stay shut until the player's collected total reaches their cost. Listens COLLECT (the board's running total — stars, coins, keys) and flips every door whose cost is met, stamping open on the shared door rows and emitting GATE_OPENED for the first newly opened door (the shared entity is the render authority for the rest). While a closed door's rect contains the player it emits GATE_BLOCKED once per approach — re-arming only after the player steps out — so the board can answer with a PLACE back and a locked fx. RESTART re-locks every door and zeroes the total. Renders nothing; boards draw closed doors as bars/walls and open ones as gaps."
2
+ "Headless collectible-gate mechanic: doors that stay shut until the player's collected total reaches their cost. Listens COLLECT (the board's running total — stars, coins, keys) and flips every door whose cost is met, stamping open on the shared door rows and emitting GATE_OPENED for the first newly opened door (the shared entity is the render authority for the rest). While a closed door's rect contains the player it emits GATE_BLOCKED once per approach — re-arming only after the player steps out — so the board can answer with a PLACE back and a locked fx. RESTART re-locks every door and zeroes the total. Renders nothing; boards draw closed doors as bars/walls and open ones as gaps. Corresponds to the design-sheet field(s): challenge, rewards."
3
3
  orbital GateLockOrbital {
4
4
  type Door = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-lives "1.0.0"
2
- "Headless lives + checkpoint authority for boards with stakes: owns lives, the current respawn point, and nothing else. DAMAGE (call sites rename their hazard sources — BODY_HAZARD, BODY_FELL, PATROL_HIT — onto it) costs one life, respecting an invulnerability window so overlapping hazards can't chain-drain; losing a life emits LIFE_LOST plus RESPAWN with the current checkpoint (boards route RESPAWN to the body authority's PLACE), and losing the last emits GAME_OVER instead. Checkpoints advance automatically: BODY_MOVED crossing a configured checkpoint's atX moves the respawn point forward and emits CHECKPOINT_REACHED once per checkpoint (tracked by furthest atX reached, so checkpoints are ordered along the run). RESTART reseeds lives and respawn to the spawn. Renders nothing — HUDs read lives off the shared entity."
2
+ "Headless lives + checkpoint authority for boards with stakes: owns lives, the current respawn point, and nothing else. DAMAGE (call sites rename their hazard sources — BODY_HAZARD, BODY_FELL, PATROL_HIT — onto it) costs one life, respecting an invulnerability window so overlapping hazards can't chain-drain; losing a life emits LIFE_LOST plus RESPAWN with the current checkpoint (boards route RESPAWN to the body authority's PLACE), and losing the last emits GAME_OVER instead. Checkpoints advance automatically: BODY_MOVED crossing a configured checkpoint's atX moves the respawn point forward and emits CHECKPOINT_REACHED once per checkpoint (tracked by furthest atX reached, so checkpoints are ordered along the run). RESTART reseeds lives and respawn to the spawn. Renders nothing — HUDs read lives off the shared entity. Corresponds to the design-sheet field(s): challenge, feedback."
3
3
  orbital LivesOrbital {
4
4
  type Checkpoint = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-loop-lock "1.0.0"
2
- "Headless winding-lock mechanic: locks that open only after the player travels a full revolution around their anchor. Listens BODY_MOVED and, while the player stays within a radial band of a lock's ring, accumulates the wrapped angular delta of their position into swept (radians, signed — either direction counts); when |swept| reaches turns × 2π the lock flips unlocked and emits LOOP_UNLOCKED once. Entering the band reseeds the angle so leaving and returning never jumps the sweep; progress is kept across exits, so a revolution can be completed in stages. RESTART re-locks every lock. Renders nothing; boards draw the ring/chest and read swept from the shared entity (the render authority)."
2
+ "Headless winding-lock mechanic: locks that open only after the player travels a full revolution around their anchor. Listens BODY_MOVED and, while the player stays within a radial band of a lock's ring, accumulates the wrapped angular delta of their position into swept (radians, signed — either direction counts); when |swept| reaches turns × 2π the lock flips unlocked and emits LOOP_UNLOCKED once. Entering the band reseeds the angle so leaving and returning never jumps the sweep; progress is kept across exits, so a revolution can be completed in stages. RESTART re-locks every lock. Renders nothing; boards draw the ring/chest and read swept from the shared entity (the render authority). Corresponds to the design-sheet field(s): challenge, rewards."
3
3
  orbital LoopLockOrbital {
4
4
  type LoopLock = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-objective-flow "1.0.0"
2
- "Headless win/lose authority for objective boards: owns only result. Listens PROGRESS (objectivesLeft + movesLeft) and sets result to won when every objective is reached, lost when the move budget runs out first, else none. Renders nothing."
2
+ "Headless win/lose authority for objective boards: owns only result. Listens PROGRESS (objectivesLeft + movesLeft) and sets result to won when every objective is reached, lost when the move budget runs out first, else none. Renders nothing. Corresponds to the design-sheet field(s): goals, feedback."
3
3
  orbital ObjectiveFlowOrbital {
4
4
  entity FlowState [runtime, shared] {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-pad-lock "1.0.0"
2
- "Headless pad-lock mechanic: floor pads that light when the player steps on them, completing a set when every pad is lit. Listens BODY_MOVED and lights any unlit live pad the player's rect touches (|dx| <= reachX, |dy| <= reachY of the pad center); a lit pad stays lit. Pads may carry a group number (grp 0 = ungrouped, always live): when groups are used, only pads of the lowest uncompleted group are live — pads of later groups refuse to light until the current group finishes, so one sum must be finished before the next. When a group completes the trait emits PAD_GROUP_COMPLETED once for it (first newly completed group reports; the shared entity carries the rest); when every pad in the set is lit it stamps completed and emits PAD_SET_COMPLETED once. The lowest uncompleted group is stamped on the shared entity as currentGrp so boards can pulse exactly the live pads (0 = no group open / ungrouped pads). RESTART unlights every pad and resets the set. Renders nothing; boards draw the pads and read lit from the shared entity (the render authority)."
2
+ "Headless pad-lock mechanic: floor pads that light when the player steps on them, completing a set when every pad is lit. Listens BODY_MOVED and lights any unlit live pad the player's rect touches (|dx| <= reachX, |dy| <= reachY of the pad center); a lit pad stays lit. Pads may carry a group number (grp 0 = ungrouped, always live): when groups are used, only pads of the lowest uncompleted group are live — pads of later groups refuse to light until the current group finishes, so one sum must be finished before the next. When a group completes the trait emits PAD_GROUP_COMPLETED once for it (first newly completed group reports; the shared entity carries the rest); when every pad in the set is lit it stamps completed and emits PAD_SET_COMPLETED once. The lowest uncompleted group is stamped on the shared entity as currentGrp so boards can pulse exactly the live pads (0 = no group open / ungrouped pads). RESTART unlights every pad and resets the set. Renders nothing; boards draw the pads and read lit from the shared entity (the render authority). Corresponds to the design-sheet field(s): challenge, mechanics."
3
3
  orbital PadLockOrbital {
4
4
  type PadLock = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-patrol-hazard "1.0.0"
2
- "Headless patrol-hazard mechanic for side-view boards: moves each configured patrol back and forth along its [x0, x1] beat at its own speed (33ms tick, ping-pong with clamped turnarounds; a patrol declaring waveAmp/wavePeriod also bobs vertically — cy = y + waveAmp·sin(2πt/wavePeriod from a per-row time accumulator — and the hit test and render read cy, so a waveAmp of 0 keeps the flat beat), tracks the player position off the body authority's BODY_MOVED, and emits PATROL_HIT once per contact — a per-patrol hit flag re-arms only after the player separates, so damage rules stay sparse (when two patrols connect on the same tick the first reports; the other reports on the next tick). Patrols live on a [runtime, shared] entity for the render layer (boards draw them as markers/sprites); damage, lives, and respawn stay downstream (std-lives) — this atom simulates, it never judges. Renders nothing."
2
+ "Headless patrol-hazard mechanic for side-view boards: moves each configured patrol back and forth along its [x0, x1] beat at its own speed (33ms tick, ping-pong with clamped turnarounds; a patrol declaring waveAmp/wavePeriod also bobs vertically — cy = y + waveAmp·sin(2πt/wavePeriod from a per-row time accumulator — and the hit test and render read cy, so a waveAmp of 0 keeps the flat beat), tracks the player position off the body authority's BODY_MOVED, and emits PATROL_HIT once per contact — a per-patrol hit flag re-arms only after the player separates, so damage rules stay sparse (when two patrols connect on the same tick the first reports; the other reports on the next tick). Patrols live on a [runtime, shared] entity for the render layer (boards draw them as markers/sprites); damage, lives, and respawn stay downstream (std-lives) — this atom simulates, it never judges. Renders nothing. Corresponds to the design-sheet field(s): challenge, dynamics."
3
3
  orbital PatrolHazardOrbital {
4
4
  type Patrol = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-pickup "1.0.0"
2
- "Headless side-view collectible authority — the platformer twin of grid std-gather. Listens BODY_MOVED and, when the player touches an uncollected feature (|dx| <= reachX, |dy| <= reachY of the feature center — the coef-pad touch idiom minus the grounded requirement, so airborne pickups work), stamps it collected on the shared entity and emits PICKED once per item (id, kind, position, glyph, message) plus COLLECT{total} with the running count (the event std-gate-lock already consumes). When every feature is collected it emits PICKUP_SET_COMPLETED once. RESTART re-arms every feature and zeroes the count. kind is board-defined vocabulary (star, boost, …) — this atom reports, boards judge. Renders nothing; boards draw the features and read collected from the shared entity."
2
+ "Headless side-view collectible authority — the platformer twin of grid std-gather. Listens BODY_MOVED and, when the player touches an uncollected feature (|dx| <= reachX, |dy| <= reachY of the feature center — the coef-pad touch idiom minus the grounded requirement, so airborne pickups work), stamps it collected on the shared entity and emits PICKED once per item (id, kind, position, glyph, message) plus COLLECT{total} with the running count (the event std-gate-lock already consumes). When every feature is collected it emits PICKUP_SET_COMPLETED once. RESTART re-arms every feature and zeroes the count. kind is board-defined vocabulary (star, boost, …) — this atom reports, boards judge. Renders nothing; boards draw the features and read collected from the shared entity. Corresponds to the design-sheet field(s): rewards."
3
3
  orbital PickupOrbital {
4
4
  type PickupFeature = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-platformer-body "1.0.0"
2
- "Headless run/jump platformer-physics authority: the SOLE writer of body + fell + hazardId + goalId on side-view boards. Where std-motion-body owns free 2D drift (no collision), this atom owns the platformer contract: every 33ms physics tick it integrates gravity into the body's vertical velocity, steps position in per-second units, and collides the body rect against the config platforms with one-way semantics — a body moving in the gravity direction that overlaps a ground/platform tile lands on its anti-gravity face (vy zeroed, grounded set), while a body moving against gravity passes through, so jumping up through a platform and walking up a staircase both just work. The sign of gravity IS the vertical convention: positive pulls toward +y (screen boards, y down — sprite canvases), negative toward −y (math canvases, y up); jumps always fire against it. Intents: STEER sets horizontal velocity (dir −1/0/1 × moveSpeed, hold-to-run: keydown steers, keyup steers 0), JUMP kicks vertical velocity when grounded, PLACE teleports (spawns, hazard respawns), RESTART reseeds. Emits BODY_MOVED every tick for the render layer (boards that don't subscribe pay nothing), plus the sparse rule signals a board needs to score: BODY_JUMPED, BODY_LANDED (with impact speed), BODY_HAZARD (once per hazard entry, re-arms on exit), BODY_GOAL (same arming), BODY_FELL (once per fall past killY, re-armed by PLACE/RESTART). Drift regions: config.driftRegions lists axis-aligned rects each carrying a constant acceleration (ax, ay) applied with the same 0.033s dt whenever the body's center is inside (empty list = zero behavior change). Curve skating: when config.skate is on and the grounded body comes within skateSnap of the config.skateCurve surface, the body rides the curve — y snaps to the interpolated surface and tangential gravity (g·slope/(1+slope²)) accelerates vx, and the vertical velocity is the tangential projection (s = vx·cos θ, vy = s·sin θ — no discontinuous jumps at sample boundaries), so the body slides downhill along the graph itself and launches ballistically off its ends; jumping kicks free. Sparse BODY_SKATE_START/BODY_SKATE_END signals fire on engage/disengage so boards can layer fx. Lives, score, and win/lose stay downstream — this atom simulates, it never judges. Renders nothing."
2
+ "Headless run/jump platformer-physics authority: the SOLE writer of body + fell + hazardId + goalId on side-view boards. Where std-motion-body owns free 2D drift (no collision), this atom owns the platformer contract: every 33ms physics tick it integrates gravity into the body's vertical velocity, steps position in per-second units, and collides the body rect against the config platforms with one-way semantics — a body moving in the gravity direction that overlaps a ground/platform tile lands on its anti-gravity face (vy zeroed, grounded set), while a body moving against gravity passes through, so jumping up through a platform and walking up a staircase both just work. The sign of gravity IS the vertical convention: positive pulls toward +y (screen boards, y down — sprite canvases), negative toward −y (math canvases, y up); jumps always fire against it. Intents: STEER sets horizontal velocity (dir −1/0/1 × moveSpeed, hold-to-run: keydown steers, keyup steers 0), JUMP kicks vertical velocity when grounded, PLACE teleports (spawns, hazard respawns), RESTART reseeds. Emits BODY_MOVED every tick for the render layer (boards that don't subscribe pay nothing), plus the sparse rule signals a board needs to score: BODY_JUMPED, BODY_LANDED (with impact speed), BODY_HAZARD (once per hazard entry, re-arms on exit), BODY_GOAL (same arming), BODY_FELL (once per fall past killY, re-armed by PLACE/RESTART). Drift regions: config.driftRegions lists axis-aligned rects each carrying a constant acceleration (ax, ay) applied with the same 0.033s dt whenever the body's center is inside (empty list = zero behavior change). Curve skating: when config.skate is on and the grounded body comes within skateSnap of the config.skateCurve surface, the body rides the curve — y snaps to the interpolated surface and tangential gravity (g·slope/(1+slope²)) accelerates vx, and the vertical velocity is the tangential projection (s = vx·cos θ, vy = s·sin θ — no discontinuous jumps at sample boundaries), so the body slides downhill along the graph itself and launches ballistically off its ends; jumping kicks free. Sparse BODY_SKATE_START/BODY_SKATE_END signals fire on engage/disengage so boards can layer fx. Lives, score, and win/lose stay downstream — this atom simulates, it never judges. Renders nothing. Corresponds to the design-sheet field(s): mechanics, dynamics."
3
3
  orbital PlatformerBodyOrbital {
4
4
  type PlatformerBody = {
5
5
  x : number!
@@ -1,5 +1,5 @@
1
1
  app std-tutorial-overlay "1.0.0"
2
- "Tutorial modal with live-demo steps for game boards and learning shells: a paged overlay — title, a live previewTrait frame playing the mechanic via std-tutorial-autodemo (a bare game canvas, no shell chrome), one line of body copy, a step counter, and Back / Next / Skip — composed entirely from registered render types (stack + text + button + trait frame) into the overlay slot, so no new UI component is needed. autoShow opens it on INIT for first-time players; a board's help button re-opens it any time via SHOW (which rewinds to step one). DISMISS (or finishing the last step) marks the run done, clears the overlay, and emits TUTORIAL_DONE so the board can unpause or log. Steps are pure config — a board teaches a new mechanic by adding one { id, title, body, demoId } row plus a previewTrait binding."
2
+ "Tutorial modal with live-demo steps for game boards and learning shells: a paged overlay — title, a live previewTrait frame playing the mechanic via std-tutorial-autodemo (a bare game canvas, no shell chrome), one line of body copy, a step counter, and Back / Next / Skip — composed entirely from registered render types (stack + text + button + trait frame) into the overlay slot, so no new UI component is needed. autoShow opens it on INIT for first-time players; a board's help button re-opens it any time via SHOW (which rewinds to step one). DISMISS (or finishing the last step) marks the run done, clears the overlay, and emits TUTORIAL_DONE so the board can unpause or log. Steps are pure config — a board teaches a new mechanic by adding one { id, title, body, demoId } row plus a previewTrait binding. Corresponds to the design-sheet field(s): feedback, agency."
3
3
  orbital TutorialOverlayOrbital {
4
4
  type TutorialStep = {
5
5
  id : string!
@@ -1,5 +1,5 @@
1
1
  app std-velocity-gate "1.0.0"
2
- "Headless velocity-gate mechanic: gates that open only when the player crosses them inside a speed band, optionally in a required direction, optionally sustained for a dwell. Listens BODY_MOVED and, per closed gate, tests the player's rect (padded by reachMargin), their speed against [minSpeed, maxSpeed], and their horizontal direction against dir (0 = either). Instant gates (dwellMs 0) open on the first passing cross; dwell gates (dwellMs > 0) accumulate ~33ms per passing move and open once held reaches dwellMs — a failing move resets the hold. The first newly opened gate emits VELOCITY_GATE_OPENED (the shared entity carries the rest). Entering a closed INSTANT gate while NOT passing emits VELOCITY_GATE_DENIED once per approach — re-arming only after the player steps out — so the board can answer with a PLACE back and a hint fx; dwell gates never deny (a hot entry is fine — coming to rest inside is the point), a failed hold simply resets. RESTART re-closes every gate. Renders nothing; boards draw the gate band/chest and read open/held from the shared entity (the render authority)."
2
+ "Headless velocity-gate mechanic: gates that open only when the player crosses them inside a speed band, optionally in a required direction, optionally sustained for a dwell. Listens BODY_MOVED and, per closed gate, tests the player's rect (padded by reachMargin), their speed against [minSpeed, maxSpeed], and their horizontal direction against dir (0 = either). Instant gates (dwellMs 0) open on the first passing cross; dwell gates (dwellMs > 0) accumulate ~33ms per passing move and open once held reaches dwellMs — a failing move resets the hold. The first newly opened gate emits VELOCITY_GATE_OPENED (the shared entity carries the rest). Entering a closed INSTANT gate while NOT passing emits VELOCITY_GATE_DENIED once per approach — re-arming only after the player steps out — so the board can answer with a PLACE back and a hint fx; dwell gates never deny (a hot entry is fine — coming to rest inside is the point), a failed hold simply resets. RESTART re-closes every gate. Renders nothing; boards draw the gate band/chest and read open/held from the shared entity (the render authority). Corresponds to the design-sheet field(s): challenge, mechanics."
3
3
  orbital VelocityGateOrbital {
4
4
  type VelocityGate = {
5
5
  id : string!
@@ -0,0 +1,302 @@
1
+ app std-platformer-puzzle "1.0.0"
2
+ "Platformer + puzzle genre substrate organism. Composes the standard authorities — platformer-body, pickup, objective-flow, choice-gate, fx-particles, fx-narrative, tutorial-overlay — and enforces five trait-typed pillar slots: agency, challenge, goal, reward, feedback. Levels consume this organism, fill every slot with a local rebinding trait, and add their own geometry, render, and math rules. Math targets and grade levels stay downstream in the domain package; this substrate is domain-agnostic."
3
+
4
+ orbital PlatformerPuzzleOrbital {
5
+ uses Body from "std/behaviors/std-platformer-body"
6
+ uses Pickup from "std/behaviors/std-pickup"
7
+ uses Gate from "std/behaviors/std-objective-flow"
8
+ uses Choice from "std/behaviors/std-choice-gate"
9
+ uses Particles from "std/behaviors/std-fx-particles"
10
+ uses Narrative from "std/behaviors/std-fx-narrative"
11
+ uses Tutorial from "std/behaviors/std-tutorial-overlay"
12
+
13
+ type PlatformerBody = {
14
+ x : number!
15
+ y : number!
16
+ width : number!
17
+ height : number!
18
+ vx : number
19
+ vy : number
20
+ grounded : boolean
21
+ facingRight : boolean
22
+ }
23
+ type PlatformerPlatform = {
24
+ id : string
25
+ x : number!
26
+ y : number!
27
+ width : number!
28
+ height : number!
29
+ type : "ground" | "platform" | "hazard" | "goal"
30
+ }
31
+ type PlatformerCurveSample = {
32
+ x : number!
33
+ y : number!
34
+ }
35
+ type BodyDriftRegion = {
36
+ id : string!
37
+ x0 : number!
38
+ x1 : number!
39
+ y0 : number!
40
+ y1 : number!
41
+ ax : number!
42
+ ay : number!
43
+ }
44
+ type CurveMod = {
45
+ x0 : number!
46
+ x1 : number!
47
+ a : number!
48
+ b : number
49
+ h : number!
50
+ k : number!
51
+ }
52
+ type PlatformerTuning = {
53
+ jumpStrength : number
54
+ moveSpeed : number
55
+ gravity : number
56
+ }
57
+ type PickupFeature = {
58
+ id : string!
59
+ x : number!
60
+ y : number!
61
+ kind : string!
62
+ glyph : string
63
+ message : string
64
+ collected : boolean
65
+ }
66
+ type ChoiceOption = {
67
+ id : string!
68
+ dx : number!
69
+ label : string!
70
+ correct : boolean!
71
+ }
72
+ type ChoiceGate = {
73
+ id : string!
74
+ x : number!
75
+ y : number!
76
+ hint : string
77
+ options : [ChoiceOption]!
78
+ solved : boolean
79
+ chosen : string
80
+ }
81
+ type Fx = {
82
+ id : string!
83
+ type : string!
84
+ x : number!
85
+ z : number
86
+ y : number
87
+ message : string
88
+ ttl : number!
89
+ maxTtl : number
90
+ bornAt : number
91
+ space : string
92
+ effect : string
93
+ color : string
94
+ size : number
95
+ vx : number
96
+ vy : number
97
+ vz : number
98
+ particleCount : number
99
+ animation : string
100
+ }
101
+ type FxPreset = {
102
+ type : string!
103
+ color : string
104
+ color2 : string
105
+ size : number
106
+ shape : string
107
+ count : number
108
+ glow : number
109
+ gravity : number
110
+ vx : number
111
+ vy : number
112
+ vz : number
113
+ space : string
114
+ effect : string
115
+ particleCount : number
116
+ animation : string
117
+ }
118
+ type NarrativeCue = {
119
+ text : string!
120
+ style : "hint" | "fact" | "warn" | "celebrate"
121
+ x : number
122
+ y : number
123
+ ttl : number
124
+ space : "screen" | "world"
125
+ }
126
+ type StyleDef = {
127
+ color : string!
128
+ size : number!
129
+ ttl : number!
130
+ effect : string!
131
+ }
132
+ type TutorialStep = {
133
+ id : string!
134
+ title : string!
135
+ body : string
136
+ demoId : string
137
+ }
138
+ type Asset = {
139
+ url : asset
140
+ atlas : asset
141
+ sprite : string
142
+ role : string
143
+ category : string
144
+ animations : [string]
145
+ style : string
146
+ variant : string
147
+ dimension : string
148
+ aspect : string
149
+ name : string
150
+ thumbnailUrl : string
151
+ }
152
+ type DirectionAssets = {
153
+ up : Asset
154
+ down : Asset
155
+ left : Asset
156
+ right : Asset
157
+ }
158
+
159
+ entity PlatformerPuzzleData [runtime, shared] {
160
+ id : string!
161
+ body : PlatformerBody = { x: 0, y: 0, width: 1, height: 1, vx: 0, vy: 0, grounded: false, facingRight: true }
162
+ fell : boolean = false
163
+ hazardId : string = ""
164
+ goalId : string = ""
165
+ skating : boolean = false
166
+ curveMods : [CurveMod] = []
167
+ tuning : PlatformerTuning = {}
168
+ pickups : [PickupFeature] = []
169
+ pickupCompleted : boolean = false
170
+ total : number = 0
171
+ choices : [ChoiceGate] = []
172
+ result : string = "none"
173
+ fx : [Fx] = []
174
+ narrativeSeq : number = 0
175
+ lastNarrative : string = ""
176
+ step : number = 0
177
+ done : boolean = false
178
+ score : number = 0
179
+ lives : number = 3
180
+ objectivesLeft : number = 1
181
+ celebrated : boolean = false
182
+ }
183
+
184
+ trait PlatformerPuzzleBody = Body.traits.PlatformerBody -> PlatformerPuzzleData {
185
+ events {
186
+ STEER: STEER
187
+ JUMP: JUMP
188
+ PLACE: PLACE
189
+ BODY_MOVED: BODY_MOVED
190
+ BODY_JUMPED: BODY_JUMPED
191
+ BODY_LANDED: BODY_LANDED
192
+ BODY_HAZARD: BODY_HAZARD
193
+ BODY_GOAL: BODY_GOAL
194
+ BODY_FELL: BODY_FELL
195
+ BODY_SKATE_START: BODY_SKATE_START
196
+ BODY_SKATE_END: BODY_SKATE_END
197
+ CURVE_MOD_ADD: CURVE_MOD_ADD
198
+ CURVE_MOD_CLEAR: CURVE_MOD_CLEAR
199
+ SET_TUNING: SET_TUNING
200
+ }
201
+ config { running: true }
202
+ }
203
+
204
+ trait PlatformerPuzzlePickup = Pickup.traits.Pickup -> PlatformerPuzzleData {
205
+ events {
206
+ BODY_MOVED: BODY_MOVED
207
+ }
208
+ config { running: true }
209
+ }
210
+
211
+ trait PlatformerPuzzleObjective = Gate.traits.ObjectiveFlow -> PlatformerPuzzleData {
212
+ events {
213
+ PROGRESS: PROGRESS
214
+ GAME_END: GAME_END
215
+ }
216
+ config { running: true }
217
+ }
218
+
219
+ trait PlatformerPuzzleChoice = Choice.traits.ChoiceGate -> PlatformerPuzzleData {
220
+ events {
221
+ BODY_MOVED: BODY_MOVED
222
+ }
223
+ config { running: true }
224
+ }
225
+
226
+ trait PlatformerPuzzleFx = Particles.traits.FxParticles -> PlatformerPuzzleData {
227
+ events {
228
+ BURST: BURST
229
+ }
230
+ config { running: true }
231
+ }
232
+
233
+ trait PlatformerPuzzleNarrative = Narrative.traits.FxNarrative -> PlatformerPuzzleData {
234
+ events {
235
+ NARRATE: NARRATE
236
+ BURST: BURST
237
+ }
238
+ config { running: true }
239
+ }
240
+
241
+ trait PlatformerPuzzleTutorial = Tutorial.traits.TutorialOverlay -> PlatformerPuzzleData {
242
+ events {
243
+ SHOW: SHOW
244
+ TUTORIAL_DONE: TUTORIAL_DONE
245
+ }
246
+ config { autoShow: false, previewTrait: @trait.PlatformerPuzzleNoopPreview }
247
+ }
248
+
249
+ trait PlatformerPuzzleNoopPreview -> PlatformerPuzzleData [interaction, instance] {
250
+ initial: idle
251
+ state idle {
252
+ INIT -> idle
253
+ (render-ui overlay null)
254
+ }
255
+ }
256
+
257
+ trait PlatformerPuzzle -> @rebindable PlatformerPuzzleData [interaction, instance] {
258
+ initial: active
259
+
260
+ state active {
261
+ INIT -> active
262
+ (render-ui main null)
263
+ }
264
+
265
+ config {
266
+ agencyTrait : trait
267
+ @label "Agency trait"
268
+ @description "Trait that provides player verbs and immediate response. Usually a rebinding of std-platformer-body, std-motion-body, or std-hero-nav."
269
+ @tier "domain"
270
+ challengeTrait : trait
271
+ @label "Challenge trait"
272
+ @description "Trait that provides the obstacle, decision, or opposition. Usually a rebinding of std-choice-gate, std-gate-lock, std-patrol-hazard, std-velocity-gate, std-loop-lock, or std-pad-lock."
273
+ @tier "domain"
274
+ goalTrait : trait
275
+ @label "Goal trait"
276
+ @description "Trait that resolves the win condition. Usually a rebinding of std-objective-flow or std-objective-reach."
277
+ @tier "domain"
278
+ rewardTrait : trait
279
+ @label "Reward trait"
280
+ @description "Trait that provides collectibles or scoring. Usually a rebinding of std-pickup, std-score, std-xp, or std-gold."
281
+ @tier "domain"
282
+ feedbackTrait : trait
283
+ @label "Feedback trait"
284
+ @description "Trait that provides visual, audio, or narrative feedback. Usually a rebinding of std-fx-particles, std-fx-narrative, std-tutorial-overlay, std-audio-cue, or std-zone-card."
285
+ @tier "domain"
286
+ backgroundAsset : Asset = {}
287
+ @label "Background Asset"
288
+ @description "Game-shell background panel sprite (theme chrome)."
289
+ @tier "presentation"
290
+ hudBackgroundAsset : Asset = {}
291
+ @label "HUD Background Asset"
292
+ @description "HUD panel background sprite (theme chrome)."
293
+ @tier "presentation"
294
+ directionAssets : DirectionAssets = {}
295
+ @label "Direction Assets"
296
+ @description "D-pad direction icon sprites."
297
+ @tier "presentation"
298
+ }
299
+ }
300
+
301
+ page "/platformer-puzzle" as PlatformerPuzzlePage -> PlatformerPuzzleBody, PlatformerPuzzlePickup, PlatformerPuzzleObjective, PlatformerPuzzleChoice, PlatformerPuzzleFx, PlatformerPuzzleNarrative, PlatformerPuzzleTutorial, PlatformerPuzzle
302
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Headless choice-gate mechanic for side-view boards: a gate of N labeled option platforms where progress stops until the player commits to an answer. Listens BODY_MOVED and judges a gate when the player stands grounded on one of its option platforms (|dx| <= reachX of the option center, |dy| <= reachY of the gate's option plane — the pad-lock touch pattern): the correct option stamps the gate solved + chosen on the shared entity and emits CHOICE_CORRECT once (a solved gate never judges again, so the path stays open); a wrong option emits CHOICE_WRONG carrying the gate id, the chosen optionId, and the option's world position, so the board can bounce the player back and float the gate's hint (the board owns the bounce — the atom only reports). RESTART unsolves every gate. Renders nothing; boards draw the option platforms and labels from the shared entity (the render authority).",
2
+ "description": "Headless choice-gate mechanic for side-view boards: a gate of N labeled option platforms where progress stops until the player commits to an answer. Listens BODY_MOVED and judges a gate when the player stands grounded on one of its option platforms (|dx| <= reachX of the option center, |dy| <= reachY of the gate's option plane — the pad-lock touch pattern): the correct option stamps the gate solved + chosen on the shared entity and emits CHOICE_CORRECT once (a solved gate never judges again, so the path stays open); a wrong option emits CHOICE_WRONG carrying the gate id, the chosen optionId, and the option's world position, so the board can bounce the player back and float the gate's hint (the board owns the bounce — the atom only reports). RESTART unsolves every gate. Renders nothing; boards draw the option platforms and labels from the shared entity (the render authority). Corresponds to the design-sheet field(s): challenge, agency.",
3
3
  "ledger": {
4
4
  "entries": {
5
5
  "ent_01M144Y1KF1D8W68N3195C53AC": {
@@ -847,7 +847,87 @@
847
847
  ]
848
848
  }
849
849
  }
850
- ]
850
+ ],
851
+ "types": {
852
+ "ChoiceGate": [
853
+ {
854
+ "name": "id",
855
+ "required": true,
856
+ "type": "string"
857
+ },
858
+ {
859
+ "name": "x",
860
+ "required": true,
861
+ "type": "number"
862
+ },
863
+ {
864
+ "name": "y",
865
+ "required": true,
866
+ "type": "number"
867
+ },
868
+ {
869
+ "name": "hint",
870
+ "type": "string"
871
+ },
872
+ {
873
+ "name": "options",
874
+ "properties": [
875
+ {
876
+ "name": "id",
877
+ "required": true,
878
+ "type": "string"
879
+ },
880
+ {
881
+ "name": "dx",
882
+ "required": true,
883
+ "type": "number"
884
+ },
885
+ {
886
+ "name": "label",
887
+ "required": true,
888
+ "type": "string"
889
+ },
890
+ {
891
+ "name": "correct",
892
+ "required": true,
893
+ "type": "boolean"
894
+ }
895
+ ],
896
+ "required": true,
897
+ "type": "[object]"
898
+ },
899
+ {
900
+ "name": "solved",
901
+ "type": "boolean"
902
+ },
903
+ {
904
+ "name": "chosen",
905
+ "type": "string"
906
+ }
907
+ ],
908
+ "ChoiceOption": [
909
+ {
910
+ "name": "id",
911
+ "required": true,
912
+ "type": "string"
913
+ },
914
+ {
915
+ "name": "dx",
916
+ "required": true,
917
+ "type": "number"
918
+ },
919
+ {
920
+ "name": "label",
921
+ "required": true,
922
+ "type": "string"
923
+ },
924
+ {
925
+ "name": "correct",
926
+ "required": true,
927
+ "type": "boolean"
928
+ }
929
+ ]
930
+ }
851
931
  }
852
932
  ],
853
933
  "schemaVersion": 1,
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Headless pedagogy→fx translator for game boards and learning shells: turns high-level narrative events into big transient screen-space or world-space text effects consumed by std-fx-particles / fx-overlay. Levels emit NARRATE { text, style } and get a correctly styled, centered (or positioned) floating text burst without hand-rolling particle structs. Tutorials emit TUTORIAL_SHOW and the atom forwards SHOW to a composed std-tutorial-overlay trait. Renders nothing; centralizes the FX vocabulary so every level's teaching text looks and behaves the same.",
2
+ "description": "Headless pedagogy→fx translator for game boards and learning shells: turns high-level narrative events into big transient screen-space or world-space text effects consumed by std-fx-particles / fx-overlay. Levels emit NARRATE { text, style } and get a correctly styled, centered (or positioned) floating text burst without hand-rolling particle structs. Tutorials emit TUTORIAL_SHOW and the atom forwards SHOW to a composed std-tutorial-overlay trait. Renders nothing; centralizes the FX vocabulary so every level's teaching text looks and behaves the same. Corresponds to the design-sheet field(s): feedback.",
3
3
  "ledger": {
4
4
  "entries": {
5
5
  "ent_01M1GXD11PARSZADDZ8Y7G9B7Q": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Headless transient-fx mechanic serving BOTH game boards and learning shells: appends spawned particles on BURST — stamping maxTtl (fade envelope) and bornAt (epoch ms, smooth render interpolation) when absent — decays each entry's ttl every tick, drops the dead ones, and clears on RESTART. Name-blind mechanism: the effect-kind vocabulary is consumer-declared (FxPreset tables at the render call sites). Composed onto a [runtime, shared] entity; renders nothing — the board/shell owns the single render authority (draw-fx-layer for space \"world\", fx-overlay for space \"screen\").",
2
+ "description": "Headless transient-fx mechanic serving BOTH game boards and learning shells: appends spawned particles on BURST — stamping maxTtl (fade envelope) and bornAt (epoch ms, smooth render interpolation) when absent — decays each entry's ttl every tick, drops the dead ones, and clears on RESTART. Name-blind mechanism: the effect-kind vocabulary is consumer-declared (FxPreset tables at the render call sites). Composed onto a [runtime, shared] entity; renders nothing — the board/shell owns the single render authority (draw-fx-layer for space \"world\", fx-overlay for space \"screen\"). Corresponds to the design-sheet field(s): feedback, rewards.",
3
3
  "ledger": {
4
4
  "entries": {
5
5
  "ent_01KXG04TFZP9QXE9KF516SP9KC": {
@@ -643,7 +643,87 @@
643
643
  }
644
644
  ]
645
645
  }
646
- ]
646
+ ],
647
+ "types": {
648
+ "Fx": [
649
+ {
650
+ "name": "id",
651
+ "required": true,
652
+ "type": "string"
653
+ },
654
+ {
655
+ "name": "type",
656
+ "required": true,
657
+ "type": "string"
658
+ },
659
+ {
660
+ "name": "x",
661
+ "required": true,
662
+ "type": "number"
663
+ },
664
+ {
665
+ "name": "z",
666
+ "type": "number"
667
+ },
668
+ {
669
+ "name": "y",
670
+ "type": "number"
671
+ },
672
+ {
673
+ "name": "message",
674
+ "type": "string"
675
+ },
676
+ {
677
+ "name": "ttl",
678
+ "required": true,
679
+ "type": "number"
680
+ },
681
+ {
682
+ "name": "maxTtl",
683
+ "type": "number"
684
+ },
685
+ {
686
+ "name": "bornAt",
687
+ "type": "number"
688
+ },
689
+ {
690
+ "name": "space",
691
+ "type": "string"
692
+ },
693
+ {
694
+ "name": "effect",
695
+ "type": "string"
696
+ },
697
+ {
698
+ "name": "color",
699
+ "type": "string"
700
+ },
701
+ {
702
+ "name": "size",
703
+ "type": "number"
704
+ },
705
+ {
706
+ "name": "vx",
707
+ "type": "number"
708
+ },
709
+ {
710
+ "name": "vy",
711
+ "type": "number"
712
+ },
713
+ {
714
+ "name": "vz",
715
+ "type": "number"
716
+ },
717
+ {
718
+ "name": "particleCount",
719
+ "type": "number"
720
+ },
721
+ {
722
+ "name": "animation",
723
+ "type": "string"
724
+ }
725
+ ]
726
+ }
647
727
  }
648
728
  ],
649
729
  "schemaVersion": 1,