# 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. - Each free side of the active page shows a small "+" circle just off its edge; tapping it (or `Alt+Arrow`) adds a blank page there. A quick finger fling past a free edge highlights that side's "+" for a few seconds, but never adds a page by itself. - The canvas background is a faint grid with one cell per active page, aligned to its edges; Settings can hide it or subdivide it. - 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 (page menu: presets, or a custom size in mm). ## 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 for now; GitLab not implemented), 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**: IndexedDB locally; Git repo via the GitHub REST API (token in the browser, no proxy). ## 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. **How the app applies it** (`src/lib/ink/palm.ts`): - Each touch is evaluated with an intent. `draw` (finger ink) gets the full policy above. `navigate` (pan, pinch, and taps on canvas buttons such as the add-page "+") skips the 5 s pen session and the hover lockout, so fingers can move around and tap between pen strokes; pen-down, wide contacts and the 150 ms window still reject it. - Once a pen has been used, fingers only navigate. "Draw with finger" in Settings turns finger ink off entirely. - Each rule (pen session, wide contact, timing, hover) can be switched off in Settings → Pen & touch. - An interrupted pointer (`pointercancel`) drops the stroke or erase in progress instead of committing it. **Ink engine (implemented)**: - `StrokeRecorder.recordPoint()` stores `x, y, pressure, tiltX, tiltY, t` per sample in a flat `Stroke.points` array (stride 6); rendering replays it. Tilt is recorded but not yet used for rendering. - Outlines are smoothed with `perfect-freehand`; mouse and finger strokes simulate pressure. - Pen, highlighter (translucent, no thinning) and stroke eraser, with configurable colour palettes; the pen's eraser end erases too. - Undo/redo covers ink, erasing and page-tree changes. - Strokes are written to the PDF both as Ink annotations and as JSON attachments. ## 10. Open Items - [ ] Conflict copies: sync currently lets the newer version win silently; keep the losing version as a separate file. - [ ] Tell the user when a new version of the app has been deployed (the service worker updates, but the open tab keeps old code until reload). - [ ] CI that runs `check`, `test` and `build` on every pull request. - [ ] Use recorded tilt for rendering. - [ ] GitLab sync.