Skip to content

[feat] 33 LOD groups: pack lods, a LOD Group in object settings, force/edit/select, VR force - #257

Merged
AlexZ005 merged 2 commits into
feat/1.19from
feat/33-lod-editor
Oct 2, 2026
Merged

AlexZ005 merged 2 commits into
feat/1.19from
feat/33-lod-editor

Conversation

@AlexZ005

@AlexZ005 AlexZ005 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Roadmap 33 lane 33-lod-editor: items K2 (loading pack LODs, contract P1) and K6 (a LOD Group in object settings). K1's moving-only flicker turned out not to be LOD: it is z-fighting in the asset (33-pack-fix-lod measured it, and the fix is in packs).

What it does

  • Pack lods (contract P1). A row's lods: [{file, ratio}] is placed as the object's LOD group (userData.lod). It is saved, replicated and undone with the object, and it rides the pack stub.
    • Levels are a render-time per-mesh geometry swap on the same tree, matched by node name. Each level draws with LOD0's own material, so materials are shared and animated items keep animating; 33-anim-core asked for exactly this.
    • Levels are built lazily, the first time a view needs one, and once per file.
    • Thresholds are by screen size: 25% / 10% by default, agreed with 33-pack-fix-lod's no-visible-pop gate. A level only returns to the finer one after a 15% hysteresis band. The quality governor's lodBias pulls the thresholds in.
    • A piece placed before its pack had lods gets an implicit group from the pack row.
  • Properties ▸ LOD (LodGroupPanel.svelte):
    • a level bar with draggable edges: live locally, ONE undo entry and ONE message per drag
    • Force LOD (Auto / LOD0 / LOD1 / …), Generate levels (meshopt, in the worker), cull
    • replace a level with another scene object, or drop an Explorer item on the bar
    • select a level to preview it on this screen, then back to Auto
    • a per-level material override
    • Move level: the gizmo goes on a proxy, writes the level's offset, and leaves the object where it is
    • "Show LOD level", a colour overlay on this screen only
  • Wire. objectParameters {parameter: 'lod', uuid, lod} with a wireValidate shape, undone through the props kind with a lod key.
  • VR. The properties panel gains a LOD row: a readout plus Force LOD cycling.
  • api.lod. The handle gains force(n) and levels().
  • Docs. The PACKS.md lods field and MODULES.md. The user docs page is in the docs repo (docs-33-lod-editor).

Design write-up: the top of the lane handover (STATUS-33-lod-editor.md).

