Commit Graph

401 Commits

Author SHA1 Message Date
Jeff Emmett 6d1661a4f3 feat: template seeding system for new spaces
Every non-demo space gets generic "Getting Started" content (~25 shapes)
covering all rApp modules so users see what each module can do immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:03:45 -08:00
Jeff Emmett 4e9284fa5a feat: feed view — mobile-friendly infinite scroll for canvas
Add a toggle that switches the 2D spatial canvas into a vertical
scrollable feed layout. Shapes flow as a flex-column list, sortable
by position, creation time, type, or alphabetically. Pan/zoom/drag
gestures are suppressed in feed mode while shape editing stays active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:57:24 -08:00
Jeff Emmett dfa09a39f6 feat: email invite endpoint, canvas share panel, backlog task-77 done
- Add POST /:slug/invite email endpoint (nodemailer via Mailcow SMTP)
- Add share badge + panel UI to canvas whiteboard
- Mark task-77 (encrypted VPS backup) as Done with updated references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:39:43 -08:00
Jeff Emmett 1ff4c5ace7 refactor: consolidate EncryptID into main docker-compose.yml
Merge encryptid + encryptid-db services from separate docker-compose.encryptid.yml
into the main compose file. Update Dockerfile.encryptid to use additional_contexts
for encryptid-sdk (matching main Dockerfile pattern) instead of fragile context: ..

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:36:17 -08:00
Jeff Emmett 94c5346eda fix: account completion indicators, email verify token type, SW cache
- Add /api/account/status endpoint returning email, multi-device,
  social recovery completion state
- Show red/green status dots on Account modal section headers for
  incomplete vs complete steps (email, device, recovery, data storage)
- Highlight Data Storage section with red warning when using local-only
  storage so users know they're responsible for their own data
- Fix email verification 500 error: change token type from
  'email_verification' to 'email_verify' to match DB check constraint
- Fix service worker: skip non-http(s) schemes to prevent
  chrome-extension:// cache put errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:28:13 -08:00
Jeff Emmett 606c60c511 fix: remove auto-redirect from demo space when logged in
Logged-in users visiting demo.rspace.online were auto-redirected to
their personal subdomain. Remove this redirect so the demo stays
accessible regardless of auth state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:25:41 -08:00
Jeff Emmett 48769281c6 feat: animated edges, rich node modals, hover effects for rFunds Diagram
Port standalone rfunds-online UX polish to rSpace integration:
- Animated flowing edges with glow paths and CSS-animated dashes
- Wider Sankey-proportional stroke widths (12/10/8px)
- Rich outcome modal with phase accordion, task checkboxes, funding progress
- Rich source modal with type picker grid and type-specific config
- Node hover tooltips showing key stats + connected edge highlighting
- Sufficiency glow pulse on funnel status text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:20:55 -08:00
Jeff Emmett 7ffabe9b0a fix: use source 'card' and require funnelId for Flow Service deposit
Flow Service expects source to be wallet|card|bank, not 'transak'.
funnelId falls back to FUNNEL_ID env var when not in partnerOrderId.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:55:59 -08:00
Jeff Emmett 0ef5aad3ad chore: add backlog tasks 79-81
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:25:12 -08:00
Jeff Emmett 1af7df41bb feat: Tiptap rich text editor for rNotes — toolbar, slash commands, sync
Replace bare contenteditable divs with a full Tiptap editor (vanilla JS,
no React) inside the <folk-notes-app> web component. Adds formatting
toolbar (bold/italic/underline/strike/code, heading dropdown, lists,
blockquote, code block, link/image insert, undo/redo), slash command
menu (/ at start of empty block), syntax-highlighted code blocks via
lowlight, and task list checkboxes.

