You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Engine bodies have no identity beyond their array index, and the engine's only population path is the destructive initialCondition (C42, elastica.ts:126-205). The DOM layer maps Map-insertion-order → index and never reconciles: addBox/removeBox only mutate the boxesRefs Map, and the init effect deps are [elastica, sectionRect] (dom-elastica.tsx:159-184) — registration changes never re-run it.
Add: a 6th BoundaryBox mounts later. positions[5] is undefined → skipped by every engine guard → the new element never moves and never collides until an unrelated resize re-inits. A README-style update callback without guards (velocity[1] += ..., readme.md:183) throws TypeErrorevery frame.
Remount/reorder: React remounts a middle child (key change — and the README's canonical example uses key={i}) → Map delete+set moves it to the end → index-shift corruption for everything after it.
Canvas mode "fixes" this by nuking the world on every register/unregister (C14, separate issue) — the two modes disagree on the same contract.
Direction
Short-term: re-run init on registration-set change (matches canvas semantics, still teleports — document it) and say in docs that children must be a static set. Real fix (audit design tension 2): engine-level addBody()/removeBody() returning stable handles with an internal free list (SoA stays internal), React maps child → handle. C5, C14, C15, C26 and C42 all collapse into that one abstraction. Audit open question 4: are dynamic element lists in scope for v1?
Severity: Critical (C5) + Medium (C42) · Status: CONFIRMED (independently re-verified)
Problem
Engine bodies have no identity beyond their array index, and the engine's only population path is the destructive
initialCondition(C42,elastica.ts:126-205). The DOM layer maps Map-insertion-order → index and never reconciles:addBox/removeBoxonly mutate theboxesRefsMap, and the init effect deps are[elastica, sectionRect](dom-elastica.tsx:159-184) — registration changes never re-run it.Failure scenarios
boxes.length === 4butpositions[0..3]still hold the old bodies — every remaining element inherits its predecessor's position/velocity/angle (all visually teleport); box Bump next from 16.1.5 to 16.1.7 in /website in the npm_and_yarn group across 1 directory #4's state is orphaned.positions[5]isundefined→ skipped by every engine guard → the new element never moves and never collides until an unrelated resize re-inits. A README-styleupdatecallback without guards (velocity[1] += ..., readme.md:183) throwsTypeErrorevery frame.key={i}) → Map delete+set moves it to the end → index-shift corruption for everything after it.Canvas mode "fixes" this by nuking the world on every register/unregister (C14, separate issue) — the two modes disagree on the same contract.
Direction
Short-term: re-run init on registration-set change (matches canvas semantics, still teleports — document it) and say in docs that children must be a static set. Real fix (audit design tension 2): engine-level
addBody()/removeBody()returning stable handles with an internal free list (SoA stays internal), React maps child → handle. C5, C14, C15, C26 and C42 all collapse into that one abstraction. Audit open question 4: are dynamic element lists in scope for v1?