Skip to content

1.32.0 — Your 1.31 review, fixed (roadmaps 40 + 41) - #365

Merged
AlexZ005 merged 112 commits into
mainfrom
feat/41
Oct 13, 2026
Merged

AlexZ005 merged 112 commits into
mainfrom
feat/41

Conversation

@AlexZ005

Copy link
Copy Markdown
Collaborator

Release 1.32.0 — roadmap 40 (the 1.31 review) + roadmap 41 (review of preview-1-32, round 1) + roadmap 41b (round 2). Integrators 40-int → 41-int → 41b-int.

User approved preview-1-32c (app ab66862) on device 2026-10-14 ("ANSWERED: OK").
Gates: svelte-check 299/39 (baseline ratcheted), vitest 175 files / 2014, check:tokens/storage/zindex, build, scene-lint 33 scenes 0 errors. e2e battery 191 suites in two slots: every red identical on the round-1 head (A/B) or pre-existing. Perf budget gate green; draw calls/triangles unchanged for all 13 games. Preview proof on preview-1-32c: H rows 243/0, G rows 683/0, roadmap-40 104/0.

🤖 Generated with Claude Code

AlexZ005 and others added 30 commits October 8, 2026 13:48
… back and forth

- 40 F12: on a phone Aquarium's water refraction switched off and on by itself. The
  governor walked 6 -> 5 after 10 s of cheap frames at "post off", level 5 brought the
  screen-space water pass back and overloaded 3 s later; doubling the recovery hold only
  slowed the flap (10/20/40/80 s)
- a step back UP to the level a recovery just left (within flapWindowMs) now locks that
  level as the lowest recovery may reach, until clearFlapLock: a new scene (load end),
  releaseQuality / keepFullQuality, or the auto-quality switch. Every auto toggle (water,
  fluid, HDRI tier, shadows, resolution, AO, post, particles) derives from the level, so
  all of them get the rule. A scene that becomes light still walks back
- keepFullQuality(): full quality and no automatic step for the rest of the page session
  (not saved; the Settings auto switch stays on)
- unit: qualityFlapLock (10-minute phone simulation, counterfactual: >8 refraction
  switches without the lock, <=3 with it), the old flap test now ends in the lock

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…elocity, body wave (40 F15)

- motion/motionCore.js (pure, unit-tested): centripetal Catmull-Rom paths with arc
  length, loop/pingpong/once + offset, signed curvature, bank roll, seeded smooth
  bounded noise with an analytic rate, the body-wave envelope/drive/offset
- motion/motionNodes.js (three leaf): Follow Path rides a drawn Spline, a Flow path
  or its own waypoints in world space, faces along it and banks into turns; Wander
  drifts inside an area object's box (or a box around its base), seeded per object;
  Orient to Velocity faces the frame's motion with smoothed turning + bank and holds
  while still; Body Wave bends any mesh subtree with a vertex-shader travelling wave
  whose amplitude/frequency follow speed and whose bend follows turn rate (per-mesh
  material clones keeping the original uuid, put back when the wave stops)
- flowRuntime applies the followers after the movers (stable sort, graphs without
  them unchanged) and prunes waves that stopped
- catalog (Animation group), sockets (path/area take an object), cards, doc lines
- tests/unit/motionCore.test.js: 23 tests incl. the bank-direction counterfactual

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s remember their image

- setObjectsTexture no longer refuses files over 8 MB: the path already downscales to
  1024 px, so the cap only refused photos it was built to shrink (roadmap 40 F13,
  image-large). The one limit left is a 64 MB decode-safety cap.
- material.userData.mapSource = the content hash of the Explorer image a texture was
  made from (Explorer drop, UV slot drop). It rides the `map` message as an additive
  `source` field, the `materials` payload as `mapSources`, and a material-type switch.
  Any write without one (paint, undo, a file from disk, an older peer) drops the link.
- texturesFromSource(hash) / linkTextureSource(uuid, slot, hash): the seams the Image
  editor's Save uses to re-texture every material made from an image.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…(40 F16)

