Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e4f2e07
Remove micro-game and the platformer debug-warp; tidy example lists
claude Jun 14, 2026
93271f3
Kit Wave 5: wall-jump, dash, double-jump, duck-reshape, platform-carry
claude Jun 14, 2026
e1dc572
docs: Wave 5 player actions across the reference, guide, changelog, plan
claude Jun 14, 2026
c3f4558
Platformer: turn on the Wave 5 moves and teach them in the help
claude Jun 14, 2026
f0feb9d
Platformer: rebalance the four levels + a moving-platform lift mechanic
claude Jun 14, 2026
8eebd9b
Kit: persistent spritesheet cache - load atlases once, not per level
claude Jun 14, 2026
02ffa17
docs: b2kSheetPersist (the spritesheet cache) in the reference + chan…
claude Jun 14, 2026
1d5e7cc
Kit: harden the spritesheet cache identity (review pass)
claude Jun 14, 2026
2def779
docs+tools: one-zip platformer distribution + refreshed install guide
claude Jun 14, 2026
8e05fea
Demo: build the chrome once, reuse it on reopen
claude Jun 14, 2026
968196c
Builder: sweep orphaned part graphics on rebuild + reopen
claude Jun 14, 2026
6ab88a3
Kit: duck no longer sinks the player art below ground; fix L1 crawl-t…
claude Jun 14, 2026
e50be67
Kit: b2kReshape preserves the collision filter (fixes drop-through wh…
claude Jun 14, 2026
8af7dce
Revert "Kit: b2kReshape preserves the collision filter (fixes drop-th…
claude Jun 14, 2026
80cd804
Revert my duck art-lift change (caused the mid-air float) + remove it…
claude Jun 14, 2026
e2c163d
Platformer: duckScale=1 (reliable stop-in-place duck); retire the cra…
claude Jun 14, 2026
8dea333
Dash: ground-only option (platformer opts in); L4 lava pit breaks the…
claude Jun 14, 2026
c348a60
Platformer: skin the static placeholder slabs with stretched sheet art
claude Jun 14, 2026
fe674ab
Platformer polish: lift-bay hazard is lava sprite; crate PYRAMID arou…
claude Jun 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@
# Python bytecode (from tools/)
__pycache__/
*.pyc

# Generated distribution zips (tools/make-release.py); the saved stack and the
# built zip are artifacts -- dist/INSTALL.md is the tracked source.
/dist/*.zip
/dist/*.livecode
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,54 @@ The native shim's ABI is tracked separately by `b2Version()` (currently `4`).
one-way platform builders at chains (chain segments are the one-sided
primitive).

### Removed

- **The micro-game example (`box2dxt-microgame.livecodescript`) was
retired.** The repo concentrates its game work on the platformer showcase;
the "build a whole game" pattern it demonstrated is preserved in
kit-guide §20. Dropped from the embedded-Kit sync list and the example
lists in the README and CLAUDE.md.

### Added

- **Kit: a persistent spritesheet cache (`b2kSheetPersist`) — load atlases
once, not per level (statically verified + harness v14).** Opt-in (default
off, so every other example and the harness are byte-for-byte unchanged).
When on, loaded sheets are assets that **survive `b2kTeardown`** (like
synthesized sounds): a level rebuild reuses them instead of re-decoding
each PNG, re-parsing each XML, and re-slicing every frame — the costliest
work the Kit does, previously repeated on every level transition. An
identical `b2kSheetLoad`/`LoadAtlas`/`FromImage` becomes a no-op, sliced
frames survive, and because source/frame images are named deterministically
(`b2ksheet_<name>` / `b2kfr_<sheet>_<n>`, tagged with the file path) a
**saved stack** carries the cache — on reopen the load adopts the in-stack
images, skipping the disk import entirely. `b2kSheetsWipe` stays the
explicit purge. The **platformer** turns it on at `openCard` (Shift+Reset
purges) to cut its between-levels load time.
- **Wave 5 (player actions II) — five new player-controller moves
(statically verified + harness v13).** All **opt-in** through
`b2kPlayerSet` knobs whose defaults leave the pre-Wave-5 controller
byte-for-byte unchanged, and each idle path costs one compare per frame:
- **Double-jump** (`airJumps` — extra mid-air jumps, refilled on landing).
- **Wall-slide + wall-jump** (`wallSlideMax` caps the fall while pressing
into a wall; `wallJumpX`/`wallJumpY` launch up and away with a brief
steer-lock; a side ray runs only while airborne). New `wallslide` state.
- **Dash** (`dashSpeed`/`dashMs`/`dashCooldownMs` on the new `dash` action,
bound to SHIFT/X — a flat horizontal burst with gravity parked; yields to
climb/swim). New `dash` state.
- **Duck capsule-reshape** (`duckScale < 1` turns the Wave 2 brake-duck into
a feet-anchored **crawl** via `b2kReshape`, with a headroom check before
standing — so the hero slips under low gaps).
- **Moving-platform carry** (`platformCarry 1` — a grounded player inherits
the velocity of the moving kinematic body it rides; a vertical lift's
carry is exempt from the ground-snap).
- New helpers: `b2kPlayerHalfH()`/`b2kPlayerHalfW()` (live capsule extents,
serving gotcha 28), `b2kPlayerInLadder()`/`b2kPlayerInWater()` (this
frame's zone membership), and `b2kPlayerRespawn x,y` (teleport + zero
velocity + clean state). `b2kPlayerAnims` gains `wall`/`dash` slots.
- The **platformer showcase** turns them all on and leans each beat on one
(double-jump throughout, a wall-jump shaft, a dash gap, a crawl tunnel,
moving-platform lifts). Self-test **v13** adds six hand-stepped tests.
- **Wave 4 (liquids) — SWIM, the Kit's first new player-action since
Wave 2 (statically verified + harness v12; user play-tested in the
platformer).** A new `b2kPlayerAddWater x1,y1,x2,y2` registers a polled
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ Docs live in `docs/` (`architecture.md`, `building.md`, `getting-started.md`, `a
`kit-guide.md`, `kit-reference.md`, `game-engine-spec.md`, `expansion-prep.md`). Drop-in prebuilt
binaries are in `prebuilt/`. The **Game Kit** (input/sprites/player/camera/sound modules, plan.md
Phases 0-5) is implemented and user-verified on Win32; `plan.md`'s decision log is the as-built
record. Seven examples: demo, contraption builder, spike (Phase-0 harness), **platformer showcase**,
**micro-game** (the "copy this to start a game" file), **slingshot** (angry-birds-style tower
knockdown — the physics core carrying a whole game with zero events and zero assets), and the
record. Six examples: demo, contraption builder, spike (Phase-0 harness), **platformer showcase**
(the Game Kit pushed hard — the focus of this repo's game work), **slingshot** (angry-birds-style
tower knockdown — the physics core carrying a whole game with zero events and zero assets), and the
**self-test harness** (below).

## The golden rule: the embedded-Kit sync
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ Box2D v3.1.0 (fetched by CMake)
[contraption builder](examples/box2dxt-contraption-builder.livecodescript):
a full build-and-run physics sandbox with fans, magnets, lasers, bombs,
motors, and save/load. Game-minded? The
[micro-game](examples/box2dxt-microgame.livecodescript) is a complete
two-level platformer (menu → levels → win screen, embedded art,
synthesized sound), the
[platformer showcase](examples/box2dxt-platformer.livecodescript) is the
Game Kit pushed hard — player controller (run/jump/climb/duck/swim),
scrolling camera, spritesheets, coin puzzles, a hilltop swim pool — and the
Game Kit pushed hard — player controller (run, double-jump, wall-jump,
dash, climb, crawl, swim), scrolling camera, spritesheets, moving
platforms, coin puzzles, a hilltop swim pool — and the
[slingshot](examples/box2dxt-slingshot.livecodescript) is pure physics
joy: catapult cannonballs into toppling towers, angry-birds style
(three levels, ballistic aim preview, zero assets). And the
Expand Down
100 changes: 100 additions & 0 deletions dist/INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Box2Dxt Platformer — Install & Run

Everything needed to run the **Box2Dxt** physics platformer is in this folder.
No C compiler, no internet, no extra downloads — just these files and an
**OpenXTalk (OXT)** or **LiveCode 9.6.3+** IDE you already have installed.

## What's in this package

```
box2dxt-platformer/
├── INSTALL.md ← you are here
├── box2dxt.lcb ← the Box2Dxt extension (the b2… physics API)
├── platformer.livecode ← the platformer stack (you open this last)
└── lib/
├── box2dxt.dll ← native library — Windows (x64)
├── box2dxt.dylib ← native library — macOS (Intel + Apple Silicon)
└── box2dxt.so ← native library — Linux (x86-64)
```

You only need the **one** `lib/` file for your operating system.

---

## Step 1 · Put the native library where the engine can find it

Box2Dxt's physics run in a small native library. Copy the file for your OS:

| Your OS | Copy this file | To here |
|---------|----------------|---------|
| **Windows** | `lib/box2dxt.dll` | the **same folder** as `platformer.livecode` |
| **macOS** | `lib/box2dxt.dylib` | the **same folder** as `platformer.livecode` |
| **Linux** | `lib/box2dxt.so` | a library search path — see the note below |

**Do not rename these files.** They are already the bare name the loader looks
for (`box2dxt`, with no `lib` prefix). Renaming is the #1 cause of "unable to
load foreign library".

> **Linux only.** The dynamic loader does *not* search the stack's folder. Put
> `box2dxt.so` somewhere the loader looks:
> ```
> sudo cp lib/box2dxt.so /usr/lib/ && sudo ldconfig
> ```
> (or place it next to the OXT engine binary, or add its folder to
> `LD_LIBRARY_PATH` before launching OXT).

---

## Step 2 · Install the extension

The extension `box2dxt.lcb` adds the `b2…` physics handlers to the IDE.

1. Launch **OXT / LiveCode**.
2. Open **Tools → Extension Manager**.
3. Click **+ (Add)**, choose **`box2dxt.lcb`** from this folder, then click
**Load**.

> Alternatively: **Tools → Extension Builder**, open `box2dxt.lcb`, and click
> **Test** — that compiles and loads it in one step.

**Confirm it worked:** open the **Message Box** (the small toolbar icon, or
Ctrl/Cmd-M) and type:

```
put b2Version()
```

Press Enter. You should see **`4`**. If you get an error, see *Troubleshooting*.

---

## Step 3 · Open the platformer

Open **`platformer.livecode`** (File → Open Stack…, or double-click it). The
game builds itself and starts immediately.

- **First run** may ask you to locate a spritesheet folder. Click **Cancel** to
play with the built-in placeholder art, or point it at a Kenney spritesheet
folder if you have one. Once you **save** the stack, the artwork is remembered
and loads instantly every time after.
- **Controls:** **arrows** or **WASD** to move · **Space** to jump · **↓** to
duck. Grab the coins and touch the flag to advance — there are four levels.

That's it. Enjoy the physics.

---

## Troubleshooting

| Symptom | Fix |
|---------|-----|
| `b2Version()` errors, or "handler not found" | The extension isn't loaded. Redo **Step 2** (Extension Manager → Load `box2dxt.lcb`). It loads per IDE session. |
| First physics call says **"unable to load foreign library"** | The native library isn't found. Make sure the `lib/` file for your OS sits **next to `platformer.livecode`** (Windows/macOS) or on a loader path (Linux). Don't rename it. *Tip: launch OXT from a terminal — it prints the exact filename it's looking for.* |
| `b2Version()` returns a number **other than 4** | Your `box2dxt.lcb` and the native library are from different builds. Use the `.lcb` and the `lib/` file **from this same package** together. |
| The window opens but nothing moves, or a `b2…` call errors | The extension loaded but the native library didn't (or is the wrong build). Re-check Steps 1–2 and confirm `put b2Version()` is `4` before opening the stack. |

---

*Box2Dxt is the Box2D v3 physics engine packaged for OpenXTalk and the xTalk
language family. The platformer is one of several example games. For the full
toolkit, source, and documentation, see the project repository.*
31 changes: 31 additions & 0 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ new platform/architecture). Most users can skip this and grab a
- [Build](#build)
- [Run the tests](#run-the-tests)
- [Output files](#output-files)
- [Packaging a distribution zip](#packaging-a-distribution-zip)
- [Platform & CPU notes](#platform--cpu-notes)
- [Continuous integration](#continuous-integration)

Expand Down Expand Up @@ -74,6 +75,36 @@ the loader maps to these platform names. Deploy the file next to your stack or
standalone (when you build a standalone, bundle the matching platform library
with it).

## Packaging a distribution zip

To hand someone a ready-to-run game (no repo, no toolchain, no internet),
bundle the extension, the per-platform native libraries, a built **and saved**
stack, and the end-user install guide into one zip. `tools/make-release.py`
does it:

```sh
# Build & SAVE the stack in OXT first (e.g. the platformer), then:
python3 tools/make-release.py --stack /path/to/platformer.livecode
# -> dist/box2dxt-platformer.zip
```

It copies `src/box2dxt.lcb` and `dist/INSTALL.md`, renames each `prebuilt/`
library to the bare name the loader wants under `lib/`, and adds your saved
stack — producing:

```
box2dxt-platformer/
├── INSTALL.md # the three-step end-user install guide
├── box2dxt.lcb
├── platformer.livecode # your --stack
└── lib/box2dxt.{dll,dylib,so}
```

Override a library with `--win` / `--mac` / `--linux` (e.g. an SSE2 or
older-glibc build); `--check` validates the inputs without writing the zip.
The recipient just follows `INSTALL.md`: drop their platform's `lib/` file
beside the stack, **Load** `box2dxt.lcb`, open the stack.

## Platform & CPU notes

- **AVX2 / SIMD.** Box2D assumes **AVX2** on x64 by default. If your binary must
Expand Down
3 changes: 2 additions & 1 deletion docs/expansion-prep.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ that keep the expansion as reliable as the engine underneath it.
| Wave 3 | **BUILT — statically verified 2026-06-13** (bestiary I + HAUNTED HOLLOW; see §10) |
| Showcase polish | **BUILT — statically verified 2026-06-13** (pre-Wave-4: longer/re-spaced levels, the kit's first JOINT mechanics — rope bridge + boulder + barrel; a prototyped wrecking ball was cut as un-sprite-able — and four variety species; all example-side, zero Kit change, no harness bump) |
| Wave 4 | **SWIM user play-tested in the platformer 2026-06-14** (harness **v12**, two Opus reviews clean; see §11). The Kit gained `b2kPlayerAddWater` + a buoyant `swim` mode/state/anim; the platformer's L1 GREEN HILLS gained a **HILLTOP POOL** (a raised-bank basin — the swim showcase, where it's tested), tuned heavier and with the hero hitbox fixed to match the art (gotcha 28), all per the user's OXT pass. DONE: swim zones, pit-dwellers (the micro-game `fish`, debut), lava (already in platformer L4). CARRY-OVER: the collapsing-bridge trap, and the micro-game's L3 "THE DEEP" (built but shows an example-side white-world build issue — set aside) |
| Next | **Wave 5 — player actions II** (wall-slide/jump, dash, double-jump; capsule reshape on duck) — see §7 and §12. Loose ends: the collapsing bridge + the micro-game L3 fix |
| Wave 5 | **BUILT — statically verified 2026-06-14** (player actions II: double-jump `airJumps`, wall-slide/jump, dash, duck capsule-reshape, moving-platform carry — all opt-in Kit knobs, defaults unchanged; harness **v13**, six new tests; see §12). Enabled + showcased in the platformer; the micro-game was retired (focus is the platformer). Awaiting the OXT feel pass. |
| Next | Iterate Wave 5 feel in OXT (the new moves' tuning numbers are first-pass); the collapsing-bridge trap remains a loose end |
| Companions | [plan.md](../plan.md) (history/decision log) · [game-engine-spec.md](game-engine-spec.md) (module design) |

---
Expand Down
24 changes: 21 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ This guide takes you from nothing to a running, draggable physics scene in
**OpenXTalk (OXT)** — or any compatible **LiveCode 9.6.3+** IDE. It assumes no
C toolchain: you'll use a prebuilt native library.

> **Just want to *play*, not code?** If you were handed the prebuilt **platformer
> package** (a zip with the extension, the native libraries, and a saved
> `platformer.livecode`), open its `INSTALL.md` and follow three steps — no
> scripting. This guide is for building your *own* scenes from scratch.

- [1. Get the native library](#1-get-the-native-library)
- [2. Load the extension](#2-load-the-extension)
- [3. Sanity check](#3-sanity-check)
Expand All @@ -25,11 +30,11 @@ file for your platform from [`prebuilt/`](../prebuilt/) (or from the
|----------|----------|--------------|
| Windows x64 | `prebuilt/box2dxt-windows-x64.dll` | `box2dxt.dll` |
| macOS (Intel/Apple Silicon) | `prebuilt/libbox2dxt-macos-universal.dylib` | `box2dxt.dylib` |
| Linux x86-64 | `prebuilt/linux-x86_64/libbox2dxt.so` | `box2dxt.so` |
| Linux x86-64 | `prebuilt/libbox2dxt-linux-x86_64.so` | `box2dxt.so` |

OXT's loader resolves the name `box2dxt` to the **bare platform filename with no
`lib` prefix** (the table above). This bites on Linux especially: the committed
file is `libbox2dxt.so`, but OXT asks `dlopen` for `box2dxt.so` — leaving the
file is `libbox2dxt-linux-x86_64.so`, but OXT asks `dlopen` for `box2dxt.so` — leaving the
`lib` prefix on is the single most common cause of "unable to load foreign
library".

Expand Down Expand Up @@ -116,6 +121,18 @@ you can **drag** them with the mouse. That's it — a live physics scene.
builds static walls around the card edges, and starts the loop. From there,
`b2kSpawnBall`/`b2kSpawnBox` create controls *and* their bodies in one go.

**Try a few more things** in the Message Box while the card is open:

```
b2kSpawnCapsule 220, 60, 70, 28, "teal" -- a pill-shaped body
put the result into tPill -- every b2kSpawn… reports its ref
b2kImpulse tPill, 0, -12 -- a sharp upward kick (mass-aware)
b2kSpawnBox 320, 40, 50, 50, "purple" -- drop another box in
```

Negative `y` is *up* here (screen coordinates). The
[Kit Reference](kit-reference.md) lists the full spawn / force / query surface.

## 5. Attach controls you designed in the IDE

Prefer to draw your objects in the IDE? Attach physics to **any** control —
Expand Down Expand Up @@ -183,14 +200,15 @@ of the [Kit](kit-reference.md).
| `b2Version()` throws / "handler not found" | The extension isn't loaded. Re-add and **Load** `box2dxt.lcb` in the Extension Manager. |
| First `b2…` call (or `b2Version()`) errors **"unable to load foreign library"** | The native library isn't found or is misnamed. Use the **no-`lib`** bare name: `box2dxt.dll` / `box2dxt.dylib` / `box2dxt.so`. On **Linux** the stack folder isn't searched — put it in `/usr/lib` then run `sudo ldconfig`, or place it next to the OXT engine. (Tip: launching OXT from a terminal prints `dlopen failed <name>` showing the exact filename it wants.) |
| `b2Version()` returns a different number | Your `box2dxt.lcb` and native library are from different versions. Rebuild/redownload both from the same tag. |
| Library won't load on an older PC (Linux/Windows) | Use the committed SIMD-disabled `prebuilt/` binary, or build with `-DBOX2D_DISABLE_SIMD=ON` (see [building.md](building.md)). |
| Library won't load on an older PC (Linux/Windows) | The CPU may lack AVX2. Build with `-DBOX2D_DISABLE_SIMD=ON` (see [building.md](building.md#platform--cpu-notes)), or grab a Release binary built for older CPUs. |
| Bodies jitter or behave non-deterministically | You're stepping with a variable timestep. Let the Kit drive the loop, or step in fixed 1/60 s chunks (see [API Reference → Notes](api-reference.md#notes-and-gotchas)). |
| Objects fly off instantly / explode | Sizes are wrong for Box2D's MKS units. Keep moving objects roughly 4–400 px at the default 40 px/m scale. |

## Where to go next

- [**Kit Guide**](kit-guide.md) — the complete, teach-you-everything walkthrough of the `b2k…` toolkit, with runnable examples.
- [Kit Reference](kit-reference.md) — the same `b2k…` API as quick-lookup tables.
- **Example games** — beyond the demo, [`examples/`](../examples/) ships a full **platformer**, an angry-birds-style **slingshot**, and a **contraption builder**, each a single self-contained paste. Hand one to someone else as a zero-setup zip with [`tools/make-release.py`](building.md#packaging-a-distribution-zip).
- [API Reference](api-reference.md) — the low-level `b2…` API and units/gotchas.
- [Architecture](architecture.md) — how it all works under the hood.
- [Building](building.md) — compile the native library yourself.
Loading
Loading