web based infinite canvas

docs: README content

* added theme variables

+368 -3
+1
.markdownlint.json
··· 1 + { "MD033": false, "MD013": false, "MD024": false }
+181
README.md
··· 1 + # INKFINITE 2 + 3 + An infinite canvas whiteboard application for creative visual thinking and collaboration. 4 + 5 + ## Overview 6 + 7 + Inkfinite is a web-based infinite canvas application. 8 + 9 + ## Architecture 10 + 11 + Inkfinite is built with a reactive architecture and optimized canvas rendering. 12 + There are pan, zoom, and shape manipulation tools. 13 + 14 + The project is organized as a pnpm monorepo with the following structure: 15 + 16 + ```sh 17 + . 18 + ├── packages/ 19 + │ ├── core/ # Core logic and state management 20 + │ └── renderer/ # Canvas rendering engine 21 + └── apps/ 22 + └── web/ # SvelteKit web application 23 + ``` 24 + 25 + ## Packages 26 + 27 + <details> 28 + <summary><code>packages/core</code></summary> 29 + 30 + ### Modules 31 + 32 + - **Math** (`math.ts`) - Vector mathematics and geometric operations 33 + - `Vec2`: 2D vector operations (add, subtract, scale, normalize, distance, etc.) 34 + - `Mat3`: 3x3 transformation matrices for 2D transforms 35 + - `Box2`: Axis-aligned bounding boxes 36 + 37 + - **Camera** (`camera.ts`) - Viewport and coordinate system transforms 38 + - World ↔ screen coordinate conversions 39 + - Pan and zoom operations 40 + - Camera state management 41 + 42 + - **Geometry** (`geom.ts`) - Shape hit testing and spatial queries 43 + - Point-in-shape testing 44 + - Bounding box calculations 45 + - Shape picking/selection 46 + 47 + - **Reactivity** (`reactivity.ts`) - Observable state management 48 + - RxJS-based reactive store 49 + - State subscription and updates 50 + - Computed values and derived state 51 + 52 + - **Model** (`model.ts`) - Data structures and types 53 + - Shape definitions (rect, ellipse, line, arrow, text) 54 + - Editor state 55 + - Page management 56 + 57 + - **Actions** (`actions.ts`) - User input event system 58 + - Input event normalization 59 + - Pointer, keyboard, and wheel events 60 + - Coordinate space conversions 61 + 62 + </details> 63 + 64 + <details> 65 + <summary><code>packages/renderer</code></summary> 66 + 67 + High-performance canvas renderer with: 68 + 69 + - Reactive Rendering: Subscribes to state changes and efficiently redraws 70 + - Optimized Drawing: Uses requestAnimationFrame with dirty flag pattern 71 + - HiDPI Support: Automatic pixel ratio scaling for crisp rendering 72 + - Camera Transforms: Applies world-to-screen transformations 73 + - Shape Rendering: Draws all shape types (rect, ellipse, line, arrow, text) 74 + - Selection Visualization: Highlights selected shapes with dashed outlines 75 + - Text Wrapping: Automatic text layout within bounded areas 76 + 77 + </details> 78 + 79 + <details> 80 + <summary><code>apps/web</code></summary> 81 + 82 + SvelteKit-based web application providing the user interface. 83 + 84 + ### Tech Stack 85 + 86 + - **Testing:** Vitest with Playwright (browser tests) and Node (unit tests) 87 + 88 + ### Development 89 + 90 + ```bash 91 + pnpm dev # Start development server 92 + pnpm build # Build for production 93 + pnpm test # Run tests 94 + ``` 95 + 96 + </details> 97 + 98 + ## Development 99 + 100 + ### Prerequisites 101 + 102 + - Node.js 18+ 103 + - pnpm 8+ 104 + 105 + ### Setup 106 + 107 + ```bash 108 + # Install dependencies 109 + pnpm install 110 + 111 + # Run tests 112 + pnpm test 113 + 114 + # Build all packages 115 + pnpm build 116 + 117 + # Start web app in development 118 + cd apps/web 119 + pnpm dev 120 + ``` 121 + 122 + <details> 123 + <summary> 124 + Project Structure 125 + </summary> 126 + 127 + ```sh 128 + . 129 + ├── packages/ 130 + │ ├── core/ 131 + │ │ ├── src/ 132 + │ │ │ ├── math.ts # Vector and matrix math 133 + │ │ │ ├── camera.ts # Camera transforms 134 + │ │ │ ├── geom.ts # Geometry utilities 135 + │ │ │ ├── model.ts # Data structures 136 + │ │ │ ├── reactivity.ts # State management 137 + │ │ │ └── actions.ts # Input system 138 + │ │ └── package.json 139 + │ └── renderer/ 140 + │ ├── src/ 141 + │ │ └── index.ts # Canvas renderer 142 + │ └── package.json 143 + └── apps/ 144 + └── web/ 145 + ├── src/ 146 + │ ├── routes/ # SvelteKit routes 147 + │ └── lib/ # Svelte components 148 + └── package.json 149 + ``` 150 + 151 + </details> 152 + 153 + <details> 154 + <summary> 155 + Design Principles 156 + </summary> 157 + 158 + ### Code Organization 159 + 160 + - **Namespace pattern** - Types and operations co-located (e.g., `Vec2` type + `Vec2.add()` function) 161 + - **Pure functions** - Immutable operations, no side effects 162 + - **Type safety** - Full TypeScript coverage with strict mode 163 + 164 + ### Coordinate Systems 165 + 166 + - **World space** - Infinite 2D plane for shape coordinates 167 + - **Screen space** - Viewport pixels, origin at top-left 168 + - **Camera** - Mediates between world and screen coordinates 169 + 170 + </details> 171 + 172 + <details> 173 + <summary> 174 + Theme 175 + </summary> 176 + 177 + - **Light:** Nord color palette 178 + - **Dark:** Iceberg.vim color palette 179 + - **Font:** Space Grotesk 180 + 181 + </details>
-3
README.txt
··· 1 - ----------------------------------------------------------------------------- 2 - INKFINITE 3 - -----------------------------------------------------------------------------
+186
apps/web/src/app.css
··· 1 + @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap'); 2 + 3 + /* Light Theme - Nord */ 4 + :root { 5 + /* Polar Night - backgrounds */ 6 + --bg-primary: #eceff4; 7 + --bg-secondary: #e5e9f0; 8 + --bg-tertiary: #d8dee9; 9 + 10 + /* Snow Storm - foreground/text */ 11 + --fg-primary: #2e3440; 12 + --fg-secondary: #3b4252; 13 + --fg-tertiary: #434c5e; 14 + --fg-muted: #4c566a; 15 + 16 + /* Frost - accent colors */ 17 + --accent-cyan: #8fbcbb; 18 + --accent-blue-bright: #88c0d0; 19 + --accent-blue: #81a1c1; 20 + --accent-blue-dark: #5e81ac; 21 + 22 + /* Aurora - semantic colors */ 23 + --color-error: #bf616a; 24 + --color-warning: #d08770; 25 + --color-info: #ebcb8b; 26 + --color-success: #a3be8c; 27 + --color-purple: #b48ead; 28 + 29 + /* Semantic UI colors */ 30 + --surface: var(--bg-primary); 31 + --surface-elevated: var(--bg-secondary); 32 + --surface-overlay: var(--bg-tertiary); 33 + --text: var(--fg-primary); 34 + --text-secondary: var(--fg-secondary); 35 + --text-muted: var(--fg-muted); 36 + --border: var(--fg-tertiary); 37 + --accent: var(--accent-blue); 38 + --accent-hover: var(--accent-blue-dark); 39 + } 40 + 41 + /* Dark Theme - Iceberg */ 42 + @media (prefers-color-scheme: dark) { 43 + :root { 44 + /* Backgrounds */ 45 + --bg-primary: #161821; 46 + --bg-secondary: #1e2132; 47 + --bg-tertiary: #272c42; 48 + 49 + /* Foreground/text */ 50 + --fg-primary: #c6c8d1; 51 + --fg-secondary: #89b8c2; 52 + --fg-tertiary: #84a0c6; 53 + --fg-muted: #6b7089; 54 + 55 + /* Accents */ 56 + --accent-purple: #a093c7; 57 + --accent-cyan: #89b8c2; 58 + --accent-blue: #84a0c6; 59 + --accent-search: #e4aa80; 60 + 61 + /* Semantic colors */ 62 + --color-error: #e27878; 63 + --color-warning: #e2a478; 64 + --color-success: #b4be82; 65 + --color-info: #e4aa80; 66 + --color-purple: #a093c7; 67 + 68 + /* UI elements */ 69 + --line-numbers: #444b71; 70 + --selection: #272c42; 71 + 72 + /* Semantic UI colors */ 73 + --surface: var(--bg-primary); 74 + --surface-elevated: var(--bg-secondary); 75 + --surface-overlay: var(--bg-tertiary); 76 + --text: var(--fg-primary); 77 + --text-secondary: var(--fg-secondary); 78 + --text-muted: var(--fg-muted); 79 + --border: var(--line-numbers); 80 + --accent: var(--accent-blue); 81 + --accent-hover: var(--accent-cyan); 82 + } 83 + } 84 + 85 + /* Manual theme override classes */ 86 + [data-theme='light'] { 87 + /* Polar Night - backgrounds */ 88 + --bg-primary: #eceff4; 89 + --bg-secondary: #e5e9f0; 90 + --bg-tertiary: #d8dee9; 91 + 92 + /* Snow Storm - foreground/text */ 93 + --fg-primary: #2e3440; 94 + --fg-secondary: #3b4252; 95 + --fg-tertiary: #434c5e; 96 + --fg-muted: #4c566a; 97 + 98 + /* Frost - accent colors */ 99 + --accent-cyan: #8fbcbb; 100 + --accent-blue-bright: #88c0d0; 101 + --accent-blue: #81a1c1; 102 + --accent-blue-dark: #5e81ac; 103 + 104 + /* Aurora - semantic colors */ 105 + --color-error: #bf616a; 106 + --color-warning: #d08770; 107 + --color-info: #ebcb8b; 108 + --color-success: #a3be8c; 109 + --color-purple: #b48ead; 110 + 111 + /* Semantic UI colors */ 112 + --surface: var(--bg-primary); 113 + --surface-elevated: var(--bg-secondary); 114 + --surface-overlay: var(--bg-tertiary); 115 + --text: var(--fg-primary); 116 + --text-secondary: var(--fg-secondary); 117 + --text-muted: var(--fg-muted); 118 + --border: var(--fg-tertiary); 119 + --accent: var(--accent-blue); 120 + --accent-hover: var(--accent-blue-dark); 121 + } 122 + 123 + [data-theme='dark'] { 124 + /* Backgrounds */ 125 + --bg-primary: #161821; 126 + --bg-secondary: #1e2132; 127 + --bg-tertiary: #272c42; 128 + 129 + /* Foreground/text */ 130 + --fg-primary: #c6c8d1; 131 + --fg-secondary: #89b8c2; 132 + --fg-tertiary: #84a0c6; 133 + --fg-muted: #6b7089; 134 + 135 + /* Accents */ 136 + --accent-purple: #a093c7; 137 + --accent-cyan: #89b8c2; 138 + --accent-blue: #84a0c6; 139 + --accent-search: #e4aa80; 140 + 141 + /* Semantic colors */ 142 + --color-error: #e27878; 143 + --color-warning: #e2a478; 144 + --color-success: #b4be82; 145 + --color-info: #e4aa80; 146 + --color-purple: #a093c7; 147 + 148 + /* UI elements */ 149 + --line-numbers: #444b71; 150 + --selection: #272c42; 151 + 152 + /* Semantic UI colors */ 153 + --surface: var(--bg-primary); 154 + --surface-elevated: var(--bg-secondary); 155 + --surface-overlay: var(--bg-tertiary); 156 + --text: var(--fg-primary); 157 + --text-secondary: var(--fg-secondary); 158 + --text-muted: var(--fg-muted); 159 + --border: var(--line-numbers); 160 + --accent: var(--accent-blue); 161 + --accent-hover: var(--accent-cyan); 162 + } 163 + 164 + /* Base styles */ 165 + * { 166 + margin: 0; 167 + padding: 0; 168 + box-sizing: border-box; 169 + } 170 + 171 + body { 172 + font-family: 173 + 'Space Grotesk', 174 + -apple-system, 175 + BlinkMacSystemFont, 176 + 'Segoe UI', 177 + sans-serif; 178 + background-color: var(--surface); 179 + color: var(--text); 180 + line-height: 1.6; 181 + } 182 + 183 + ::selection { 184 + background-color: var(--accent); 185 + color: var(--surface); 186 + }