Skip to content

1.27.0 — Sky images, walls and stairs, smarter nodes and sparks that fly 🏛️ - #342

Merged
AlexZ005 merged 45 commits into
mainfrom
feat/1.27
Oct 7, 2026
Merged

AlexZ005 merged 45 commits into
mainfrom
feat/1.27

Conversation

@AlexZ005

@AlexZ005 AlexZ005 commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

1.27.0 — Sky images, walls and stairs, smarter nodes and sparks that fly 🏛️

Roadmap 37, release 1.27 (integrator 37-int-127). Lane PRs merged into feat/1.27 (merge commits, in this order):
#328 hdri (R2) · #318 arch (R3) · #327 nodes (R6 R7-parked R8) · #319 fx (R12 R17 R19) · #338 bugs (R26).

Union fixes:

  • hdri's Sky image quality row rebuilt on the 1.26 Settings kit (Scene ▸ Performance, beside Water quality).
  • What's New's cloud section uses 1.26's shared $lib/changelog.js parser.
  • R26 × 1.26 R1: R1's multi-select light / render-order writers kept; their 500 ms seals carry R26's history gesture (+ merge handlers for flags / light); DragRow keeps both the liveText skip and the Esc reverting guard.
  • New: history.registerPendingSeal — undo/redo flush the Inspector's pending seals, so a Ctrl+Z right after a drag undoes that drag (before: it undid the step before it — scrub-undo removed the light). Counterfactual: 3 reds without the flush.
  • Orchestrator decision (21-C risk 6): the module gallery reads modules@format-1 (a moving tag, retagged per modules release — RELEASING.md); unit test + counterfactual.

Proof: svelte-check 306/47 (= baseline), vitest 149 files / 1802, build, check:storage clean, check:tokens rc0; e2e battery (~110 suites, two slots) — every lane suite green on the union; reds A/B'd identical on v1.26.0 (vr-passthrough, export-zip, environment, environment-v2, scene-post, scene-post-effects, MOD:dungeon-realms, MOD:untangle) or known stale (game-waves 1.2, dock-chrome 9.3, flow-palette, flow-customnode-io, shader-editor texture wait, animation-curves key right-click); variadic-nodes flakes identically on its lane branch (1 red + 1 green each). Preview https://preview-1-27.theprototype.pages.dev proof ALL PASS. Modules: car 1.3.0 + Blocks 1.0.0 (modules #42 → dev, #46 → main 3ddfbee; format-1 retagged). Cloud #47 (What's New section) ships with this release.

🤖 Generated with Claude Code

AlexZ005 and others added 30 commits October 6, 2026 02:08
…s (37 R3 phase 1)

- src/lib/arch/archGeometry.js (three only): Wall (length/height/thickness, doors
  and windows as openings on half-metre centres with a pier kept), Door (frame +
  leaves with hinge/swing/angle/panes/sill), Window (frame, ledge, sash with
  cols x rows panes, fixed or casement), Staircase (straight / L / U / spiral,
  steps/rise/run, solid or open treads)
- registered as GEOMETRY_PARAMS build specs (the 21-C1 Terrain precedent): the
  existing geometry message, history kind and userData.geometryParams carry them
- cleanParams is the wire boundary: every param clamped, ints rounded, unknown
  choices and keys dropped (a 10^6-step staircase from a peer builds the 40-step one)
- ParamSpec gains `show` (the Inspector hides rows that do not apply)
- vitest archGeometry (37): plain group-free soups, determinism, frames on the 1 m
  grid, openings are real holes, swing directions, and in real rapier a ball rolls
  through a wall doorway (a wall without one stops it) and the walker climbs the
  stair on its trimesh with the app's autostep (a block of the same height stops it)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…undled CC0 HDRIs + presets, PMREM layer (full/low tier), env tone-mapping pass + half-float composer, water samples the PMREM, Inspector section + upload, export/scene-asset hooks

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ehaviour runtime (37 R3 phase 2-3, WIP: not yet e2e-verified)

