Skip to content

feat(canvas): converge web and desktop CanvasViews on a shared core (0277) - #403

Merged
crs48 merged 11 commits into
mainfrom
claude/0277-canvasview-feature-parity-audit-and-convergence
Jul 7, 2026
Merged

feat(canvas): converge web and desktop CanvasViews on a shared core (0277)#403
crs48 merged 11 commits into
mainfrom
claude/0277-canvasview-feature-parity-audit-and-convergence

Conversation

@crs48

@crs48 crs48 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Implements exploration 0277 — the CanvasView feature-parity audit (the gate 0230 Phase 5 / 0276 Theme 3 was waiting for) and the full convergence it green-lights, in one pass.

The audit

docs/explorations/0277_[x]_CANVASVIEW_FEATURE_PARITY_AUDIT_AND_CONVERGENCE_DECISIONS.md decides all 22 single-sided features: 13 port, 8 platform-specific, 1 deprecate. Two 0276 premises corrected along the way (ModeratedMedia was never in the web canvas; the "electron-only" selection ops were one-line engine delegations).

The convergence

Shared core (packages/views/src/canvas-view/ + canvas cards/surfaces in packages/editor):
useCanvasViewController (selection, alias/comment, ingestion, creation, presence), useCanvasUndoLadder, useCanvasQueryFrames + executors, useCanvasSourceReferences, useCanvasCommands (registry registration), CanvasSelectionHud, shared panels, renderCanvasNodeCard + card set, useCanvasPeek + CanvasPeekOverlay, CanvasInlinePageSurface/CanvasDatabasePreviewSurface.

Web gains (previously desktop-only): peek + zoom-gated inline editing of pages/notes/databases, query-frame execution + refresh, linked-copies ("Copies") panel, the full selection HUD (lock/align/distribute/tidy/connect/layering), frame present/export on desktop too, multi-domain undo, desktop's richer page-preview and pinned-record cards.

Desktop gains (previously web-only): dashboard widget cards, the rich media/PDF card, edge selection, editable canvas title + presence avatars.

Sync-parity fixes: widget and media nodes synced across platforms previously rendered degraded or not at all on desktop; frame nodes were written with two different wire shapes (M2). Both fixed — every node type now renders through the same components on both sides.

Bug found during live validation: CanvasHandle.undo() delegates back to onUndoRedoShortcut, so the desktop undo ladder's scene rung recursed instead of undoing. The shared ladder now owns the scene Y.UndoManager directly — fixing desktop scene undo and preserving web's.

Moderation (M1): the shared media card routes previews through a mediaGate slot; web passes ModeratedMedia. Desktop has no moderation stack yet and renders ungated until one exists.

Behavior change (release-noted): inside a focused canvas, Mod+Z now walks the multi-domain ladder — it can undo an inline-edited source document when that was the latest change, instead of only scene moves.

