Pilot/terrain lab - #52
Merged
Merged
Conversation
Composing SnapLine inside <Camera> had two pan leaks: - connector line drags never touched global.data.allowCameraControl, so drawing a connection also panned the canvas; startDragOutLine now disables it and _endLineDragCleanup restores it (mirroring node drags) - nodes only disabled it in onDragStart, which fires after the 3px drag threshold — the camera panned by one pointer-move event first; the flag now flips in onCursorDown and restores in onUp/onDragEnd Adds the previously missing camera+snapline coverage: a /snapline-camera demo route (nodes inside <Camera wheelZoomModifier="ctrlOrMeta">) and a snapline-camera e2e suite (pan, ctrl-wheel zoom, node drag and line drag without panning, connect after pan+zoom), run via test:snapline-camera. Piloted by Terrain Lab (see terrain-lab pilot branch notes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a `panButton` option to CameraControlConfig (default 'left', so existing consumers/tests/demos are unaffected) and forward it through the Svelte Camera wrapper. onCursorDown now gates the pan-start on the configured button instead of hard-coding the left button; the pan-end path already keys off pointerId, so a middle-button release ends the pan cleanly. This frees the left button for other gestures (e.g. rubber-band select) while the middle button pans — the standard node-editor model. The camera demo reads ?panButton= so the e2e suite exercises the modes without a second route; adds a test asserting middle-drag pans and left-drag does not when panButton='middle'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing, owned suspension - writeTransformRecursive: write twin of readDomRecursive (synchronous polymorphic recursion over transformChildren; prunes transformMode:none and non-element children). Descendant world values are already correct via the epoch cache - the cascade only flushes DOM. - Collider.containsWorldPoint: synchronous world-space point test on the cached bounds, independent of the frame-delayed collision sweep. - input: #resolveResizeOwner - a pointerdown inside a registered resize hitbox resolves the gesture owner to the hitbox's parent object, with precedence over DOM routing (covers grabs beyond the element's edge). - GlobalManager.suspend/resume/isSuspended: owned suspension channels (token per suspender) replacing last-writer-wins shared booleans. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nsion reads
- wheelPan + wheelPanSensitivity: unmodified wheel (trackpad two-finger
scroll) pans; ctrl/cmd wheel and pinch still zoom. Pan and zoom speeds
tune independently.
- zoomSensitivity + pinch gain; zoom direction fixed so pinch-out /
scroll-up zooms in.
- panButton: left|middle|both for pointer pans.
- Grouped config (wheel: {action, zoomModifier, zoomSensitivity,
panSensitivity, pinchZoomGain}, pointer: {panButton, panLock}) resolved
at read time via resolveCameraOptions; flat keys remain as deprecated
aliases. React Camera gains the previously svelte-only options.
- Camera readers honor global.isSuspended(cameraControl) alongside the
legacy allowCameraControl boolean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ship refactor
Features:
- GroupNodeComponent: a resizable box that carries any node whose center
is inside it. Live geometric membership maintained at settle events
(move-end, resize, node drop); transient transform-parenting rides the
engine's write cascade; onMemberEnter/Leave/onDragCommit callbacks.
- JS node resize (CSS resize is unsupported on iOS Safari): a virtual
CircleCollider at a configurable corner anchor (tl|tr|bl|br, default
br) with signed drag deltas and a fixed opposite corner; opt-in per
node (resizable, minWidth/minHeight, resizeHandleRadius).
Framework-DOM-ownership refactor (per the SnapSort-derived contract:
structural DOM is framework-owned; transforms/data-*/property writes may
stay engine-direct):
- Node width/height delegated: core fires nodeCallback.onSizeChange and
adapters render the size as state; core setSizeState keeps hitboxes in
sync and never writes the DOM box.
- Selection rectangle delegated: selectCallback.onRectChange carries
{x,y,width,height,visible}; Select adapters render (and can restyle)
the box. No flush handshake - not paint-atomic.
- Base positioning styles moved into adapter markup.
- nodeCallback EventProxyFactory dict (onSizeChange/onResizeCommit/
onLinesChanged) with deprecated setLineListCallback/_onResizeCommit
shims; DEFAULT_NODE_CONFIG/DEFAULT_GROUP_CONFIG single-site merges;
#-private internals with hitBox/config getters; typed global.data
accessors in snapline-globals.ts; line-method renames with deprecated
aliases (scheduleLineWrites/writeLinesNow/resyncNodeGeometry).
- React parity: Group.tsx, Node resize props/handle, state-rendered
Select box; demos and e2e for both frameworks (group, resize incl.
TL-anchor fixed-corner and min-clamp cases).
- AGENTS.md documents the ownership contract and v1 design limits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A gesture owner now blocks global input listeners at the dispatch layer: engine.input.claimPointer(pointerId), called from the owner's pointerDown handler. While claimed, that pointer's global pointerDown/Move and dragStart/drag are not delivered (owner dispatch unaffected), pinches involving the pointer are suppressed, and wheel is suppressed while any claim is held. End events (pointerUp/dragEnd/pinchEnd) always deliver so a global listener engaged before a late claim terminates cleanly. Claims anchor to the input layer's per-pointer records, which are cleaned up on pointer up/cancel regardless of owner liveness - so claims auto-release and cannot be stranded. This deletes every manual resume (dual release paths, destroy hooks) from node/connector/demo/website writers, removes the GlobalManager suspend/resume/isSuspended channel API (no consumers remain), and leaves the camera with zero knowledge of the mechanism (only the legacy third-party allowCameraControl boolean read remains). Per-pointer semantics: a second pointer can still pan or pinch the camera while the first is claimed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e prep Broad working-tree snapshot committed ahead of rebasing onto origin/website-update: - snapsort: coalesced onVisualGeometryInvalidated container event (invalidation plumbing through drag/session, animations, and settle), plus a ghost-safe base Item.invalidateVisualGeometry (Item.rootContainer falls back to the item itself for detached ghost anchors; the missing method aborted the FLIP pass mid-loop, killing displaced-item animations for every entry after the ghost — upward-moving rows jumped) and an upward-reorder animation regression test - snapline: placement/query modules, nested group demo, framework adapters and package metadata churn - asset-base: camera config and adapter updates - docs/website: snapline docs, demo component, catalog and layout updates - publish workflow and package validation updates Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d-edges EdgeSync
Two workstreams landing together (interleaved in the connector layer):
Surface connectors and capabilities (parallel stream): ConnectorCapabilities
(source/target/maxIncoming/reconnect/allowParallel), surface strategies with
priority hit-testing, virtual connectors, onConnectionRequest creation seam,
ConnectorLinePhase state machine, live updateConfig, reconnect gestures,
arming semantics (click no longer creates a preview line), docs guide and
connector-config unit tests.
NodeManager + controlled edges (this stream):
- NodeManager: per-engine registry of live nodes/connectors, lazy-created via
getNodeManager(engine) on first component registration (GlobalManager is
app-wide, so managers key by engine); query.ts enumeration delegates to it;
home for engine-scoped facilities (edge sync now, layout helpers later)
- EdgeSyncController + EdgeSync adapters (Svelte/React): the consumer's edge
document is the only edge authority; sync() reconciles lines to it
(hydration origin, in-flight drag lines and foreign lines untouched,
#syncing guard suppresses intent echo) and gestures forward as semantic
onEdgeConnect/onEdgeDisconnect intents ({node, port} endpoints; gesture +
replacement forward, programmatic/hydration/teardown never). Intents fire
synchronously in the drop dispatch; adapters reconcile in a same-task
microtask so accept and reject both resolve before paint. Connector
registration nudges a coalesced re-sync so remounted nodes re-hydrate
their document edges.
- node unmount now tears down lines with reason 'teardown' (was the
'programmatic' default), keeping the reason contract honest
- snapline-edges e2e suite (7 tests: intents, programmatic silence,
doc-driven replacement ordering, reject reconcile + paint-flicker
observer, unmount silence + re-hydration, mid-drag safety) + React parity
suite (3), node_ui_edges demos in both frameworks, AGENTS.md contract docs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The website's copies under website/static/ (the ones its components reference) are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nothing in the website references it; its license.txt goes with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
No description provided.