Bring the LiveCode Kit + Contraption Builder to professional quality - #4
Merged
Merged
Conversation
Bridges: span planks now use a new internal 'deckpin' joint — a hinge with a fixed +/-30 deg flex limit (kBridgeFlex) — so a loaded deck sags but can never fold back on itself. The limit is applied in connectJoint, so it is re-derived when a saved bridge reloads (no new serialization needed); the loader and world-anchor guard accept 'deckpin' alongside 'pin'. Chains: span links are finer (up to 40, ~tD/18), lighter (density 0.3) and start with a deeper drape, so a chain settles into a smoother catenary. Chain links keep the free-pivoting 'pin'. Both spans still save/load/delete as ordinary parts + joints. GUI-only changes; the embedded Kit is untouched (sync check passes).
Kit: add b2kAddChain pControl, pPoints[, pLoop] — a smooth static chain attached to a control (body at the control's centre, local points, registered like b2kAddBox/Polygon) so it selects, drags, resizes, deletes and saves as a normal static part, unlike the world-only b2kChain. Re-synced into both examples. Contraption builder: the Hill terrain now builds a smooth chain following an undulating outline instead of a single convex polygon, so a fast body rides over it without catching on seams. Bump count scales with width (narrow = dome, wide = rolling). Integrated through the existing terrain paths: placeTerrain (chain on create), regenTerrain/resizePart/setPartDimension (rebuild the chain on resize/rotate/load via new rebuildHillChain), drag (b2kMoveTo moves the centred chain), delete (b2kRemove destroys it), and save/load (deterministic outline, no new format). Point order puts the solid side under the surface. GUI-only builder changes; the embedded Kit matches src (sync check passes).
Add a "Collision layer" setting (Physics tab) to every solid dynamic part: 0 collides with everything (default); layers 1-8 give the part a shared negative collision group via b2kSetCollisionGroup, so parts on the same layer pass through each other while still hitting the ground and other layers. Wired through the inspector (partProps/propGroup/propLabel/ adjustPartProp), a new applyCollisionLayer helper, and save/load (partSpecial "lyr"/applyPartSpecial). GUI-only; embedded Kit unchanged.
Add a "Sensor" SPECIAL part: a non-solid zone (b2kAddSensor) that parts pass through, but when a dynamic body ENTERS it (on b2kSensorEnter) it fires the same signal as a pressure plate — triggerSignal (arm bombs + toggleAllMotors). Occupancy-tracked (gSensorCount) so it fires once on 0->1 and re-arms when empty; reset on clear and at the start of each Run. Mirrors the plate across palette/dispatch/register/rebuild/partProps/ help/glyph and adds on b2kSensorExit. Kit: b2kReshape now also preserves the sensor flag (not just sensor events), so a resized sensor zone stays non-solid. Re-synced. GUI changes + one Kit line; embedded Kit matches src (sync check passes).
Add a "Servo" joint tool backed by the Kit's b2kMotorTo. It drives part A to hold its current position + angle relative to part B, yielding under load and springing back (unlike a rigid weld) — good for self-righting parts, soft platforms and return-to-home arms. New connectJoint "servo" case (requires two parts; offset/angle captured at creation so it survives save/load via the normal joint path), constants kServoForce/kServoTorque, and palette/label/glyph/name/help wiring. No inspector props in v1, which showJointInspector already handles gracefully. GUI-only; Kit unchanged.
Add a "World feel" cycle button to BUILD OPTIONS (beside Gravity) that tunes the whole world via the Kit's world setters: Default, Bouncy (low restitution threshold), Floaty (soft contacts + speed cap) and Snappy (stiff contacts). New gWorldFeel state with cycle/apply/refresh/name handlers, applied on cycle, re-applied each Run, and saved/loaded in the "world" line (back-compatible: older saves default). GUI-only; Kit unchanged. Preset values are a sensible first pass, tunable after testing.
Add a Draw terrain tool: press-drag across the field to sketch a ground line (points sampled every kDrawStep px with a live preview), and on release it becomes a smooth one-sided chain via b2kAddChain (open). Points are normalised left->right so the solid side faces up (bodies rest on top). New drawing input mode in mouseDown/mouseMove/mouseUp (gDragMode "draw"), handlers beginDrawTerrain/extendDrawTerrain/finishDrawTerrain, a placeDrawPlaceholder for load, and reversedLines/ptsPacked helpers. Saves/ loads as its own point list (partSpecial "pts=", packed with "|" since ";" and TAB are taken; applyPartSpecial rebuilds the chain). Drags via b2kMoveTo, deletes via b2kRemove. Palette/name/glyph/help wired; Hill help updated to say "rolling". GUI-only; Kit unchanged.
- terrainPoints (smooth hill): rename bare locals env/bump/th/hx/hy/ih/yBase to t-prefixed (tEnv/tBump/tT/tHx/tHy/tIh/tYBase). 'env' is the kind of bare name that can collide with an xTalk reserved word (cf. pLayers/players); prefixing matches the file convention and removes the risk. Full-file scan of all locals/params now shows zero reserved-word collisions. - ptsPacked: pack a drawn terrain's CURRENT points (the points of the graphic) instead of the stale uPoints, so dragging a Draw piece before saving no longer reverts it to its original spot on load. Also filter blank lines. GUI-only; embedded Kit in sync.
- Drawn ground line is now kDrawLineSize (7px) instead of 4, so it reads as solid ground and is much easier to click/select (addresses the thin-line selection note). - Add a Cannon recipe: static carriage + barrel (axis-aligned to avoid the rotated-static-body render gotcha) and a heavy ball that fires across the field on Run via the launch system, into a crate stack. Ball + barrel share a collision layer so the ball clears the barrel cleanly — also a showcase of the new collision-layer feature. Wired into the Examples menu (panel grown to fit) and the recipe dispatch. GUI-only; embedded Kit in sync.
The freehand Draw terrain fell through / vanished: an open chain wound left-to-right puts the solid side DOWN (Box2D: solid = right of travel; the smoke test's ground runs right-to-left for solid-up), so bodies passed through, and the thin open line was easy to miss. Draw is now a filled, CLOSED ground mass: the drawn contour down to the arena floor, laid out bottom-right / contour right-to-left / bottom-left so the loop's solid side faces out and up. It renders as solid ground, is easy to click, and collides reliably. Load restores it as a closed loop too. The smooth Hill shared the same backwards loop winding (untested); its outline is now reversed (reversedLines) so its solid side also faces out. GUI-only; embedded Kit in sync. New locals are t-prefixed (no reserved-word clashes); valid LC syntax throughout.
Three more one-click recipes, following the established pattern (place parts -> connect joints -> set densities/launch -> renderBuild): - Trebuchet: a long arm hinged off-centre, a heavy counterweight welded to the short end, a ball on the long end; gravity flings it on Run. - Crane: a static mast + a motorised hinge jib (26 deg/s) with a load hung on a rope so it trails and sways. - Wrecking Ball: a static gantry, a heavy roped ball given a sideways launch on Run to swing into a brick wall. Careful with LC gotchas: static scenery is axis-aligned (exact static render), parts are built before joints, nothing is teleported after jointing. All locals are t-prefixed (no reserved-word clashes). Wired into the Examples menu (panel grown) + dispatch. GUI-only; embedded Kit in sync. Note: the flat Examples list is now near its practical limit (15 entries) — a categorised, scrollable gallery is the next step for adding more.
… more) Expose more of box2dxt per object so the demo covers the full surface: - Body type is now a 3-way cycle dynamic -> static -> KINEMATIC. A kinematic part ignores gravity/collisions and moves at its launch velocity — i.e. a moving platform. propLabel/adjustProp updated; applyPartSpecial restores static AND kinematic (was static-only). - Sleep threshold: every dynamic kind gets a "Sleeps below: N px/s" stepper (b2kSetSleepThreshold), saved/loaded as "slp". - Imported images can choose their collision shape (box/ball/capsule) via a new "imgshape" property + uShape; a new partShape() helper routes resize/ reshape through it so the choice survives resizing; saved/loaded as "ishp". - Filled-out thin inspectors: Draw ground gets a colour; Anchors get bounce and grip (friction). propGroup files the new keys under the right tabs (imgshape=shape, sleep= physics). All keys are string literals; new helper/props are t-/u-prefixed. Full-file scan: no reserved-word clashes. GUI-only; embedded Kit in sync.
- Examples menu rebuilt as a two-column gallery grouped into categories (Launchers / Machines / Chain Reactions / Toys & Tests) with headers, via a new recipeCategory() layout helper. Fits the card without scrolling and scales to more machines. kUIVersion bumped 3 -> 4 so the chrome rebuilds (buildUI clears old chrome first, so no duplicates). - "Active" (in-simulation) toggle on every dynamic part -> b2kDisable/ b2kEnable, saved/loaded as "act". GUI-only; embedded Kit in sync. Full-file scan: no reserved-word clashes.
…shape Add a 'sensor' inspector toggle to solid parts (box/image/ball/capsule/ poly) that flips them between solid and a non-solid trigger zone. A flagged part fires the same b2kSensorEnter/Exit signal as the dedicated Sensor and shows translucent so it reads as a ghost zone. Saved/restored via the 'sen' special key, with a single reshape that also covers the image collision shape. Add b2kSetSensor to the Kit so the flag can be toggled on an existing part (the shape is rebuilt with b2kReshape, which re-applies the sensor state). Re-apply the collision layer after every b2kReshape (sensor/image-shape toggle, resize, dimension edit, load) — a reshape builds a fresh shape with a default filter, which previously dropped a part's collision layer.
…ettings The Physics tab had grown to 14 settings but the inspector renders at most 10 rows, so Collision layer, Sleep, In-simulation and the new Sensor toggle were silently cut off. Re-balance the tabs: Physics keeps the 10 material/ dynamics settings, a renamed Collide tab gathers the collision and simulation-state settings (layer, sensor, active, sleep), and the launch settings move to Special. Every setting a part offers is now reachable. Bump kUIVersion so an older saved stack rebuilds its chrome with the new tab button.
Add a Collision filter to every solid part, opened from its Collide tab: a popup with two rows of eight channel toggles — the channels the part is on (category) and the channels it collides with (mask). Two parts collide only when each is on a channel the other collides with, so sets of parts can be made to ignore one another while still resting on the ground. Built on the Kit's b2kSetCategory / b2kSetMask, re-applied after every reshape (via a new reapplyCollision helper), saved and loaded, and dismissable by clicking away. The default (uncustomised) filter is left untouched so ordinary parts keep hitting everything, and the panel defaults a part to colliding with all channels so it stays on the floor unless deliberately changed.
Give the four inspector tabs even widths so the 7-character labels (Physics, Collide, Special) never clip, and order the Collide tab so the collision settings (layer, sensor, filter) lead, with the simulation-state ones (in-simulation, sleep) after.
SethMorrowSoftware
marked this pull request as ready for review
June 6, 2026 15:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A sweep to bring the xTalk/LiveCode side of box2dxt up to a professional, demo-ready level. The Contraption Builder example now exercises essentially every capability the Kit exposes, and the Kit itself is de-duplicated, hardened, and covered by CI.
Infrastructure & correctness
tools/sync-embedded-kit.py(BEGIN/END sentinels keep the embedded copy byte-identical tosrc/box2dxt-kit.livecodescript)..github/workflows/build.yml): build + C smoke test on Linux/macOS/Windows, a fast "embedded Kit in sync" gate, and binary attach on published releases / manual dispatch.pLayerswas being read as the reserved wordplayers. Renamed offenders and swept the builder for bare reserved-word locals.b2kReshape(atomic rebuild, preserves the sensor flag) and fix motor re-arm on Run.New Builder capabilities (all driven by the Kit)
This session
b2kSetSensor.b2kSetCategory/b2kSetMask, re-applied after every reshape, saved/loaded, click-away to dismiss.Testing
python3 tools/sync-embedded-kit.py --checkpasses (embedded Kit in sync).🚧 Draft while the latest Builder additions are exercised in OXT.
https://claude.ai/code/session_01JbLzd79E6fNV5CWqSVcW9r