- material presets carry the thin film (iridescence, its IOR and thickness range) and
  the transmission volume; three's [min, max] range maps both ways
- a new starter "Fish scales": an iridescent physical look over a procedural, tileable
  scale relief (scales hang like shingles, lower row in front), a light clear coat and
  a hint of transmission; the swatch shows the film as a hue sweep
- materialTiersCore (pure) + materialTiers (runtime): every physical material is drawn
  at this device's tier, the water rule (headset or post off = low, a phone's start =
  mid): mid drops transmission (the extra full-scene pass), low also drops the thin
  film and sheen. LOCAL only; the authored numbers ride as userData.lookTierAuthored,
  written only when a device draws less, so a desktop save stays byte-identical and a
  headset's save restores the full look elsewhere; an edit made since is the new look
- debug hooks: materialTiers, motionNodes
- tests: materialTiers.test.js (10, incl. a save on a low device reloading at full
  look), the starter list grew by one

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… full quality" per toggle

- 40 F12: when the device lowers a quality toggle on its own it says so once per toggle per
  session, batched per drop: "Lowered water quality and the scene look to keep it smooth"
  with a "Keep full quality" action (keepFullQuality: full quality for the rest of the page
  session, the Settings auto switch untouched)
- the rule is pure (qualityNoticeCore: which toggles, newly lowered, the words); the
  AutoQualityNotice component watches qualityOverrides + simplifiedWater, counts only
  automatic drops (frames / long tasks / the phone's lighter start, never a game preset or
  the headset floor), holds a drop made in Play or a headset until you are back, and judges
  in a microtask because publish writes the overrides before the reason
- replaces the object list's first-step toast (gone whenever that window was closed) and
  SimplifiedWaterNotice; the quality chip says "stays this way for this scene" while held
- governorForTest: setLevel on a synthetic clock, flapLock / clearFlapLock
- e2e auto-quality-notice (phone 390x844 touch + desktop 1440x900: the drop, one retry, held
  for 10 min, counterfactual 15 switches, scene load clears the lock, Play deferral, tap
  Keep full quality, shadows on desktop); fb-water-phone part 3 asserts a game preset is
  not announced; unit qualityNotice

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- F6 docked tab strip: the bar paints from a non-scrolling wrapper, so every tab
  (not just the first three) sits on it when scrolled and the edge fade masks only
  the tabs; one shared scroll position survives a tab pick (each panel mounts its
  own strip, which used to start at 0)
- F7 window header names: one line + ellipsis, full name on hover and touch
  long-press ($lib/ui/fullName.js, on WindowChrome titles and the docked .tp-dock-sub
  which had no rule); a phone-narrow Animation moves the name out of the control row
- F8 docked windows carry no close or undock button (tabs carry the close, the
  dock code workspace keeps its unsaved-tabs ask through registerDockCloser); the
  undock button sits left of "minimize the dock" and undocks the active tab, or
  every tab as one tabbed group (Settings > Interface > Windows & chrome > Undock
  button); a floating tab group gets a dock-all button left of "close all tabs"
- F9 phone "+" (floating windows off) opens a sheet of every window with show/hide
  switches; with floating windows on it is the desktop menu
- F10 a docked tab dropped onto/into a floating window joins it as a tab
  (windowTabs.windowAt + queueMerge); dragWindow's size watch and window-resize
  re-clamp stand down for tab members, which threw a revealed member off its group
- F11 the Layouts popover is the kit ModalDialog (it painted with a theme var most
  themes no longer define); own desktop width because the kit width prop loses to
  the layered !important frame rule
- bottomDock.armDockModes queues several dock-mode arms (the slot is write-once)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…swimming with the motion nodes (40 F14)

- lodGroupCore: an additive `fallback: true` group — LOD0 (the object itself) is a STAND-IN,
  drawn only while the real model's levels are loading or unreachable; the pick runs over
  levels 1..n (pickFallbackLevel, hysteresis kept). Unit tests incl. the counterfactual.