- createGeometry builds Wall/Door/Window/Staircase from fromArgs params; collider hints
- Add menu Architecture group (12 variants); placement rounds to the 1 m grid
- Inspector hides rows whose show() is false; edits store cleaned params
- arch/archParts.js: door leaves / window sashes rebuilt idempotently per scene poke,
  registered via animatedImports.registerProceduralBehavior; late joiners get door
  state on the getanim reply; object list hides part children

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

- variadicNodes.js (leaf): typed N inputs a..h for math/gate (data.sockets, absent = 2), folds add/sub/mul/div/min/max and and/or/xor (xor = parity); switcher in<i> sockets typed by data.vtype, value output, wired index overrides the radio, unnamed output stays the index; pure socketRemovalPlan
- variadicEdit.js: add/remove socket, add item, switcher type change as ONE undo step, replicated on ordinary edge/node messages
- groups drop the IO entry of a removed socket (socketExists); cards with + input / - rows; wired readouts unwrap handle maps
- vitest variadicNodes 15 green; e2e variadic-nodes written, NOT RUN yet; svelte-check 318/47 held

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

- particleShader: one closed-form slotAge/simPos shared by every render mode;
  new strip (stretch/trails) and ribbon vertex shaders + strip fragment shader
- particleStrips.js (pure leaf): strip/ribbon layouts, slot expansion,
  smoothed emitter velocity (vitest particleStrips, 13)
- particleRuntime: render modes points|stretch|trails|ribbon, per-slot birth
  stamps of origin + emitter velocity (aVel), uInherit/uTrail/uSegs uniforms,
  ribbon zeroes life jitter + phase noise, VR cap by whole particles
- presets: Sparks stretched along motion (+inherit 0.5); new Ribbon trail and
  Magic wisps; defaults render/inherit/stretch/trail/trailSegments
- Inspector: ParticleMotionRows (Draw as / Stretch / Trail / Inherit velocity)
- e2e particles-fx: 13/15 green; the two ribbon pixel checks use a
  brightness>600 metric that misses the (visible, blue) band - metric to fix

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

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

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

- cameraRig.js (three leaf): rigGoal (follow/lookat/both, world or target-space offset, aim height; -Z forward, the camera-marker convention) + rigStep (damping as a time constant, dt clamped to 0.25 s)
- flowRuntime: camerarig is an effect (animationTypes) applied to the Object Selector's object; LOCAL per peer, never sent; refuses anything without userData.camera (one toast); keeps a smoothed world pose per node+camera, pruned when the rig goes so the restore loop hands the authored pose back
- catalog (Game group, beside Set Active Camera), sockets target:object offset:vector3, AnimationNode card, docs line
- vitest cameraRig 8 green; e2e camera-rig written (editor camera of both peers untouched, no move sent), not run yet; svelte-check 318/47

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…presets by eye (rig suns lower, Meadow IBL 0.6, Photo studio lights a plain backdrop); probe frames the camera

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

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…i.physics.rapier (37-fx R12 R17 R19)

- a joint that leaves DURING a run breaks: physics drops the live rapier joint
  (it used to hold until the next run) and, on every peer (each applies its own
  jointdelete), sparks fly from the anchor + On impact emitters on either end fire;
  edit-time detach stays quiet; sparks:false opts out (joints.onJointRemoved)
- the simulator follows the joint list mid-run (syncLiveJoints): new defs build live
- buildLiveJoint extracted from startSimulation; anchors/axis read through the body's
  current rotation (identity at start, so the start path is unchanged)
- JointDef options: limits [min,max], contacts:false, motor {pos,stiffness,damping}
  (jointOptions validates); physics.setJointMotorPosition + SDK surface
- copyJointsWithin(uuidMap): duplicating BOTH ends clones the joint (one end: no),
  wired beside copyCablesWithin in duplicateObject/duplicateSelection
- api.physics.rapier(): the loaded rapier for a module's own local world (Blocks)
- e2e joints-fx (two peers); particles-fx: coloured-pixel metric, deselected grey box,
  the sweep resolves the box by uuid

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- cloudHooks.whatsNewCloud + setWhatsNewCloud (validated, 20k cap; null = no plugin,
  the OSS window is byte-identical)
