htmlboard 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +289 -2
- package/bin/htmlboard.js +297 -0
- package/package.json +48 -4
- package/skills/htmlboard/SKILL.md +95 -0
- package/src/client/explorer.css +703 -0
- package/src/client/explorer.js +693 -0
- package/src/client/index.html +191 -0
- package/src/index.js +20 -0
- package/src/server.js +451 -0
- package/src/skills.js +116 -0
- package/src/templates/artboards/components.html +199 -0
- package/src/templates/artboards/desktop.html +397 -0
- package/src/templates/artboards/mobile.html +383 -0
- package/src/templates/designs.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HtmlBoard Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,290 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ✦ HtmlBoard
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Infinite canvas and design explorer for HTML artboards — designed for humans and LLMs.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/htmlboard)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](package.json)
|
|
9
|
+
|
|
10
|
+
**HtmlBoard** turns any folder of HTML files into a Figma-like interactive infinite canvas. Inspect responsive variants, mobile and desktop layouts, design system components, and full application flows side-by-side with instant live reload.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 💡 Why HtmlBoard?
|
|
15
|
+
|
|
16
|
+
Modern AI agents and developers generate dozens of HTML mockups, layout variations, and prototypes in seconds. But previewing them has always been awkward:
|
|
17
|
+
- **Tabs upon tabs:** Flipping between dozens of browser tabs breaks context and comparison.
|
|
18
|
+
- **Figma is locked down:** Exporting code into proprietary design tools is slow and out of sync.
|
|
19
|
+
- **Traditional dev servers only show one page:** You lose the holistic bird's-eye view of your product's flow.
|
|
20
|
+
|
|
21
|
+
**HtmlBoard bridges this gap.** It gives you an infinite 2D canvas for HTML artboards — zero config, zero external dependencies, blazing fast, and purpose-built for AI-driven frontend prototyping.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ✨ Features
|
|
26
|
+
|
|
27
|
+
- 🛸 **Infinite Canvas**: Smoothly pan, zoom (from 5% to 300%), and fly across dozens of artboards with trackpad or mouse.
|
|
28
|
+
- ⚡ **Zero Dependencies**: Pure native Node.js ES modules. Runs instantly with `npx htmlboard` without installing heavy packages.
|
|
29
|
+
- 🔄 **State-Preserving Live Reload**: Automatically watches files via Server-Sent Events (SSE). When you or an LLM edit an HTML file, the corresponding artboard updates instantly without resetting your canvas pan/zoom position; editing a shared CSS, script or image reloads them all.
|
|
30
|
+
- 🔍 **Auto-Discovery**: Point HtmlBoard at any folder. It automatically discovers all HTML files, extracts their titles, classifies them by device type, and renders them onto the canvas.
|
|
31
|
+
- 📐 **Declarative Manifest (`designs.json`)**: Optional structured schema to organize artboards into sections, define custom viewports (iPhone, iPad, MacBook, 4K), and attach metadata.
|
|
32
|
+
- 📱 **Multi-Device Categories**: One-click filters for Mobile (390×844), Desktop (1280×820), Tablet (768×1024), and Component kits.
|
|
33
|
+
- 🎯 **Focus & Zoom-to-Fit**: Instantly center any artboard with a click in the sidebar, or hit <kbd>F</kbd> to fit all designs on screen.
|
|
34
|
+
- 🔗 **Deep Links**: The URL follows the focused artboard (`http://localhost:3000/#checkout-b`), so you can share or reload a view of one design.
|
|
35
|
+
- ⌨️ **Keyboard-First Workflow**: Full suite of intuitive shortcuts matching design industry standards.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🚀 Quick Start
|
|
40
|
+
|
|
41
|
+
Run instantly in any project containing HTML files:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx htmlboard
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or install globally:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install -g htmlboard
|
|
51
|
+
htmlboard
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Scaffold a Starter Project
|
|
55
|
+
|
|
56
|
+
To create a new workspace with starter templates (mobile screen, desktop dashboard, and component library):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx htmlboard --init
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🛠️ CLI Usage
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Usage:
|
|
68
|
+
htmlboard [directory] [options]
|
|
69
|
+
npx htmlboard [directory] [options]
|
|
70
|
+
htmlboard skills <install|uninstall> [options] Teach your AI agent to use HtmlBoard
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
-p, --port <number> Port to listen on (default: 3000)
|
|
74
|
+
-d, --dir <path> Directory to serve HTML artboards from (default: .)
|
|
75
|
+
-r, --root <path> Serve files from this parent folder, so artboards can link to
|
|
76
|
+
shared files outside the designs folder (default: the designs folder)
|
|
77
|
+
-o, --open Open the explorer automatically in default browser
|
|
78
|
+
--init Scaffold starter designs.json and sample artboards
|
|
79
|
+
-v, --version Display HtmlBoard version
|
|
80
|
+
-h, --help Display help message
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Examples
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Serve current directory on port 3000
|
|
87
|
+
htmlboard
|
|
88
|
+
|
|
89
|
+
# Open in browser automatically
|
|
90
|
+
htmlboard --open
|
|
91
|
+
|
|
92
|
+
# Serve a specific designs directory on port 8080
|
|
93
|
+
htmlboard ./src/designs -p 8080
|
|
94
|
+
|
|
95
|
+
# Artboards in ./design that link to the site's own ../css and ../js
|
|
96
|
+
htmlboard design --root .
|
|
97
|
+
|
|
98
|
+
# Initialize sample templates in a new folder
|
|
99
|
+
htmlboard ./my-new-ui --init --open
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 🤖 Working with LLMs (AI-Assisted Prototyping)
|
|
105
|
+
|
|
106
|
+
HtmlBoard is built from the ground up to pair with AI coding agents (Claude, Gemini, Codex, ChatGPT, Antigravity, Cursor).
|
|
107
|
+
|
|
108
|
+
### Install the agent skill
|
|
109
|
+
|
|
110
|
+
HtmlBoard ships an [Agent Skill](https://agentskills.io) that teaches your agent how to use it: where to put artboards, how to size and name them, how `designs.json` works and how to start the canvas. Install it in your project:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npx htmlboard skills install
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This writes `.claude/skills/htmlboard/` (Claude Code) and `.agents/skills/htmlboard/` (Codex and other agents that read `.agents/skills`). Commit them so everyone working on the project gets the skill. Then start a new agent session and just ask for a design.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx htmlboard skills install --global # for your user (~/.claude/skills, ~/.agents/skills), all projects
|
|
120
|
+
npx htmlboard skills install --agent claude # only one agent: claude | agents | all (default)
|
|
121
|
+
npx htmlboard skills install --force # update a copy you edited locally
|
|
122
|
+
npx htmlboard skills uninstall # remove it (accepts the same --global / --agent)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Running `install` again after upgrading HtmlBoard updates the skill; a copy you edited is kept unless you pass `--force`.
|
|
126
|
+
|
|
127
|
+
### The workflow
|
|
128
|
+
|
|
129
|
+
1. **Ask your LLM to generate artboards:**
|
|
130
|
+
> *"Create 3 design explorations for our checkout flow in `artboards/checkout-v1.html`, `artboards/checkout-v2.html`, and `artboards/checkout-v3.html`."*
|
|
131
|
+
|
|
132
|
+
2. **Run HtmlBoard in the background:**
|
|
133
|
+
```bash
|
|
134
|
+
npx htmlboard
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
3. **Watch the canvas update live:**
|
|
138
|
+
As the LLM writes or refines each HTML file, HtmlBoard detects the file change and reloads the iframe on the canvas immediately. You never have to refresh your browser or hunt for file URLs.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 📋 The `designs.json` Manifest
|
|
143
|
+
|
|
144
|
+
While HtmlBoard automatically discovers HTML files, you can add a `designs.json` file in your designs folder for custom layout and organization. Only `sections[].designs[].file` is required; the short form is enough:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"sections": [
|
|
149
|
+
{
|
|
150
|
+
"title": "Home",
|
|
151
|
+
"designs": [
|
|
152
|
+
{ "file": "home-mobile.html", "title": "Home · phone", "width": 390, "height": 844 },
|
|
153
|
+
{ "file": "home-mobile.html?theme=dark", "title": "Home · phone · dark", "width": 390, "height": 844 },
|
|
154
|
+
{ "file": "home-desktop.html", "title": "Home · desktop", "width": 1440 }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Sections are rows (top to bottom) and designs run left to right. A `file` may carry a query string, so one HTML file can show several states. Leave `height` out to let the frame grow with its page. `id` and `category` are derived from the file when left out.
|
|
162
|
+
|
|
163
|
+
The full form adds ids, descriptions, categories (for the toolbar filters) and searchable tags (`name`/`artboards` are synonyms of `title`/`designs`):
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"title": "Fintech Mobile & Web App",
|
|
168
|
+
"description": "Exploration of screen flows, responsive layouts, and UI components",
|
|
169
|
+
"sections": [
|
|
170
|
+
{
|
|
171
|
+
"id": "screens",
|
|
172
|
+
"name": "Screen Layouts",
|
|
173
|
+
"description": "Full page layouts across mobile and desktop viewports",
|
|
174
|
+
"artboards": [
|
|
175
|
+
{
|
|
176
|
+
"id": "desktop-dashboard",
|
|
177
|
+
"title": "Desktop Dashboard",
|
|
178
|
+
"file": "artboards/desktop.html",
|
|
179
|
+
"width": 1280,
|
|
180
|
+
"height": 820,
|
|
181
|
+
"category": "desktop",
|
|
182
|
+
"tags": ["desktop", "dashboard", "analytics"]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "mobile-app",
|
|
186
|
+
"title": "Mobile App Feed",
|
|
187
|
+
"file": "artboards/mobile.html",
|
|
188
|
+
"width": 390,
|
|
189
|
+
"height": 844,
|
|
190
|
+
"category": "mobile",
|
|
191
|
+
"tags": ["mobile", "ios", "finance"]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"id": "components",
|
|
197
|
+
"name": "Component Library",
|
|
198
|
+
"artboards": [
|
|
199
|
+
{
|
|
200
|
+
"id": "ui-primitives",
|
|
201
|
+
"title": "UI Kit Elements",
|
|
202
|
+
"file": "artboards/components.html",
|
|
203
|
+
"width": 780,
|
|
204
|
+
"height": 720,
|
|
205
|
+
"category": "components",
|
|
206
|
+
"tags": ["design-system", "buttons", "inputs"]
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## ⌨️ Keyboard Shortcuts
|
|
217
|
+
|
|
218
|
+
| Shortcut | Action |
|
|
219
|
+
| :--- | :--- |
|
|
220
|
+
| <kbd>Space</kbd> + <kbd>Drag</kbd> | Pan the canvas freely |
|
|
221
|
+
| <kbd>Ctrl</kbd> / <kbd>⌘</kbd> + <kbd>Wheel</kbd> | Zoom in/out anchored to cursor |
|
|
222
|
+
| <kbd>+</kbd> / <kbd>-</kbd> | Zoom in / Zoom out |
|
|
223
|
+
| <kbd>0</kbd> | Reset zoom to 100% |
|
|
224
|
+
| <kbd>F</kbd> or <kbd>Shift</kbd> + <kbd>1</kbd> | Fit all artboards in viewport |
|
|
225
|
+
| <kbd>/</kbd> or <kbd>⌘</kbd> + <kbd>K</kbd> | Search artboards by title, tag, or path |
|
|
226
|
+
| <kbd>[</kbd> or <kbd>]</kbd> | Toggle navigation sidebar |
|
|
227
|
+
| <kbd>1</kbd> – <kbd>5</kbd> | Quick filter by device category |
|
|
228
|
+
| <kbd>?</kbd> | Show keyboard shortcuts modal |
|
|
229
|
+
| <kbd>Esc</kbd> | Close modals or blur search |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 🔌 Programmatic API
|
|
234
|
+
|
|
235
|
+
You can also embed HtmlBoard into your own build tools, testing pipelines, or dev environments:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
import { startServer } from 'htmlboard';
|
|
239
|
+
|
|
240
|
+
const instance = await startServer({
|
|
241
|
+
dir: './designs',
|
|
242
|
+
port: 3000
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
console.log(`HtmlBoard running at ${instance.url}`);
|
|
246
|
+
|
|
247
|
+
// Later, when done:
|
|
248
|
+
// await instance.close();
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The skill installer is exported too:
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
import { installSkills } from 'htmlboard';
|
|
255
|
+
|
|
256
|
+
installSkills({ dir: process.cwd(), agent: 'all' });
|
|
257
|
+
// → [{ skill: 'htmlboard', path: '…/.claude/skills/htmlboard', status: 'installed' }, …]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 📂 Project Structure
|
|
263
|
+
|
|
264
|
+
```text
|
|
265
|
+
htmlboard/
|
|
266
|
+
├── bin/
|
|
267
|
+
│ └── htmlboard.js # CLI executable
|
|
268
|
+
├── src/
|
|
269
|
+
│ ├── index.js # Library entry point & API exports
|
|
270
|
+
│ ├── server.js # HTTP server, SSE live reload, auto-discovery
|
|
271
|
+
│ ├── skills.js # `htmlboard skills` installer
|
|
272
|
+
│ ├── client/ # The infinite canvas frontend
|
|
273
|
+
│ │ ├── index.html # Explorer shell & canvas DOM
|
|
274
|
+
│ │ ├── explorer.css # Dark theme styles & canvas grid
|
|
275
|
+
│ │ └── explorer.js # Pan/zoom engine, SSE listener, auto-measure
|
|
276
|
+
│ └── templates/ # Starter scaffold templates
|
|
277
|
+
│ ├── designs.json # Starter manifest
|
|
278
|
+
│ └── artboards/ # Sample mobile, desktop, & component screens
|
|
279
|
+
├── skills/
|
|
280
|
+
│ └── htmlboard/ # Agent skill (SKILL.md) copied by `htmlboard skills install`
|
|
281
|
+
├── package.json
|
|
282
|
+
├── README.md
|
|
283
|
+
└── LICENSE
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 📄 License
|
|
289
|
+
|
|
290
|
+
MIT © Luiz Carlos & Contributors
|
package/bin/htmlboard.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { exec } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { startServer } from '../src/server.js';
|
|
8
|
+
import { installSkills, uninstallSkills } from '../src/skills.js';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const PKG_PATH = path.join(__dirname, '..', 'package.json');
|
|
13
|
+
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
|
|
14
|
+
|
|
15
|
+
// Parse command line arguments
|
|
16
|
+
function parseArgs(args) {
|
|
17
|
+
const options = {
|
|
18
|
+
port: 3000,
|
|
19
|
+
dir: process.cwd(),
|
|
20
|
+
root: null,
|
|
21
|
+
open: false,
|
|
22
|
+
init: false,
|
|
23
|
+
help: false,
|
|
24
|
+
version: false
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < args.length; i++) {
|
|
28
|
+
const arg = args[i];
|
|
29
|
+
|
|
30
|
+
if (arg === '--help' || arg === '-h') {
|
|
31
|
+
options.help = true;
|
|
32
|
+
} else if (arg === '--version' || arg === '-v') {
|
|
33
|
+
options.version = true;
|
|
34
|
+
} else if (arg === '--open' || arg === '-o') {
|
|
35
|
+
options.open = true;
|
|
36
|
+
} else if (arg === '--init') {
|
|
37
|
+
options.init = true;
|
|
38
|
+
} else if (arg === '--port' || arg === '-p') {
|
|
39
|
+
const next = args[++i];
|
|
40
|
+
if (next && !next.startsWith('-')) {
|
|
41
|
+
options.port = parseInt(next, 10);
|
|
42
|
+
}
|
|
43
|
+
} else if (arg.startsWith('--port=')) {
|
|
44
|
+
options.port = parseInt(arg.split('=')[1], 10);
|
|
45
|
+
} else if (arg === '--dir' || arg === '-d') {
|
|
46
|
+
const next = args[++i];
|
|
47
|
+
if (next && !next.startsWith('-')) {
|
|
48
|
+
options.dir = next;
|
|
49
|
+
}
|
|
50
|
+
} else if (arg.startsWith('--dir=')) {
|
|
51
|
+
options.dir = arg.split('=')[1];
|
|
52
|
+
} else if (arg === '--root' || arg === '-r') {
|
|
53
|
+
const next = args[++i];
|
|
54
|
+
if (next && !next.startsWith('-')) {
|
|
55
|
+
options.root = next;
|
|
56
|
+
}
|
|
57
|
+
} else if (arg.startsWith('--root=')) {
|
|
58
|
+
options.root = arg.split('=')[1];
|
|
59
|
+
} else if (!arg.startsWith('-')) {
|
|
60
|
+
// Positional directory argument e.g. `htmlboard ./my-designs`
|
|
61
|
+
options.dir = arg;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return options;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function showHelp() {
|
|
69
|
+
console.log(`
|
|
70
|
+
HtmlBoard v${pkg.version}
|
|
71
|
+
Infinite canvas and design explorer for HTML artboards — designed for humans and LLMs
|
|
72
|
+
|
|
73
|
+
Usage:
|
|
74
|
+
htmlboard [directory] [options]
|
|
75
|
+
npx htmlboard [directory] [options]
|
|
76
|
+
htmlboard skills <install|uninstall> [options] Teach your AI agent to use HtmlBoard
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
-p, --port <number> Port to listen on (default: 3000)
|
|
80
|
+
-d, --dir <path> Directory to serve HTML artboards from (default: .)
|
|
81
|
+
-r, --root <path> Serve files from this parent folder, so artboards can link to
|
|
82
|
+
shared files outside the designs folder (default: the designs folder)
|
|
83
|
+
-o, --open Open the explorer automatically in your default browser
|
|
84
|
+
--init Scaffold starter designs.json and sample artboards in target directory
|
|
85
|
+
-v, --version Display HtmlBoard version
|
|
86
|
+
-h, --help Display this help message
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
htmlboard # Run in current directory on http://localhost:3000
|
|
90
|
+
htmlboard --open # Run and launch browser automatically
|
|
91
|
+
htmlboard ./designs -p 8080 # Serve ./designs on port 8080
|
|
92
|
+
htmlboard design --root . # Artboards in ./design that link to ../css/…
|
|
93
|
+
htmlboard --init # Initialize starter templates in current folder
|
|
94
|
+
htmlboard skills install # Add the HtmlBoard skill to this project's agents
|
|
95
|
+
|
|
96
|
+
Keyboard Shortcuts in Canvas:
|
|
97
|
+
Space + Drag Pan canvas
|
|
98
|
+
Ctrl/Cmd + Wheel Zoom into focal point
|
|
99
|
+
+ / - Zoom in / Zoom out
|
|
100
|
+
0 Reset zoom to 100%
|
|
101
|
+
F Zoom to fit all artboards
|
|
102
|
+
/ or Cmd+K Search artboards
|
|
103
|
+
[ or ] Toggle navigation sidebar
|
|
104
|
+
? Show shortcuts help dialog
|
|
105
|
+
`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function openBrowser(url) {
|
|
109
|
+
const startCmd = process.platform === 'darwin'
|
|
110
|
+
? 'open'
|
|
111
|
+
: process.platform === 'win32'
|
|
112
|
+
? 'start'
|
|
113
|
+
: 'xdg-open';
|
|
114
|
+
|
|
115
|
+
exec(`${startCmd} ${url}`, (err) => {
|
|
116
|
+
if (err) {
|
|
117
|
+
console.warn(`[htmlboard] Unable to auto-launch browser: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function scaffoldProject(targetDir) {
|
|
123
|
+
const templatesDir = path.join(__dirname, '..', 'src', 'templates');
|
|
124
|
+
const targetConfig = path.join(targetDir, 'designs.json');
|
|
125
|
+
const targetArtboardsDir = path.join(targetDir, 'artboards');
|
|
126
|
+
|
|
127
|
+
console.log(`[htmlboard] Scaffolding starter project in ${targetDir}...`);
|
|
128
|
+
|
|
129
|
+
if (!fs.existsSync(targetDir)) {
|
|
130
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!fs.existsSync(targetArtboardsDir)) {
|
|
134
|
+
fs.mkdirSync(targetArtboardsDir, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Copy designs.json if not present
|
|
138
|
+
if (!fs.existsSync(targetConfig)) {
|
|
139
|
+
const srcConfig = path.join(templatesDir, 'designs.json');
|
|
140
|
+
if (fs.existsSync(srcConfig)) {
|
|
141
|
+
fs.copyFileSync(srcConfig, targetConfig);
|
|
142
|
+
console.log(` ✓ Created designs.json`);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
console.log(` ℹ designs.json already exists (skipped)`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Copy starter artboards
|
|
149
|
+
const starterFiles = ['mobile.html', 'desktop.html', 'components.html'];
|
|
150
|
+
for (const file of starterFiles) {
|
|
151
|
+
const srcFile = path.join(templatesDir, 'artboards', file);
|
|
152
|
+
const destFile = path.join(targetArtboardsDir, file);
|
|
153
|
+
if (!fs.existsSync(destFile) && fs.existsSync(srcFile)) {
|
|
154
|
+
fs.copyFileSync(srcFile, destFile);
|
|
155
|
+
console.log(` ✓ Created artboards/${file}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(`\n🎉 Starter templates created successfully!`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function showSkillsHelp() {
|
|
163
|
+
console.log(`
|
|
164
|
+
Usage:
|
|
165
|
+
htmlboard skills install [options] Copy the HtmlBoard skill into your agents' skill folders
|
|
166
|
+
htmlboard skills uninstall [options] Remove it
|
|
167
|
+
|
|
168
|
+
Options:
|
|
169
|
+
-g, --global Install for your user (~/.claude/skills, ~/.agents/skills) instead of this project
|
|
170
|
+
-a, --agent <name> claude (.claude/skills), agents (.agents/skills: Codex and other agents), or all (default)
|
|
171
|
+
-d, --dir <path> Project root (default: current directory)
|
|
172
|
+
-f, --force Replace a skill that was changed locally
|
|
173
|
+
-h, --help Display this help message
|
|
174
|
+
`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function runSkills(args) {
|
|
178
|
+
const [action, ...rest] = args;
|
|
179
|
+
const options = { agent: 'all', global: false, dir: process.cwd(), force: false };
|
|
180
|
+
|
|
181
|
+
for (let i = 0; i < rest.length; i++) {
|
|
182
|
+
const arg = rest[i];
|
|
183
|
+
if (arg === '--global' || arg === '-g') options.global = true;
|
|
184
|
+
else if (arg === '--force' || arg === '-f') options.force = true;
|
|
185
|
+
else if (arg === '--agent' || arg === '-a') options.agent = rest[++i];
|
|
186
|
+
else if (arg.startsWith('--agent=')) options.agent = arg.split('=')[1];
|
|
187
|
+
else if (arg === '--dir' || arg === '-d') options.dir = rest[++i];
|
|
188
|
+
else if (arg.startsWith('--dir=')) options.dir = arg.split('=')[1];
|
|
189
|
+
else if (arg === '--help' || arg === '-h') return showSkillsHelp();
|
|
190
|
+
else {
|
|
191
|
+
console.error(`[htmlboard] Unknown option: ${arg}`);
|
|
192
|
+
showSkillsHelp();
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (action !== 'install' && action !== 'uninstall') {
|
|
198
|
+
showSkillsHelp();
|
|
199
|
+
process.exit(action && action !== '--help' && action !== '-h' ? 1 : 0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let results;
|
|
203
|
+
try {
|
|
204
|
+
results = action === 'install' ? installSkills(options) : uninstallSkills(options);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
console.error(`[htmlboard] ${err.message}`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const labels = {
|
|
211
|
+
installed: '\x1b[32m✓ installed\x1b[0m',
|
|
212
|
+
updated: '\x1b[32m✓ updated\x1b[0m',
|
|
213
|
+
unchanged: '\x1b[90m= up to date\x1b[0m',
|
|
214
|
+
skipped: '\x1b[33m! changed locally, kept (use --force to replace)\x1b[0m',
|
|
215
|
+
removed: '\x1b[32m✓ removed\x1b[0m',
|
|
216
|
+
absent: '\x1b[90m- not installed\x1b[0m'
|
|
217
|
+
};
|
|
218
|
+
for (const { path: dest, status } of results) {
|
|
219
|
+
console.log(` ${labels[status]} ${path.relative(process.cwd(), dest) || dest}`);
|
|
220
|
+
}
|
|
221
|
+
if (action === 'install' && results.some((r) => r.status === 'installed' || r.status === 'updated')) {
|
|
222
|
+
console.log(`\n Restart your agent session to load the skill, then ask it for a design.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function main() {
|
|
227
|
+
const args = process.argv.slice(2);
|
|
228
|
+
|
|
229
|
+
if (args[0] === 'skills') {
|
|
230
|
+
runSkills(args.slice(1));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const options = parseArgs(args);
|
|
235
|
+
|
|
236
|
+
if (options.help) {
|
|
237
|
+
showHelp();
|
|
238
|
+
process.exit(0);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (options.version) {
|
|
242
|
+
console.log(`htmlboard v${pkg.version}`);
|
|
243
|
+
process.exit(0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const targetDir = path.resolve(options.dir);
|
|
247
|
+
|
|
248
|
+
if (options.init) {
|
|
249
|
+
scaffoldProject(targetDir);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// If directory is empty, auto-prompt or auto-scaffold
|
|
253
|
+
let entries = [];
|
|
254
|
+
try {
|
|
255
|
+
entries = fs.readdirSync(targetDir);
|
|
256
|
+
} catch (_) {
|
|
257
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const hasHtml = entries.some((e) => e.endsWith('.html')) ||
|
|
261
|
+
(fs.existsSync(path.join(targetDir, 'artboards')) &&
|
|
262
|
+
fs.readdirSync(path.join(targetDir, 'artboards')).some((e) => e.endsWith('.html')));
|
|
263
|
+
const hasDesignsJson = fs.existsSync(path.join(targetDir, 'designs.json'));
|
|
264
|
+
|
|
265
|
+
if (!hasHtml && !hasDesignsJson && entries.filter((e) => !e.startsWith('.')).length === 0) {
|
|
266
|
+
console.log(`[htmlboard] Directory is empty. Initializing starter artboards...`);
|
|
267
|
+
scaffoldProject(targetDir);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const { url, rootDir } = await startServer({
|
|
272
|
+
dir: targetDir,
|
|
273
|
+
root: options.root ? path.resolve(options.root) : undefined,
|
|
274
|
+
port: options.port
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
console.log(`
|
|
278
|
+
✦ \x1b[1m\x1b[36mHtmlBoard\x1b[0m \x1b[90mv${pkg.version}\x1b[0m
|
|
279
|
+
\x1b[90mInfinite Canvas & Design Explorer for HTML Artboards\x1b[0m
|
|
280
|
+
|
|
281
|
+
\x1b[32m➜\x1b[0m \x1b[1mLocal:\x1b[0m \x1b[36m${url}\x1b[0m
|
|
282
|
+
\x1b[32m➜\x1b[0m \x1b[1mTarget:\x1b[0m \x1b[90m${targetDir}\x1b[0m${rootDir !== targetDir ? `\n \x1b[32m➜\x1b[0m \x1b[1mRoot:\x1b[0m \x1b[90m${rootDir}\x1b[0m` : ''}
|
|
283
|
+
\x1b[32m➜\x1b[0m \x1b[1mLive:\x1b[0m \x1b[32mWatching files for hot live reload\x1b[0m
|
|
284
|
+
|
|
285
|
+
\x1b[90mPress \x1b[1mCtrl+C\x1b[0m\x1b[90m to stop.\x1b[0m
|
|
286
|
+
`);
|
|
287
|
+
|
|
288
|
+
if (options.open) {
|
|
289
|
+
openBrowser(url);
|
|
290
|
+
}
|
|
291
|
+
} catch (err) {
|
|
292
|
+
console.error(`[htmlboard] Error starting server:`, err.message);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "htmlboard",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Infinite canvas and design explorer for HTML artboards — designed for humans and LLMs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"htmlboard": "bin/htmlboard.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./src/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"src",
|
|
13
|
+
"skills",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "node ./bin/htmlboard.js",
|
|
19
|
+
"dev": "node ./bin/htmlboard.js",
|
|
20
|
+
"test": "node --test"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"canvas",
|
|
24
|
+
"design",
|
|
25
|
+
"artboard",
|
|
26
|
+
"html",
|
|
27
|
+
"ui",
|
|
28
|
+
"explorer",
|
|
29
|
+
"infinite-canvas",
|
|
30
|
+
"llm",
|
|
31
|
+
"prototyping",
|
|
32
|
+
"live-reload",
|
|
33
|
+
"agent-skills",
|
|
34
|
+
"claude-code",
|
|
35
|
+
"codex"
|
|
36
|
+
],
|
|
37
|
+
"author": "Luiz Carlos (https://github.com/luizcarlos1405)",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/luizcarlos1405/htmlboard.git"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/luizcarlos1405/htmlboard#readme",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/luizcarlos1405/htmlboard/issues"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|