- lodGroup: a pack level that does not pair with the object (or any level of a fallback
  group) is a TREE level, cloned per object, casting shadows; lodTrees.js (a leaf) lists
  the substitutes so Body Wave bends the real model and the look tier reaches its film
- Body Wave: each mesh set (the object's own, each substitute) bends in its own frame,
  from the local matrix chain
- author-templates: a `lod` object field; the card builds every fallback level first and
  draws each object's finest real model
- the Aquarium: six reef fish (clownfish Wander + Orient to Velocity, tangs and angelfish
  Follow Path loops with banking, every fish a Body Wave), a reef rock arch (was the torus),
  staghorn coral, eelgrass and Amazon swords — all aquarium-kit models over the old
  primitives as stand-ins wearing the thin film
- tests: e2e aquarium-reef (motion, fallback LOD, saves, tier, offline counterfactual);
  select-inside-36 / fb-water-probe find the fish the loaded Aquarium has

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…enu taps (F2)

- F1: $lib/ui/sheetDrag (the shared drag/flick/keyboard gesture) + sheetSnap.settleSheet
  (free-height rest rule: snap to min/max, swipe down to the end closes) + ui/SheetGrip
  (the sticky grab bar). Wired into the shell's framed sheets, ui/Sheet, the Inspector /
  Configure Scene, the main menu, the profile menu, every phone context menu (Add), the
  notes sheet, toolboxes, Customize character and the dock (grab bar drawn by PhoneShell;
  swipe-away minimizes the dock). Heights remembered under each sheet's existing key.
- phoneSheetMax / --ps-sheet-max: no sheet rises into the top bar or pushes the selection
  strip under it; the bar + strip rise over every open sheet so Play is never covered
  (cover-play-and-handle). The notification centre's desktop click-catcher stands down
  on the phone.
- F2: the profile menu inherited pointer-events:none from the top-right corner chrome on
  the phone, so Customize character / Profile settings never got the tap. On the phone it
  is a plain sheet above the bar (no top layer), tappable.
- e2e phone-sheets (104, real touch events, F2 counterfactual); mobile-map and
  mobile-ui-fixes assert the new above-the-bar contract; vitest sheetSnap +4.
- svelte-check 300/40 (baseline ratcheted from 300/41).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ersions (WIP)

- src/lib/image/imageOps.js: pure raster maths (crop/rotate/flip/area+bilinear resize/
  brightness-contrast-saturation), vitest imageOps (19 green)
- src/lib/image/imageVersions.js: per-image version history in idb (Original always kept, cap 20)
- src/lib/image/imageEditor.js: open/close, decode/encode, saveImage (same record, version kept,
  linked textures re-textured as one undo), restoreImageVersion, saveImageCopy, editMaterialTexture
- ImageEditorWindow.svelte: WindowShell canvas + right sidebar (Edit / Versions), zoom/pan/pinch,
  crop drag, editor-local undo, phone sheet above Play
- entry points: Explorer "Edit image...", preview #preview-edit, Inspector #texture-edit
- storage breakdown: "Image versions" category
- e2e image-editor (WIP: sections 1-8 pass; save is slow on a janky page, being profiled)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…g fixes

- dock-chrome-40 (45 checks, phone touch + desktop mouse), green; counterfactual:
  keepScroll neutered -> F6.3/F6.5 red
- suites that clicked the removed docked close/undock buttons now use the tab x
  ([data-dock-tab-close]) and #dock-undock
- phone '+' sheet ends at the phone bar (Play visible) and its switches fit
- Layouts dialog: Escape in the window capture phase (the menu tree stops keydown)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n, toolbar strip (40 F3)

- $lib/ui/touchHold: touch hold opens an Explorer item's menu (the phone action sheet);
  the browser's touch contextmenu / native dragstart are swallowed on Explorer items only.
  File cards: hold-and-lift = menu, hold-then-move = the existing touch pick-up.
- the inline rename field's ::selection uses --accent-fill / --on-accent.
- docked Explorer toolbar is a ui/ScrollStrip on the phone shell (#explorer-dock-strip).
- e2e explorer-phone: 20 PASS / 8 FAIL — remaining failures are TEST sequencing
  (the folder menu has no "Open" row and Escape does not close the action sheet, so the
  later sections run with a menu open), see the STATUS handover.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… reef suite test fixes (40 F14)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- lod.js afterRender and the water runtime's afterSceneRender returned early on a
  nested render BEFORE calling the hook they wrap, while their before-hooks always
  call theirs: every water reflection pass leaked one depth into the wrapped hook,
  so the LOD group pass was skipped forever after the first frames (pre-existing,
  seen on the 1.31 Aquarium too). Both now always hand on to prevAfter.
- vitest lodHookChain (counterfactual: depth 5 / 0 passes with the old hook);
  aquarium-reef 2.0 asserts the pass keeps running with water in the scene.
- GroupEntry typedef carries the lastWant debug field (svelte-check back to 300/41).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…erty (40 F14)

- the tang loop is an ellipse (1.45 x 0.5 m), so two fish half a lap apart
  are never closer than its minor diameter, 1.0 m: the old > 1.2 m threshold
  could not pass. The check now asserts their midpoint stays on the loop centre
  (measured 0.00 m); with a broken offset it would be 0.5-1.45 m off.
- suite 32/32 green with the packs reachable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…on, toolbar strip (40 F3)

- finishes the wip commit: e2e explorer-phone 28/28 (real CDP touch, dark + light).
- an action sheet closes on a tap on its backdrop (a phone has no Escape); the folder
  menu's rows are Share folder / Properties / ... (no "Open").
- counterfactuals: no folder onhold -> the folder-sheet check reds; touchHold's swallow
  removed -> a touch contextmenu opens a second menu before the hold (menus 1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d Play; suite green

- the phone shell's top bar (64 px) covered the editor's header and close button: the
  sheet now starts under it and ends at the bottom bar (--ps-bar-h), so Play stays tappable
- canvas and sidebar no longer squeeze side by side at 390 px (232 px canvas, a sidebar
  clipping its own labels): the Edit/Versions panel stacks under a full-width canvas,
  its tabs a row of 44 px touch targets
- image-editor suite: GPU backend (on software GL two pages + the 14 MB photo starved the
  compositor, ~1 s per round trip, profiled: JS idle), wider post-Save waits, diagnostic
  logging removed, the phone section finds the shell's #ps-play and asserts the close
  button and the stacked panel (counterfactual: both red with the CSS removed)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- cause (measured with an instrumented ResizeObserver): ui/ScrollStrip watched every child
  and never stopped watching a REMOVED one. The docked Explorer's header measures itself
  inside a resize pass, finds it is narrow and unmounts its storage chip (a strip child) in
  that pass; a detached node's 0x0 notification cannot be delivered in the same pass, so the
  browser raised "loop completed with undelivered notifications" and the crash toast showed
  it (the user's phone had Explorer + Animation docked: feedback-1.31/resizeobserver.jpg).
- the strip un-watches a child in its MutationObserver, which runs at the same microtask
  checkpoint as the removal, before the next gather. Every ScrollStrip inherits it.
- e2e resize-observer-loop (14): 350x716 touch, dark + light, Explorer + Animation (Graph)
  docked, tab switches, a real-touch dock resize; desktop open + resize. Counterfactual: the
  old ScrollStrip reds 6 checks (1 loop error + the toast, per theme).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ct (40 F3)

- section 5 asserted the docked header TRUNCATES the project chip at 520px; at <= 640px the
  phone shell is up and F3 made that toolbar a sideways strip on purpose (the name was cut to
  "Unt..." on a phone). The truncation contract moves to 660px (narrow, not phone) unchanged,
  and 520px asserts the strip: search keeps its width, the name shows whole, a scroll brings
  the chip fully into view, the page does not overflow. 71/71.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… view

- the sidebar's scroller is shared by Edit and Versions, so after scrolling down in Edit the
  short Versions list opened scrolled out of sight and read as empty (measured on a phone:
  the list 525 px above the visible area). Each panel resets the scroller when it mounts.
- on a phone the stacked panel showed Apply crop half under the bottom bar after Crop...;
  entering crop mode scrolls it into the panel's view
- suite: phone checks for both, the touch drag's crop box asserted directly, the first-draw
  canvas read polls instead of sampling once (counterfactual run15: three checks red)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…0 repro

- windowTabs.tabbable: a header press that never travels (4px) is a click that raises
  the window, not a merge. Latent before: it only stopped hiding once F10 kept group
  members on their group rect, which put a member's header band under a window that
  overlaps the strip (tab-group-stacking went red: a raised object list joined the group)
- dock-chrome-40 F10: the joining window's own remembered spot is parked off the right
  edge first, plus F10.5 (a browser resize and two more tab switches). With the
  dragWindow tab-member guards removed F10.3 now goes red (it did not before)
- dock-splits / docking / layout: #flow-undock -> #dock-undock (the docked window has no
  undock button of its own since F8). Their remaining reds are identical on 1.31.0

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/components/editors/Explorer.svelte
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ranking (window-header-ranking 220/190 px overflow)

40-image added #preview-edit after the ranking was set; at 220 px and below the row overflowed.
It now gives way with the up-a-folder button (Edit image… stays on the Explorer menu and the
Inspector texture row). The suite tracks it in the ranking.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…act (hold = action sheet, hold+move = pick up)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…0 F3)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…Undock button' (40 F8), 'scale' finds the Fish scales preset (40 F16)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AlexZ005 and others added 22 commits October 11, 2026 08:50
…reloads (41-editors' suite meets 41-modals' G16)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…scope chip (the breadcrumb sits above the pane now)

41 G15 moved the crumbs into the layout flow but FIT_PADDING kept its 56px top, so a short docked
pane (270px, minimap on) framed below minZoom and clamped at 0.2. node-ux-notes clicks nodes by
their own middle and re-reads c after Align (it used to hit another member by luck).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d in the same frame

- $lib/ui/bottomEdge.js: ONE live bottom edge — the bottom bar and whatever is open along it
  (framed sheet, Inspector, notes sheet + note card, toolbox sheet, dock + its tab row, Add list),
  read once per animation frame; `followBottomEdge(fn)` calls back only on change.
- PhoneShell: the strip sits at bottom 0 and is lifted by a TRANSFORM written in that rAF (no
  layout), replacing a 120 ms poll that moved `bottom` — the strip held a stale place for frames,
  then jumped ("inspect toolbar stutter when I resize drawers").
- strip-follow-41b (new): CDP touch drags of the dock grip, a framed sheet's handle and the
  Inspector's grab bar with a per-frame sampler. Counterfactual on feat/41-int: 95-102 of ~169
  frames more than one frame behind and 17-18 jumps per drag (7 reds); after: 0 / 0, 16 pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… is room; no avatar in the profile sheet

- H4 (refines G21): the chip shows "Connected" / "Connecting…" / "Offline" (connectionLabel(tone),
  $lib/connectionStatus) beside its dot when the chip's slot between the logo and the right-hand
  chrome has room, and drops to the dot alone only when it is crowded (the peers button and a call's
  mic narrow it) — a ResizeObserver container-width rule, not a device rule. The label's natural
  width comes from an always-laid-out hidden copy (a hidden label measures 0). The full sentence
  stays the tooltip and accessible name. Phone only: the screenshots and G21's complaint are phone.
- H11: the phone profile sheet drops the notch avatar from its header (the avatar is already top
  right); the name takes the row. Desktop keeps the notch circle.
- signaling-reconnect: its "the chip carries no text" check follows H4 (one state word; the chip
  fits its slot). vitest connectionLabel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ay's own menu; Play defaults to Play

- H6: More may leave the bar ($lib/ui/phoneBar: no forced More; More comes back at the end). The
  first removal opens a kit modal "To get More back, press and hold any item on the bottom bar"
  ("Keep More" undoes it; one-time, `phoneBarMoreHint`). The editor's header reads
  "More ▸ Edit bar…" and "More" returns to the More menu.
- H6: a long press on Play opens PLAY'S OWN phone menu instead of forwarding to the desktop
  toolbar's (whose Move left/right walked a bar a phone does not draw, plus Always on top / Move
  toolbar / Collapse / Customize): the shared "Play as" rows, Test play in a game, Move left /
  Move right (Play walks along the bar, `phoneBarPlayAt`; the middle is forgotten) and Edit bar…
  (so a bar emptied down to Play stays editable). Reset to default also re-centres Play.
- H7: `vrOverride` is three-state — 'true' / 'false' are a choice, absent is the DEVICE default
  (sceneStore `readVrOverride`; inputDevice `handheldDevice` = a coarse pointer that is not a
  headset browser): a phone plays on its screen like desktop, a headset still enters VR.
  `choosePlayAs` / `playAsItems` ($lib/playMode) are the one write for both play buttons'
  menus; Settings ▸ VR writes OFF as 'false'; resetting VR settings returns to the device default.
  The phone Play glyph follows the choice like desktop (triangle / headset / headset with A R).
- Suites: phone-bar-41b (new, 34: H4 / H6 / H7 / H11 on the folded N6 + desktop parity);
  mobile-map's "More cannot be taken off" follows H6; play-mode-menu counts the menu it gets (41 G1
  grew the toolbar tail — red on feat/41-int before this, A/B'd). vitest phoneBar.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r on a phone

- Desktop / unfolded N6: the panel is the notification centre's tool window (ui/WindowChrome:
  "Connected" + count + the All|Rooms switch + close — same 40 px header), 320 px at least and as wide
  as its rows up to 420 px. Each peer is ONE row: avatar · name (ellipsis, full name as the tooltip)
  over one muted line (where they are, their role, mode / mute / VR / quality, the short id — the
  place ellipsizes first, nothing wraps) · actions on the right (role picker, Watch / Go to / Join /
  Request access).