- cloudApi.setWhatsNewSection({title, markdown}) (additive, typeof-probed)
- WhatsNew.svelte: the section first and open, through the same escaped subset
- e2e whats-new-cloud

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mposer + env pass, exposure + counterfactual, sun alignment + rotation sign, replication, custom .hdr by hash, low tier, water, None; waterDebug().env

Run 1 was 25/28; the 3 reds were test bugs (fixed here, rerun owed).

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

- e2e camera-rig found both: lookat used the smoothed state as its position, so a switch from follow froze the camera where follow left it; the goal now takes the marker's authored world pose (the restore loop has just put it there)
- the 0.25 s dt clamp made a damped camera fall behind whenever frames were rare (it never settled in a throttled headless page); an exponential step cannot overshoot, so the clamp is gone
- vitest cameraRig 7 green

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

- geoParams depended only on the Inspector's own edit tick, so a peer's edit or an
  undo left the rows (and which rows show) on the old params
- arch-primitives: connection premise, polling waits, GPU args for the third page

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…counterfactual); first-show tour for the sky cards (T1, replay in Settings ▸ Tours); Quest-budget A/B script

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

8 emitters x 500 per mode, then under the VR cap (200/emitter): every mode inside the
Quest budget (trails, the heaviest: 28 calls / 25.8k prims); desktop p50 16.7 ms = vsync
in every mode. Run under e2e-slot --exclusive.

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tcher-mux split out (8-minute cap)

e2e run 4 (warm server): camera-rig all green, switcher-mux all green, variadic-nodes 2 red (Gate 'AND over five: all five true' / 'XOR over four trues' after four back-to-back toggle setNodeData writes in one evaluate - suspected the documented setNodeData burst loss, not the fold; vitest covers foldGate). Undo/ungroup checks now green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…Data burst does not all land)

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

- merged origin/feat/38-tokens (clean); per the 37 rule, the UI this lane added or changed is built from src/components/ui: Math/Gate '+ input' and per-row remove = kit Button (ghost / icon, Icon names), Gate a/b = kit Toggle, Switcher '+ item' + the ⓘ remove/add = kit Button; colours are tokens only (check:tokens 0 in both cards)
- test hooks (.variadic-add/.variadic-remove/.switcher-add) live on wrapper spans: Button spreads extra props after its own class
- svelte-check 318/47, vitest 1584/1584

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

- ParticleMotionRows: Draw as = a 4-way kit Segmented in a control PropRow; Stretch /
  Trail length / Segments / Inherit velocity = kit PropRow sliders; note text in tokens
  (merged origin/feat/38-tokens first, clean; check-tokens: no raw colours in the file)
- particles-fx section 9: real clicks on the Segmented set render, rows follow, dark +
  light screenshots (05-inspector-*.png) — e2e run QUEUED at commit time, not yet green
- svelte-check 318/47 = baseline on the merged tree

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

Run 5 read "target space" with the rig still in lookat: the camera sat at its
authored pose aiming at the box, i.e. the setNodeData that switched the mode
never landed (the same lost-write shape the Gate steps hit). Every rig data
write now reads the node back and re-writes until each key holds; the box's
quarter turn goes out as a `move` so the peer's copy agrees with it.

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

Run 6 read "with no rig the camera is back at its authored pose" with the camera
still at the rig's last pose (6, 3, 5): section 6 replaced A's graph with restoreGraphs,
which does not broadcast, and with equal node counts nodesync's peer-id tie-break
(different every run) pulled B's OLD rig graph back onto A. The section now sends
the graph, waits for the peer to hold it, and checks the premise on A first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he PropRow column) (37-fx)

- the label sits above and the Segmented spans the row; tokens only, kit untouched
- particles-fx: every Draw as label fits its button; screenshot grabs the whole block

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AlexZ005 and others added 15 commits October 6, 2026 22:01
Run 7: after sendNodes the peer never held the box-only graph and A lost it too —
a `nodes` push merges (the old rig stays on the receiver) and nodesync's drift heal
then copied the bigger graph back onto A. Both pages restore the same document now.

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… SettingRow has no row id)

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

