diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..450de7b --- /dev/null +++ b/plan.md @@ -0,0 +1,471 @@ +# From Box2Dxt to **xGE** — a plan for a complete xTalk 2D game engine + +> **Status:** planning only. This document proposes the architecture and a +> phased roadmap to grow today's Box2D physics kit into a full, modular 2D game +> engine that is usable **two ways**: (a) **script‑only** as a set of `start +> using`‑able libraries, and (b) through a **GUI game‑creation editor** built in +> pure xTalk for LiveCode/OpenXTalk **9.6.3 Community**. No project code is +> changed by this document. +> +> Working name **“xGE — the xTalk Game Engine.”** Handler prefix **`ge`**, +> engine modules named **`ge-.livecodescript`**. (Name/prefix are +> provisional — finalising them is the first Phase‑0 task.) + +--- + +## 1. Vision & goals + +Build a 2D game engine where: + +1. **The physics is real.** Keep Box2D v3 (via today's Kit) as the simulation core. +2. **You can build a whole game in script.** Add engine modules (`ge…`) that are + each a small, independent, `start using`‑able library — exactly like the Kit + is today. A developer can write a platformer in a `.livecodescript` with no + editor at all. +3. **You can build a whole game with a mouse.** A GUI editor (a generalisation of + today's Contraption Builder) authors *projects* — scenes, entities, behaviors, + assets — and a thin **runtime** plays them. The editor never adds capabilities + the script API doesn't already have; it just drives them visually. +4. **It ships.** One‑click export to a standalone that bundles the native library, + the runtime, and the project — on Windows/macOS/Linux, all from Community. +5. **It stays simple.** Idiomatic xTalk throughout: controls are entities, + LiveCode *behaviors* are components, library stacks are modules. Prefer the + boring, native option over a clever abstraction. + +**Non‑goals (at least initially):** 3D, a node‑graph visual scripting VM, a custom +rendering pipeline replacing LiveCode controls, networking/multiplayer, and an +asset store. Each is a possible *later* module, none is on the critical path. + +--- + +## 2. Where we are today (honest assessment) + +| Layer | File(s) | State | Role in xGE | +|------|---------|-------|-------------| +| **L0 Native** | `src/box2d_lc.c` + Box2D v3.1 → `box2dxt` lib | Solid, 95 fns, prebuilt for 3 OSes | Unchanged simulation core | +| **L1 Binding** | `src/box2dxt.lcb` (`b2…`, 95 handlers) | Solid | Unchanged; *small* additions for filtering/sensors | +| **L2 Physics Kit** | `src/box2dxt-kit.livecodescript` (`b2k…`, ~95 handlers) | Mature: world, fixed‑step loop, coord conversion, attach/spawn, materials, forces, getters, joints (hinge/weld/rope/slider/wheel + motors/springs/limits), drag, raycast, contacts, explode, **reshape** | **The physics module of xGE.** Stays script‑only; grows a little | +| **L3 Engine core** | — | **Missing** | New, this plan | +| **L4 GUI editor** | `examples/box2dxt-contraption-builder.livecodescript` (4.2k LOC) | A *proto‑editor*: 5‑region UI, palette, live inspector, build/run modes, CB2 save/load, recipes, onboarding, tooltips, duplicate, reset | Harvested into the editor | +| **L5 Runtime / export** | — | **Missing** | New, this plan | + +**What the Kit already gives the engine for free** (don't rebuild these): + +- A **fixed‑timestep, generation‑guarded, screen‑locked loop** (`b2kStart/Stop`, + `b2kStep`) and a per‑frame hook (`b2kFrameTarget` → `b2kFrame`). +- **Control ⇄ body mapping** (`b2kAdd*`, `b2kSpawn*`, `b2kBodyOf`, `b2kControlAt`). +- A **camera primitive**: `b2kSetOrigin` / `b2kSetScale` + the world↔screen + converters already implement pan; zoom is one step away. +- **Collision events**: `b2kContactTarget` + `b2kDispatchContacts` (the pressure + plate proves the pattern) → the engine's collision messages. +- **Raycasts, explosions, forces, joints** — gameplay primitives most engines + make you write yourself. + +**Gaps the Kit needs filled (small L1/L2 additions, Phase 1.5):** + +- **Collision filtering** (category/mask layers) — likely a new `b2SetShapeFilter` + binding + `b2kSetLayer/b2kSetMask`. +- **Sensors** (non‑solid trigger shapes with begin/end events) — generalise the + pressure‑plate idea into `b2kSensor`/`geTrigger`. +- **Body user‑data round‑trip** is implicit via control refs already — fine. + +--- + +## 3. Design principles (the guardrails against over‑engineering) + +1. **Script‑first, editor‑second.** Every capability lands as a script API in an + L2/L3 module **before** any editor UI uses it. The editor is a *client* of the + same API a developer would call. This guarantees the “usable via script alone” + requirement and keeps the editor thin. +2. **Controls are entities.** A game object *is* a LiveCode control (graphic, + image, group) plus a custom‑property bag plus a behavior list. No parallel + entity database. This is what the Kit already assumes. +3. **Behaviors are components — use the native feature.** A “behavior” is a + script‑only button/stack implementing lifecycle handlers (`geCreate`, + `geUpdate dt`, `geCollide other`, `geInput action`, `geDestroy`). The engine + **`dispatch`es** these messages to an entity's list of behaviors. This reuses + LiveCode's own behavior/message machinery instead of inventing an ECS. +4. **One module = one concern = one `.livecodescript`.** Each is independently + `start using`‑able and depends only on layers **below** it (and a tiny shared + core). No module imports the editor. A dependency you can't draw as a downward + arrow is a bug in the design. +5. **A single, stable contract.** All behaviors talk to the engine through one + documented set of messages (lifecycle/physics/input) and one set of service + calls (`geSpawn`, `geDestroy`, `geFind`, `geCamera…`, `gePlaySound`, + `geGoScene`, `geTween…`, `geAfter…`). Portability of behaviors depends on this + contract never drifting. +6. **Default to LiveCode controls for rendering; keep an escape hatch.** + Control‑per‑entity is simple and is the default. For games that need thousands + of cheap sprites, add an *optional* image‑buffer renderer module later — never + as a prerequisite. +7. **Community‑only.** Nothing depends on commercial LiveCode features. Standalone + building, script‑only stacks, behaviors, and our own extension are all + available in 9.6.3 Community. +8. **Backwards compatible.** The Kit and both existing demos keep running. The + Contraption Builder survives as a **“Physics Sandbox” template** inside the + engine. + +--- + +## 4. Target architecture + +### 4.1 The layer stack (each layer usable on its own) + +``` + L5 Runtime + Export ge-runtime (play a project) · Export-to-standalone + │ (plays projects authored by L4, using only L2+L3) + L4 GUI Editor scene tree · asset browser · inspector · behavior + │ picker · tilemap/shape editors · project format + │ (authoring only — calls the same API as a script developer) + L3 Engine Core (NEW) loop · entity · scene · assets · sprite · input · + │ camera · audio · behavior · ui · particles · + │ tilemap · tween/timers · save + L2 Physics Kit box2dxt-kit (b2k…) ← script-only today + L1 Binding box2dxt.lcb (b2…) + L0 Native box2d_lc.c + Box2D v3.1 +``` + +Two consumption paths share **L0–L3 + L5**: + +- **Script‑only game:** `start using` the engine libs, write behaviors, call the + `ge…` API. (No L4.) +- **Editor‑authored game:** L4 writes a *project file*; L5 runtime plays it. Same + L2/L3 underneath. + +### 4.2 Engine‑core modules (L3) + +Pure‑xTalk, script‑only, one file each, dependencies point downward only. + +| Module | Prefix | Responsibility | Depends on | +|--------|--------|----------------|-----------| +| `ge-core` | `ge` | Shared: module registry, the **message contract**, entity tagging, `geSpawn/geDestroy/geFind`, service locator | L2 | +| `ge-loop` | `ge` | Master update loop: drives physics step → `geUpdate dt` to behaviors → camera → render sync → audio. Wraps `b2kFrame`. Fixed‑step logic, variable render, pause/timescale | ge-core, L2 | +| `ge-entity` | `ge` | Entity model over controls: kind, layer/z, behavior list, property bag; create/clone/destroy; bridges to `b2kAdd*` | ge-core, L2 | +| `ge-scene` | `ge` | Scenes/rooms: a named collection of entities + settings; enter/exit lifecycle; serialise/deserialise; transitions | ge-entity | +| `ge-assets` | `ge` | Asset registry: images, spritesheets, audio, fonts; load/cache/reference by name; resolve in editor *and* standalone | ge-core | +| `ge-sprite` | `ge` | Sprite + frame animation: spritesheet slicing, named clips, play/loop/flip/tint, z‑order; renders via image controls | ge-entity, ge-assets | +| `ge-input` | `ge` | Input mapping: raw keyboard/mouse/touch/gamepad → named **actions**; both polling (`geHeld`) and events (`geInput`) | ge-core | +| `ge-camera` | `ge` | Viewport: position, follow target, world bounds, shake, parallax, (optional) zoom; sets `b2kSetOrigin/Scale` | ge-core, L2 | +| `ge-audio` | `ge` | SFX/music: named clips, channels, volume, fade; thin wrapper over `play` | ge-core, ge-assets | +| `ge-behavior` | `ge` | Behavior framework + standard library (see 4.4); attach/detach by name; param schema; the `dispatch` fan‑out | ge-entity | +| `ge-tween` | `ge` | Property tweening + easing, timers (`geAfter`), sequences, simple state machines | ge-core, ge-loop | +| `ge-particles`| `ge` | Emitters/particles (generalises the shock ring); pooled controls | ge-loop | +| `ge-ui` | `ge` | In‑game HUD/menus: score text, bars, buttons, mode‑independent of physics | ge-core | +| `ge-tilemap` | `ge` | Grid tilemaps → batched static colliders + tile rendering | ge-entity, L2 | +| `ge-save` | `ge` | Runtime save/load of live game state (distinct from editor project save) | ge-scene | + +> **Minimum runnable core** = `ge-core + ge-loop + ge-entity + ge-camera`. The +> rest are opt‑in. A script‑only game pulls in only what it uses. + +### 4.3 The behavior/message contract (the heart of modularity) + +Every behavior is a script object receiving a fixed, documented set of messages, +and calling a fixed set of services. **This contract is the public engine API.** + +**Lifecycle (sent by `ge-loop`/`ge-entity`):** +- `geCreate pEntity` — once, after spawn. +- `geUpdate pEntity, pDt` — every logic tick (seconds). +- `geLateUpdate pEntity, pDt` — after physics/camera (good for HUD follow). +- `geDestroy pEntity` — once, before removal. + +**Physics (from `b2kDispatchContacts` → `ge-core`):** +- `geCollideEnter pEntity, pOther, pData` / `geCollideExit …` +- `geSensorEnter pEntity, pOther` / `geSensorExit …` + +**Input (from `ge-input`):** +- `geInput pEntity, pAction, pPhase` (`pressed`/`released`); plus poll `geHeld(action)`. + +**Services (callable from any behavior):** +`geSpawn(prefab, x, y)`, `geDestroy(entity)`, `geFind(query)`, `geCameraFollow`, +`geCameraShake`, `gePlaySound(name)`, `geGoScene(name)`, `geTween(entity, prop, +to, secs, ease)`, `geAfter(secs, message)`, `geSet/geGet(entity, key)`. + +A behavior never reaches “down” into Box2D directly unless it wants to — the Kit +(`b2k…`) remains available for advanced use, but the `ge…` contract is enough for +ordinary gameplay. **Stability of these names is a release‑blocking contract.** + +### 4.4 Starter behavior library (ships with `ge-behavior`) + +Reusable, parameterised, no code required to use: + +- **Controllers:** `platformer` (run/jump/coyote‑time), `topdown` (8‑way), + `car` (uses wheel joints), `draggable`. +- **Movement:** `patrol` (waypoints), `follow` (chase/flee), `spinner`, + `mover` (constant velocity), `homing`. +- **Gameplay:** `health` (+damage/death), `damageOnTouch`, `collectible`, + `spawner`, `trigger` (sensor → message), `checkpoint`, `killzone`, + `timerBomb` (already prototyped as the bomb), `lift` (already prototyped as the + balloon), `windZone`/`magnet` (already prototyped). +- **Camera/util:** `cameraTarget`, `parallaxLayer`, `destroyOffscreen`. + +Several of these are literally the Contraption Builder's special objects +re‑expressed as behaviors — a strong sign the design fits the existing code. + +--- + +## 5. What we reuse from today's code (so we build *less*) + +| Need in xGE | Already exists as | Action | +|-------------|-------------------|--------| +| Game loop & per‑frame hook | `b2kStart/Stop`, `b2kFrameTarget`/`b2kFrame` | `ge-loop` wraps it | +| Entity ⇄ body | `b2kAdd*`, `b2kSpawn*`, `b2kBodyOf`, `b2kControlAt` | `ge-entity` builds on it | +| Camera pan | `b2kSetOrigin`, world↔screen converters | `ge-camera` adds follow/bounds/shake/zoom | +| Collision events | `b2kContactTarget`, `b2kDispatchContacts` | `ge-core` re‑emits as `geCollide…` | +| Triggers/sensors | pressure‑plate pattern | generalise into `geTrigger` + Kit sensors | +| Particles | bomb shock ring | `ge-particles` generalises it | +| Special objects | balloon / bomb / fan / magnet / plate | become **behaviors** in `ge-behavior` | +| Editor shell | Contraption Builder 5‑region UI, palette, inspector, modes, tooltips, onboarding | harvested into L4 editor modules | +| Live property editing | the 8‑row data‑driven inspector (`partProps`/`propLabel`/`adjustPartProp`) | generalised into the component/behavior inspector | +| Serialization | CB2 format (`serializeText`/`rebuildFromText`/`partSpecial`) | generalised into the **project/scene** format | +| Reusable examples | recipes (cart, swing, balloon lift, …) | become **prefabs/templates** | +| Pre‑run snapshot | `gePreRun` reset | becomes editor **play‑in‑editor** reset | + +--- + +## 6. Roadmap (phased, each phase shippable) + +Each phase ends with: a tagged set of modules, a sample that exercises them, smoke +tests, and docs. Phases 0–3 deliver the **script‑only engine**; 4 adds the +**editor**; 5 makes it **ship**; 6 is polish/content. + +### Phase 0 — Foundations & conventions *(small, decisive)* +- Finalise the name/prefix (`ge`), the module‑loading convention (script‑only + library stacks; `start using` order), and the **message contract** (4.3) as a + written spec (`docs/engine-contract.md`). +- Create the repo skeleton: `engine/` for L3 modules, `runtime/` for L5, + `editor/` for L4, `games/` for samples/templates. Keep `src/` (L0–L2) as is. +- Define the **project/scene file format** on paper (extends CB2: a project = game + settings + asset manifest + N scenes; a scene = entities + their behaviors/params + + layers/camera). +- **Acceptance:** spec docs merged; empty modules load via `start using` with a + version handshake (`geVersion`). + +### Phase 1 — Engine core (script‑only “you can make a game in code”) +- Implement `ge-core`, `ge-loop`, `ge-entity`, `ge-scene`, `ge-camera`, + `ge-assets`, `ge-sprite`, `ge-input`, `ge-audio`. +- **Phase 1.5 (physics‑layer additions):** add collision filtering and sensors to + L1/L2 (`b2SetShapeFilter` binding if needed; `b2kSetLayer/b2kSetMask`, + `b2kSensor`), since gameplay needs layers (player/enemy/pickup/world). +- **Milestone sample:** `games/sample-topdown` — a top‑down scene: player entity + (sprite + `topdown` movement written inline), walls, a pickup using a sensor, + camera‑follow, a sound on pickup, a HUD score. **All in one `.livecodescript`, + no editor.** +- **Acceptance:** the sample runs in 9.6.3 Community at 60 fps with a few dozen + entities; each module has a smoke test; `docs/engine-getting-started.md`. + +### Phase 2 — Behaviors & gameplay systems +- Implement `ge-behavior` (attach/dispatch + param schema) and the **starter + behavior library** (4.4), porting balloon/bomb/fan/magnet/plate as behaviors. +- Implement `ge-tween` (tweens, easing, `geAfter`, sequences, tiny FSM), + `ge-particles`, `ge-ui`. +- **Milestone sample:** `games/sample-platformer` — built **entirely from stock + behaviors + prefabs**, zero game‑specific script: platformer controller, + patrolling enemies, collectibles, a moving platform, death/respawn, a win flag. +- **Acceptance:** the platformer is authored without writing a custom handler; + behaviors are documented with their params. + +### Phase 3 — Content systems (still script) +- Implement `ge-tilemap` (grid → batched static colliders + rendering), + prefab library API, and `ge-save` (runtime save states). +- **Milestone sample:** a tilemap‑based level loaded from data, with a saved/loaded + checkpoint. +- **Acceptance:** a 50×30 tilemap builds colliders without tanking the frame rate; + save→quit→load restores entity state. + +### Phase 4 — GUI editor (generalise the Contraption Builder) +- **4a — Harvest & refactor:** extract the Builder's reusable shell (5‑region + layout, palette/inspector/status/tooltips/onboarding builders, build/run modes, + reset) into `editor/` modules. Re‑point the inspector at the generic + component/behavior model. Keep the Builder working throughout. +- **4b — New editor surfaces:** + - **Scene tree / outliner** + **layers** panel. + - **Asset browser** (import images/spritesheets/audio; bind to `ge-assets`). + - **Object/prefab palette** (replaces the fixed SHAPES/SPECIAL palette). + - **Inspector v2:** transform + physics + **component/behavior list** (add from + the `ge-behavior` library, edit params via the existing +/− row engine). + - **Sprite/animation panel**, **collision‑shape editor**, **tilemap painter**. + - **Editor ergonomics:** grid + snap, multi‑select, copy/paste, align/distribute, + **undo/redo** (command stack over the project model), zoom/pan canvas. + - **Play‑in‑editor:** the existing build/run + reset, now “Play/Stop,” running + the *real* runtime in a sub‑region. +- **4c — Project I/O:** load/save the Phase‑0 project format; scene switching. +- **Acceptance:** the Phase‑2 platformer can be **rebuilt with the mouse only**, + saved as a project, closed, reopened, and played — no script typed. + +### Phase 5 — Runtime & export +- `ge-runtime`: a tiny player that loads a project, brings up the first scene, and + runs the loop — **L2+L3 only, no editor code**. +- **Export to standalone:** a one‑click build that (1) sets the standalone's + stackfiles to the runtime + engine libs, (2) bundles the project + assets, (3) + copies the correct **prebuilt native lib** per target OS into the bundle, and + (4) emits startup code that `load extension`s `box2dxt.lcb` and the native lib. + Document the per‑platform packaging (this is the one genuinely fiddly bit — + see §7.2). +- **Project settings:** title, window size/resolution policy, default scene, icon. +- **Acceptance:** the platformer exports to a double‑clickable app on at least one + desktop OS and runs with no IDE present. + +### Phase 6 — Polish, docs, templates, performance +- **Templates:** Platformer, Top‑down adventure, Physics puzzle, Breakout, and the + **Physics Sandbox** (today's Contraption Builder, re‑homed). +- **Docs:** engine architecture, the contract reference, per‑module API, a + “make your first game” tutorial (script *and* editor tracks). +- **Performance pass:** measure entity ceilings; ship the optional + **image‑buffer renderer** (`ge-render-batch`) for sprite‑heavy games; object + pooling in `ge-particles`/`ge-spawner`. +- **Acceptance:** a published 0.1 with templates, docs, and at least one exported + demo game. + +--- + +## 7. Cross‑cutting concerns (decide once, early) + +### 7.1 Rendering strategy & performance +- **Default:** one LiveCode control per entity (what the Kit does). Simple, + debuggable, plenty for puzzle/platformer/top‑down games (hundreds of entities). +- **The known ceiling:** thousands of controls cost CPU on sync/redraw (the + Builder's Stress Test already exposes this). **Mitigations, in order:** screen‑ + lock during sync (done), sleep inactive bodies (done), `destroyOffscreen` + behavior, object pooling, and finally the **optional batch renderer** that draws + many sprites into a single image via `imageData`/`import snapshot`. Batch + rendering is a Phase‑6 module, **never** a core dependency. +- **Camera zoom** implies per‑frame scaling of controls (costly) — implement pan + + follow + shake first (cheap; just `b2kSetOrigin`), treat **zoom** as an + advanced/batch‑renderer feature with a documented cost. + +### 7.2 Packaging & export (the fiddly part, so plan it explicitly) +- The native lib must travel with the standalone and be loaded at startup. Provide + a `geLoadNative` helper that picks `prebuilt//…` and calls + `load extension from file`. The export step copies the right binary into the + bundle and wires `geLoadNative` into the runtime's startup. +- Verify behavior across the Community standalone engine on each OS in CI where + possible; document the manual steps where CI can't. + +### 7.3 Assets +- An **asset manifest** maps logical names → files; the editor imports/copies into + a project assets folder; the runtime resolves names the same way. Spritesheets + carry slice metadata (grid or named frames). Keep formats text/JSON‑ish and + diff‑friendly (consistent with CB2's plain‑text ethos). + +### 7.4 Input +- Map at the **action** layer (`jump`, `moveX`) so the same game works with + keyboard or gamepad and behaviors stay device‑agnostic. Default bindings + + editor‑editable bindings. Gamepad via LiveCode's available input where present; + keyboard/mouse/touch first. + +### 7.5 Save formats — two of them, kept distinct +- **Project file (editor):** the authored game (scenes, prefabs, assets, settings). + Superset of CB2. Versioned, forward‑compatible loader (CB1/CB2 lesson applied). +- **Save game (runtime, `ge-save`):** a snapshot of live state for players. Smaller, + scene‑scoped. + +### 7.6 Testing & CI +- Per‑module smoke tests (load, basic call, teardown) like `tests/smoke_test.c` + but at script level. Sample games double as integration tests. Keep the existing + `b2…`/`b2k…` tests green; add a `geVersion`/contract test. + +### 7.7 Documentation & contract stability +- The §4.3 contract gets its own reference and a **stability policy**: additive + changes only within a major version. Behaviors and tutorials depend on it. + +### 7.8 Backwards compatibility +- `b2…` and `b2k…` APIs and both existing demos remain working and supported. The + Kit may gain handlers (filtering/sensors) but loses none. The Contraption Builder + ships on as the Physics Sandbox template. + +--- + +## 8. Module dependency rules (keep it acyclic) + +- L3 modules may depend on **L2, L1, L0** and on **`ge-core`** only — plus the + specific lower `ge-*` modules listed in 4.2. No sideways cycles. +- **No L3 module may reference L4 (editor)**. The editor depends on L3; never the + reverse. (This is what makes the runtime able to ship without the editor.) +- A new capability is added at the **lowest layer that can own it**, exposed as + script API, then consumed upward. + +--- + +## 9. Risks & mitigations + +| Risk | Mitigation | +|------|-----------| +| **Scope explosion / over‑engineering** | Phase gates; “minimum runnable core” is 4 modules; everything else opt‑in; behaviors over ECS; controls over custom renderer | +| **Entity‑count performance** | Pooling, offscreen culling, sleep, screen‑lock now; optional batch renderer later (Phase 6), never on the critical path | +| **Standalone native‑lib packaging** | Treat as a first‑class Phase‑5 deliverable with a helper + CI checks + docs; prebuilt libs already exist | +| **Contract churn breaking behaviors** | Freeze §4.3 early; additive‑only policy; contract test in CI | +| **Editor rewrite destabilising a working demo** | Harvest incrementally; keep the Builder runnable every commit (it becomes a template, not a casualty) | +| **9.6.3 Community limitations** | Validate each module on Community early; avoid commercial‑only features by policy | +| **Two consumption paths drifting** | The editor must call the *same* `ge…` API as scripts; no editor‑only engine code | + +--- + +## 10. Immediate next steps (the first few PRs) + +1. **Phase 0 spec PR:** `docs/engine-contract.md` (the message/service contract), + the project/scene format draft, the `engine/`‑`runtime/`‑`editor/`‑`games/` + skeleton, and a stub `ge-core` with `geVersion` + module registry. +2. **`ge-loop` + `ge-entity` PR:** wrap `b2kFrame`, add `geSpawn/geDestroy/geFind` + and `geUpdate` dispatch; a 10‑line script demo that spawns a falling box and + logs `geUpdate`. +3. **`ge-input` + `ge-camera` PR:** action mapping + camera‑follow; extend the demo + to a WASD‑moved, camera‑followed box. +4. **Phase‑1.5 physics PR:** collision filtering + sensors in L1/L2. +5. **`ge-sprite` + `ge-assets` PR, then the `sample-topdown` milestone.** + +After that, Phase 2 behaviors turn the existing special objects into the first +reusable library — the moment xGE stops being “physics + helpers” and becomes a +game engine. + +--- + +## Appendix A — what a script‑only game looks like (target DX) + +```livecodescript +-- mygame.livecodescript (start using ge-* + box2dxt-kit; no editor) +on openCard + geStart 960, 540 -- world, loop, camera, input + geAddScene "level1" + local tPlayer + put geSpawn("sprite", 200, 100) into tPlayer + geAddBehavior tPlayer, "platformer", "speed=320,jump=520" + geCameraFollow tPlayer + geMakeGround 0, 520, 960, 520 -- a floor (Kit segment under the hood) + geSpawnPrefab "coin", 400, 300 +end openCard + +-- a custom behavior is just a script object implementing the contract: +on geCollideEnter pEntity, pOther + if geKind(pOther) is "coin" then + gePlaySound "ding" + geDestroy pOther + geSet pEntity, "score", geGet(pEntity, "score") + 1 + end if +end geCollideEnter +``` + +## Appendix B — a stock behavior (shape of the library) + +```livecodescript +-- ge-behavior/platformer (a script-only behavior object) +on geCreate pE + geSet pE, "vx", 0 +end geCreate + +on geUpdate pE, pDt + local tSpeed : put geParam(pE, "speed", 320) into tSpeed + if geHeld("left") then b2kSetVelocity pE, -tSpeed, b2kVelocityY(pE) + if geHeld("right") then b2kSetVelocity pE, tSpeed, b2kVelocityY(pE) +end geUpdate + +on geInput pE, pAction, pPhase + if pAction is "jump" and pPhase is "pressed" and geOnGround(pE) then + b2kPush pE, 0, geParam(pE, "jump", 520) + end if +end geInput +``` + +--- + +*End of plan. Implementation begins at Phase 0; no engine code exists yet, and no +existing project code is modified by this document.*