Zone-based rendering keeps the editor DOM persistent across re-renders.
Content stored as Tiptap JSON in the existing Automerge content field
with a new contentFormat discriminator. Legacy HTML notes auto-migrate
on first edit. Remote sync updates applied without cursor disruption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:20:33 -08:00
Jeff Emmett a70d5fc1a2 fix: use c.req.json() for Transak webhook body parsing
Hono consumes the request body upstream, so c.req.raw.clone().text()
returns empty. Use c.req.json() directly and re-serialize for HMAC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:10:04 -08:00
Jeff Emmett 4bca76cf45 fix: handle body read in Transak webhook — clone request for HMAC + JSON
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:08:24 -08:00
Jeff Emmett 34c96b5a45 feat: Transak credit card → USDC fiat on-ramp for rFunds TBFF
Add Transak widget integration so users can fund flows with a credit card.
Server receives webhook on order completion and deposits USDC into the flow
via the existing Flow Service API. Includes HMAC signature verification
when TRANSAK_WEBHOOK_SECRET is configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:04:53 -08:00
Jeff Emmett 46c2a0b035 feat: layered local-first data architecture — encrypted backup, relay persistence, at-rest encryption
Implement the 4-layer data model (device → encrypted backup → shared sync → federated):

- Extract shared encryption-utils from community-store (deriveSpaceKey, AES-256-GCM, rSEN format)
- Encrypt module docs at rest when space has meta.encrypted === true
- Fix relay mode persistence: relay-backup/relay-restore wire protocol + .automerge.enc blob storage
- Add backup store + REST API (PUT/GET/DELETE /api/backup/:space/:docId) with JWT auth
- Add client BackupSyncManager with delta-only push, full restore, auto-backup
- Wire backup stubs in encryptid-bridge to BackupSyncManager
- Add rspace-backups Docker volume
- Create docs/DATA-ARCHITECTURE.md design doc with threat model and data flow diagrams

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:09:07 -08:00
Jeff Emmett 5ee59f86d6 feat: people online panel — live peer presence on canvas
- community-sync: re-announce on reconnect, handle peer-list/joined/left/ping events
- presence: export peerIdToColor helper
- server: track peer announcements, broadcast join/leave, relay ping-user
- canvas: people online badge + expandable panel with avatar dots and ping button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:45:57 -08:00
Jeff Emmett 4dd212ef7d fix: add shared/local-first to EncryptID Docker build context
login-button.ts imports encryptid-bridge from shared/local-first/
which was missing from the Dockerfile.encryptid COPY steps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:38:18 -08:00
Jeff Emmett 88118cd157 fix: use server-initiated WebAuthn flow for guardian acceptance and login
The guardian page and auth.rspace.online login page were using the
client-side authenticatePasskey()/registerPasskey() SDK functions which
generate their own challenge and return AuthenticationResult — but then
tried to send result.challenge and result.credential (both undefined)
to the server. This caused postgres to throw "UNDEFINED_VALUE" resulting
in a 500 "Internal Server Error" that the client couldn't parse as JSON.

Fix: use the proper server-initiated flow matching rstack-identity.ts:
1. POST /api/auth/start (or /register/start) to get server challenge
2. navigator.credentials.get/create with that challenge
3. POST /api/auth/complete (or /register/complete) with challenge + credential

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:34:43 -08:00
Jeff Emmett 9443178d1c feat: Phase 5 — remove PostgreSQL from rForum, rSpace now fully PG-free
Migrate rForum provisioning metadata from shared PG pool to Automerge.
rForum was the last module using PostgreSQL; shared/db/pool.ts is now archived.

- Create modules/rforum/schemas.ts (ForumDoc, ForumInstance, ProvisionLog)
- Rewrite mod.ts: replace sql with Automerge getDoc/changeDoc, add onInit
- Rewrite provisioner.ts: pass SyncServer, logStep/updateInstance via changeDoc
- Fix dashboard snake_case → camelCase field references
- Archive schema.sql and shared/db/pool.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:25:26 -08:00
Jeff Emmett 1cbced27f8 docs: add rSpace ecosystem ontology
Documents the three-layer architecture (rStack foundation, rSpace platform,
rApps modules) covering identity, local-first data, micropayments, wallet
abstraction, spatial canvas, module system, and token/value architecture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:22:13 -08:00
Jeff Emmett 9ffd5de10a chore: add backlog task files (task-77, task-78)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:05:24 -08:00
Jeff Emmett 8900eb32b9 feat: Phase 4 — remove PostgreSQL from 11 modules, switch to Automerge
Replace all sql.unsafe() calls with Automerge document operations
across rfunds, rbooks, rsplat, rnotes, rwork, rvote, rcal, rfiles,
rcart, rtrips, and rinbox. Only rforum retains PG (Discourse provisioning).

