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