feat(editor): preset-system primitives (#340)#341
Open
wass08 wants to merge 1 commit into
Open
Conversation
…e round-trip, isolate + setCaptureMode enum, headless exports Per #340 (redesigned: single live canvas, no Viewer scene prop). Core - `capabilities.presettable` on `NodeDefinition` + `isPresettable` / `isPresettableKind` helpers. Explicit `false` on level / building / site / zone / spawn / guide / scan / item; implicit `true` for any kind with `def.parametrics`. - `sceneApi.getSubtreeSnapshot(rootId)` + `materializeSubtree(subtree, position, parentId?)` for round-tripping a node subtree through catalog storage. Strips id / parentId / absolute root position / host refs (`wallId`, `wallT`); fresh IDs minted at materialize time; child ordering preserved (FIFO walk). Viewer - `<Viewer isolate>` prop + `ViewerHandle.setIsolated(ids | null)`. Walks `sceneRegistry`, hides every registered group not in the isolated set's ancestor + descendant closure. Building block for preset capture + future focus-mode UX. Editor - `useEditor.captureMode: CaptureMode` discriminated union (`idle` | `standard` | `preset`). `isCaptureMode` stays as a derived boolean for the existing read sites; `setCaptureMode` accepts both the boolean shape (back-compat) and the enum. - `preset` capture mode in `SnapshotCaptureOverlay`: drag locked to a square, mode-picker hidden, transparent flag forwarded through the `camera-controls:generate-thumbnail` emitter event. - Headless exports: `Inspector` (alias of `ParametricInspector`), `FloatingMenu` (alias of `FloatingActionMenu`), `ToolbarLeft` / `ToolbarRight` (aliases of `ViewerToolbarLeft` / `ViewerToolbarRight`), `useSelection` hook returning `{selectedIds, selectedNode, building/ level/zone}`, plus re-exports of `useScene` / `useViewer` from core / viewer so consumer shells (community, embedders) need only one import. Out of scope by design (see issue #340 "Out of scope"): a separate offscreen Viewer rendering an arbitrary subtree. The unified preset modal captures inside the live canvas via isolation + the existing snapshot pipeline — no `useScene` factory / React context refactor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Editor-side primitives for the unified preset system (pascalorg/private-editor:plans/community-preset-system.md). Per the redesign discussed on #340: single live canvas, capture happens against it via
isolate+ the existing snapshot pipeline. No<Viewer scene={subtree}>prop, nouseScenefactory / React context refactor.Closes #340.
What's in
Core
capabilities.presettableonNodeDefinition+isPresettable/isPresettableKindhelpers. Explicitfalseonlevel/building/site/zone/spawn/guide/scan/item; implicittruefor any kind withdef.parametrics.sceneApi.getSubtreeSnapshot(rootId)+materializeSubtree(subtree, position, parentId?)for catalog round-trips. Stripping rules from the spec: ids, root parentId, root absolute position, host refs (wallId,wallT). Fresh ids minted at materialize time; child order preserved (FIFO walk).Viewer
<Viewer isolate>prop +ViewerHandle.setIsolated(ids | null). WalkssceneRegistry, hides every registered group not in the isolated set's ancestor + descendant closure. Composite-visibility note in the implementation explains why ancestors must stay visible.Editor
useEditor.captureMode: CaptureModediscriminated union (idle|standard|preset).isCaptureModestays as a derived boolean (every existing read site continues to work);setCaptureModeaccepts both shapes (back-compat).presetcapture mode wired intoSnapshotCaptureOverlay: drag locked to a square, mode-picker hidden,transparentflag forwarded throughcamera-controls:generate-thumbnail.Inspector,FloatingMenu,ToolbarLeft/ToolbarRight(aliases),useSelectionhook, plus re-exports ofuseScene/useViewerso consumer shells (community, embedders) only need one import.Out of scope by design
NodeSubtree. The new design captures inside the live canvas — see the issue's "Out of scope" section for the rationale.useScenefactory + React context. Stays a singleton.Test plan
bunx tsc --noEmitclean for core / viewer / editor / nodes / apps/editorbun test packages/core/src— 181 pass / 5 pre-existing fails identical to main; new subtree tests pass (6/6)bun test packages/editor/src— 11/11 passbun test packages/nodes/src packages/viewer/src— 113 pass / 3 pre-existing fails identical to mainbun run buildsucceeds forapps/editorviewerRef.setIsolated([...])+setCaptureMode({ mode: 'preset', isolated: [...] })against the live editor canvas and gets a square transparent PNG via the existingonThumbnailCapturecallback🤖 Generated with Claude Code