htmlboard 0.0.0-stage β†’ 0.2.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 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,307 @@
1
- # Temporary Holding Version
1
+ <h1>
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/luizcarlos1405/htmlboard/main/brand/logo-dark.svg">
4
+ <img alt="htmlboard" src="https://raw.githubusercontent.com/luizcarlos1405/htmlboard/main/brand/logo-light.svg" height="56">
5
+ </picture>
6
+ </h1>
2
7
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
8
+ > **Infinite canvas and design explorer for HTML artboards β€” designed for humans and LLMs.**
9
+
10
+ [![npm version](https://img.shields.io/npm/v/htmlboard.svg?style=flat-square&color=3D9DFF)](https://www.npmjs.com/package/htmlboard)
11
+ [![license](https://img.shields.io/npm/l/htmlboard.svg?style=flat-square&color=48484D)](LICENSE)
12
+ [![node version](https://img.shields.io/node/v/htmlboard.svg?style=flat-square)](https://nodejs.org)
13
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg?style=flat-square)](package.json)
14
+
15
+ **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.
16
+
17
+ ---
18
+
19
+ ## πŸ’‘ Why HtmlBoard?
20
+
21
+ Modern AI agents and developers generate dozens of HTML mockups, layout variations, and prototypes in seconds. But previewing them has always been awkward:
22
+ - **Tabs upon tabs:** Flipping between dozens of browser tabs breaks context and comparison.
23
+ - **Figma is locked down:** Exporting code into proprietary design tools is slow and out of sync.
24
+ - **Traditional dev servers only show one page:** You lose the holistic bird's-eye view of your product's flow.
25
+
26
+ **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.
27
+
28
+ ---
29
+
30
+ ## ✨ Features
31
+
32
+ - πŸ›Έ **Infinite Canvas**: Drag or scroll to move, <kbd>Ctrl</kbd>/<kbd>⌘</kbd> + scroll or pinch to zoom (2% to 800%), with a mouse, a trackpad or a touch screen. Names and section titles stay sharp at any zoom, and the dot grid keeps its spacing.
33
+ - ⚑ **Zero Dependencies**: Pure native Node.js ES modules, fonts included. Runs instantly with `npx htmlboard`, offline too.
34
+ - πŸ”„ **State-Preserving Live Reload**: The server watches the project and pushes every save (Server-Sent Events). Saving a design reloads its frame; saving a file designs use (a stylesheet, a script, an image, data) reloads just the designs that loaded it; new, removed and renamed designs show up by themselves. Your view never moves.
35
+ - πŸ” **Auto-Discovery**: Point HtmlBoard at any folder. It finds every HTML file, names it after its `<title>`, sizes it from words in its path (mobile, tablet, desktop…) and lays the folders out as rows.
36
+ - πŸ“ **Declarative Manifest (`designs.json`)**: Optional file to choose the sections, the order, the sizes and the names.
37
+ - πŸ”Ž **Search**: Find designs by name, file, tags or section (case and accents don't matter); the others fade out in place.
38
+ - 🎯 **Focus & Zoom-to-Fit**: Click a design in the list or double-click it on the canvas to fit it, <kbd>Shift</kbd> + <kbd>1</kbd> fits everything, <kbd>←</kbd> <kbd>β†’</kbd> step through the designs.
39
+ - πŸ”— **Deep Links**: The URL follows the selected design (`http://localhost:3000/#checkout-b`), so you can share or reload a view of one design.
40
+ - ⌨️ **Keyboard-First Workflow**: Figma-like shortcuts; <kbd>?</kbd> lists them.
41
+
42
+ ---
43
+
44
+ ## πŸš€ Quick Start
45
+
46
+ Run instantly in any project containing HTML files:
47
+
48
+ ```bash
49
+ npx htmlboard
50
+ ```
51
+
52
+ Or install globally:
53
+
54
+ ```bash
55
+ npm install -g htmlboard
56
+ htmlboard
57
+ ```
58
+
59
+ ### Scaffold a Starter Project
60
+
61
+ To create a new workspace with starter templates (mobile screen, desktop dashboard, and component library):
62
+
63
+ ```bash
64
+ npx htmlboard --init
65
+ ```
66
+
67
+ ---
68
+
69
+ ## πŸ› οΈ CLI Usage
70
+
71
+ ```text
72
+ Usage:
73
+ htmlboard [directory] [options]
74
+ npx htmlboard [directory] [options]
75
+ htmlboard skills <install|uninstall> [options] Teach your AI agent to use HtmlBoard
76
+
77
+ Options:
78
+ -p, --port <number> Port to listen on (default: 3000)
79
+ -d, --dir <path> Directory to serve HTML artboards from (default: .)
80
+ -r, --root <path> Serve files from this parent folder, so artboards can link to
81
+ shared files outside the designs folder (default: the designs folder)
82
+ -o, --open Open the explorer automatically in default browser
83
+ --init Scaffold starter designs.json and sample artboards
84
+ -v, --version Display HtmlBoard version
85
+ -h, --help Display help message
86
+ ```
87
+
88
+ ### Examples
89
+
90
+ ```bash
91
+ # Serve current directory on port 3000
92
+ htmlboard
93
+
94
+ # Open in browser automatically
95
+ htmlboard --open
96
+
97
+ # Serve a specific designs directory on port 8080
98
+ htmlboard ./src/designs -p 8080
99
+
100
+ # Artboards in ./design that link to the site's own ../css and ../js
101
+ htmlboard design --root .
102
+
103
+ # Initialize sample templates in a new folder
104
+ htmlboard ./my-new-ui --init --open
105
+ ```
106
+
107
+ ---
108
+
109
+ ## πŸ€– Working with LLMs (AI-Assisted Prototyping)
110
+
111
+ HtmlBoard is built from the ground up to pair with AI coding agents (Claude, Gemini, Codex, ChatGPT, Antigravity, Cursor).
112
+
113
+ ### Install the agent skill
114
+
115
+ 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:
116
+
117
+ ```bash
118
+ npx htmlboard skills install
119
+ ```
120
+
121
+ 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.
122
+
123
+ ```bash
124
+ npx htmlboard skills install --global # for your user (~/.claude/skills, ~/.agents/skills), all projects
125
+ npx htmlboard skills install --agent claude # only one agent: claude | agents | all (default)
126
+ npx htmlboard skills install --force # update a copy you edited locally
127
+ npx htmlboard skills uninstall # remove it (accepts the same --global / --agent)
128
+ ```
129
+
130
+ Running `install` again after upgrading HtmlBoard updates the skill; a copy you edited is kept unless you pass `--force`.
131
+
132
+ ### The workflow
133
+
134
+ 1. **Ask your LLM to generate artboards:**
135
+ > *"Create 3 design explorations for our checkout flow in `artboards/checkout-v1.html`, `artboards/checkout-v2.html`, and `artboards/checkout-v3.html`."*
136
+
137
+ 2. **Run HtmlBoard in the background:**
138
+ ```bash
139
+ npx htmlboard
140
+ ```
141
+
142
+ 3. **Watch the canvas update live:**
143
+ 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.
144
+
145
+ ---
146
+
147
+ ## πŸ“‹ The `designs.json` Manifest
148
+
149
+ 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:
150
+
151
+ ```json
152
+ {
153
+ "sections": [
154
+ {
155
+ "title": "Home",
156
+ "designs": [
157
+ { "file": "home-mobile.html", "title": "Home Β· phone", "width": 390, "height": 844 },
158
+ { "file": "home-mobile.html?theme=dark", "title": "Home Β· phone Β· dark", "width": 390, "height": 844 },
159
+ { "file": "home-desktop.html", "title": "Home Β· desktop", "width": 1440 }
160
+ ]
161
+ }
162
+ ]
163
+ }
164
+ ```
165
+
166
+ 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.
167
+
168
+ The full form adds ids, descriptions (shown in the list), categories and tags (searchable); `name`/`artboards` are synonyms of `title`/`designs`:
169
+
170
+ ```json
171
+ {
172
+ "title": "Fintech Mobile & Web App",
173
+ "description": "Exploration of screen flows, responsive layouts, and UI components",
174
+ "sections": [
175
+ {
176
+ "id": "screens",
177
+ "name": "Screen Layouts",
178
+ "description": "Full page layouts across mobile and desktop viewports",
179
+ "artboards": [
180
+ {
181
+ "id": "desktop-dashboard",
182
+ "title": "Desktop Dashboard",
183
+ "file": "artboards/desktop.html",
184
+ "width": 1280,
185
+ "height": 820,
186
+ "category": "desktop",
187
+ "tags": ["desktop", "dashboard", "analytics"]
188
+ },
189
+ {
190
+ "id": "mobile-app",
191
+ "title": "Mobile App Feed",
192
+ "file": "artboards/mobile.html",
193
+ "width": 390,
194
+ "height": 844,
195
+ "category": "mobile",
196
+ "tags": ["mobile", "ios", "finance"]
197
+ }
198
+ ]
199
+ },
200
+ {
201
+ "id": "components",
202
+ "name": "Component Library",
203
+ "artboards": [
204
+ {
205
+ "id": "ui-primitives",
206
+ "title": "UI Kit Elements",
207
+ "file": "artboards/components.html",
208
+ "width": 780,
209
+ "height": 720,
210
+ "category": "components",
211
+ "tags": ["design-system", "buttons", "inputs"]
212
+ }
213
+ ]
214
+ }
215
+ ]
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## ⌨️ Keyboard Shortcuts
222
+
223
+ | Shortcut | Action |
224
+ | :--- | :--- |
225
+ | Drag, <kbd>Space</kbd> + drag | Move around |
226
+ | Scroll (<kbd>Shift</kbd>: sideways) | Move around |
227
+ | <kbd>Ctrl</kbd>/<kbd>⌘</kbd> + scroll, pinch | Zoom, anchored to the pointer |
228
+ | <kbd>+</kbd> / <kbd>βˆ’</kbd> | Zoom in / out |
229
+ | <kbd>Shift</kbd> + <kbd>0</kbd> | Zoom to 100% |
230
+ | <kbd>Shift</kbd> + <kbd>1</kbd> | Fit everything (what the search keeps) |
231
+ | <kbd>Shift</kbd> + <kbd>2</kbd>, double-click | Fit the design |
232
+ | <kbd>←</kbd> / <kbd>β†’</kbd> | Previous / next design |
233
+ | <kbd>Enter</kbd> | Open the selected design on its own |
234
+ | <kbd>/</kbd> | Search (<kbd>Enter</kbd> fits the first match, <kbd>Esc</kbd> clears) |
235
+ | <kbd>R</kbd> | Reload the designs |
236
+ | <kbd>\</kbd> | Show or hide the list |
237
+ | <kbd>?</kbd> | Show the shortcuts |
238
+ | <kbd>Esc</kbd> | Deselect |
239
+
240
+ On the canvas the designs are pictures: the canvas takes every click and scroll, so <kbd>Ctrl</kbd> + scroll never zooms the page itself. Use **Open** (or <kbd>Enter</kbd>) to try a design's links and hover states on its own.
241
+
242
+ ---
243
+
244
+ ## πŸ”Œ Programmatic API
245
+
246
+ You can also embed HtmlBoard into your own build tools, testing pipelines, or dev environments:
247
+
248
+ ```javascript
249
+ import { startServer } from 'htmlboard';
250
+
251
+ const instance = await startServer({
252
+ dir: './designs',
253
+ port: 3000
254
+ });
255
+
256
+ console.log(`HtmlBoard running at ${instance.url}`);
257
+
258
+ // Later, when done:
259
+ // await instance.close();
260
+ ```
261
+
262
+ The skill installer is exported too:
263
+
264
+ ```javascript
265
+ import { installSkills } from 'htmlboard';
266
+
267
+ installSkills({ dir: process.cwd(), agent: 'all' });
268
+ // β†’ [{ skill: 'htmlboard', path: '…/.claude/skills/htmlboard', status: 'installed' }, …]
269
+ ```
270
+
271
+ ---
272
+
273
+ ## πŸ“‚ Project Structure
274
+
275
+ ```text
276
+ htmlboard/
277
+ β”œβ”€β”€ bin/
278
+ β”‚ └── htmlboard.js # CLI executable
279
+ β”œβ”€β”€ src/
280
+ β”‚ β”œβ”€β”€ index.js # Library entry point & API exports
281
+ β”‚ β”œβ”€β”€ server.js # HTTP server, SSE live reload, auto-discovery
282
+ β”‚ β”œβ”€β”€ skills.js # `htmlboard skills` installer
283
+ β”‚ β”œβ”€β”€ client/ # The canvas
284
+ β”‚ β”‚ β”œβ”€β”€ index.html # Explorer shell: list, canvas, toolbar, shortcuts
285
+ β”‚ β”‚ β”œβ”€β”€ explorer.css # Dark chrome, dot grid
286
+ β”‚ β”‚ β”œβ”€β”€ explorer.js # Layout, pan/zoom, search, live reload
287
+ β”‚ β”‚ β”œβ”€β”€ favicon.svg, logo.svg, mark.svg
288
+ β”‚ β”‚ └── fonts/ # Inter and Bricolage Grotesque (OFL)
289
+ β”‚ └── templates/ # Starter scaffold templates
290
+ β”‚ β”œβ”€β”€ designs.json # Starter manifest
291
+ β”‚ └── artboards/ # Sample mobile, desktop, & component screens
292
+ β”œβ”€β”€ skills/
293
+ β”‚ └── htmlboard/ # Agent skill (SKILL.md) copied by `htmlboard skills install`
294
+ β”œβ”€β”€ brand/ # The logo's files (from design/tools/logo.py)
295
+ β”œβ”€β”€ design/ # htmlboard's own designs, on its own canvas: `npx htmlboard design --root .`
296
+ β”œβ”€β”€ package.json
297
+ β”œβ”€β”€ README.md
298
+ └── LICENSE
299
+ ```
300
+
301
+ ---
302
+
303
+ ## πŸ“„ License
304
+
305
+ MIT Β© Luiz Carlos & Contributors
306
+
307
+ The explorer ships the Inter and Bricolage Grotesque fonts under the SIL Open Font License 1.1 (see `src/client/fonts/`).
@@ -0,0 +1,294 @@
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 the 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
+ On the canvas:
97
+ Drag, scroll Move around
98
+ Ctrl/Cmd + scroll Zoom (or pinch)
99
+ Double-click Fit a design (Shift + 1 fits everything)
100
+ / Search
101
+ ? All the shortcuts
102
+ `);
103
+ }
104
+
105
+ function openBrowser(url) {
106
+ const startCmd = process.platform === 'darwin'
107
+ ? 'open'
108
+ : process.platform === 'win32'
109
+ ? 'start'
110
+ : 'xdg-open';
111
+
112
+ exec(`${startCmd} ${url}`, (err) => {
113
+ if (err) {
114
+ console.warn(`[htmlboard] Unable to auto-launch browser: ${err.message}`);
115
+ }
116
+ });
117
+ }
118
+
119
+ function scaffoldProject(targetDir) {
120
+ const templatesDir = path.join(__dirname, '..', 'src', 'templates');
121
+ const targetConfig = path.join(targetDir, 'designs.json');
122
+ const targetArtboardsDir = path.join(targetDir, 'artboards');
123
+
124
+ console.log(`[htmlboard] Scaffolding starter project in ${targetDir}...`);
125
+
126
+ if (!fs.existsSync(targetDir)) {
127
+ fs.mkdirSync(targetDir, { recursive: true });
128
+ }
129
+
130
+ if (!fs.existsSync(targetArtboardsDir)) {
131
+ fs.mkdirSync(targetArtboardsDir, { recursive: true });
132
+ }
133
+
134
+ // Copy designs.json if not present
135
+ if (!fs.existsSync(targetConfig)) {
136
+ const srcConfig = path.join(templatesDir, 'designs.json');
137
+ if (fs.existsSync(srcConfig)) {
138
+ fs.copyFileSync(srcConfig, targetConfig);
139
+ console.log(` βœ“ Created designs.json`);
140
+ }
141
+ } else {
142
+ console.log(` β„Ή designs.json already exists (skipped)`);
143
+ }
144
+
145
+ // Copy starter artboards
146
+ const starterFiles = ['mobile.html', 'desktop.html', 'components.html'];
147
+ for (const file of starterFiles) {
148
+ const srcFile = path.join(templatesDir, 'artboards', file);
149
+ const destFile = path.join(targetArtboardsDir, file);
150
+ if (!fs.existsSync(destFile) && fs.existsSync(srcFile)) {
151
+ fs.copyFileSync(srcFile, destFile);
152
+ console.log(` βœ“ Created artboards/${file}`);
153
+ }
154
+ }
155
+
156
+ console.log(`\nπŸŽ‰ Starter templates created successfully!`);
157
+ }
158
+
159
+ function showSkillsHelp() {
160
+ console.log(`
161
+ Usage:
162
+ htmlboard skills install [options] Copy the HtmlBoard skill into your agents' skill folders
163
+ htmlboard skills uninstall [options] Remove it
164
+
165
+ Options:
166
+ -g, --global Install for your user (~/.claude/skills, ~/.agents/skills) instead of this project
167
+ -a, --agent <name> claude (.claude/skills), agents (.agents/skills: Codex and other agents), or all (default)
168
+ -d, --dir <path> Project root (default: current directory)
169
+ -f, --force Replace a skill that was changed locally
170
+ -h, --help Display this help message
171
+ `);
172
+ }
173
+
174
+ function runSkills(args) {
175
+ const [action, ...rest] = args;
176
+ const options = { agent: 'all', global: false, dir: process.cwd(), force: false };
177
+
178
+ for (let i = 0; i < rest.length; i++) {
179
+ const arg = rest[i];
180
+ if (arg === '--global' || arg === '-g') options.global = true;
181
+ else if (arg === '--force' || arg === '-f') options.force = true;
182
+ else if (arg === '--agent' || arg === '-a') options.agent = rest[++i];
183
+ else if (arg.startsWith('--agent=')) options.agent = arg.split('=')[1];
184
+ else if (arg === '--dir' || arg === '-d') options.dir = rest[++i];
185
+ else if (arg.startsWith('--dir=')) options.dir = arg.split('=')[1];
186
+ else if (arg === '--help' || arg === '-h') return showSkillsHelp();
187
+ else {
188
+ console.error(`[htmlboard] Unknown option: ${arg}`);
189
+ showSkillsHelp();
190
+ process.exit(1);
191
+ }
192
+ }
193
+
194
+ if (action !== 'install' && action !== 'uninstall') {
195
+ showSkillsHelp();
196
+ process.exit(action && action !== '--help' && action !== '-h' ? 1 : 0);
197
+ }
198
+
199
+ let results;
200
+ try {
201
+ results = action === 'install' ? installSkills(options) : uninstallSkills(options);
202
+ } catch (err) {
203
+ console.error(`[htmlboard] ${err.message}`);
204
+ process.exit(1);
205
+ }
206
+
207
+ const labels = {
208
+ installed: '\x1b[32mβœ“ installed\x1b[0m',
209
+ updated: '\x1b[32mβœ“ updated\x1b[0m',
210
+ unchanged: '\x1b[90m= up to date\x1b[0m',
211
+ skipped: '\x1b[33m! changed locally, kept (use --force to replace)\x1b[0m',
212
+ removed: '\x1b[32mβœ“ removed\x1b[0m',
213
+ absent: '\x1b[90m- not installed\x1b[0m'
214
+ };
215
+ for (const { path: dest, status } of results) {
216
+ console.log(` ${labels[status]} ${path.relative(process.cwd(), dest) || dest}`);
217
+ }
218
+ if (action === 'install' && results.some((r) => r.status === 'installed' || r.status === 'updated')) {
219
+ console.log(`\n Restart your agent session to load the skill, then ask it for a design.`);
220
+ }
221
+ }
222
+
223
+ async function main() {
224
+ const args = process.argv.slice(2);
225
+
226
+ if (args[0] === 'skills') {
227
+ runSkills(args.slice(1));
228
+ return;
229
+ }
230
+
231
+ const options = parseArgs(args);
232
+
233
+ if (options.help) {
234
+ showHelp();
235
+ process.exit(0);
236
+ }
237
+
238
+ if (options.version) {
239
+ console.log(`htmlboard v${pkg.version}`);
240
+ process.exit(0);
241
+ }
242
+
243
+ const targetDir = path.resolve(options.dir);
244
+
245
+ if (options.init) {
246
+ scaffoldProject(targetDir);
247
+ }
248
+
249
+ // If directory is empty, auto-prompt or auto-scaffold
250
+ let entries = [];
251
+ try {
252
+ entries = fs.readdirSync(targetDir);
253
+ } catch (_) {
254
+ fs.mkdirSync(targetDir, { recursive: true });
255
+ }
256
+
257
+ const hasHtml = entries.some((e) => e.endsWith('.html')) ||
258
+ (fs.existsSync(path.join(targetDir, 'artboards')) &&
259
+ fs.readdirSync(path.join(targetDir, 'artboards')).some((e) => e.endsWith('.html')));
260
+ const hasDesignsJson = fs.existsSync(path.join(targetDir, 'designs.json'));
261
+
262
+ if (!hasHtml && !hasDesignsJson && entries.filter((e) => !e.startsWith('.')).length === 0) {
263
+ console.log(`[htmlboard] Directory is empty. Initializing starter artboards...`);
264
+ scaffoldProject(targetDir);
265
+ }
266
+
267
+ try {
268
+ const { url, rootDir } = await startServer({
269
+ dir: targetDir,
270
+ root: options.root ? path.resolve(options.root) : undefined,
271
+ port: options.port
272
+ });
273
+
274
+ console.log(`
275
+ \x1b[90mhtml\x1b[0m\x1b[1mboard\x1b[0m \x1b[90mv${pkg.version}\x1b[0m
276
+ \x1b[90mInfinite canvas for HTML designs\x1b[0m
277
+
278
+ \x1b[32m➜\x1b[0m \x1b[1mLocal:\x1b[0m \x1b[36m${url}\x1b[0m
279
+ \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` : ''}
280
+ \x1b[32m➜\x1b[0m \x1b[1mLive:\x1b[0m \x1b[32mWatching files for hot live reload\x1b[0m
281
+
282
+ \x1b[90mPress \x1b[1mCtrl+C\x1b[0m\x1b[90m to stop.\x1b[0m
283
+ `);
284
+
285
+ if (options.open) {
286
+ openBrowser(url);
287
+ }
288
+ } catch (err) {
289
+ console.error(`[htmlboard] Error starting server:`, err.message);
290
+ process.exit(1);
291
+ }
292
+ }
293
+
294
+ main();
package/package.json CHANGED
@@ -1,6 +1,50 @@
1
1
  {
2
2
  "name": "htmlboard",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.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"
49
+ }
50
+ }