openink 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.
Files changed (52) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +164 -0
  4. package/bin/openink.js +4 -0
  5. package/docs/ai-assistants.md +35 -0
  6. package/docs/architecture.md +50 -0
  7. package/docs/blocks.md +604 -0
  8. package/docs/extending.md +86 -0
  9. package/docs/getting-started.md +97 -0
  10. package/docs/spec.md +215 -0
  11. package/package.json +38 -0
  12. package/schema/spec.schema.json +2641 -0
  13. package/src/build.js +82 -0
  14. package/src/cli.js +133 -0
  15. package/src/dev.js +53 -0
  16. package/src/export.js +68 -0
  17. package/src/icons.js +47 -0
  18. package/src/index.js +14 -0
  19. package/src/render/blocks/actions.js +68 -0
  20. package/src/render/blocks/content.js +86 -0
  21. package/src/render/blocks/data.js +24 -0
  22. package/src/render/blocks/feedback.js +29 -0
  23. package/src/render/blocks/forms.js +86 -0
  24. package/src/render/blocks/index.js +42 -0
  25. package/src/render/blocks/layout.js +102 -0
  26. package/src/render/blocks/media.js +65 -0
  27. package/src/render/blocks/navigation.js +67 -0
  28. package/src/render/blocks/overlay.js +18 -0
  29. package/src/render/blocks/shared.js +20 -0
  30. package/src/render/blocks/text.js +49 -0
  31. package/src/render/context.js +63 -0
  32. package/src/render/page.js +76 -0
  33. package/src/runtime/chart.js +85 -0
  34. package/src/runtime/dom.js +21 -0
  35. package/src/runtime/i18n.js +24 -0
  36. package/src/runtime/icon.js +28 -0
  37. package/src/runtime/index.js +64 -0
  38. package/src/runtime/navigation.js +27 -0
  39. package/src/runtime/placeholder.js +88 -0
  40. package/src/spec/docs.js +65 -0
  41. package/src/spec/schema.js +110 -0
  42. package/src/spec/validate.js +219 -0
  43. package/src/styles/openink.css +250 -0
  44. package/src/styles/themes/blueprint.css +31 -0
  45. package/src/styles/themes/color.css +28 -0
  46. package/src/styles/themes/dark.css +31 -0
  47. package/src/styles/themes/pastel.css +26 -0
  48. package/src/themes.js +10 -0
  49. package/templates/starter/AGENTS.md +18 -0
  50. package/templates/starter/README.md +11 -0
  51. package/templates/starter/gitignore +3 -0
  52. package/templates/starter/spec.yaml +55 -0
