feat: embed surface — export in-canvas affordances + transparent/faint-ink viewer support

Lets a host mount the editor's real editing experience on a bare <Viewer>
without the full <Editor> shell.

editor: export Grid, NodeArrowHandles, MoveTool, ToolManager — the selection
handles, the kind-owned mover, the build-tool host, and the drafting grid that
feeds tools their grid:* pointer events. See the doc comment in index.tsx for
how they cooperate with host camera controls and selection.

viewer: two opt-in, non-persisted presentation flags (both default off, so the
editor and every other consumer are unchanged):
- transparentBackground / <Viewer transparent>: emit premultiplied RGBA masked
  by geometry + outline alpha (outputColorTransform off on that path) so the
  scene can float on any page background. ACES tone-mapping makes a true-white
  opaque background impossible, hence transparency.
- inkOpacity: override the per-mode ink-edge opacity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aymeric Rabot
2026-06-17 11:07:43 -04:00
committed by Wassim SAMAD
co-authored by Claude Opus 4.8
parent 8775734aa8
commit 3cb37c98cd
4 changed files with 83 additions and 6 deletions
+24
View File
@@ -12,12 +12,34 @@ export { default as Editor } from './components/editor'
// surface uses the shorter, shell-friendly names from the unified
// preset-system spec.
export { FloatingActionMenu as FloatingMenu } from './components/editor/floating-action-menu'
// Embed surface — the editor's real in-canvas affordances, so a host can mount
// authentic selection handles, interactive build tools, and the mover on top
// of a bare `<Viewer>` without the full `<Editor>` shell.
// - `NodeArrowHandles` renders the selected node's registry resize/rotate/move
// handles.
// - `MoveTool` runs the kind-owned mover once a translate handle arms
// `useEditor.movingNode`.
// - `ToolManager` mounts the active registry build tool (wall / door / window /
// …) for interactive placement when `useEditor` is in build mode with a
// tool, plus the snap/alignment guide layers. Mount it only while a tool is
// active to avoid its select-mode boundary editors.
// - `Grid` is the interactive drafting plane: it raycasts the pointer and
// emits the `grid:move` / `grid:click` events the build tools consume (the
// wall tool is driven entirely by them; door/window use them for free-follow
// alongside the viewer's `wall:*` mesh events). Without it the tools mount
// but their cursor never tracks the pointer. Mount it while a tool is active.
// All read `useViewer` selection + `useEditor` state, and cooperate with host
// camera controls via the `useViewer.inputDragging` / `useEditor.movingNode`
// flags. Tools place onto `useViewer.selection.levelId`, so the host must set a
// building + level selection first.
export { Grid } from './components/editor/grid'
export {
DimensionPill,
type DimensionPillPart,
formatMeasurement,
MeasurementPill,
} from './components/editor/measurement-pill'
export { NodeArrowHandles } from './components/editor/node-arrow-handles'
export {
type SnapshotCameraData,
ThumbnailGenerator,
@@ -40,6 +62,7 @@ export {
type FencePlanPoint,
snapFenceDraftPoint,
} from './components/tools/fence/fence-drafting'
export { MoveTool } from './components/tools/item/move-tool'
// Placement-math helpers — shared by kind-owned placement tools in
// `@pascal-app/nodes` (wall curve sagitta snap, door / window placement,
// item drop) so kinds don't reach into editor internals.
@@ -101,6 +124,7 @@ export {
DEFAULT_STAIR_TYPE,
DEFAULT_STAIR_WIDTH,
} from './components/tools/stair/stair-defaults'
export { ToolManager } from './components/tools/tool-manager'
export {
createWallOnCurrentLevel,
getSegmentGridStep,