E10 residual (in doc Risks): all canvas commands register once in the shared registry; the desktop palette keeps its metadata table over the same actions via a now-transitional CanvasViewHandle (the registry schema can't carry icons/groups/keywords yet, and the shell needs the two viewport methods for open/close animations).

Numbers

  • Web CanvasView: 1,843 → ~1,040 lines; desktop: 3,195 → ~1,110 (shell chrome only).
  • Guarded by canvas-view-convergence.test.ts (shared-component assertions + M2 wire-shape golden + line-count ceiling) plus the 0276 drift tripwire.

Validation

  • Verified live in the running web app: toolbar creation, shared HUD (full action set on source-backed cards), comment composer, undo (Mod+Z) / redo (Mod+Y), peek overlay with the inline page editor.
  • pnpm typecheck green; electron renderer additionally checked with tsc -b apps/electron/tsconfig.json (the desktop app has no typecheck script — pre-existing gap).
  • No publishable packages touched (views/editor/canvas/dashboard are all private) — no changesets needed.

🤖 Generated with Claude Code

xNet Test and others added 10 commits July 6, 2026 17:54
…gence decisions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Web hand-rolled frame properties while desktop used
createCanvasFrameVariantProperties — two wire shapes for the same synced
node type (0277 M2). Both sides now write the factory shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The desktop canvas ignored the connectors map entirely: edge changes did
not bump the scene revision and a selected connector had no HUD (0277
W9). Mirrors the web view's edge handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two sync-parity gaps closed (0277 Phase 0): media nodes dropped on the
web rendered as bare text cards on desktop (no image preview, no PDF
page viewer, no storage-policy badge), and dashboard widget nodes fell
through to the engine default on desktop.

- CanvasMediaCard moves to @xnetjs/editor with a mediaGate slot; the web
  passes its ModeratedMedia veil (M1) so every canvas media preview is
  moderation-gated. Desktop has no moderation stack yet and renders
  ungated until one exists.
- CanvasWidgetNodeCard + the canvas/dashboard schema registry move to
  @xnetjs/views (canvas-view area); DashboardView re-exports the shared
  registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s in

Settles the 0277 Phase 1 location question the same way 0276 settled
DataWorkspaceCore: shared app-view cores live under packages/views. The
desktop-only canvas-shell resolution helpers (display type, source id,
preview model) move here unchanged with their tests; both apps now
import them from @xnetjs/views.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The verbatim middle of the two CanvasView forks moves into
useCanvasViewController (@xnetjs/views): scene observation, selection
resolution, alias/comment editing, ingestion, primitive creation, and
presence intent. Cards unify behind renderCanvasNodeCard
(@xnetjs/editor); alias/comment/shortcut-help panels render from one
implementation. Web adopts the desktop page/note preview cards (0277
E9) and the pinned source-record card (E2).

M3: canvas test attributes unify on data-canvas-* (web loses the
data-web-canvas-* namespace); e2e selectors updated.

Web: 1,843 → ~900 lines. Desktop: 3,195 → ~2,050 lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… platforms

Phase 2 of the 0277 convergence:

- Query frames (E1/E2): the saved-view executor moves to @xnetjs/views
  with the schema registry as a parameter; both platforms execute
  against the shared canvas/dashboard registry, and the web now runs +
  refreshes query frames synced from desktop.
- Source references (E3): useCanvasSourceReferences and the merged
  current-canvas scan move to the shared package; the web gains the
  "Copies" panel and reveal-in-canvas.
- Undo (E5/W8): the desktop's four-domain undo ladder is the shared
  model. The web's registry-claimed Mod+Z now dispatches into it, so
  undo inside a focused canvas can target an inline-edited source
  document — a deliberate behavior change from the old scene-only undo.
- Selection HUD (E6/W6/W9): one shared HUD on both platforms — web
  gains lock/align/distribute/tidy/connect/layering, Open, query-frame
  Refresh, and Copies; frame Present/Export moves into the controller
  and appears on desktop for the first time.
- W5: the desktop canvas header becomes an editable title with presence
  avatars, matching the web.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 3 of the 0277 convergence:

- E4: CanvasInlinePageSurface and CanvasDatabasePreviewSurface move to
  @xnetjs/editor with a shared useCanvasPeek hook + CanvasPeekOverlay.
  The web canvas gains Peek (modal source preview) and zoom-gated
  inline editing of pages, notes, and databases — previously the web
  could only navigate away.
- E10: useCanvasCommands registers every canvas action once in the
  shared workspace command registry from the core. The desktop palette
  keeps its metadata table as presentation over the same actions via
  the (now transitional) imperative handle; full handle deletion waits
  on registry palette metadata, tracked in the doc's Risks.
- W1 verified: the shared core has no Desk branches — the Desk (0273)
  composes via config override, empty-state slot, overlay slot, and the
  pin-ingestion queue.
- The view-drift tripwire already covers the pair on main; both sides
  changed together throughout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ards

Live validation of the converged web canvas caught a latent desktop bug
the audit had missed: CanvasHandle.undo() delegates straight back to
onUndoRedoShortcut, so the ladder's scene rung called itself instead of
undoing — scene undo on the desktop canvas could never complete. The
shared ladder now owns the scene Y.UndoManager (the web's 0179 manager)
directly, which fixes scene undo on desktop and restores it on web.

Verified in the running web app: toolbar create → Mod+Z removes the
object, Mod+Y restores it; shared HUD, comment panel, and the peek
overlay (inline page editor) all render and operate.

Also adds canvas-view-convergence.test.ts: source-level guards that both
apps render through the shared dispatcher/cards/controller, plus the M2
frame wire-shape golden assertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@crs48
crs48 temporarily deployed to pr-403 July 7, 2026 02:54 — with GitHub Actions Inactive
…ergence decisions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@crs48
crs48 temporarily deployed to pr-403 July 7, 2026 02:56 — with GitHub Actions Inactive
@crs48
crs48 merged commit 1c98ff9 into main Jul 7, 2026
13 of 16 checks passed
@crs48
crs48 deleted the claude/0277-canvasview-feature-parity-audit-and-convergence branch July 7, 2026 02:57
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Preview removed for PR #403.

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