Each module now uses _syncServer.getDoc/changeDoc/setDoc for all CRUD,
with ensureDoc() helpers for lazy document creation. Schema SQL files
archived to .sql.archived. Adds Automerge round-trip test suite (35 tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:48:01 -08:00
Jeff Emmett 88d618c1af feat: replace My Account submenu with consolidated popup modal
Consolidates email, device, recovery, postal address, data storage,
and dark mode settings into a single scrollable modal with collapsible
section cards — matching the existing My Spaces modal pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:22:13 -08:00
Jeff Emmett 25174b87e6 fix: bump rCal JS cache version to v=4
Bust Cloudflare CDN cache after unified layout deploy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:18:29 -08:00
Jeff Emmett 2ce0b4730c feat: rCal unified layout — no tabs, auto-map, lunar overlay, scroll zoom
Remove the 3-tab system (Temporal/Spatial/Lunar) in favor of a unified view:
- Calendar always primary with floating/docked/minimizable map panel
- Lunar phases as compact overlay bar below nav (click to expand synodic detail)
- Scroll/trackpad zoom controls temporal granularity with 120ms debounce
- 'm' key cycles map panel: floating → docked → minimized → floating
- Mobile: floating map full-width, docked stacks vertically
- cal-demo.ts cleaned up (dead tab-switching code removed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:07:31 -08:00
Jeff Emmett 22db2f439f feat: client-side encryption wiring + space scoping UI (Phase 5+6)
Phase 5 — EncryptID → DocCrypto bridge:
- Add EncryptedDocBridge connecting WebAuthn PRF to document encryption
- Add per-doc relay mode to SyncServer (encrypted spaces bypass participant mode)
- Wire encryption toggle to syncServer.setRelayOnly() on PATCH /:slug/encryption
- Restore relay mode for encrypted spaces on server startup
- Initialize DocBridge from PRF on login, clear on sign-out (both login-button + identity)
- Use bridge helpers for encrypted backup toggle in My Account

Phase 6 — Space scoping UI:
- Add "Modules" tab to Edit Space modal (enable/disable modules, scope toggles, encryption)
- Auto-filter app switcher by space's enabledModules via renderShell()
- Show "G" badge on global-scoped modules in app switcher
- Show lock icon in header for encrypted spaces
- Add getSpaceShellMeta() helper for auto-populating shell options

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:50:16 -08:00
Jeff Emmett 33156cc249 fix: resolve all pre-existing tsc --noEmit errors (10 errors across 5 files)
- folk-map-viewer.ts: remove explicit return type, let TS infer
- test-x402.ts: cast account as any (test script, readContract unused)
- key-derivation.ts: cast Uint8Array at WebCrypto boundaries (BufferSource/ArrayBuffer)
- wallet-store.ts: cast .buffer as ArrayBuffer
- webauthn.ts: cast PRF output as ArrayBuffer | undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:48:37 -08:00
Jeff Emmett 03a7b6d063 feat: add explicit ports with drag-to-connect wiring to rFunds canvas
Adds named, colored ports to every node type (source outflow, funnel
inflow/spending/overflow, outcome inflow/overflow) with a full wiring
state machine supporting both click-to-wire and drag-to-wire interaction.
Edges now originate from specific port positions. Outcomes gain overflow
allocations so fully-funded outcomes can cascade surplus onward.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:30:14 -08:00
Jeff Emmett ef3d0ce447 feat: batch local-first migration for 10 modules (Phase 3)
Add Automerge schemas, lifecycle hooks (onInit, docSchemas), and
local-first client wrappers for all remaining PG modules:
rWork, rVote, rCal, rFiles, rCart, rBooks, rTrips, rInbox, rSplat, rFunds.

Each module now:
- Defines typed Automerge document schemas (schemas.ts)
- Registers docSchemas and onInit hook with SyncServer reference
- Moves initDB() from top-level to onInit for unified startup
- Has a client-side local-first wrapper (local-first-client.ts)

Dual-write route handlers will be wired incrementally per module
following the rNotes pattern established in Phase 2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:01:58 -08:00
Jeff Emmett 6a7f21dc19 feat: rNotes local-first pilot migration (Phase 2)
Migrate rNotes from PostgreSQL to Automerge local-first stack with
dual-write support. Reads go Automerge-first with PG fallback; writes
go to both backends during the migration window.

- Add Automerge schemas for NotebookDoc (schemas.ts)
- Add lifecycle hooks (onInit, onSpaceCreate) to rnotes module
- Dual-write all 8 API routes (notebooks + notes CRUD)
- Add NotesLocalFirstClient wrapping DocSyncManager + EncryptedDocStore
- Enhance migration runner with --dry-run, --module, --verify flags
- Add listDocs() to SyncServer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:51:31 -08:00
Jeff Emmett b2ea5e04cf feat: unified space lifecycle & module scoping contract (Phase 0+1)
Extend RSpaceModule with scoping, lifecycle hooks (onInit, onSpaceCreate/Delete
with SpaceLifecycleContext, onSpaceEnable/Disable), and DocSchema support.
Add scoping to all 25 modules (8 space, 11 global-configurable, 6 global-fixed).
Consolidate 4 space creation endpoints into shared createSpace() function.
Add enabledModules enforcement middleware and module configuration API
(GET/PATCH /api/spaces/:slug/modules). Deprecation header on /api/communities.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:35:41 -08:00
Jeff Emmett 347c7193d0 fix: rcal API base URL — match /rcal path and fall back to space attribute
The regex matched /cal instead of /rcal, so getApiBase() always returned
empty string, causing 404s on api/events, api/lunar, and api/sources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:27:49 -08:00
Jeff Emmett f0d27bde16 feat: replace static rFunds diagram with interactive flow canvas
Transform the Diagram tab from a read-only SVG into a full interactive
canvas with draggable nodes, zoom/pan, Sankey-width edges with +/-
allocation controls, slide-in editor panel, live simulation, node CRUD,
keyboard shortcuts, and lz-string URL sharing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:16:55 -08:00
Jeff Emmett b252004f48 fix: disconnect from spaces and redirect on EncryptID sign-out
Prevents stale WebSocket reconnect loops after sign-out by adding an
intentional-disconnect flag to CommunitySync. Canvas and shell pages
now redirect to homepage when the user signs out.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:15:09 -08:00
Jeff Emmett e7f9507d9d test: add stack view + wiring test page
Standalone test harness for flow tubes, particle animation, and
interactive port wiring with event logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:03:29 -08:00
Jeff Emmett 4ebbf9f116 feat: add Copy to Space context menu for shapes
Right-click shapes (single or multi-selected) to copy them to another
space the user owns or is a member of. Server endpoint handles ID
remapping, arrow reference preservation, and position centering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:58:44 -08:00
Jeff Emmett 1f0ef59369 feat: add flow tubes, stable particle animation, and interactive port wiring
Replace invisible particle-only flow visualization with colored 3D tubes
between layers, spread horizontally to avoid overlap. Particles now travel
along tube paths. Add click-to-wire interaction on I/O port chips with
visual feedback (glow/breathe/dim). Prevent animation restart on Automerge
sync by surgically updating flow elements in-place.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:55:16 -08:00
Jeff Emmett 91494a9c5c feat: port spatio-temporal calendar from standalone rcal-online
Rewrite folk-calendar-view with 5 views (Day/Week/Month/Season/Year),
3 tabs (Temporal/Spatial/Lunar), Leaflet map with event markers and
transit polylines, temporal-spatial zoom coupling, and lunar phase display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:45:24 -08:00
Jeff Emmett 5c21b64a99 feat: add My Account submenu with dark mode + encrypted backup toggles
Reorganize user dropdown into expandable "My Account" submenu containing
account actions (Add Email, Add Device, Recovery) plus Dark Mode and
Encrypted Backup toggle switches. Move theme toggle from toolbar into
account settings, default to dark mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:45:11 -08:00
Jeff Emmett a402caacd8 fix: app-switcher routes through tab system + canvas fills viewport in tab pane
- App-switcher now dispatches module-select event instead of full page navigation
  for same-origin links; shell routes through TabCache for instant tab switching
- Tab pane gets height:100% in canvas-layout mode so #canvas fills the viewport
  (fixes pan/zoom not working on empty canvas background)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:35:38 -08:00
Jeff Emmett be271de7fb feat: add Gnosis Safe + EncryptID passkey wallet abstraction
Derive a deterministic secp256k1 EOA from the passkey's PRF output via
HKDF-SHA256, enabling hardware-backed signing for x402 micropayments and
Safe treasury proposals without storing private keys.

Key changes:
- EOA key derivation with domain-separated HKDF (eoa-derivation.ts)
- Key manager integration with PRF-only EOA path (key-derivation.ts)
- Encrypted client-side wallet store for Safe associations (wallet-store.ts)
- Passkey-backed x402 signer replacing EVM_PRIVATE_KEY (passkey-signer.ts)
- Safe propose/confirm/execute proxy routes in rwallet (mod.ts)
- Wallet capability flag in JWT via users.wallet_address (server.ts)
- Payment operation permissions: x402, safe-propose, safe-execute (session.ts)

Privacy: Safe wallet associations stored client-side only (AES-256-GCM
encrypted localStorage). Server only knows user has wallet capability.

108 tests passing across 5 test suites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:18:34 -08:00
Jeff Emmett c8e63b5c9f fix: mobile/touch UX for toolbar buttons and ghost tool placement
- Switch ghost tracking from mousemove to pointermove (fires for touch/pen/mouse)
- Add cancel button (✕) on ghost outline for mobile (no ESC key available)
- Center ghost on viewport for touch devices instead of (0,0)
- Add touch-action: manipulation to all toolbar buttons (eliminates 300ms tap delay)
- Bump mobile touch targets to 44px min-height with larger padding

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:18:07 -08:00
Jeff Emmett 74b15ba1b7 feat: add x402 test endpoint and payment test script
Add POST /api/x402-test — a standalone payment-gated endpoint with
no auth required, for testing the x402 flow end-to-end.

Add scripts/test-x402.ts using @x402/fetch to automatically handle
the 402 → sign → retry cycle on Base Sepolia.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:28:55 -08:00
Jeff Emmett 2a7071edb4 fix: use correct x402 facilitator URL (www.x402.org)
The bare domain x402.org/facilitator returns a 308 redirect that
breaks payment verification. Use www.x402.org/facilitator instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:39:07 -08:00
Jeff Emmett 5090676eda fix: remove DATABASE_URL from docker-compose, now in Infisical
DATABASE_URL, ADMIN_DIDS, and ENCRYPTID_DEMO_SPACES are now stored
in Infisical and injected via the entrypoint. Remove the last
docker-compose.yml reference that was temporarily re-added.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:41:16 -08:00
Jeff Emmett 15812195f1 fix: set canvas-layout class on initial server render
When loading the rspace canvas directly (not via tab navigation),
#app lacked the canvas-layout class. Without it, #canvas collapses
to 0 height and pointer events for panning miss the canvas element.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:33:55 -08:00
Jeff Emmett 424152415a fix: add DATABASE_URL to docker-compose environment
The shared/db/pool.ts requires DATABASE_URL but it was missing from
both docker-compose.yml and Infisical, causing the container to
crash-loop on startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 19:31:02 -08:00
Jeff Emmett 19e9455f1d fix: make folk-rapp header a drag handle so shapes can be grabbed
folk-rapp used class "rapp-header" but the drag detection in
folk-shape checks for ".header" or "[data-drag]". Added both so
the rapp header works as a drag handle like every other shape type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:11:30 -08:00
Jeff Emmett 7850b9d34c feat: move rApp secrets to Infisical, add seed script
Remove DATABASE_URL and ADMIN_DIDS from docker-compose.yml (now
injected via Infisical entrypoint). Add scripts/seed-infisical.sh
to interactively populate 21 module-specific secrets (R2, Immich,
Twenty, Discourse, FAL, RunPod, etc.) into the rspace Infisical
project. Update Dockerfile to include scripts/ in the image.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:06:21 -08:00
Jeff Emmett 5e0f30567a fix: prevent pointer events from hijacking two-finger touch pan
On touch devices, both pointer and touch events fire. When a second
finger was added, the pointer handler re-captured the interaction,
fighting the touch-based pan/pinch. Now the touch handler releases
pointer captures and sets a flag that blocks the pointer handler
during two-finger gestures. Also cancels shape drag on multi-touch
and closes the context menu on touchstart for reliable mobile dismiss.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:02:53 -08:00
Jeff Emmett 658eb966d6 fix: push overlapping siblings instead of displacing the dragged shape
The overlap resolver now moves siblings in the drag direction rather
than snapping the dragged shape away from them. Supports chain-pushing
(A pushes B into C) with a recursion depth of 3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 17:51:34 -08:00