@@ -0,0 +1,97 @@
1
+ # Getting started
2
+
3
+ ## 1. Create a project
4
+
5
+ ```bash
6
+ npx openink init my-wireframes
7
+ cd my-wireframes
8
+ npx openink dev
9
+ ```
10
+
11
+ Open <http://localhost:3000>. Edit `spec.yaml` and the page reloads on save.
12
+
13
+ **Skipping `npx`.** `npx openink` downloads the tool on first use. To pin a version per project, or to type just `openink`, install it:
14
+
15
+ ```bash
16
+ npm install -g openink # anywhere on your machine
17
+ # or, per project:
18
+ npm install --save-dev openink
19
+ ```
20
+
21
+ Once installed globally, every `npx openink <command>` in these docs can be written as `openink <command>`.
22
+
23
+ You now have:
24
+
25
+ ```
26
+ my-wireframes/
27
+ ├── spec.yaml ← the whole prototype
28
+ ├── AGENTS.md ← instructions for AI coding assistants (see docs/ai-assistants.md)
29
+ ├── README.md
30
+ └── .gitignore
31
+ ```
32
+
33
+ ## 2. Describe screens
34
+
35
+ ```yaml
36
+ name: Shop
37
+
38
+ nav:
39
+ - { label: Home, go: home }
40
+
41
+ screens:
42
+ - id: home
43
+ title: Home
44
+ blocks:
45
+ - { type: h1, text: Welcome }
46
+ - type: grid
47
+ cols: 3
48
+ children:
49
+ - type: card
50
+ go: product # clicking the card opens the "product" screen
51
+ children:
52
+ - { type: image, h: 120, label: Photo }
53
+ - { type: h3, text: Blue shirt }
54
+ - { type: text, muted: true, text: CHF 39 }
55
+
56
+ - id: product
57
+ title: Product page
58
+ blocks:
59
+ - { type: h1, text: Blue shirt }
60
+ - { type: button, label: Add to cart, primary: true, toast: Added }
61
+ ```
62
+
63
+ - A **screen** is one page or state. `id` is what `go:` links point to.
64
+ - A **block** is `{ type: <name>, ...props }`. Blocks such as `grid`, `card` and `row` hold other blocks in `children:`.
65
+ - `go: <screen id>` on a button, card, table row or nav item navigates. `toast: "text"` shows a message.
66
+
67
+ Every block and its props: [blocks.md](blocks.md), or run `npx openink blocks`.
68
+
69
+ ## 3. Check and share
70
+
71
+ | Goal | Command |
72
+ |---|---|
73
+ | Catch mistakes (typos, dead links, unreachable screens) | `npx openink validate` |
74
+ | Static site for hosting | `npx openink build` → `dist/` |
75
+ | PDF, one screen per page | `npx openink pdf` → `dist/<name>.pdf` |
76
+ | One PNG per screen | `npx openink png` → `dist/png/` |
77
+
78
+ `dist/index.html` works when double-clicked and offline. To host it, upload `dist/` anywhere that serves static files (Netlify, Vercel, GitHub Pages, S3).
79
+
80
+ PDF and PNG export need Chrome, Chromium or Edge installed. Set `CHROME_PATH` if it is not found.
81
+
82
+ ## Editor autocomplete
83
+
84
+ The first line of the starter spec points at the JSON Schema:
85
+
86
+ ```yaml
87
+ # yaml-language-server: $schema=https://unpkg.com/openink/schema/spec.schema.json
88
+ ```
89
+
90
+ With the YAML extension in VS Code (or any editor using yaml-language-server) you get completion for block types and props, hover docs, and inline errors.
91
+
92
+ ## Next
93
+
94
+ - [Spec reference](spec.md): top-level fields, navigation, languages, theming, assets
95
+ - [Block reference](blocks.md)
96
+ - [Working with AI assistants](ai-assistants.md)
97
+ - [Extending Open Ink](extending.md)
package/docs/spec.md ADDED
@@ -0,0 +1,215 @@
1
+ # Spec reference
2
+
3
+ `spec.yaml` (or `spec.yml` / `spec.json`) sits at the root of a project.
4
+
5
+ ## Top-level fields
6
+
7
+ | Field | Type | Description |
8
+ |---|---|---|
9
+ | `name` * | string | Shown in the header and browser tab. Also names the PDF. |
10
+ | `screens` * | list | The screens. The first one is the start screen. |
11
+ | `nav` | list or object | Header buttons. See [Navigation](#navigation). |
12
+ | `modals` | list | Dialogs any screen can open. See [Modals](#modals). |
13
+ | `languages` | list | Language codes, e.g. `[en, de]`. The first is the default. See [Languages](#languages). |
14
+ | `theme` | string | A colour theme (`sketch`, `color`, `pastel`, `blueprint`, `dark`) or the path of your own `.css` file. See [Colour](#colour). |
15
+ | `colors` | object | Override single colours of the theme. See [Colour](#colour). |
16
+ | `footer` | string | Footer text (default: "Wireframe · not the final design"). |
17
+ | `x-*` | anything | Free-form; a place for YAML anchors. See [Reusing blocks](#reusing-blocks-yaml-anchors). |
18
+
19
+ \* required
20
+
21
+ ## Screens
22
+
23
+ ```yaml
24
+ screens:
25
+ - id: dashboard # required, unique: letters, digits, "-" and "_", starting with a letter
26
+ title: Dashboard # shown in the tab title and above the page in the PDF
27
+ nav: owner # which nav set to show (default: "default")
28
+ note: "Only the owner sees this." # yellow sticky note at the top of the screen
29
+ width: narrow # narrow (~520px, phone-like) | medium (~760px) | wide (default, full width)
30
+ tone: blue # optional: tint the whole screen (see Colour)
31
+ blocks: [ ... ]
32
+ ```
33
+
34
+ Use `note:` (and the `note` block) for things a sketch cannot show: rules, states, open questions.
35
+
36
+ ## Colour
37
+
38
+ Colour is optional and works at three levels. Mix them freely: a plain-sketch project with a few coloured parts, or a fully coloured one.
39
+
40
+ ### 1. The whole project: `theme:` and `colors:`
41
+
42
+ ```yaml
43
+ theme: color # sketch (default) | color | pastel | blueprint | dark
44
+ colors: # optional: override single tokens on top of the theme
45
+ accent: "#f97316"
46
+ ```
47
+
48
+ | Theme | Look |
49
+ |---|---|
50
+ | `sketch` | Pencil grey on warm paper with one orange accent. The default. |
51
+ | `color` | Indigo and rose on warm white. Filled buttons, coloured charts. |
52
+ | `pastel` | Soft pinks and lilacs. Friendly. |
53
+ | `blueprint` | White lines on blue graph paper. |
54
+ | `dark` | Dark background, light lines, coral accent. |
55
+
56
+ Try them without editing the spec: `openink dev --theme dark`.
57
+
58
+ `colors:` accepts `ink` (text and lines), `paper` (page background), `muted` (secondary text and outlines), `line` (dashed dividers), `accent` (pins, sliders, active states, "wait" badges), `note` (sticky notes) and `card` (card and dialog background). Values are any CSS colour.
59
+
60
+ For full control, point `theme:` at your own file (any value ending in `.css`); it is copied next to the page and loaded after the base styles:
61
+
62
+ ```yaml
63
+ theme: brand.css
64
+ ```
65
+
66
+ ```css
67
+ /* brand.css */
68
+ :root { --ink: #1e3a8a; --accent: #dc2626; --gap: 1.25rem; }
69
+ body { font-family: "Comic Neue", cursive; }
70
+ ```
71
+
72
+ Also available: `--wired-toggle-on-color`, `--wired-slider-knob-color`, `--wired-progress-color`, `--card-bg`, `--ok` (green of "on" badges) and the tone palette `--blue`, `--blue-bg`, … (see `src/styles/openink.css`).
73
+
74
+ ### 2. One part: `tone:` and `fill:` on any block
75
+
76
+ ```yaml
77
+ - { type: card, tone: pink, title: New, children: [...] } # pink outline, text and drawings
78
+ - { type: button, label: Delete, icon: trash, tone: red }
79
+ - { type: text, text: Saved, tone: green, fill: true } # plus a tinted background
80
+ - { type: chart, kind: bar, tone: purple }
81
+ ```
82
+
83
+ `tone` is one of `blue`, `green`, `yellow`, `red`, `purple`, `pink`, `orange`, `teal`, `gray`. It recolours the block and everything inside it, including hand-drawn placeholders, charts and icons. `fill: true` adds a tinted background (a neutral tint if there is no tone). Primary buttons inside a tone become solid.
84
+
85
+ ### 3. One screen: `tone:` on a screen
86
+
87
+ ```yaml
88
+ - id: promo
89
+ tone: orange
90
+ blocks: [ ... ]
91
+ ```
92
+
93
+ The screen gets a tinted background and its blocks take the colour.
94
+
95
+ ## Modals
96
+
97
+ A modal is a dialog that opens over the screen. Open it with `open: <id>` on any clickable block (`button`, `card`, `avatar`, `link`, nav and tab-bar items). Close it with a `close: true` button, the X, the Escape key, or a click outside.
98
+
99
+ Define modals once in the top-level `modals:` list so every screen can open them:
100
+
101
+ ```yaml
102
+ modals:
103
+ - id: share
104
+ title: Share
105
+ width: narrow # narrow | medium (default) | wide
106
+ children:
107
+ - { type: search, placeholder: Search people }
108
+ - { type: button, label: Send, primary: true, close: true, toast: Sent }
109
+
110
+ screens:
111
+ - id: feed
112
+ blocks:
113
+ - { type: button, icon: send, open: share }
114
+ ```
115
+
116
+ A `{ type: modal, id: ... }` block inside a screen works too, but only from that screen. `validate` reports `open:` targets that don't exist.
117
+
118
+ ## Reusing blocks (YAML anchors)
119
+
120
+ Top-level keys starting with `x-` are ignored by openink, so you can define a block once there with an anchor (`&name`) and reuse it anywhere with an alias (`*name`):
121
+
122
+ ```yaml
123
+ x-post-actions: &post-actions
124
+ type: row
125
+ children:
126
+ - { type: button, icon: heart }
127
+ - { type: button, icon: send }
128
+
129
+ screens:
130
+ - id: feed
131
+ blocks:
132
+ - *post-actions
133
+ - *post-actions
134
+ ```
135
+
136
+ See `examples/photo-sharing` for a full example.
137
+
138
+ ## Navigation
139
+
140
+ A single list of header buttons (each with a `label`, an `icon`, or both):
141
+
142
+ ```yaml
143
+ nav:
144
+ - { icon: home, label: Home, go: home }
145
+ - { label: Pricing, go: pricing }
146
+ ```
147
+
148
+ Or several **named sets**. A screen picks one with `nav:`; screens that don't choose use `default`. This is how you show different headers to different roles (an empty list `[]` hides the header buttons):
149
+
150
+ ```yaml
151
+ nav:
152
+ default:
153
+ - { label: Home, go: home }
154
+ - { label: Log in, go: login }
155
+ admin:
156
+ - { label: Dashboard, go: dashboard }
157
+ - { label: Users, go: users }
158
+
159
+ screens:
160
+ - id: dashboard
161
+ nav: admin
162
+ blocks: [ ... ]
163
+ ```
164
+
165
+ For a mobile bottom bar, use the `tabbar` block inside a `device` frame instead.
166
+
167
+ ## Linking
168
+
169
+ `go: <screen id>` works on `button`, `card`, `avatar`, `link`, `nextbar`, nav and tab-bar items, and table rows (`rows: [{ cells: [...], go: user }]`). `validate` and `build` report links to screens that don't exist and warn about screens nothing links to.
170
+
171
+ ## Languages
172
+
173
+ ```yaml
174
+ languages: [en, de]
175
+
176
+ screens:
177
+ - id: home
178
+ title: { en: Home, de: Startseite }
179
+ blocks:
180
+ - { type: h1, text: { en: Welcome, de: Willkommen } }
181
+ - { type: input, placeholder: { en: Your name, de: Ihr Name } }
182
+ ```
183
+
184
+ - Any text value may be a string or a `{ code: text }` object.
185
+ - The header gets a language switcher; the choice is remembered in the browser.
186
+ - A missing translation falls back to the first language, and `validate` warns about it.
187
+ - Language codes are 2 or 3 letters. There is no built-in list, so `pt`, `ja`, `gsw` all work.
188
+
189
+ ## Icons
190
+
191
+ `icon` blocks, `button.icon`, nav items and tab-bar items use a built-in set of hand-drawn icons (`home`, `search`, `heart`, `comment`, `send`, `bell`, `user`, `camera`, …). The full list is at the end of the [block reference](blocks.md#icons). An unknown name is an error with a "did you mean" hint.
192
+
193
+ ## Quoting text with commas
194
+
195
+ Inside `{ ... }` a comma ends the value, so YAML reads `{ type: text, text: Hello, world }` as text `Hello` plus a stray key `world`. Wrap such text in quotes: `text: "Hello, world"`. `validate` warns when it sees this.
196
+
197
+ ## Assets
198
+
199
+ Put images, logos or fonts in `assets/` next to the spec; the folder is copied to `dist/assets/`. Reference them from your theme CSS (`url(assets/logo.svg)`). Wireframes normally use the drawn placeholders instead of real images.
200
+
201
+ ## Output
202
+
203
+ `openink build` writes:
204
+
205
+ ```
206
+ dist/
207
+ ├── index.html all screens in one page; navigation is client-side (#screen-id)
208
+ ├── openink.js runtime, with wired-elements and RoughJS bundled in
209
+ ├── openink.css
210
+ ├── theme-<name>.css (if `theme:` is a preset other than sketch)
211
+ ├── <your>.css (if `theme:` is your own file)
212
+ └── assets/ (if the folder exists)
213
+ ```
214
+
215
+ Screens are addressable: `dist/index.html#dashboard` opens the dashboard directly, which is handy for links in emails and chat.
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "openink",
3
+ "version": "0.1.0",
4
+ "description": "Describe screens in YAML, get a clickable hand-drawn wireframe prototype (static HTML, PDF, PNG). Built on wired-elements and RoughJS.",
5
+ "keywords": ["wireframe", "prototype", "sketch", "mockup", "hand-drawn", "wired-elements", "roughjs", "ux", "static-site-generator"],
6
+ "license": "MIT",
7
+ "author": "Mediusware",
8
+ "repository": { "type": "git", "url": "git+https://github.com/mediuswareltd/openink.git" },
9
+ "homepage": "https://github.com/mediuswareltd/openink#readme",
10
+ "bugs": { "url": "https://github.com/mediuswareltd/openink/issues" },
11
+ "publishConfig": { "access": "public" },
12
+ "type": "module",
13
+ "bin": { "openink": "bin/openink.js" },
14
+ "main": "./src/index.js",
15
+ "exports": {
16
+ ".": "./src/index.js",
17
+ "./schema.json": "./schema/spec.schema.json",
18
+ "./package.json": "./package.json"
19
+ },
20
+ "files": ["bin", "src", "templates", "schema", "docs", "!docs/img", "LICENSE", "README.md", "CHANGELOG.md"],
21
+ "engines": { "node": ">=20" },
22
+ "scripts": {
23
+ "generate": "node scripts/generate.js",
24
+ "test": "node --test \"test/*.test.js\"",
25
+ "prepare": "node scripts/setup-hooks.js",
26
+ "prepublishOnly": "npm test",
27
+ "lint:commit": "node scripts/commit-lint.js",
28
+ "screenshots": "node scripts/screenshots.js",
29
+ "dev": "node bin/openink.js dev examples/rental-portal"
30
+ },
31
+ "dependencies": {
32
+ "esbuild": "^0.28.2",
33
+ "puppeteer-core": "^25.12.0",
34
+ "roughjs": "4.3.1",
35
+ "wired-elements": "3.0.0-rc.6",
36
+ "yaml": "^2.5.0"
37
+ }
38
+ }