The first CI run after 9cff528 failed e2e 41 again, at the release this
time (task 405): the hold was fine for 54 frames, but the first sample
after the release was 6.9 units below the hold, over the bound of 3.
The test took its release time after the round trip of the mouse event
and one more evaluate. The frames in between were missing, so the
first counted sample was already about 100 ms into the fall.
- The page stamps the release itself with a capturing `pointerup`
listener. Held and released samples are split at that stamp.
- The fixed bound on the first sample after the release is gone. How
far that frame has fallen follows the frame time. Instead every
sample in the first 200 ms must stay below the hold and keep
falling, which is what "let go at rest" means: no jump, no kick up.
- The 200 ms fall still has to be more than 1 and less than 40 units.
The comment now says about 25, as measured, instead of under 20.
Tests:
- e2e 41 on melektaus-atx: 8 of 8 runs ALL PASSED, 21 checks. The
first sample came 6 to 42 ms after the stamp.
- Counter-check: a release velocity of y -2 instead of 0 in
PhysicsSystem makes the body rise to -3510 and the check fails.
- Gate on melektaus-atx: 195 files, 2829 tests, CHECK EXIT 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The drag check in e2e 41 was red about every other run under WSL and
twice on stein2. The diagnosis in the issue was wrong: "held" were not
two samples but the first and the last one, and -3475 is the height of
the ninth of ten moves. The last move reaches the body a few frames
later (preview, physics step, drawn one step behind). Reading right
after the move sometimes beat it, and slower frames under WSL made
that likely.
- The check first waits until the crate is at the pointer, for at most
2 s. If it never gets there, the check fails with "arrived: false"
instead of stopping the run.
- The page then records the crate's height in every frame and the
check fetches the samples once. The count follows the frames, not the
CDP round trips, and the check asks for at least 30 held frames.
- Held and released samples are split by page timestamps taken right
before and after the mouse release. "Fell" is the last sample within
200 ms of letting go.
Tests:
- e2e 41 on melektaus-atx (WSL): 6 of 6 runs ALL PASSED, 21 checks,
59 to 64 held frames.
- Gate on melektaus-atx: 195 files, 2827 tests, CHECK EXIT 0.
- Counter-check: without passing the hold to the world the crate stays
on the ground and the check fails.
- Not caught by this check: a body let go without zeroing its speed.
After a second of holding the speed is 0 anyway. The unit test "grab
too short for a physics step" covers it, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dragging a sprite with a dynamic rigidbody in the scene view during
play barely moved it. Only a quick drag and release got through. A
dragged object should follow the mouse as if it had no rigidbody and
start from rest when it is let go.
- The scene view reports the dragged objects as held through
EditorState. The game tick no longer writes its own position over a
drag position that has not been read in yet. This affected every
object in play, not only rigidbodies.
- A held dynamic body turns kinematic and is set straight to the drag
target. Gravity and velocity no longer pull it away between two
mouse moves, and the "moved directly" warning stays quiet.
- A body counts as held when the object itself, an object above it
or its rigidbody is dragged.
- On release the body turns dynamic again with linear and angular
velocity set to 0.
Not changed: a press on an unselected crate still lands on its
same-sized collider (rule from #203). Dragging while play is paused
and in the editor run is untouched.
Tests:
- ./check.sh: 155 files, 2273 tests, CHECK EXIT 0 (before 2271).
- e2e 41 alone: 21 checks. e2e 1-16,39-43: 641 checks, all passed.
- 2 unit tests: a held body stays where the drag puts it and starts
from rest, also for a grip shorter than one physics step. The tick
does not overwrite a drag position that is not read in yet.
- 1 e2e check in 41b: the crate is lifted 150 units with the real
mouse, holds exactly at -3490 for a second, then falls from rest
(1.3 px, then 5.1 px) with an empty log.
- Counter-checks: without holding in physics the crate falls back to
the ground and the old warning shows. With the tick writing back
the unit test fails. Without zeroing, a short grip keeps 490 px/s
and the test fails.
- Check total 1356 + 1 = 1357, calculated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scene view drew its symbols from its own SVGs, each in a type
colour and some on a plate. They looked heavier than the panel icons
and were hard to read on busy ground. Symbols of different objects
also sat on top of each other whenever their positions met.
- Every symbol is now the panel icon of its kind, one file for both
places. The scene-only SVGs in src/viewport/icons are gone.
- Symbols are white in a thin dark outline with no plate behind them.
haloSvg widens each shape of the file by its own stroke and draws
that silhouette dark under the icon, so no second file is needed.
- A butt stroke end would leave its end without outline. The halo caps
such strokes square, and the rigidbody arrow shaft is now a filled
rect so its top edge is outlined exactly.
- Symbols are 18 world units across, stay upright and are clickable.
A click selects the object, a drag moves it.
- symbolLayout places every symbol on its object's position. Symbols
that overlap stand on a ring round the middle of their positions,
evenly spaced one icon apart. A ring that reaches into another
symbol takes it in until nothing overlaps. Ownership plays no part.
- Names sit beside their symbol, on the outside of a ring. Selection
frames and parent links follow the symbol.
- A collider icon no longer shows trigger or invalid state. The
outline colour of the shape still does.
- A lone collider sits on its sprite's middle again. A press there on
an unselected sprite drags the collider, so e2e 02 and 16 now grab
the sprite beside its middle. Hook __gm.container.objectRect helps
16 find that spot.
Tests:
- check.sh: 2245 tests, CHECK EXIT 0 (+8 for layout and halo)
- e2e 1-16,31,39-43: 670 PASS, 2 FAIL. Both were sampling too
strictly for the thinner, smaller icons. 5c looked for the exact
outline colour, which the thin outline only reaches blended at this
zoom. 31n started the ring scan one pixel past the smaller ring.
Both are fixed, and e2e 5,31 then passed with 48 checks.
- 5c checks white with an outline and none of the old colours, 41b
checks the ring positions and that a click on a symbol selects its
object, 31n checks the now white particle ring.
- Counter-checks: without the halo only 5c fails, also with the looser
outline match. Without the layout the ring and click checks in 41b
fail. Originals restored by cmp.
- The e2e check total stays 1351.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Colliders were the only placed part without a symbol in the scene
view. A collider that sits exactly on its sprite was hard to find and
could only be picked by its outline.
- The symbol is the box with four corner handles from the asset
panel. It stays upright and has a fixed size in world units.
- colliderColor() holds the colour rule of the outline (green,
trigger colour, red for a shape that collides with nothing). The
outline and the symbol share it.
- The symbol sits 28 units left of the collider centre. The sprite
centre stays free for grabbing the sprite, and a rigidbody symbol
on the same spot is not covered.
- The symbol has its own 26x26 hit area and the outline's handler.
A click selects the collider and a drag moves it. sceneStack counts
it as a hit under the pointer.
- The hook __gm.sceneIcon(id) also returns x, y, color, screen and
clickable.
Findings:
- With the clickable symbol on the sprite centre, four checks in 01
and 09 dragged the collider instead of the crate. That is why the
symbol moved beside the centre.
Tests:
- ./check.sh: 153 files, 2237 tests, CHECK EXIT 0 (was 152 / 2234).
- New unit test for colliderColor. svg-icons.test.ts lists the
collider symbol.
- e2e 41b: 3 new checks (beside the centre without and with a
rigidbody, click selects the collider).
- e2e 1-16,39-43: ALL PASSED, 635 checks. e2e 41 alone: 20 checks.
- Counter-probes: no symbol fails both placement checks. A symbol
without hit area fails only the click check.
- Check total 1348 + 3 = 1351, computed, not yet measured by CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Add collider" and "Add rigidbody" could only create a fresh asset.
Reusing one meant creating a copy by hand, and a new box collider
never matched the sprite it was added to.
- "Add collider…" and "Add rigidbody…" open a second menu at the same
spot: a search field, "Create new …", a separator, then every asset
of that kind sorted by name. Enter takes the first match.
- An existing asset is placed as a shared child, not copied. An asset
the object already carries is greyed out.
- The rule for when the entries are available lives in one place in
the collider commands. An object without a resolvable asset is
greyed out again, as with the old canAddCollider.
- "Fit to sprite" in the menu of a placed collider sizes it to its
sprite and centres it (position 0,0, z kept) as one undo step.
- Fit writes overrides of that placement, not the asset, because a
collider can now sit on several sprites. A value equal to the asset
value clears the override instead.
- Fit removes the collider's own scale, swaps width and height near
90 degrees and gives a circle the radius that fits (min/2). It is
greyed out for polygon and frame outlines and off a sprite.
- Menu has no submenus, so a second menu opens instead, similar to
"Add Component" in Unity. That costs one click more than before.
Tests:
- ./check.sh: 152 files, 2234 tests, CHECK EXIT 0 (before 151/2228).
- 6 new unit tests in tests/core/collider-parts.test.ts.
- 3 new e2e checks in 08a: submenu with search and greying, an
existing collider via search and Enter, Fit on oc2.
- 09, 40 and 41 follow the new labels.
- e2e 1-16,39-41 on the final build: ALL PASSED, 596 checks.
- Counter-checks: no greying, existing asset ignored and fit without
centring each fail at their own check. Breaking the override rule
fails 2 unit tests.
- CI confirmed 1345 checks at 2cf7202 (task 265). New total 1348,
calculated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>