- Phone: `peersPanelOpen` (appStore) replaces the component's own flag, so PhoneShell frames the
  panel like the notification centre: the shell's sheet with its grab bar, a scrim, swipe down to
  close (G5); the desktop click-catcher stands down there; the selection strip hides under it (G20).
- peers-panel-41b (new, 25): four long-named peers in long-named scenes with roles, on desktop, the
  unfolded and the folded N6 (real touch swipe). Counterfactual on feat/41-int: 288 px, every row's
  second line wraps, no full-name tooltip, no header — then no drawer. peers-popover reads the new
  header. Shot drivers peersShots41b / phoneShots41b (evidence, not suites).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s stay on the label's row

- $lib/ui/rowFit.js: each row measures its control's max-content (an invisible, absolutely-positioned
  clone — the live row never reflows) against the row and keeps it beside the label when the text
  column keeps >= 150 px (no one-word columns, G19's narrow-width fix). One ResizeObserver + a
  MutationObserver per control, batched; verdicts land a frame later from inside the observer so a
  row-height flip cannot raise a ResizeObserver loop error
- ui/SettingRow: G19's container queries (every segmented / two-piece control under 560 px, all but
  a lone switch under 420 px) replaced by the measured verdict (`sr-fit-stack`); a stacked
  segmented / slider / text field / `wide` row stretches, the rest keep their width; a stacked
  segmented wider than its row wraps to two columns (`sr-seg-wrap`, "Double-click action" on a
  phone); an empty `extra` snippet takes no room (the shortcut rows' dead gap)
- folded N6: shortcut keys, Light helper length, Length, colour swatches + Reset, Grid size/colour,
  Version, Diagnostics Copy, Clear saved session, Reset all settings, Session size, voice-typing
  Test back on one row (the 1.31 look); unfolded N6: Node editor mouse/opens and Ping sound too
- tests: settings-row-fit (new, 47; counterfactual red on feat/41-int — every folded row stacks);
  settingsNarrowShared floor 180 -> 150 + a description-less one-line label (Version) counts as fine

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tions, a setting to roll back

- the user's FINAL burger decision (feedback-1.32b): COMPACT = a strict two-column grid at list-row
  height, icons beside labels — [New from template…] / [Load][Save ▾] / [Import][Export…]. Save saves
  with the last-used options, ▾ opens "Save options", Export… opens Publish / Export. LIST = the 1.32
  rows; its ⚙ opens the same Save options. The action ids (#open-templates, #open-publish-export)
  move with their action; the cloud slot still follows Save in both
- Save options (SaveOptionsModal.svelte, the kit's ModalDialog + Segmented + Toggles): format
  (Project / Scene, GLTF / JSON once offered), what a .tpscene / .tp includes, the two optional
  formats — a DRAFT: Save remembers and saves, Cancel forgets. It replaces the cog's small popup.
  $lib/saveOptions.js holds the options under the SAME localStorage keys (saveFormat, showGltfFormat,
  showJsonFormat, tpscene*, tpProjectVersions), so a device keeps its choices
- Settings ▸ Interface ▸ Lists & menus ▸ Project actions = Auto / Compact / List ($lib/projectActions,
  `ui:projectActions`, absent = Auto = List on the phone shell, Compact on desktop + unfolded N6),
  keywords for settings search (burger, main menu, compact grid…), Reset Interface resets it
- tests: burger-project-actions (new: both device defaults, the grid's geometry, Save ▾ -> Save
  downloads the chosen format + remembers it, one-press Save, Export…, instant rollback, search, the
  fold/unfold posture); files-format-row / project-open-import / scene-versions-in-file / tpscene /
  community-seams pin the List layout and drive Save options; modal-layering measures the modal;
  text-selection reads either label

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…(41b H10)

- the overlay thumb is a CHILD of the scroller, placed at scrollTop + inset, so it was part of
  the scrollable overflow: content that shrank under a scrolled view kept its old scrollHeight
  through the thumb, and every scroll event moved the thumb up by its 2 px inset - the view
  drained 2 px a frame for seconds with the content above it (Modules: Browse scrolled down,
  then Core = "a huge scrollbar that shrinks, then the items appear")
- place() measures with the thumb out of layout, so the offset clamps on the first frame;
  fixed once in the primitive, every redesigned scroller inherits it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…pens at its top (41b H8 H9 H10)

- H8: a module row is a grid - name/description on the left, the management controls on its
  RIGHT on every width (Core: download + switch, User: Remove + switch, Browse: Install), the
  module's own actions (Button & door "+ Button", Pong spawn/remove, Update) under the text;
  the dev URL row wraps so "Auto" never leaves the card (clipped at 360 css px before)
- H8: a clamped description is a tap target with a chevron - expands in place, a second tap
  collapses it (no tooltip: touch has no hover); nothing to tap when the text fits
- H9: Browse installs are per-module JOBS ($lib/moduleInstallJobs: a per-id promise map, a
  second click joins the running install) - the old single galleryBusy id was overwritten by
  the next click, so earlier cards went back to "Install" mid-download (the Waves report);
  installUrl takes an onStatus reporter so a job never writes the shared status line
- H9: a failed install stays on its card: the reason in words, Retry, and Details with the raw
  message (it used to land on the User tab's one status line, overwritten by the next install)
- H10: switching tab scrolls the modal body to the top (with the minimalScroll fix, Core is
  at its final height from the first painted frame)
- suite modules-phone-jobs (37): folded N6 + desktop, routed slow/failing module fetches,
  rapid clicks on four modules incl. Waves; 14 red on feat/41-int, all green here

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… them

- Properties (the Inspector's selection view), Objects, Notes, Layouts and
  Configure Scene are tabs of the bottom dock on a phone, through the G22
  registry: bottomDock PHONE_DOCK_TABS (+ titles/icons, DOCK_KEYS for the
  strip order), dockMenu PHONE_DOCK_WINDOWS (phone-only rows of the "+"
  sheet/menu) with registerDockOpener/registerDockCloser; no undock for them.
- $lib/phoneDock: occupancy while the phone posture is on; the ONE Inspector
  element as two tabs (an outside close is read after a 120 ms settle, since
  showSidebar closes and reopens on a kind switch); the posture memory
  (folded <-> unfolded/desktop: each panel to its wider-screen home and back,
  the tab in front kept; opens/closes carry over; session memory only);
  Inspect opens or focuses Properties; phoneBarTap (H5: a tap on the view on
  screen minimizes the dock, a floating window with undocking on toggles);
  Objects stays a floating window when undocking on touch is on (41 G6).
- PhoneDockHost.svelte: the dock frame (.tp-dock-panel + DockTabs, the shell's
  grab bar) that re-seats #inspector / #object-list / #notes-drawer via
  [data-pd-host]; renders the Layouts list and a "Nothing selected" state.
- The note card sits under the phone bar (it was on --z-popover and covered
  the raised Play circle) and is a page of the Notes tab when it is in front,
  its grab bar resizing the dock.
- appStore seams: setInspectorRevealer (showSidebar / openSceneSection on a
  covered tab bring it to the front) and setPanelsHook (Settings / spectating
  give back the tab that was in front, and nothing reopens while hidden).
- The dock's swipe-away puts the height back to where the gesture started
  (the live drag left flowDockHeight at 0 and every later tab 27 px tall).
- Suites adapted to the tab model (their intent kept): phone-sheets,
  sheet-handoff, notes-phone-drillin, drawer-layering, mobile-map,
  dock-add-registry, dock-chrome-40 F11, select-41 reset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e only

The main menu closes as Configure Scene opens on a phone (it is a dock tab
under the menu sheet); on a wider screen it stays open beside the drawer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Real touch on a folded N6: Inspect = the Properties tab (and focuses it over
the Explorer), Objects/Notes/Configure Scene/Layouts tabs, the kind follows
the tab, tab close, the "+" sheet rows, no undock, Play never covered (Notes
tab + note card), H5 minimize/restore + floating toggle, H2 on phone vs
desktop, the posture round trip 390 -> 770 -> 390 -> 1440 -> 390.
58/0 on the lane; red on feat/41-int (counterfactual).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/components/phone/PhoneShell.svelte
… svelte-check to 299/39

41b H1 made Objects and the Inspector dock tabs on a phone, so 41b-bar's
strip-follow rows for "a framed sheet (Objects)" and "the Inspector sheet"
no longer open a sheet. The framed-sheet row drives Chat (still a framed
sheet); the Inspector's grip is the dock's now, covered by the dock row.
The union is one svelte-check error below the baseline (41b-bar).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The 41 section gains the phone dock tabs, the bottom-bar changes, the burger
Project grid + Save options, the Modules window and install jobs, the peers
panel; the pill and settings-row lines now say what round 2 made of them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…) in settings search; a phone's 'Play on the screen' default is ON (H7)

- lock-search: re-recorded on the union; the only change is the new Settings ▸ Interface ▸
  Project actions row in 7 queries (2 of which now also land in Interface).
- lock-settings: one value edited by hand, the 390x844 VR ▸ "Play on the screen, even in a
  headset" default false → true (H7: absent vrOverride = the device default, and a phone plays on
  its screen). A full LOCK_RECORD re-shuffles ~3k lines of probe output, so it was not kept.
- Battery round 2: image-editor touch crop red identically on pristine 353dfea; notes-v2 and
  fb-water-phone green on rerun.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…a built app (preview proof)

The H10 minimalScroll probe imports '/src/lib/ui/minimalScroll.js', which exists on a dev
server only; against preview-1-32c the import threw and took the H8 layout checks after it
down (24/0 then SCRIPT FAILED). On a build the probe is skipped with a SKIP line; the
Core-frame H10 checks above it still run. Dev server: unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lected offers the whole scene), matching B1.2

Sidebar #format-gltf and SAVE_FORMATS gltf still said "Exports the scene as glTF";
fileHandler exports the selection and asks before exporting everything.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant