From 3d29255d0c6f16e2ffd219dca9d2061fbd167758 Mon Sep 17 00:00:00 2001 From: agent Date: Sun, 27 Sep 2026 21:31:12 +0000 Subject: [PATCH] Add background grid settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Appearance now has a toggle for the background grid and a choice of subdivisions (none, 2×2 up to 16×16) that split each page-sized cell into fainter lines. Subdivisions are left out when zoomed so far out that they would be under 8 px apart. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GaoZtJQZwLXkEgWs8twCia --- src/app.css | 2 ++ src/lib/components/CanvasView.svelte | 28 ++++++++++++++++++------- src/lib/components/SettingsModal.svelte | 14 +++++++++++++ src/lib/state/settings.svelte.ts | 9 ++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/app.css b/src/app.css index 76440c5..912d602 100644 --- a/src/app.css +++ b/src/app.css @@ -61,6 +61,7 @@ --shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 16px rgba(0, 0, 0, 0.08); --page-line: rgba(0, 0, 0, 0.18); --grid-line: rgba(0, 0, 0, 0.05); + --grid-line-minor: rgba(0, 0, 0, 0.028); --ghost: rgba(0, 0, 0, 0.045); --ghost-border: rgba(0, 0, 0, 0.12); --radius: 6px; @@ -88,6 +89,7 @@ --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35); --page-line: rgba(255, 255, 255, 0.16); --grid-line: rgba(255, 255, 255, 0.04); + --grid-line-minor: rgba(255, 255, 255, 0.022); --ghost: rgba(255, 255, 255, 0.04); --ghost-border: rgba(255, 255, 255, 0.14); color-scheme: dark; diff --git a/src/lib/components/CanvasView.svelte b/src/lib/components/CanvasView.svelte index 5b2b27f..4746268 100644 --- a/src/lib/components/CanvasView.svelte +++ b/src/lib/components/CanvasView.svelte @@ -30,11 +30,28 @@ let stage: HTMLDivElement; const cssVars = pageCssVars(); - // Background grid: one cell per active page, aligned to its edges (A4 at the origin if none). - const grid = $derived.by(() => { + // Background grid: one cell per active page, aligned to its edges (A4 at the origin if none), + // optionally split into fainter subdivisions. + const gridStyle = $derived.by(() => { + const g = settings.data.grid; + if (!g.show) return ''; const r = (doc.activeId && doc.rects.get(doc.activeId)) || { x: 0, y: 0, ...A4 }; const s = viewport.scale; - return { w: r.width * s, h: r.height * s, x: viewport.x + r.x * s, y: viewport.y + r.y * s }; + const w = r.width * s; + const h = r.height * s; + const lines = (color: string) => [ + `linear-gradient(to right, ${color} 1px, transparent 1px)`, + `linear-gradient(to bottom, ${color} 1px, transparent 1px)` + ]; + const images = lines('var(--grid-line)'); + const sizes = [`${w}px ${h}px`, `${w}px ${h}px`]; + // Leave out subdivisions once they'd be too dense to read. + const n = g.divisions; + if (n > 1 && Math.min(w, h) / n >= 8) { + images.push(...lines('var(--grid-line-minor)')); + sizes.push(`${w / n}px ${h / n}px`, `${w / n}px ${h / n}px`); + } + return `background-image: ${images.join(', ')}; background-size: ${sizes.join(', ')}; background-position: ${viewport.x + r.x * s}px ${viewport.y + r.y * s}px`; }); // ---- autosave -------------------------------------------------------- @@ -605,7 +622,7 @@ class:panning class:erasing={tools.tool === 'eraser'} bind:this={stage} - style="background-size: {grid.w}px {grid.h}px; background-position: {grid.x}px {grid.y}px" + style={gridStyle} onpointerdown={onPointerDown} onpointermove={onPointerMove} onpointerup={onPointerUp} @@ -760,9 +777,6 @@ user-select: none; -webkit-user-select: none; background-color: var(--bg-canvas); - background-image: - linear-gradient(to right, var(--grid-line) 1px, transparent 1px), - linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px); } .stage :global(.cm-content) { user-select: text; diff --git a/src/lib/components/SettingsModal.svelte b/src/lib/components/SettingsModal.svelte index 6b92676..9c8f886 100644 --- a/src/lib/components/SettingsModal.svelte +++ b/src/lib/components/SettingsModal.svelte @@ -83,6 +83,20 @@ +
+
Background grid
Faint lines behind the pages, one cell per active page.
+ +
+
+
Grid subdivisions
Split each page-sized cell into a finer grid for sketching and lining things up.
+ +
{:else if tab === 'input'}

Pen & touch

diff --git a/src/lib/state/settings.svelte.ts b/src/lib/state/settings.svelte.ts index 4fa5724..92cee0b 100644 --- a/src/lib/state/settings.svelte.ts +++ b/src/lib/state/settings.svelte.ts @@ -6,6 +6,12 @@ import { DEFAULT_PALM, type PalmOptions } from '$lib/ink/palm'; export type ThemePref = 'system' | 'light' | 'dark'; export type PageStylePref = 'paper' | 'match'; +export interface GridSettings { + show: boolean; + /** Minor lines per page cell side (1 = page-sized cells only). */ + divisions: number; +} + export interface GitHubSettings { token: string; owner: string; @@ -18,6 +24,7 @@ export interface GitHubSettings { interface SettingsData { theme: ThemePref; pageStyle: PageStylePref; + grid: GridSettings; fingerDraw: boolean; palm: PalmOptions; github: GitHubSettings; @@ -30,6 +37,7 @@ interface SettingsData { const DEFAULTS: SettingsData = { theme: 'system', pageStyle: 'match', + grid: { show: true, divisions: 1 }, fingerDraw: true, palm: DEFAULT_PALM, github: { token: '', owner: '', repo: '', branch: 'main', dir: '' }, @@ -48,6 +56,7 @@ function load(): SettingsData { return { ...DEFAULTS, ...saved, + grid: { ...DEFAULTS.grid, ...saved.grid }, palm: { ...DEFAULTS.palm, ...saved.palm }, github: { ...DEFAULTS.github, ...saved.github } };