openink 0.1.1 → 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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes are documented here. The format follows [Keep a Changelog](h
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.0] - 2026-10-02
8
+
9
+ ### Added
10
+
11
+ - A `wireframe` skill for AI coding agents that turns a description into a validated, screenshot-checked prototype in
12
+ any folder. Claude Code: `claude plugin marketplace add mediuswareltd/openink`, then
13
+ `claude plugin install openink@openink`. Cursor, Codex, Gemini CLI, GitHub Copilot and others:
14
+ `npx skills add mediuswareltd/openink`.
15
+
16
+ ### Fixed
17
+
18
+ - An image, video, map, dropzone or chart placed directly in a `row` is drawn as a 4:3 thumbnail of its height. It
19
+ used to collapse to the width of its label and showed no box (#17).
20
+ - The PDF button (and Ctrl+P) no longer prints image, video and map placeholders and charts as empty boxes with only
21
+ their label. Screens that had not been opened were printed before their sketches were drawn.
22
+
7
23
  ## [0.1.1] - 2026-10-02
8
24
 
9
25
  ### Added
package/README.md CHANGED
@@ -82,6 +82,27 @@ openink dev
82
82
 
83
83
  Requires Node 20+. PDF and PNG export need Chrome, Chromium or Edge installed (set `CHROME_PATH` if it isn't found).
84
84
 
85
+ ### With an AI coding agent
86
+
87
+ Give your agent the Open Ink skill once, then just describe what you want ("wireframe a booking app for a hair salon").
88
+
89
+ **Claude Code**: install the plugin:
90
+
91
+ ```bash
92
+ claude plugin marketplace add mediuswareltd/openink
93
+ claude plugin install openink@openink
94
+ ```
95
+
96
+ To get updates automatically, turn on auto-update for the **openink** marketplace in `/plugin` → **Marketplaces**.
97
+
98
+ **Cursor, Codex, Gemini CLI, GitHub Copilot, Windsurf and other agents**: add the skill with the [skills](https://skills.sh) CLI, which asks which of your agents to install it for:
99
+
100
+ ```bash
101
+ npx skills add mediuswareltd/openink
102
+ ```
103
+
104
+ The agent writes and validates the spec, checks screenshots of every screen and tells you where the prototype is. See [docs/ai-assistants.md](docs/ai-assistants.md).
105
+
85
106
  ## What you can draw
86
107
 
87
108
  48 blocks in 10 groups; see the [block reference](docs/blocks.md) and the [gallery example](examples/gallery), which shows every one.
@@ -6,6 +6,35 @@ Open Ink is designed so that an assistant (Claude Code, Cursor, Copilot, ChatGPT
6
6
 
7
7
  The assistant writes `spec.yaml`, the tool checks it, and you get a consistent hand-drawn result. Because the spec is small and validated, it is cheap to iterate: "add a second tab to the listing page" is a five-line diff.
8
8
 
9
+ ## Install the Open Ink skill
10
+
11
+ Open Ink comes with a `wireframe` skill that teaches your agent the whole loop. Once it is installed, the agent uses it whenever you ask for a wireframe, mockup or clickable prototype, in any folder, so you do not need to mention Open Ink or run `init` first.
12
+
13
+ The skill follows the same steps as the `AGENTS.md` below: it reads the block reference, edits only `spec.yaml`, validates until the spec is clean, checks a PNG of every screen and tells you where the result is. In a folder without a spec, it creates the project in a new subfolder so it does not overwrite your files.
14
+
15
+ ### Claude Code
16
+
17
+ Install the plugin once:
18
+
19
+ ```bash
20
+ claude plugin marketplace add mediuswareltd/openink
21
+ claude plugin install openink@openink
22
+ ```
23
+
24
+ Inside a session the same is `/plugin marketplace add mediuswareltd/openink` and `/plugin install openink@openink`. You can also call the skill directly with `/openink:wireframe`.
25
+
26
+ For updates, turn on auto-update for the **openink** marketplace in `/plugin` → **Marketplaces**, or run `/plugin marketplace update openink`.
27
+
28
+ ### Cursor, Codex, Gemini CLI, GitHub Copilot and other agents
29
+
30
+ Add the skill with the [skills](https://skills.sh) CLI:
31
+
32
+ ```bash
33
+ npx skills add mediuswareltd/openink
34
+ ```
35
+
36
+ It asks which of your agents to install it for, and whether to install it for this project or for your user. To skip the questions, name the agents and add `-y`, for example `npx skills add mediuswareltd/openink -a cursor -a codex -y`, and add `-g` to install it for every project. Run `npx skills update` to get the latest version.
37
+
9
38
  ## How it works
10
39
 
11
40
  `openink init` puts an `AGENTS.md` in your project. Most assistants read it automatically; it tells them to:
package/docs/blocks.md CHANGED
@@ -43,7 +43,7 @@ Vertical stack of blocks.
43
43
 
44
44
  ### `row` · children
45
45
 
46
- Horizontal row that wraps on small screens.
46
+ Horizontal row that wraps on small screens. Images, videos, maps and charts in a row are 4:3 thumbnails of their height.
47
47
 
48
48
  | Prop | Type | Description |
49
49
  |---|---|---|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openink",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Describe screens in YAML, get a clickable hand-drawn wireframe prototype (static HTML, PDF, PNG). Built on wired-elements and RoughJS.",
5
5
  "keywords": [
6
6
  "wireframe",
@@ -364,7 +364,7 @@
364
364
  },
365
365
  {
366
366
  "type": "object",
367
- "description": "Horizontal row that wraps on small screens.",
367
+ "description": "Horizontal row that wraps on small screens. Images, videos, maps and charts in a row are 4:3 thumbnails of their height.",
368
368
  "required": [
369
369
  "type"
370
370
  ],
@@ -13,7 +13,7 @@ export default [
13
13
  {
14
14
  name: "row",
15
15
  group: "Layout",
16
- summary: "Horizontal row that wraps on small screens.",
16
+ summary: "Horizontal row that wraps on small screens. Images, videos, maps and charts in a row are 4:3 thumbnails of their height.",
17
17
  children: true,
18
18
  props: {
19
19
  between: { type: "boolean", doc: "Push the first and last child to opposite ends." },
@@ -12,7 +12,7 @@ class Chart extends HTMLElement {
12
12
  const kind = this.getAttribute("kind") || "line";
13
13
  const values = (this.getAttribute("values") || "").split(",").map((s) => s.trim()).filter(Boolean).map(Number).filter(Number.isFinite);
14
14
  const data = values.length ? values : SAMPLE[kind] || SAMPLE.line;
15
- this.style.cssText += `display:block;position:relative;height:${h}px`;
15
+ this.style.cssText += `display:block;position:relative;height:${h}px;--oi-w:${Math.round((h * 4) / 3)}px`;
16
16
 
17
17
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
18
18
  svg.style.cssText = "position:absolute;inset:0;width:100%;height:100%";
@@ -70,6 +70,7 @@ class Chart extends HTMLElement {
70
70
  }
71
71
  };
72
72
 
73
+ this.draw = draw; // print draws every screen at once, before a ResizeObserver would fire
73
74
  draw();
74
75
  new ResizeObserver(draw).observe(this);
75
76
  const label = this.getAttribute("label");
@@ -11,7 +11,7 @@ class Placeholder extends HTMLElement {
11
11
  const h = +this.getAttribute("h") || 120;
12
12
  // A round placeholder (avatar) is square and must have a width of its own to sit in a flex row.
13
13
  const width = this.hasAttribute("round") ? `width:${h}px;flex:none;` : "";
14
- this.style.cssText += `display:block;position:relative;height:${h}px;${width}`;
14
+ this.style.cssText += `display:block;position:relative;height:${h}px;--oi-w:${Math.round((h * 4) / 3)}px;${width}`;
15
15
 
16
16
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
17
17
  svg.style.cssText = "position:absolute;inset:0;width:100%;height:100%";
@@ -72,6 +72,7 @@ class Placeholder extends HTMLElement {
72
72
  }
73
73
  };
74
74
 
75
+ this.draw = draw; // print draws every screen at once, before a ResizeObserver would fire
75
76
  draw();
76
77
  new ResizeObserver(draw).observe(this);
77
78
 
@@ -24,11 +24,13 @@ export function preparePrint() {
24
24
  return { zoom: r.height > room ? Math.max(room / r.height, 0.3) : 1, width: r.width };
25
25
  });
26
26
 
27
+ // Draw everything now: the browser prints straight after this returns, before a ResizeObserver
28
+ // would draw the placeholders and charts on screens that were hidden.
27
29
  // Draw before zooming: wired-elements size their sketch from the zoomed box, and the zoom then
28
30
  // shrinks the sketch a second time. Keep the screen's unzoomed width so its layout (and so the
29
31
  // sketches) only scales, and record the zoomed box as the size last drawn, so a resize
30
32
  // (wired-card watches its own) does not redraw at that size.
31
- $$("*").forEach((el) => el.wiredRender?.(true));
33
+ $$("*").forEach((el) => (el.wiredRender ? el.wiredRender(true) : el.draw?.()));
32
34
  screens.forEach((s, i) => {
33
35
  const { zoom, width } = zooms[i];
34
36
  if (zoom === 1) return;
@@ -101,6 +101,8 @@ p { margin: 0; }
101
101
  .row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
102
102
  .row.between { justify-content: space-between; }
103
103
  .row.center { justify-content: center; }
104
+ /* placeholders and charts have no content width, so in a row they are a 4:3 thumbnail (--oi-w is set from their height) */
105
+ .row > oi-placeholder:not([round]), .row > oi-chart { flex: none; width: var(--oi-w); max-width: 100%; }
104
106
  .grid { display: grid; grid-template-columns: repeat(var(--cols), 1fr); gap: var(--gap); align-items: start; }
105
107
  @media (max-width: 720px) { html:not(.oi-print) .grid { grid-template-columns: 1fr; } }
106
108
  .card { display: block; padding: 1rem; background: var(--card-bg); }