The band grows after the sweep (2 px at 300 ms, 132-148 at 1.2 s on a loaded box), so one
read at a fixed moment was a coin against the 150 bar. Polls up to 5 s, keeps the max: 305 px;
a still ribbon still reads 0.

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

- one read landed on whatever phase of the ~2.5 s sweep the clock gave it (r6: 201 vs 158 px under load)
- each setting now takes the max over a whole period, so both see the sweep at full width and only inherit differs
- r7: 20/20 (203 -> 256 px)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ne undo step per gesture

37 R26 (QUESTIONS-38-lock Q1-Q3):
- DragRow: Escape after TYPING puts the box text back and ignores the blur's
  change event, so the typed value is no longer re-committed (Q1)
- history: undo/redo poke selectedObject, so the Inspector transform rows show
  the restored values at once (Q2)
- history gestures ($lib/historyGesture.js, a leaf): DragRow opens one per scrub
  and per typing session, SliderRow one per range drag; entries recorded in one
  gesture fold into the stack top in place (per-kind merges for transform,
  transformSet, aibatch, props, anim, animspeed, shadergraph; else a 'gesture'
  composite), and a fold that nets to nothing is dropped (Q3)
- Inspector: the debounced transform seal carries its gesture; render order and
  light values (intensity + LIGHT_PARAMS) record props entries; Animation speed
  records an 'animspeed' entry
- new e2e suite scrub-undo (NOT YET RUN at this commit: queued behind e2e slots)

svelte-check 318/47 = baseline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
37 R26 (Q3, the last red of scrub-undo run 1): the click that ends a scrub on
an unselected node SELECTS it, and ShaderEditor wrote xyflow's `selected` into
the replicated graph doc - a second undo step per scrub (Ctrl+Z undid the
selection) and a broadcast of local view state.
- view keys (selected, dragging, measured, resizing) never enter the doc (the
  nodesHandler.serializeNode rule); an older save's copy is ignored
- selection and xyflow's measured size are carried locally across a rebuild

scrub-undo: 156 PASS / 0 FAIL (was 154/2). svelte-check 318/47 = baseline,
vitest 1544 green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/components/menu/Settings.svelte
…7 R19)

# Conflicts:
#	src/components/menu/Inspector.svelte
#	src/components/menu/WhatsNew.svelte
#	src/lib/cloudHooks.js
#	src/lib/cloudPlugin.js
#	src/lib/objectActions.js
# Conflicts:
#	src/components/menu/Inspector.svelte
#	src/components/ui/DragRow.svelte
#	src/lib/history.js
#	src/lib/objectActions.js
…-C risk 6, 37-int-127)

The module gallery read modules@main, so any modules merge reached production before its
release. MODULES_BASE now defaults to format-1 — the scenes/packs rule (non-semver, retagged
at every modules release; RELEASING.md gains the retag + purge step). Tag pushed at modules
main 2fcce49; retagged after the 1.27 modules merge.
Counterfactual: the new contentBase unit test is red with the @main fallback
(lanes-30/after-37/37-int-127/logs/cf-modules-pin.log), green with format-1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ctor seals flush first) (37-int-127)

Union of 1.26 R1 (multi-light / render-order / transform writers seal their undo step 500 ms
after the last change) and 1.27 R26 (one gesture = one step): a Ctrl+Z pressed inside those
500 ms undid the step BEFORE the drag (scrub-undo: it removed the point light itself, then the
seal recorded the drag). history.registerPendingSeal(flush): undo/redo run the registered
flushes first; the Inspector registers its three seals. scrub-undo waits past the seal for its
step count and gains an 'immediate Ctrl+Z' check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… 1.3.0, blocks 1.0.0) (37-int-127)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AlexZ005
AlexZ005 merged commit f162dab into main Oct 7, 2026
6 checks passed
@AlexZ005
AlexZ005 deleted the feat/1.27 branch October 7, 2026 16:39
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