Proof (on 81d4ccf)

  • e2e:
    • lod-group 24/24
    • lod-panel 49/49, through the real UI, two peers included
    • lod-real-packs: 33-pack-fix-lod's real files for Gate, WallStone, Duck and Cat all build as name-matched swaps covering every mesh, and far renders draw fewer triangles (Gate 5440 → 1080, Duck 8424 → 1684)
    • held suites vr-props-panel, lod (31's), inspector and undo all pass
  • vitest: 400 tests, including lodGroupCore (22).
  • svelte-check: 333 / 47, the same as the baseline.
  • npm run build: green.
  • Counterfactuals:
    • A 100-frame bob on an edge switches once; with the band set to 0 it pops back at once.
    • Force LOD taking effect in the same frame: lod-group 4.1 was red before the same-frame re-read.
  • Evidence shots: lanes-30/after-33/33-lod-editor/.

Merge notes

  • App.svelte debug tails: +lodGroup, lodGroupActions, lodLevelEdit at the end (222/222/222 on this branch; 223 after the union with [feat] 33 P2: animated, functional pack items (doors that open, no autoplay) #259); re-count after the union.
  • lod.js: the new registerLodPass seam, the overlay, simplifiedGeometry, and a REVERSED restore. Other 33 lanes do not touch it.
  • objectActions props kind, commandsHandler objectParameters, vrControls PROPS_ROWS, Scene.svelte gizmo branches: all additive hunks.
  • 33-anim-core carries root.userData.lod on objectfile / the snapshot / animimport in its own branch.

OWED on device

  • The bar's drag feel on a real pointer.
  • LOD pop visibility on real kits while walking.
  • The VR LOD row on a Quest.

🤖 Generated with Claude Code

AlexZ005 and others added 2 commits October 1, 2026 20:50
…orce (WIP: e2e pending)

- P1 contract: a pack item row's `lods` place as the object's LOD group (userData.lod,
  normalizeLodGroup in lodGroupCore.js is the one boundary); levels are a RENDER-TIME
  per-mesh geometry swap matched by node name inside lod.js's bracket (registerLodPass),
  drawn with LOD0's own material; lazy (built when first needed, once per file);
  thresholds by screen size (25% / 10% defaults, 15% hysteresis); implicit group from
  the pack row for pieces placed before their pack had lods
- write path lodGroupActions.js: one props undo entry + one objectParameters 'lod'
  message (applier in commandsHandler, wireValidate shape, props kind in objectActions)
- P2 LodGroupPanel.svelte in Inspector: level bar with draggable edges (one entry per
  drag), Force LOD, Generate levels (meshopt in the worker), replace a level with an
  object / Explorer drop, select-a-level preview, per-level material override,
  gizmo on a level (lodLevelEdit.js + Scene isLodLevelProxy branches), Show LOD level
  overlay, cull; api.lod handle gains force()/levels()
- P3 VR props panel LOD row (readout + cycle Force LOD)
- docs: PACKS.md lods field, MODULES.md
- vitest lodGroupCore (22) green; svelte-check 333/47 = baseline
- e2e lod-group: 22/24 on the first run, both reds fixed (test premises + block
  writes now take effect the same frame); re-run, lod-panel and vr-props-panel NOT
  yet run (slots/memory) - see the handover

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

- lod-real-packs (new, skips without LOD_PACKS_DIR): 33-pack-fix-lod's real level files
  (architecture-kit Gate + WallStone, default Duck with its camera node + parent scale,
  cube_diorama Cat with 3 meshes) each build as name-matched SWAPS covering every mesh and
  draw fewer triangles far away (Gate 5440 -> 1080, Duck 8424 -> 1684, Cat 20108 -> 4014)
- lod-panel 7.3 was a check that could not fail (it compared a count with itself): it now
  counts lod messages before/after the overlay toggles
- lodGroupStats levels carry `paired` + `error`
- held battery on this head: lod-group 24/24, lod-panel 49/49, vr-props-panel, lod (31),
  inspector, undo, lod-real-packs all ALL PASS; vitest 400; svelte-check 333/47 = baseline;
  npm run build green (dev server stopped)
- counterfactuals: hysteresis (vitest: a 100-frame bob on an edge switches once; band 0 pops
  back at once); a block write taking effect the same frame (lod-group 4.1 was red before
  24fe36b's same-frame re-read); shared materials (1.8: the mesh wears its own material
  mid-draw; 5.2 shows the override path is a copy)

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

AlexZ005 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Merge note for the integrator: this PR plus #259 (33-anim-core @ea7d312). A trial merge conflicts in 6 files: PACKS.md, App.svelte, Explorer.svelte, explorerDrop.js, fileHandler.svelte.js and wireValidate.js. All six are unions, because both lanes added a field at the same spot (lod here, behavior there):

  • Explorer drag payload and placePackItem, explorerDrop: keep both lods/lod: placementGroupFor(...) and behavior.
  • fileHandler.importFile: the JSDoc type gets lod?: any, behavior?: any.
    • Keep my opts.lod block first, then their opts.behavior line and their addAnimatedImport(..., position).
  • wireValidate: their behavior validator, then camera, then my objectParameters.
  • PACKS.md: both sections.
  • App.svelte tails: base 219, this PR 222, [feat] 33 P2: animated, functional pack items (doors that open, no autoplay) #259 220, union 223/223/223. Append packBehavior after my three. (The PR body said 224; it is 222 on this branch.)

On the resolved tree, svelte-check is 333/47 (the baseline) and vitest passes 418. The e2e suites were not re-run on it.

Resolved copies of the six files: lanes-30/after-33/33-lod-editor/merge-with-anim-core/.

#259 already carries root.userData.lod for animated imports, so nothing else is needed.

@AlexZ005

AlexZ005 commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Re-checked against 33-pack-fix-lod's final files (packs PR #11, origin/feat/33-fix-lod c075327). lod-real-packs is all green. In Gate, WallStone, Duck and Cat every level file builds as a name-matched swap covering every mesh (the Cat has 3). Far renders draw fewer triangles: Gate 5682 → 1122, WallStone 6134 → 3066, Duck 8424 → 1684, Cat 20108 → 4014. No page errors. Shots are in lanes-30/after-33/33-lod-editor/final/. K1 is closed on their side (asset z-fighting); nothing was needed from core.

@AlexZ005
AlexZ005 merged commit 57c6fea into feat/1.19 Oct 2, 2026
4 checks passed
@AlexZ005
AlexZ005 deleted the feat/33-lod-editor branch October 2, 2026 08:43
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