From 4dca0f1bacc31ebe193fd8d0476eb4b55f9152b6 Mon Sep 17 00:00:00 2001 From: SinachPat Date: Sat, 2 May 2026 17:33:03 +0100 Subject: [PATCH] made tiny updates --- docs/SOURCE-AWARE-CANVAS.md | 376 +++++++++++++++++++++++++----------- 1 file changed, 265 insertions(+), 111 deletions(-) diff --git a/docs/SOURCE-AWARE-CANVAS.md b/docs/SOURCE-AWARE-CANVAS.md index c08f971..c85b00c 100644 --- a/docs/SOURCE-AWARE-CANVAS.md +++ b/docs/SOURCE-AWARE-CANVAS.md @@ -192,7 +192,7 @@ Three entry points, all result in a `createArtboard()` dispatch: 3. **Duplicate** — right-click any artboard → Duplicate. Creates a copy at a different device size (opens device preset picker). **Auto-arrange (default layout):** -New artboards snap to a horizontal row with `gap: 200px`. When a row exceeds 3 artboards or total width > 6000px, a new row begins below. The vertical gap between rows is 240px. The Y position of a new row is `maxHeightInPreviousRow + 240px` (using the tallest artboard in the completed row as the row height). The layout algorithm runs on `createArtboard()` only — it computes a suggested `(x, y)` position and assigns it. The user can drag the artboard away from that position at any time; subsequent auto-arrange calls do not move manually-positioned artboards (a `manuallyPositioned: boolean` flag on each artboard record prevents re-calculation). The flag is set to `true` on `pointerup` at the end of a successful artboard drag (when the user has moved the artboard at least 4px from its pre-drag position). It is never set by the auto-arrange algorithm's own writes to `canvas_x`/`canvas_y`. +New artboards snap to a horizontal row with `gap: 200px`. When a row exceeds 3 artboards or total width > 6000px, a new row begins below. The vertical gap between rows is 240px. The Y position of a new row is `previousRowStartY + maxHeightInPreviousRow + 240px` (using the tallest artboard in the completed row as the row height — accumulated across all previous rows, not just the last one). The layout algorithm runs on `createArtboard()` only — it computes a suggested `(x, y)` position and assigns it. The user can drag the artboard away from that position at any time; subsequent auto-arrange calls do not move manually-positioned artboards (a `manuallyPositioned: boolean` flag on each artboard record prevents re-calculation). The flag is set to `true` on `pointerup` at the end of a successful artboard drag (when the user has moved the artboard at least **10 world-space pixels** from its pre-drag position — convert screen delta to world delta by dividing by `canvasTransform.scale` before comparing). It is never set by the auto-arrange algorithm's own writes to `canvas_x`/`canvas_y`. **"Re-arrange all"** button in the Artboard Navigator context menu resets all positions to the auto-grid (after a confirmation prompt, since it discards freeform layout). @@ -304,14 +304,15 @@ The viewport cull is triggered by pan and zoom events and runs on a 100ms deboun 1. When an artboard transitions from **Active** → **Near/Far**, the canvas sends `{ type: 'CAPTURE_THUMBNAIL' }` to that artboard's iframe 2. The fiber hook / DOM inspector inside the iframe receives this message, runs `html2canvas(document.body)` (the `html2canvas` library is injected by the CLI proxy alongside the fiber hook), and posts the result back: `post({ type: 'THUMBNAIL_READY', dataUrl: canvas.toDataURL('image/jpeg', 0.6) })` -3. The canvas receives `THUMBNAIL_READY`, stores the data URL in `artboardFrames[id].thumbnailDataUrl` in Zustand, and uses it to display the placeholder -4. `thumbnail_url` in Supabase stores this data URL (or a Supabase Storage URL if the image is uploaded — see §3.8) +3. The canvas receives `THUMBNAIL_READY`, stores the data URL in `artboardFrames[id].thumbnailDataUrl` in Zustand for immediate display as a placeholder +4. The canvas uploads the data URL as a JPEG to Supabase Storage (`artboard-thumbnails/{workspaceId}/{artboardId}.jpg`) and stores the resulting public Storage URL in `thumbnail_url`. **Data URIs are never written to the database** — only the Supabase Storage URL is persisted (see §3.8). If the upload fails, `thumbnail_url` remains null and the Zustand in-memory data URL continues to serve as the placeholder for the current session. **Required additions:** - `CAPTURE_THUMBNAIL` added as a valid host message type in `protocol.ts` - `THUMBNAIL_READY` added as a valid renderer message type in `protocol.ts` - `html2canvas` is bundled inside the CLI package and injected as an inline script (not a CDN URL — CDN dependency would break offline use and introduce a supply-chain risk). The CLI bundles `html2canvas` during its own build step. If `html2canvas` fails (returns a blank canvas, throws, or times out after 3s), the iframe sends `{ type: 'THUMBNAIL_READY', dataUrl: null }` and the canvas displays a "thumbnail unavailable" placeholder with the artboard label instead. Performance note: html2canvas adds ~250KB to the injected script per artboard tab — it is only injected once per page load and only when the CLI is running in dev mode. - Handler added to `dom-inspector.ts` for `CAPTURE_THUMBNAIL` +- **html2canvas injection note:** The script is injected once per page load by the CLI proxy (alongside the fiber hook) — not repeatedly per artboard. Since each artboard is a separate iframe/page load, each page gets one injection. The ~250KB cost is per page load, not per artboard-on-screen. The CLI proxy injects `html2canvas` as a separate `