CANVAS: Sketch from the Log composer and the note / menu (§60) #990

Open
opened 2026-10-03 07:10:09 +00:00 by kayg · 13 comments
Owner

Owner decision (2026-10-03, #509 C8)

The Log composer and the note / menu get Sketch. Contract: DESIGN §60 "Sketch". Builds on #976 (and #978 for Pencil).

Scope

  • Sketch opens a small canvas sheet (Pencil-ready, hand-drawn font), reusing the Canvas editor, not a second drawing surface.
  • Done saves a Sketch YYYY-MM-DD HH.MM.excalidraw.md file (folder: the Log/Journal attachments rule or next to the note; reuse the existing attachment placement) and attaches it: the Log entry shows it in its attachment deck (#822 ItemCard), a note embeds it with ![[...]] as a live preview.
  • Cancel discards with no file. Keyboard: shortcut in the composer and /sketch. Touch: the sheet follows the phone sheet rules. Tooltip with shortcut.

Verification

e2e as a User: Sketch from the composer, draw, Done, see the sketch card in the Log entry; Sketch from a note, see the live preview; reload. Screenshots incl. iPad simulator.

## Owner decision (2026-10-03, #509 C8) The Log composer and the note `/` menu get **Sketch**. Contract: DESIGN §60 "Sketch". Builds on #976 (and #978 for Pencil). ## Scope - Sketch opens a small canvas sheet (Pencil-ready, hand-drawn font), reusing the Canvas editor, not a second drawing surface. - Done saves a `Sketch YYYY-MM-DD HH.MM.excalidraw.md` file (folder: the Log/Journal attachments rule or next to the note; reuse the existing attachment placement) and attaches it: the Log entry shows it in its attachment deck (#822 ItemCard), a note embeds it with `![[...]]` as a live preview. - Cancel discards with no file. Keyboard: shortcut in the composer and `/sketch`. Touch: the sheet follows the phone sheet rules. Tooltip with shortcut. ## Verification e2e as a User: Sketch from the composer, draw, Done, see the sketch card in the Log entry; Sketch from a note, see the live preview; reload. Screenshots incl. iPad simulator.
Author
Owner

Starting #990 on job/canvas-sketch-990.

  • Branch HEAD before the dev sync: beb3bbf4b0487200af4a596b771e6690c452bfc3
  • origin/dev: 22f13995a9c6020807af57018198ecfa3cf6b2f7
  • Shared base: e3915b5b79c39b6086db40d4c93f24c4289b36ed

I will build Sketch on the approved Canvas core path and follow DESIGN §60, including C6–C14.

Starting #990 on `job/canvas-sketch-990`. - Branch HEAD before the dev sync: `beb3bbf4b0487200af4a596b771e6690c452bfc3` - `origin/dev`: `22f13995a9c6020807af57018198ecfa3cf6b2f7` - Shared base: `e3915b5b79c39b6086db40d4c93f24c4289b36ed` I will build Sketch on the approved Canvas core path and follow DESIGN §60, including C6–C14.
Author
Owner

Finding: #990 can use the existing Journal attachment field without adding a route. createNote({ canvas: true, folder: 'Documents/Other' }) creates the Canvas Note, and Calendar's range projection maps attachment paths to stable note IDs. Composer can add that saved path directly. Its Undo now removes only the draft relationship, so the Canvas remains in Home.

Finding: #990 can use the existing Journal attachment field without adding a route. `createNote({ canvas: true, folder: 'Documents/Other' })` creates the Canvas Note, and Calendar's range projection maps attachment paths to stable note IDs. Composer can add that saved path directly. Its Undo now removes only the draft relationship, so the Canvas remains in Home.
Author
Owner

Finding: the app's @calternal/editor type boundary maps to apps/web/src/lib/notes/editor-types/index.d.ts, which did not declare the package's existing slash-menu exports. The new note action is implemented through the package's injected slash-action API, so I am adding the matching declaration and keeping TypeScript aligned with the runtime package.

Finding: the app's `@calternal/editor` type boundary maps to `apps/web/src/lib/notes/editor-types/index.d.ts`, which did not declare the package's existing slash-menu exports. The new note action is implemented through the package's injected slash-action API, so I am adding the matching declaration and keeping TypeScript aligned with the runtime package.
Author
Owner

Finding from the production browser run: opening Sketch from the Journal composer left data-sketch-state="loading" after 60 seconds. The real .canvas-host was present at 341×665, but it had no children and no Canvas renderer/font requests had started. OverlaySurface inserts its slot on the opening frame, so SketchSheet's onMount could call mount() before bind:this provided the host; that call returned without a retry. I changed SketchSheet to start the renderer when the host binds. Rebuilding and rerunning the production flow now.

Finding from the production browser run: opening Sketch from the Journal composer left `data-sketch-state="loading"` after 60 seconds. The real `.canvas-host` was present at 341×665, but it had no children and no Canvas renderer/font requests had started. `OverlaySurface` inserts its slot on the opening frame, so `SketchSheet`'s `onMount` could call `mount()` before `bind:this` provided the host; that call returned without a retry. I changed SketchSheet to start the renderer when the host binds. Rebuilding and rerunning the production flow now.
Author
Owner

Production E2E created Composer canvases in Documents/Other and a Note Sketch in Notes within the same minute. They produced distinct Canvas Notes with the same title. The Note inserted ![[Sketch YYYY-MM-DD HH.MM.excalidraw]]; createWikilinkResolver correctly treated that title as ambiguous, so the body retained literal text and no data-canvas-preview widget appeared. I am updating the Note embed to carry the Canvas's exact Home path with a friendly title alias, then replaying this collision in the production E2E.

Production E2E created Composer canvases in `Documents/Other` and a Note Sketch in `Notes` within the same minute. They produced distinct Canvas Notes with the same title. The Note inserted `![[Sketch YYYY-MM-DD HH.MM.excalidraw]]`; `createWikilinkResolver` correctly treated that title as ambiguous, so the body retained literal text and no `data-canvas-preview` widget appeared. I am updating the Note embed to carry the Canvas's exact Home path with a friendly title alias, then replaying this collision in the production E2E.
Author
Owner

The 390 px and 1440 px Mac production screenshots showed the resolved Note preview with its raw ![[...]] source line still visible above it. The source remained intact in the editor document, but the live view exposed Markdown syntax beside the preview. I am adding a presentation-only inline decoration to hide resolved wiki source, with a focused editor test and a production DOM assertion; the saved Note source stays unchanged.

The 390 px and 1440 px Mac production screenshots showed the resolved Note preview with its raw `![[...]]` source line still visible above it. The source remained intact in the editor document, but the live view exposed Markdown syntax beside the preview. I am adding a presentation-only inline decoration to hide resolved wiki source, with a focused editor test and a production DOM assertion; the saved Note source stays unchanged.
Author
Owner

The Canvas Sketch profile ran on perf-test while holding /root/perf.lock; load average inside the lock was [0.38, 0.12, 0.08].

  • Sketch sheet open (12 samples): p50 861 ms, p95 4003 ms; server mean/peak RSS 172/178 MB, mean CPU 4.82%.
  • 100-element Canvas event save (20 samples): p50/p95 189/280 ms; server mean/peak RSS 397/422 MB, mean CPU 206.52%.
  • Largest scene: one 5,000-element save took 2048 ms. Eight parallel 5,000-element saves took 14,383 ms total, p50/p95 9030/12549 ms; all eight returned 204. Peak server RSS was 752 MB, peak CPU 305.49%.

docs/perf/baseline.json has no Sketch or Canvas event-save profile. Its nearest UI comparison is Composer open at p50/p95 185/349 ms and INP 112 ms; that is not a like-for-like Sketch baseline because Sketch lazily loads Excalidraw. The complete JSON is in artifacts/canvas-sketch-990-perf.json in the worktree.

The Canvas Sketch profile ran on `perf-test` while holding `/root/perf.lock`; load average inside the lock was `[0.38, 0.12, 0.08]`. - Sketch sheet open (12 samples): p50 `861 ms`, p95 `4003 ms`; server mean/peak RSS `172/178 MB`, mean CPU `4.82%`. - 100-element Canvas event save (20 samples): p50/p95 `189/280 ms`; server mean/peak RSS `397/422 MB`, mean CPU `206.52%`. - Largest scene: one 5,000-element save took `2048 ms`. Eight parallel 5,000-element saves took `14,383 ms` total, p50/p95 `9030/12549 ms`; all eight returned `204`. Peak server RSS was `752 MB`, peak CPU `305.49%`. `docs/perf/baseline.json` has no Sketch or Canvas event-save profile. Its nearest UI comparison is Composer open at p50/p95 `185/349 ms` and INP `112 ms`; that is not a like-for-like Sketch baseline because Sketch lazily loads Excalidraw. The complete JSON is in `artifacts/canvas-sketch-990-perf.json` in the worktree.
Author
Owner

Final report — Forgejo #990

READY FOR MERGE: yes

Head: 9b784bc13aade1c30a4d4e872e94666dbd9caf30
Branch: job/canvas-sketch-990, based on job/canvas-core-976; origin/dev was merged before final verification.

Built

Added a reusable Sketch sheet to Journal Composer and Notes. Sketch uses the shared Canvas host and event path. A draft stays memory-only until Done; Cancel creates no Canvas. Composer supports the Sketch toolbar action, Option+Shift+S, and a terminal /sketch command. Notes supports /sketch and a live Canvas preview. The Composer attachment has Undo scoped to the relationship, so Undo keeps the saved Canvas in Home.

Notes previews resolve an exact Home-relative wikilink target to the Note’s stable calternal-id while showing its title as the link label. This prevents same-title Canvases in different folders from resolving to the wrong item. The Notes rename cascade rewrites this internal link when a Note moves or changes title. The saved wikilink remains in the document; a presentation decoration hides its raw syntax when the live preview is ready.

Files

  • apps/web/src/lib/canvas/: CanvasReact.tsx, SketchSheet.svelte, draftProvider.ts, sketch.ts, embeds.ts, and focused tests.
  • apps/web/src/lib/composer/: Composer.svelte, attachments.svelte.ts, sketchCommand.ts, the test stub, and focused tests.
  • apps/web/src/lib/notes/: NoteEditorSurface.svelte, collab.ts, editorHost.ts, editor-types/index.d.ts.
  • apps/web/src/lib/shortcuts/registry.ts.
  • packages/editor/src/: slash.ts, extensions.ts, and focused tests.
  • apps/web/e2e/canvas-sketch-990.mjs; bench/canvas-sketch-990.mjs.

Gates

bun run check:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

Focused Vitest command:

TMPDIR=$PWD/../../target/tmp bunx vitest run src/lib/composer/attachments.test.ts src/lib/composer/sketchCommand.test.ts src/lib/composer/Composer.svelte.test.ts src/lib/shortcuts/registry.test.ts src/lib/canvas/draftProvider.test.ts src/lib/canvas/sketch.test.ts src/lib/canvas/embeds.test.ts --maxWorkers=2
 Test Files  7 passed (7)
      Tests  60 passed (60)
   Start at  02:11:26
   Duration  11.73s (transform 79%, tests 9%, import 7%, environment 4%, setup 1%)

Production E2E and screenshots, after the final origin/dev merge:

PASS production Sketch flows; 30 Mac-platform screenshots in /home/kayg/Developer/calternal-wt/canvas-sketch-990/artifacts/canvas-sketch-990

git diff --check passed with no output. #990 changed no Rust crate, so Rust crate gates were not applicable. The release server build used for the perf run completed with:

Finished `release` profile [optimized] target(s) in 12m 15s

Cleanup completed:

Removed 14959 files, 7.3GiB total

Performance

Measured on perf-test while holding /root/perf.lock; load average in the lock was [0.38, 0.12, 0.08]. No Sketch or Canvas event-save profile exists in docs/perf/baseline.json; the nearest Composer open comparison is p50/p95 185/349 ms and is not like-for-like because Sketch lazily loads Excalidraw.

Sketch open: p50 861 ms, p95 4,003 ms (12 samples); mean/peak server RSS 172/178 MB; mean CPU 4.82%. Saving 100 elements: p50/p95 189/280 ms (20 samples); mean/peak RSS 397/422 MB; mean CPU 206.52%. Worst case: one 5,000-element scene saved in 2,048 ms; eight concurrent 5,000-element writes all returned 204 in 14,383 ms, with peak RSS 752 MB and peak CPU 305.49%.

UX gaps closed

  • Cancel leaves no Canvas file; Done saves through the existing Canvas event route.
  • Composer and Notes can open Sketch from their visible actions, and Composer Undo removes only the attachment relationship.
  • Same-title cross-folder Notes embeds resolve by exact path.
  • The live preview does not display duplicate raw wikilink syntax.
  • The production flow was exercised with pointer input; the screenshot harness checks touch targets and captures macOS shortcut glyphs at 390, 820 and 1440 px in light and dark modes.

UX gaps left

  • No physical iPad/Apple Pencil or screen-reader walkthrough was run. Mobile touch emulation and macOS-platform Chromium screenshots are attached; they do not replace those checks.
  • The Sketch open p95 is 4.0 s in this cold/lazy-load profile. There is no comparable Sketch baseline yet; performance is not a merge gate.

Decisions not specified by DESIGN §60

  • Use an exact Home-relative wikilink target with a friendly title alias so duplicate Canvas titles cannot select the wrong Notes item; the existing Notes rename cascade keeps that target valid, and preview resolution switches to the stable calternal-id.
  • Hide the resolved wikilink with a presentation-only decoration; keep the underlying Notes source unchanged.

For the merge round

  • bun run test — full web unit suite.
  • bun run test:e2e and the merge-round E2E matrix — prove the merged production shell and cross-feature UI flows.
  • tests/adversarial/run.sh — run the XUser, authorization and real-server adversarial matrices on the combined branch.
  • Run the merge-round macOS client interop check under the required Mac VM lock.

Production screenshots (30)

Production Mac screenshots (30)

View 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Composer Sketch sheet 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Notes slash menu 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Notes Sketch sheet 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Composer attachment 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Note Canvas preview 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
# Final report — Forgejo #990 **READY FOR MERGE: yes** **Head:** `9b784bc13aade1c30a4d4e872e94666dbd9caf30` **Branch:** `job/canvas-sketch-990`, based on `job/canvas-core-976`; `origin/dev` was merged before final verification. ## Built Added a reusable Sketch sheet to Journal Composer and Notes. Sketch uses the shared Canvas host and event path. A draft stays memory-only until Done; Cancel creates no Canvas. Composer supports the Sketch toolbar action, Option+Shift+S, and a terminal `/sketch` command. Notes supports `/sketch` and a live Canvas preview. The Composer attachment has Undo scoped to the relationship, so Undo keeps the saved Canvas in Home. Notes previews resolve an exact Home-relative wikilink target to the Note’s stable calternal-id while showing its title as the link label. This prevents same-title Canvases in different folders from resolving to the wrong item. The Notes rename cascade rewrites this internal link when a Note moves or changes title. The saved wikilink remains in the document; a presentation decoration hides its raw syntax when the live preview is ready. ## Files - `apps/web/src/lib/canvas/`: `CanvasReact.tsx`, `SketchSheet.svelte`, `draftProvider.ts`, `sketch.ts`, `embeds.ts`, and focused tests. - `apps/web/src/lib/composer/`: `Composer.svelte`, `attachments.svelte.ts`, `sketchCommand.ts`, the test stub, and focused tests. - `apps/web/src/lib/notes/`: `NoteEditorSurface.svelte`, `collab.ts`, `editorHost.ts`, `editor-types/index.d.ts`. - `apps/web/src/lib/shortcuts/registry.ts`. - `packages/editor/src/`: `slash.ts`, `extensions.ts`, and focused tests. - `apps/web/e2e/canvas-sketch-990.mjs`; `bench/canvas-sketch-990.mjs`. ## Gates `bun run check`: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` Focused Vitest command: ```text TMPDIR=$PWD/../../target/tmp bunx vitest run src/lib/composer/attachments.test.ts src/lib/composer/sketchCommand.test.ts src/lib/composer/Composer.svelte.test.ts src/lib/shortcuts/registry.test.ts src/lib/canvas/draftProvider.test.ts src/lib/canvas/sketch.test.ts src/lib/canvas/embeds.test.ts --maxWorkers=2 Test Files 7 passed (7) Tests 60 passed (60) Start at 02:11:26 Duration 11.73s (transform 79%, tests 9%, import 7%, environment 4%, setup 1%) ``` Production E2E and screenshots, after the final `origin/dev` merge: ```text PASS production Sketch flows; 30 Mac-platform screenshots in /home/kayg/Developer/calternal-wt/canvas-sketch-990/artifacts/canvas-sketch-990 ``` `git diff --check` passed with no output. #990 changed no Rust crate, so Rust crate gates were not applicable. The release server build used for the perf run completed with: ```text Finished `release` profile [optimized] target(s) in 12m 15s ``` Cleanup completed: ```text Removed 14959 files, 7.3GiB total ``` ## Performance Measured on `perf-test` while holding `/root/perf.lock`; load average in the lock was `[0.38, 0.12, 0.08]`. No Sketch or Canvas event-save profile exists in `docs/perf/baseline.json`; the nearest Composer open comparison is p50/p95 185/349 ms and is not like-for-like because Sketch lazily loads Excalidraw. Sketch open: p50 861 ms, p95 4,003 ms (12 samples); mean/peak server RSS 172/178 MB; mean CPU 4.82%. Saving 100 elements: p50/p95 189/280 ms (20 samples); mean/peak RSS 397/422 MB; mean CPU 206.52%. Worst case: one 5,000-element scene saved in 2,048 ms; eight concurrent 5,000-element writes all returned 204 in 14,383 ms, with peak RSS 752 MB and peak CPU 305.49%. ## UX gaps closed - Cancel leaves no Canvas file; Done saves through the existing Canvas event route. - Composer and Notes can open Sketch from their visible actions, and Composer Undo removes only the attachment relationship. - Same-title cross-folder Notes embeds resolve by exact path. - The live preview does not display duplicate raw wikilink syntax. - The production flow was exercised with pointer input; the screenshot harness checks touch targets and captures macOS shortcut glyphs at 390, 820 and 1440 px in light and dark modes. ## UX gaps left - No physical iPad/Apple Pencil or screen-reader walkthrough was run. Mobile touch emulation and macOS-platform Chromium screenshots are attached; they do not replace those checks. - The Sketch open p95 is 4.0 s in this cold/lazy-load profile. There is no comparable Sketch baseline yet; performance is not a merge gate. ## Decisions not specified by DESIGN §60 - Use an exact Home-relative wikilink target with a friendly title alias so duplicate Canvas titles cannot select the wrong Notes item; the existing Notes rename cascade keeps that target valid, and preview resolution switches to the stable calternal-id. - Hide the resolved wikilink with a presentation-only decoration; keep the underlying Notes source unchanged. ## For the merge round - `bun run test` — full web unit suite. - `bun run test:e2e` and the merge-round E2E matrix — prove the merged production shell and cross-feature UI flows. - `tests/adversarial/run.sh` — run the XUser, authorization and real-server adversarial matrices on the combined branch. - Run the merge-round macOS client interop check under the required Mac VM lock. ## Production screenshots (30) ### Production Mac screenshots (30) | View | 390 light | 390 dark | 820 light | 820 dark | 1440 light | 1440 dark | | --- | --- | --- | --- | --- | --- | --- | | Composer Sketch sheet | [390 light](https://git.kayg.org/attachments/4306f8a6-57cc-4658-91ff-97df4adaad7d) | [390 dark](https://git.kayg.org/attachments/f7b187ae-068e-4ae6-a515-1e429de4c948) | [820 light](https://git.kayg.org/attachments/8d412bd9-610f-4e9e-a0d7-b5e42b60429a) | [820 dark](https://git.kayg.org/attachments/8aa1b1b5-c0d4-427d-b805-d63f7d1c5303) | [1440 light](https://git.kayg.org/attachments/ae659e70-d4ba-4485-9166-c6ddd950987c) | [1440 dark](https://git.kayg.org/attachments/194f1bce-8e4c-47e8-ba26-e4915b8c80fc) | | Notes slash menu | [390 light](https://git.kayg.org/attachments/c7a234c0-21d4-4bbe-a6c5-ee3c06b65dcc) | [390 dark](https://git.kayg.org/attachments/e209d387-b0b2-42b6-a24b-107f5e709d37) | [820 light](https://git.kayg.org/attachments/d3ecaf98-79df-4dd0-83fa-1760e89ff2af) | [820 dark](https://git.kayg.org/attachments/f54f02e3-a738-45e7-9437-d2459687d861) | [1440 light](https://git.kayg.org/attachments/d60e3462-b68d-4163-b4b9-fce590a60144) | [1440 dark](https://git.kayg.org/attachments/3cf344eb-c865-41ce-ac2d-50c1e9361a65) | | Notes Sketch sheet | [390 light](https://git.kayg.org/attachments/ce83b91d-458e-49a5-9c9c-f1234b26b4f5) | [390 dark](https://git.kayg.org/attachments/21d7b950-57dd-44cd-ab0e-aaa709d5cdd4) | [820 light](https://git.kayg.org/attachments/e86dff96-3783-48b6-82f1-c7ad6b6ddac8) | [820 dark](https://git.kayg.org/attachments/8f4bb71d-4f38-4d8f-ae4f-09bb2ad39ea1) | [1440 light](https://git.kayg.org/attachments/ff01009a-66c5-43a2-b482-d1420bb95502) | [1440 dark](https://git.kayg.org/attachments/f0e12e52-cb93-41ee-89ca-fd3bf973ede3) | | Composer attachment | [390 light](https://git.kayg.org/attachments/e7a56c2b-d917-4ddd-926b-94694160f0af) | [390 dark](https://git.kayg.org/attachments/50ef24a0-fac8-43ee-8249-1be8c331516f) | [820 light](https://git.kayg.org/attachments/5d7ce6a0-bff2-4691-b4a3-8be0e7ac4f68) | [820 dark](https://git.kayg.org/attachments/6aa3154f-f3d1-441d-a3ef-237a1cbcc74a) | [1440 light](https://git.kayg.org/attachments/e332690f-6921-4e77-ba61-0acdce415ca5) | [1440 dark](https://git.kayg.org/attachments/f14e647d-7dde-4ab5-b9ce-86bffc1988dc) | | Note Canvas preview | [390 light](https://git.kayg.org/attachments/413d6ba8-65d6-408a-8e34-5096d94583fe) | [390 dark](https://git.kayg.org/attachments/6b699846-53af-4866-b45a-72c38784a751) | [820 light](https://git.kayg.org/attachments/cba4b57e-5d68-494d-b367-1f27aa1ad6a7) | [820 dark](https://git.kayg.org/attachments/81859e5a-ddb7-49fa-a4b3-94612e9fa090) | [1440 light](https://git.kayg.org/attachments/2188609c-9f40-4bfc-8f15-04a3449362c0) | [1440 dark](https://git.kayg.org/attachments/3250bb81-7de9-41d8-8745-e825f2ea117f) |
Author
Owner

Starting work on branch job/canvas-sketch-990 from base SHA 9b784bc13aade1c30a4d4e872e94666dbd9caf30. I will inspect the Sketch sheet implementation and its e2e coverage, then fix the clipped desktop layout, post-animation Excalidraw sizing, and header actions.

Starting work on branch `job/canvas-sketch-990` from base SHA `9b784bc13aade1c30a4d4e872e94666dbd9caf30`. I will inspect the Sketch sheet implementation and its e2e coverage, then fix the clipped desktop layout, post-animation Excalidraw sizing, and header actions.
Author
Owner

Finding: SketchSheet.svelte gives its body width: min(94vw, 72rem), while the shared desktop .surface.dialog caps at 640px. At 1440px the body computes to about 1354px and overflows the dialog, whose horizontal overflow is hidden; this explains the missing right edge and toolbar. I will size the shared surface for Sketch and let its body fill that measured width.

Finding: `SketchSheet.svelte` gives its body `width: min(94vw, 72rem)`, while the shared desktop `.surface.dialog` caps at 640px. At 1440px the body computes to about 1354px and overflows the dialog, whose horizontal overflow is hidden; this explains the missing right edge and toolbar. I will size the shared surface for Sketch and let its body fill that measured width.
Author
Owner

Completed #990.

Built

  • Fixed Sketch sizing: desktop now uses a centered dialog that stays within the viewport; a phone uses the full-height shared sheet and grabber.
  • Moved the title and actions into the shared ModeHeader. Done uses the primary tone; Cancel uses the secondary tone.
  • The Canvas host now observes its real content size and refreshes Excalidraw after the shared entrance. It does not use a width captured before mount or delay drawing input.
  • The production e2e checks the sheet, editor and visible toolbars against the viewport, checks both header actions, then exercises Done saves from Journal and Notes.

Files

  • apps/web/src/lib/canvas/SketchSheet.svelte
  • apps/web/src/lib/canvas/CanvasReact.tsx
  • apps/web/e2e/canvas-sketch-990.mjs

Head SHA
728168e6c37bfddfdbc8379ace682eb555637ce5

Screenshots
All 30 macOS-platform screenshots are attached in three archives (10 each):

UX gaps closed

  • The desktop sheet and Excalidraw toolbar no longer clip off-screen.
  • Done and Cancel are visible in the header; Done saves through both real flows.
  • Excalidraw refreshes against its measured host after opening and on resize.

UX gaps left

  • None found in the requested Sketch flows.

Decisions

  • DESIGN §34 does not set Sketch dimensions. The desktop dialog uses a 72rem maximum width, a 1rem viewport inset, and a height capped at min(88dvh, 56rem). The full-height sheet applies below 768 px, matching the shared desktop presentation threshold. Touch tablets keep the shared three-quarter sheet.

Gate output (verbatim)
bun run check:

User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web
Getting Svelte diagnostics...
svelte-check found 0 errors and 0 warnings

Focused Vitest:

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web
 Test Files  2 passed (2)
      Tests  4 passed (4)
   Start at  03:02:54
   Duration  326ms (transform 55%, import 36%, tests 5%, worker 3%)

Production e2e:

PASS production Sketch flows; 30 Mac-platform screenshots in /home/kayg/Developer/calternal-wt/canvas-sketch-990/artifacts/canvas-sketch-990

Production web build and cargo build -p calternal-server succeeded. No Rust source changed. Full web tests remain with the merge-round gates per the verification policy. Cleanup output:

Removed 7238 files, 4.6GiB total
Completed #990. **Built** - Fixed Sketch sizing: desktop now uses a centered dialog that stays within the viewport; a phone uses the full-height shared sheet and grabber. - Moved the title and actions into the shared ModeHeader. Done uses the primary tone; Cancel uses the secondary tone. - The Canvas host now observes its real content size and refreshes Excalidraw after the shared entrance. It does not use a width captured before mount or delay drawing input. - The production e2e checks the sheet, editor and visible toolbars against the viewport, checks both header actions, then exercises Done saves from Journal and Notes. **Files** - `apps/web/src/lib/canvas/SketchSheet.svelte` - `apps/web/src/lib/canvas/CanvasReact.tsx` - `apps/web/e2e/canvas-sketch-990.mjs` **Head SHA** `728168e6c37bfddfdbc8379ace682eb555637ce5` **Screenshots** All 30 macOS-platform screenshots are attached in three archives (10 each): - [390 px: phone, light and dark](https://git.kayg.org/attachments/93e4fbc4-3f16-4e16-8ef9-6cc0a416a4ae) - [820 px: tablet, light and dark](https://git.kayg.org/attachments/b43bd11b-a7cf-489b-aeba-3b98ae5e43f1) - [1440 px: desktop, light and dark](https://git.kayg.org/attachments/8608c799-237b-4048-9349-e63a1ca83c20) **UX gaps closed** - The desktop sheet and Excalidraw toolbar no longer clip off-screen. - Done and Cancel are visible in the header; Done saves through both real flows. - Excalidraw refreshes against its measured host after opening and on resize. **UX gaps left** - None found in the requested Sketch flows. **Decisions** - DESIGN §34 does not set Sketch dimensions. The desktop dialog uses a 72rem maximum width, a 1rem viewport inset, and a height capped at `min(88dvh, 56rem)`. The full-height sheet applies below 768 px, matching the shared desktop presentation threshold. Touch tablets keep the shared three-quarter sheet. **Gate output (verbatim)** `bun run check`: ``` User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` Focused Vitest: ``` RUN v5.0.1 /home/kayg/Developer/calternal-wt/canvas-sketch-990/apps/web Test Files 2 passed (2) Tests 4 passed (4) Start at 03:02:54 Duration 326ms (transform 55%, import 36%, tests 5%, worker 3%) ``` Production e2e: ``` PASS production Sketch flows; 30 Mac-platform screenshots in /home/kayg/Developer/calternal-wt/canvas-sketch-990/artifacts/canvas-sketch-990 ``` Production web build and `cargo build -p calternal-server` succeeded. No Rust source changed. Full web tests remain with the merge-round gates per the verification policy. Cleanup output: ``` Removed 7238 files, 4.6GiB total ```
Author
Owner

Merge round 7c starts on job/merge-round-7c, base 4082669f7. The current owner job authorizes integration and full verification; it supersedes the original read-only #867 brief.

Canvas order: core → files → collab → Sketch → Pencil → cards. Migrations follow the combined 7b schema. No pushes or deploys. Final report will include verbatim gates, screenshots, defensive renderer review and staging readiness.

Merge round 7c starts on `job/merge-round-7c`, base `4082669f7`. The current owner job authorizes integration and full verification; it supersedes the original read-only #867 brief. Canvas order: core → files → collab → Sketch → Pencil → cards. Migrations follow the combined 7b schema. No pushes or deploys. Final report will include verbatim gates, screenshots, defensive renderer review and staging readiness.
Author
Owner

Finished merge-round-7c integration at 094d22e44507bf8bdd87dd8ffd460c254cb6329c. READY FOR STAGING: no.

Opening evidence covers Composer and Note Sketch at all widths/themes. The save retry remains open after a retitle 409 and times out. Save is not verified.

Production macOS evidence is attached to #867: 390/820/1440, light/dark. Screenshots remain outside git.

Focused Canvas viewer authority regression:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 248 filtered out; finished in 2.52s

Svelte check:

svelte-check found 0 errors and 4 warnings in 3 files

The full report, renderer boundary review, migration upgrade evidence, exact gate excerpts and decisions are in docs/audits/merge-round-7c.md and the final #867 comment. Staging blockers include the Notes process SIGSEGV after 278 passing assertions (#1069), stale performance exception pins, the retained thumbnail test conflict, Sketch save and unfinished verification. No pushes or deployments.

Finished merge-round-7c integration at `094d22e44507bf8bdd87dd8ffd460c254cb6329c`. READY FOR STAGING: no. Opening evidence covers Composer and Note Sketch at all widths/themes. The save retry remains open after a retitle 409 and times out. Save is not verified. Production macOS evidence is attached to [#867](https://git.kayg.org/kayg/calternal/issues/867): 390/820/1440, light/dark. Screenshots remain outside git. Focused Canvas viewer authority regression: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 248 filtered out; finished in 2.52s ``` Svelte check: ```text svelte-check found 0 errors and 4 warnings in 3 files ``` The full report, renderer boundary review, migration upgrade evidence, exact gate excerpts and decisions are in `docs/audits/merge-round-7c.md` and the final #867 comment. Staging blockers include the Notes process SIGSEGV after 278 passing assertions (#1069), stale performance exception pins, the retained thumbnail test conflict, Sketch save and unfinished verification. No pushes or deployments.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#990
No description provided.