Commit Graph
19 Commits
Author SHA1 Message Date
adminandClaude Opus 5 f4ec23d3d3 Colliders take a frame's outline and tiles have their own surface (#193)
game-maker / gate (push) Successful in 2m11s
game-maker / suite (push) Successful in 7m33s
Issue #193 asked where friction, bounciness and density of a tile
live. Tiles had a fixed surface (friction 0.5, bounciness 0) and a
collider could not use the outline drawn on a texture frame (#141).
Both gaps are closed here.

- A collider has a fifth shape "Frame collision" with a Frame row.
  The frame is picked like a sprite's texture and stored as the
  value 'frame'.
- The shape is linked, not copied. Redrawing the outline in the
  texture tab changes every collider using that frame, in the editor
  and on the next play.
- The frame centre sits on the collider origin, one image pixel is
  one unit. The shape turns, scales and mirrors like any other.
- Every outline ring blocks. Each ring is split into convex parts the
  same way a polygon is.
- Without a frame, with a whole texture or with a frame that has no
  outline, the collider is drawn red as a box and blocks nothing.
- Move, Rapier, raycast, detection, hit test, drawing and footprint
  all resolve the frame. At runtime an entity looks the frame up
  live in the current project.
- A tile has Friction and Bounciness next to Solid and One-way. The
  rows only show when Solid is on. Defaults and mixing rules match
  the collider. Density is left out because a tilemap never moves.
- Tilemap cells are grouped by surface as well as by one-way angle.
  Ice and stone never merge into one rectangle, and every cell brings
  its surface to Move and Rapier.

Findings:

- A tile with a collision scale below 1 is no longer flush with a
  neighbour of another surface. It is inset there like at an open
  side, the same as next to one-way tiles today.
- A bounce test first measured 0.84. The ball had landed on the hero
  at the origin, not on the tile. On the tile it measures 0.993.

Tests:

- ./check.sh: 130 files, 1931 tests, exit 0 (was 129 / 1917).
- 14 new unit tests in tests/core/surface.test.ts. The Move tests run
  against the editor run and the physics system.
- 3 new e2e checks: 40l (surface rows follow Solid), 42e (collider
  has frame size, a walker climbs the slope in the frame).
- GM_STEPS=1-8,39-43 freshly seeded: ALL PASSED, 376 checks.
- Three counter-probes bite: Move ignores the tile surface (2 fail),
  Rapier ignores it (1 fails), frame shape falls back to a box
  (5 fail).
- Check sum 1198 is computed (1195 + 3), the full run belongs to CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 07:29:26 +02:00
adminandClaude Opus 5 1c212b1ccc Scene view symbols come from SVG files: the behavior, container, rigidbody, camera and particles icons live in src/viewport/icons/ and are changed by editing the file and running npm run build; they are bundled, parsed once and drawn into a Graphics by the new module symbolIcons.ts, currentColor becomes the theme color of the symbol, the origin sits in the middle with a centered viewBox and the same units as before, so the symbols are pixel for pixel unchanged; what depends on the object (camera frame, collider outline, one-way cone) stays in code; unit tests keep the files to what Pixi's SVG parser and a browser draw alike (no transform, no polygon, fill always given), e2e 5c reads the five symbols in the theme color (#175)
game-maker / gate (push) Successful in 1m56s
game-maker / suite (push) Successful in 6m48s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 17:07:56 +02:00
adminandClaude Opus 5 5385d9e152 The one-way tolerance angle is a field: a one-way collider and a one-way tile gain One-way angle (0 to 90 degrees, default 45), a contact blocks when its normal is within that angle of the blocking side, without a value the limit is bit-identical to before, and the rule holds for Move, Raycast and dynamic bodies in Rapier; tiles with different angles never merge into one rectangle, the scene view draws the angle as a cone in the middle of the thick side, and the inspector shows Blocks from and One-way angle only while One-way is on, through the new schema option shownWith (#159)
game-maker / gate (push) Successful in 1m55s
game-maker / suite (push) Successful in 6m50s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 13:13:29 +02:00
adminandClaude Opus 5 d4ea04d4d6 The scene view outlines a tilemap's collision only along its outer edges: where two pieces meet, their shared stretch runs once in each direction and is not drawn, so an autotile lake is one outline without cross strokes at the quarters, merged rectangles of plain tiles and one-way tiles follow the same rule, the bridges from splitting concave outlines disappear and a piece doubled on two layers is outlined once; fill and collision stay as they were, and the result is cached per tilemap and rebuilt only when its collision data changes (#173)
game-maker / gate (push) Successful in 1m56s
game-maker / suite (push) Successful in 6m54s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 12:54:53 +02:00
adminandClaude Opus 5 6a31f5e0ad One-way platforms, raycast and collision stay with contact data: a collider can be one-way with a side it blocks from (turning with its object, drawn thick in the scene view) and a tile can be one-way from above, one-way cells never merge with solid tiles, a contact blocks only when its normal is within 45 degrees of the blocking side, the new node Ignore one-way lets an object drop through for a while, and it all holds for Move and for dynamic bodies in Rapier, where the decision is made before each step because the hook may not touch the engine (#155); the new Raycast node answers hit, object, collider, point, normal and distance in our own f64 geometry, the same in editor run and play, and the editor run draws each ray for 0.25 s (#153); On collision stay gains an interval with its own clock per pair, and stay and enter gain the contact point next to normal and impulse (#149); fixes that every Rapier collider of a tilemap had the shape of its last cell
game-maker / gate (push) Successful in 1m55s
game-maker / suite (push) Successful in 6m50s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 11:36:11 +02:00
adminandClaude Opus 5 32057a96fc Physics stage 2: colliders gain the shapes capsule and polygon, a polygon keeps its corners in the property points, turns, scales and mirrors with its object and is edited in the scene view (drag a corner, click an edge to insert one, double-click to delete, at least three stay, each step one undo step), a concave polygon is split into convex parts, a self-intersecting one is drawn red and collides with nothing, Rapier gets a capsule and one convex collider per part on the same body, and Move and the editor run use our own f64 geometry for the new shapes, where on a tie between two normals the one that blocks the move least wins, so a box no longer stops at the foot of a slope (#151); first version of a collision outline per texture frame, edited in the texture tab with the new Collision toggle, which a plain tile blocks with instead of its rectangle (#141, to be reworked)
game-maker / gate (push) Successful in 1m52s
game-maker / suite (push) Successful in 6m41s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 22:56:25 +02:00
adminandClaude Opus 5 78899b1ace Physics stage 1a runs on Rapier: a new Rigidbody child object (body type, mass, gravity scale, damping, fixed rotation, CCD) makes its parent fall, bounce and come to rest in play, colliders gain friction, bounciness and density, the scene gains gravity (0, 980), the new PhysicsSystem steps at a fixed 60 Hz with interpolation in world coordinates and treats a tilemap as static ground, On collision enter gains normal and impulse, play waits for Rapier and does not start without it, and the editor run keeps the old CollisionSystem; the existing collision tests run against both systems unchanged (#146)
game-maker / gate (push) Successful in 1m46s
game-maker / suite (push) Successful in 6m17s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 18:11:43 +02:00
adminandClaude Opus 5 0b32d3cbf3 The tilemap panel gains Fill and Pick: Fill floods the connected cells of the active layer that carry the same tile (edge neighbours only, bounded by the grid) as one undo step, Pick takes the tile of the clicked cell on the active layer, and holding Alt picks while any tool is active (#133)
game-maker / gate (push) Successful in 1m41s
game-maker / suite (push) Successful in 6m7s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 12:31:19 +02:00
adminandClaude Opus 5 5046ddb810 The tilemap painting tools move out of the inspector into their own panel beside the scene view, shown only while exactly one placed tilemap is selected in the scene tab; the free viewports keep their content in place on screen when they are resized (#142)
game-maker / gate (push) Canceled after 0s
game-maker / suite (push) Canceled after 0s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 11:46:23 +02:00
adminandClaude Opus 5 f53279d065 The active tilemap layer can be renamed from the painting section, and a Show setting fades or hides the other layers in the scene view while the tilemap is selected (#138)
game-maker / gate (push) Successful in 1m40s
game-maker / suite (push) Successful in 6m4s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 10:56:32 +02:00
adminandClaude Opus 5 4c411c1ff3 Tilemaps can block movement: a tile gains a Solid switch, the solid cells of all layers are merged into rectangles and the placed tilemap takes part in the collision system as one body, reported as other in collision events (#132)
game-maker / gate (push) Successful in 1m41s
game-maker / suite (push) Successful in 6m3s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 09:47:03 +02:00
adminandClaude Opus 5 732f6518ae The autotile asset is renamed to tile and gains a plain None (1 × 1) kind, which is now the default; older projects load their autotiles as floor tiles (#131)
game-maker / gate (push) Successful in 1m40s
game-maker / suite (push) Successful in 5m56s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 08:01:07 +02:00
adminandClaude Opus 5 33a7b1b63e Tilemaps are a new placeable asset type that is painted with autotiles in the scene view, with layers, brush, eraser and rectangle, and is drawn at runtime and in the export (#128)
game-maker / gate (push) Successful in 1m38s
game-maker / suite (push) Successful in 5m51s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 06:41:47 +02:00
adminandClaude Opus 5 2a390e52ff The scene view and the animation preview share one camera, the three form dialogs one base, and keys are found through one set of helpers (#85)
game-maker / gate (push) Successful in 1m36s
game-maker / suite (push) Successful in 5m41s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 14:19:53 +02:00
rootandClaude Opus 5 78baf0c719 A source wears an icon without becoming decoration (#89)
game-maker / suite (push) Successful in 9m49s
Behavior and Container draw an icon because isSymbolType() is true for them,
but that predicate does not mean "draws an icon" — it means "is editor
decoration". Four places read it that way: collectWorldItems, GameViewport.
collectFrame and syncDrawOrder all drop symbols out of the running world and
the game picture, and placementOf() gives them an upright unscaled box.
Listing 'particles' there would have handed the source an icon and taken away
its particles, in the scene view as well as in the game.

So the two questions are two functions now. hasSceneIcon() says a type draws
an icon; isSymbolType() keeps meaning decoration. The icon itself is a
SceneViewport decoration, which is editor-only for free because GameViewport
never syncs decorations.

A ring (r 10, #c26a1f) with four sparks, upright and unscaled like the other
symbols, its middle left open — unlike Behavior and Container a source draws
something of its own, and the field is densest exactly there. The name sits
beside it and a dashed line runs to the parent, same colour.

Found while writing the tests: the source's grab box scaled with its transform
while the icon did not, so the two came apart. placementOf() returns only the
translation for 'particles', making the box the upright 24 x 24 that covers
its icon. The source's own transform still feeds every particle untouched.

824 checks (821 + 3).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 08:25:49 +02:00
rootandClaude Fable 5.1 016e83c9b5 Transform: scale, rotation and mirror as properties, world transform as a matrix chain, oriented colliders (#76)
game-maker / suite (push) Successful in 9m5s
Four new rows on sprite, text, collider and container (block TRANSFORM):
scale, rotation in degrees clockwise, mirrorX, mirrorY. As properties they
get override/reset/apply, loading of old projects, write-back after play and
the Properties node for free; camera and behavior have none.

The hierarchy composes T*R*S per level (composeAlongChain replaces
sumAlongChain), so children rotate and scale with their parent. Reparenting
and grouping keep the look (carriedTransform). Drawing goes through
placeNode, the gizmo is a polygon, cull and objectRect use the AABB, drags
are computed in the parent's system.

Colliders are oriented boxes: SAT for box/box, box-circle in the box frame;
exitDistance replaces axisSeparation/axisCorrection, moveAndSlide moves along
the object's own axes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 17:25:06 +02:00
rootandClaude Opus 5 8f92a06c84 Consolidate duplicated editor code, trim comments, refresh README
Split GraphCanvas (1076 -> 831 lines) into EdgeLayer and graphMenus;
the port and marker menus were the same list and are now one function.
Value specs of the inspector and the list tab share valueSpecs.ts, and
the remaining copies (compound commands, type glyphs, typed asset
lookup, name rule, play/editor world setup, marquee) are merged.

Four copies had already drifted apart; merging them fixes:
- "Disconnect N links" in the port menu is one undo step, not N
- "+ Add collider" is hidden on a placed container instance, as in
  the hierarchy menu, instead of always failing
- a bool property coerced from the text "false" becomes false
- a port command on an unknown node type reports instead of crashing

Comment-only edits leave the bundle byte-identical. README corrected in
35 places (step limit, jump-run clock, suite duration, 409 body, ...).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 11:00:30 +02:00
root 2218046738 Scene: ausgeschaltete Objekte behalten ihren Auswahlrahmen
Ein ausgeschaltetes Objekt zeichnet nichts, verschwand bisher aber auch aus
der Auswahl - im Panel angeklickt blieb der Viewport leer, es gab kein
Anzeichen, wo es liegt. Der Rahmen kommt jetzt, gedimmt auf 45 %, damit er
sich nicht wie eine fehlgeschlagene Zeichnung liest. Ziehen bleibt aus: der
Node ist weiterhin nicht interaktiv.

Dazu __gm.gizmos() als Testhaken - Gizmos waren vorher gar nicht prüfbar. Es
meldet das alpha, das wirklich in den Strich geht, kein daneben abgeleitetes
Flag.
2026-09-10 17:36:27 +02:00
rootandClaude Opus 5 11981b40d0 Give the three asset tabs one base, and move the viewports into the editor
src/viewport/ held three classes only src/editor/ ever used, and framing.ts sat
under graph/ although the scene view wants the same bounds sum. The graph, the
texture and the container tab repeated the same header, subscription and
disposal code with two silent divergences: the graph tab said "nothing shown"
with null instead of '', and the texture tab refell back to the first asset on
a selection change but not on a project event.

These arrive together because GraphCanvas ties them: it reads framing from its
new home, hands its fold marks to folding.ts, and its '' change is what
GraphEditor must agree with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 07:14:38 +02:00