# Lecture Notes App — Architecture Doc v1 ## 1. Page Tree Model ("Comb") One canvas = one tree = one `.pdf` file. - **Trunk**: a single vertical chain of pages. Grows **up or down** (both allowed). - **Branch**: a horizontal chain of pages attached to exactly one trunk page, going **left or right**. - A branch can only ever continue in the direction it started (strictly linear — no sub-branches off a branch). - A trunk page can have at most one left branch and one right branch. - **PDF import**: creates a chain of pages in whatever direction you pick when placing it (up/down = extends the trunk, left/right = becomes a branch off the trunk page you clicked). Only one trunk exists per canvas — additional imported PDFs must attach as a branch off some trunk page, or extend an existing branch further outward in its established direction. - Hidden/unopened neighbor pages render as a gray tile with a "+" in a circle; clicking (or a shortcut) instantiates them as real pages. - Deleting a page removes it (undo via Ctrl+Z); no permanent trash. - Default zoom: one page fills the screen. Zoom out reveals the tree. - Pages default to A4, or auto-match the aspect ratio of an imported PDF page; resizable manually otherwise. ## 2. Flatten Algorithm (tree → linear page order, e.g. for PDF page order / print) Starting at the **topmost** trunk node, walk down: ``` for each trunk_node, top → bottom: emit trunk_node emit left_branch pages, closest-to-trunk → outward emit right_branch pages, closest-to-trunk → outward ``` This is recomputed at export/save time (not creation order), since the trunk can grow upward later and shift what "topmost" means. ## 3. File Format One canvas = **one `.pdf` file**, dual-layer: - **Visual layer** (any standard PDF viewer sees this): rendered markdown as real vector text, ink drawn as PDF Ink annotations, original imported PDF content where applicable. Fully readable/printable by anyone, no app required. - **Source-of-truth layer** (embedded file attachments, invisible in normal viewers): raw markdown source per page, full vector stroke data (points + pressure + tilt — richer than what Ink annotations can hold), and grid metadata (each page's tree position, size, and which PDF import it originated from, for provenance search). - App reads the attachment layer first to reconstruct the live editable canvas; falls back to parsing visual content only if attachments are missing. **Libraries**: `pdf-lib` (write/edit/attach), `pdf.js` (render/import). **Trade-off accepted**: binary PDFs mean no line-level git diffs. Flag for later if this becomes annoying — we could add a parallel auto-generated `.md` export per canvas purely for git-diff readability, PDF stays canonical. ## 4. Organization Canvases (PDF files) live in a **file tree** you define, e.g. `school/english/lecture1.pdf`, `school/math/lecture2.pdf`, `work/...`. Folders are purely organizational, no canvas of their own. ## 5. Sync & Storage - Repo-backed (GitHub/GitLab), one file per canvas. - PWA: offline-first, caches locally, explicit save/sync pushes to repo. - Multi-device: git pull/push is the sync mechanism (not real-time collab). ## 6. Tech Stack (tentative) - **Frontend**: SvelteKit, deployed on your VPS, installable as PWA. - **Ink input**: Pointer Events + pressure (your existing artifact — pending). - **PDF read/write**: pdf.js + pdf-lib. - **Storage**: Git repo via GitHub/GitLab API (or local backend proxy holding the token). ## 7. Confirmed Product Features - Live-rendered markdown (background layer) + vector ink (foreground layer), never converted to text. - Full ink toolset: colors, highlighter, eraser. - Search across typed markdown text. - Pages remember their PDF-import origin, searchable. - No export needed beyond the PDF itself (for now). ## 8. Sync, Auth & Conflicts (resolved) - **Git auth**: personal access token stored in the browser/PWA (no backend proxy, for now). - **Save model**: autocommit + periodic push, plus a manual "sync now" button that does pull + push on demand. - **Conflicts**: newer version wins (timestamp-based), no merge UI for now. - **Repo size**: not a concern for now — revisit if it becomes a problem. ## 9. Pen Input & Palm Rejection Source: user-provided `palm-rejection-test.html` test harness. The acceptance policy carries over almost verbatim: - `pointerType === 'pen'` is always accepted; its down/move/up updates `lastPenActivityTime`. - A `touch` pointer is rejected if any of: a pen stroke is active or was active within the last ~5s, its contact ellipse (`width`/`height`) exceeds ~35px (palm heel vs. fingertip), it's within 150ms of the last pen activity, or a pen is currently hovering (armed lockout before it even touches down). - A touch stroke already in progress gets cut off mid-stroke if pen activity appears. **Gaps before this is the real ink engine** (currently a raster test, not vector): - `draw()` writes straight to canvas via `ctx.lineTo`/`stroke` with pressure-scaled line width, and throws points away. Needs to become `recordPoint()`: push `{x, y, pressure, tiltX, tiltY, t}` into a `Stroke.points[]` array per stroke; rendering = replaying that array. This is what makes strokes resizable/erasable/undoable and exportable to both the PDF Ink-annotation layer and the JSON attachment layer. - `tiltX`/`tiltY` exist on the pen's `PointerEvent` but aren't read anywhere yet — needed for tilt support. - No smoothing yet (raw straight segments) — fine as a v1, can layer in curve smoothing later without changing point storage. - No undo/redo, multi-color, eraser yet — needs a `Stroke[]` array per page's ink layer with add/remove, which undo/redo just pops/pushes. ## 10. Open Items - [ ] Nothing blocking — ready to move into implementation planning (component breakdown, page-tree data structures in Svelte, PDF encode/decode module)