@khanglvm/relay 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 +21 -0
- package/README.md +325 -0
- package/bin/rly.js +9 -0
- package/docs/AGENT.md +317 -0
- package/package.json +46 -0
- package/skills/relay/SKILL.md +156 -0
- package/skills/relay/examples/blocks-showcase.json +118 -0
- package/skills/relay/examples/feature-feedback.json +27 -0
- package/skills/relay/examples/prototype-review.json +25 -0
- package/src/cli.js +629 -0
- package/src/open.js +15 -0
- package/src/server.js +371 -0
- package/src/spec.js +435 -0
- package/src/store.js +147 -0
- package/src/ui/annotate.css +151 -0
- package/src/ui/annotate.js +440 -0
- package/src/ui/app.js +605 -0
- package/src/ui/blocks.css +170 -0
- package/src/ui/blocks.js +719 -0
- package/src/ui/index.html +21 -0
- package/src/ui/kit.js +413 -0
- package/src/ui/style.css +231 -0
- package/src/util.js +19 -0
- package/vendor/VERSIONS.json +5 -0
- package/vendor/chart.umd.js +14 -0
- package/vendor/mermaid.min.js +3405 -0
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@khanglvm/relay",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Browser-based question boards with rich blocks (markdown, charts, mermaid, tables, code, sandboxed HTML) and element-level annotations for AI coding agents (Claude Code, Codex, …): ask users structured questions, present interactive visuals, collect inline comments, wait for submit, read answers as JSON.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai-agents",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"codex",
|
|
9
|
+
"cli",
|
|
10
|
+
"interactive-questions",
|
|
11
|
+
"human-in-the-loop",
|
|
12
|
+
"annotations",
|
|
13
|
+
"charts",
|
|
14
|
+
"prototype",
|
|
15
|
+
"visualization",
|
|
16
|
+
"agent-skill"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Le Vu Minh Khang (https://github.com/khanglvm)",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/khanglvm/relay.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/khanglvm/relay#readme",
|
|
25
|
+
"bugs": "https://github.com/khanglvm/relay/issues",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"rly": "bin/rly.js",
|
|
29
|
+
"relay": "bin/rly.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin",
|
|
33
|
+
"src",
|
|
34
|
+
"vendor",
|
|
35
|
+
"skills",
|
|
36
|
+
"docs",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.3"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "node test/smoke.mjs"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: relay
|
|
3
|
+
description: Ask the user interactive questions in a browser board (single/multi choice, yes-no, free text, scale) and/or present rich content blocks (markdown, mermaid diagrams, charts, interactive tables, code, sandboxed HTML), then wait for Submit and read JSON answers plus element-level annotations. PROACTIVELY use whenever you would otherwise (a) call a native ask-user/question tool with 2+ questions or options that need explanation, (b) describe a UI/design/plan/architecture in prose that a visual would show better — draft diagrams (mermaid), charts, and interactive tables as native blocks, or (c) hand-roll an HTML file or local server to demo an idea - relay replaces all three. Triggers - clarify requirements before ambiguous work, choose between approaches, plan approval, design/UX feedback, mockup or prototype review, compare alternatives, survey, metrics review, "ask the user", "show the user", "which do you prefer", "get feedback", diagram, chart, data table, architecture overview, metrics. Skip only for a single trivial yes/no confirmation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# relay (`rly`)
|
|
7
|
+
|
|
8
|
+
CLI that opens a local web board for the user, blocks until they click
|
|
9
|
+
**Submit**, and prints their answers plus element-level annotations as JSON to
|
|
10
|
+
stdout. Works for any agent (Claude Code, Codex, …). Answers autosave in real
|
|
11
|
+
time; the tab auto-closes after submit.
|
|
12
|
+
|
|
13
|
+
If `rly` is not installed: `npm i -g @khanglvm/relay` or invoke via
|
|
14
|
+
`npx -y @khanglvm/relay <command …>`.
|
|
15
|
+
|
|
16
|
+
**Full reference: run `rly agent` (complete guide) and `rly schema` (spec JSON
|
|
17
|
+
Schema).** The essentials are below.
|
|
18
|
+
|
|
19
|
+
## When to use rly vs your native question tool
|
|
20
|
+
|
|
21
|
+
| Situation | Use |
|
|
22
|
+
|---|---|
|
|
23
|
+
| One trivial confirmation ("proceed?") | native tool |
|
|
24
|
+
| 2+ questions, or options that need descriptions | **rly** |
|
|
25
|
+
| Choice is easier to make visually (layouts, designs, diagrams) | **rly** (blocks per question) |
|
|
26
|
+
| Show metrics / trends / data comparisons | **rly** (chart + table blocks) |
|
|
27
|
+
| Present a prototype / demo an idea | **rly show** — never hand-roll an HTML file + server |
|
|
28
|
+
| Gather requirements / plan approval / feedback round | **rly** |
|
|
29
|
+
| Architecture or flow that benefits from a diagram | **rly** (mermaid block) |
|
|
30
|
+
| Something you can decide yourself from context | neither — just decide |
|
|
31
|
+
|
|
32
|
+
Once the user has answered one board in a session, prefer boards for later
|
|
33
|
+
question rounds too — they've shown they engage with them. Batch related
|
|
34
|
+
questions into ONE board rather than opening several in a row.
|
|
35
|
+
|
|
36
|
+
## Choose a pattern
|
|
37
|
+
|
|
38
|
+
1. **Blocking** — simple, but your shell tool must tolerate waiting:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
rly ask --file spec.json --timeout 1800 # prints result JSON when user submits
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. **Detached** — use when your shell tool has an execution time limit
|
|
45
|
+
(e.g. run it, then wait in a separate call):
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
rly ask --file spec.json --detach # → {"boardId":"b-…","url":…} immediately
|
|
49
|
+
rly wait b-xxxxx --timeout 3500 # blocks until submit, prints result JSON
|
|
50
|
+
rly result b-xxxxx # non-blocking peek (includes live draft)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Exit codes: 0 submitted · 2 timeout · 3 cancelled · 5 not found. On
|
|
54
|
+
timeout/cancel the result still contains the autosaved `draft` of partial
|
|
55
|
+
answers and any annotations written so far.
|
|
56
|
+
|
|
57
|
+
## Minimal spec
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"title": "Pick the approach",
|
|
62
|
+
"intro": "Context for the user. Hover chart points or select text to leave comments.",
|
|
63
|
+
"questions": [
|
|
64
|
+
{ "id": "approach", "type": "single", "label": "Which one?", "required": true,
|
|
65
|
+
"options": [{ "value": "a", "label": "A", "description": "fast" }, "B"], "other": true },
|
|
66
|
+
{ "id": "parts", "type": "multi", "label": "Include?", "options": ["api", "ui"], "note": true },
|
|
67
|
+
{ "id": "ship", "type": "yesno", "label": "Ship now?" },
|
|
68
|
+
{ "id": "why", "type": "textarea", "label": "Reasoning?" },
|
|
69
|
+
{ "id": "conf", "type": "scale", "label": "Confidence", "min": 1, "max": 5 }
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Types: `single`, `multi`, `yesno`, `text`, `textarea`, `scale`. Users may
|
|
75
|
+
submit with unanswered questions (returned in `skipped`) unless
|
|
76
|
+
`"allowPartial": false` or per-question `"required": true`.
|
|
77
|
+
|
|
78
|
+
Set `"note": true` on a question to add a small optional free-text field under
|
|
79
|
+
it — use when the user may want to qualify their choice. Returned as
|
|
80
|
+
`result.notes[questionId]`.
|
|
81
|
+
|
|
82
|
+
Quick one-liners without a spec file:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
rly ask -q "Deploy now?::yesno" -q "!Env::single::dev,staging,prod" # "!" = required
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Blocks cheat-sheet
|
|
89
|
+
|
|
90
|
+
Add `"blocks": [...]` to the root or to any question.
|
|
91
|
+
|
|
92
|
+
```jsonc
|
|
93
|
+
{ "type": "markdown", "md": "## Section\n**prose**" }
|
|
94
|
+
{ "type": "mermaid", "code": "graph TD; A-->B", "height": 400 }
|
|
95
|
+
{ "type": "chart", "kind": "bar", "title": "...",
|
|
96
|
+
"labels": ["Jan","Feb"], "series": [{"label":"x","data":[1,2]}], "height": 320 }
|
|
97
|
+
{ "type": "chart", "config": { /* full Chart.js v4 config */ }, "height": 300 }
|
|
98
|
+
{ "type": "table", "columns": ["A","B"], "rows": [["x","y"]], "sortable": true }
|
|
99
|
+
{ "type": "code", "lang": "js", "code": "const x = 1;" }
|
|
100
|
+
{ "type": "html", "html": "<p>hi</p>", "height": 360 }
|
|
101
|
+
{ "type": "html", "htmlFile": "viz.html", "height": 400 }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Chart.js and Mermaid are **vendored and lazy-loaded** — the base board stays
|
|
105
|
+
dependency-free. Legacy `"html"` / `"htmlFile"` / `"htmlHeight"` on root or
|
|
106
|
+
questions are still accepted and normalised automatically.
|
|
107
|
+
|
|
108
|
+
## Annotations
|
|
109
|
+
|
|
110
|
+
Users can hover chart points, diagram nodes, table cells, or select text in
|
|
111
|
+
markdown to leave inline comments. Always mention this in the board intro.
|
|
112
|
+
|
|
113
|
+
`result.annotations` is an array of:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"id": "a1",
|
|
118
|
+
"questionId": "q-id or null",
|
|
119
|
+
"blockId": "b2",
|
|
120
|
+
"target": {
|
|
121
|
+
"kind": "chart-element | mermaid-node | table-cell | text | html-element",
|
|
122
|
+
"..."
|
|
123
|
+
},
|
|
124
|
+
"text": "user comment",
|
|
125
|
+
"createdAt": "ISO"
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Read annotations before generating your next output — a comment on a specific
|
|
130
|
+
data point often carries sharper signal than a checkbox answer.
|
|
131
|
+
|
|
132
|
+
## Recipes
|
|
133
|
+
|
|
134
|
+
**Plan approval** — board-level `markdown` block rendering the plan, one `yesno`
|
|
135
|
+
"Approve this plan?", one `multi` "Which parts should change?" (`"note": true`),
|
|
136
|
+
one `textarea` for concerns.
|
|
137
|
+
|
|
138
|
+
**Requirements gathering** — one board with: `single` for the core approach
|
|
139
|
+
(options with `description`s + `"other": true`), `multi` for scope, `scale` for
|
|
140
|
+
urgency, `textarea` for constraints.
|
|
141
|
+
|
|
142
|
+
**A/B design review** — `single` question with a `blocks` array containing an
|
|
143
|
+
`html` block showing both options side by side; options `["A", "B"]`; `scale`
|
|
144
|
+
for confidence; `textarea` for what's missing from both.
|
|
145
|
+
|
|
146
|
+
**Metrics review** — board-level `chart` block (bar or line) showing the key
|
|
147
|
+
numbers, followed by a `table` block for the raw data; at least one question
|
|
148
|
+
asking what to act on. In the intro, tell the user they can click chart points
|
|
149
|
+
and table cells to comment on specific values.
|
|
150
|
+
|
|
151
|
+
## Reuse & management
|
|
152
|
+
|
|
153
|
+
`rly history` (saved boards) · `rly spec <id>` (print spec to modify) ·
|
|
154
|
+
`rly reuse <id>` (re-run blank) · `rly reopen <id>` (re-open with saved
|
|
155
|
+
answers prefilled) · `rly list` / `rly open` / `rly stop <id>` · `rly rm <id>`.
|
|
156
|
+
Multiple boards can run concurrently.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Q2 engineering review",
|
|
3
|
+
"intro": "Below you'll find the sprint metrics, architecture overview, and a data table. Hover chart bars, click diagram nodes, or click table cells to leave inline comments — they come back with your answers. Select any text in a markdown section to annotate it too.",
|
|
4
|
+
"blocks": [
|
|
5
|
+
{
|
|
6
|
+
"type": "markdown",
|
|
7
|
+
"md": "## Sprint velocity\nThe chart below shows shipped vs planned story points for each sprint this quarter. Click any bar to comment on a specific sprint."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"type": "chart",
|
|
11
|
+
"kind": "bar",
|
|
12
|
+
"title": "Q2 velocity — shipped vs planned",
|
|
13
|
+
"labels": ["S1", "S2", "S3", "S4", "S5", "S6"],
|
|
14
|
+
"series": [
|
|
15
|
+
{ "label": "Shipped", "data": [34, 41, 29, 47, 38, 52], "color": "#4d8a66" },
|
|
16
|
+
{ "label": "Planned", "data": [40, 40, 40, 40, 40, 40], "color": "#c2674b" }
|
|
17
|
+
],
|
|
18
|
+
"height": 320
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "markdown",
|
|
22
|
+
"md": "## System architecture\nThe diagram below shows the current service topology. Click any node to comment on it."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "mermaid",
|
|
26
|
+
"code": "graph LR\n Client-->|HTTPS|Gateway\n Gateway-->AuthService\n Gateway-->APIService\n APIService-->DB[(Postgres)]\n APIService-->Cache[(Redis)]\n APIService-->Queue[[Job queue]]\n Queue-->Worker\n Worker-->DB",
|
|
27
|
+
"height": 300
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "markdown",
|
|
31
|
+
"md": "## Service health snapshot\nCurrent status as of the last deployment. Click any cell to comment."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "table",
|
|
35
|
+
"columns": [
|
|
36
|
+
{ "key": "service", "label": "Service" },
|
|
37
|
+
{ "key": "status", "label": "Status", "align": "center" },
|
|
38
|
+
{ "key": "p99ms", "label": "p99 (ms)", "align": "right" },
|
|
39
|
+
{ "key": "errRate", "label": "Error rate", "align": "right" },
|
|
40
|
+
{ "key": "owner", "label": "Owner" }
|
|
41
|
+
],
|
|
42
|
+
"rows": [
|
|
43
|
+
{ "service": "Gateway", "status": "healthy", "p99ms": 42, "errRate": "0.1%", "owner": "platform" },
|
|
44
|
+
{ "service": "AuthService", "status": "healthy", "p99ms": 98, "errRate": "0.0%", "owner": "identity" },
|
|
45
|
+
{ "service": "APIService", "status": "degraded", "p99ms": 620, "errRate": "2.4%", "owner": "core" },
|
|
46
|
+
{ "service": "Worker", "status": "healthy", "p99ms": 310, "errRate": "0.3%", "owner": "core" }
|
|
47
|
+
],
|
|
48
|
+
"sortable": true
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "markdown",
|
|
52
|
+
"md": "## Config reference\nDeployment config in use this quarter:"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "code",
|
|
56
|
+
"lang": "yaml",
|
|
57
|
+
"code": "api_service:\n replicas: 4\n memory_limit: 512Mi\n cpu_limit: 500m\n db_pool_size: 20\n cache_ttl_s: 300"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"questions": [
|
|
61
|
+
{
|
|
62
|
+
"id": "biggest_concern",
|
|
63
|
+
"type": "single",
|
|
64
|
+
"label": "Which area needs the most attention next quarter?",
|
|
65
|
+
"required": true,
|
|
66
|
+
"options": [
|
|
67
|
+
{ "value": "api_perf", "label": "API Service performance", "description": "p99 and error rate are high" },
|
|
68
|
+
{ "value": "velocity", "label": "Sprint predictability", "description": "variance between sprints" },
|
|
69
|
+
{ "value": "arch", "label": "Architecture complexity", "description": "service sprawl, dependency depth" },
|
|
70
|
+
{ "value": "on_call", "label": "On-call burden", "description": "toil from degraded services" }
|
|
71
|
+
],
|
|
72
|
+
"other": true,
|
|
73
|
+
"note": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "api_degraded_cause",
|
|
77
|
+
"type": "single",
|
|
78
|
+
"label": "What is most likely causing the APIService degradation?",
|
|
79
|
+
"options": [
|
|
80
|
+
{ "value": "db_pool", "label": "DB connection pool exhaustion" },
|
|
81
|
+
{ "value": "cache_miss","label": "Cache miss storm" },
|
|
82
|
+
{ "value": "upstream", "label": "Upstream traffic spike" },
|
|
83
|
+
{ "value": "unknown", "label": "Unknown — needs investigation" }
|
|
84
|
+
],
|
|
85
|
+
"other": true
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "ship_reliability_work",
|
|
89
|
+
"type": "yesno",
|
|
90
|
+
"label": "Should we dedicate at least one sprint to reliability before adding features?"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "velocity_target",
|
|
94
|
+
"type": "scale",
|
|
95
|
+
"label": "How ambitious should Q3's velocity target be?",
|
|
96
|
+
"min": 1,
|
|
97
|
+
"max": 5,
|
|
98
|
+
"minLabel": "conservative (≤40 pts)",
|
|
99
|
+
"maxLabel": "aggressive (60+ pts)",
|
|
100
|
+
"blocks": [
|
|
101
|
+
{
|
|
102
|
+
"type": "markdown",
|
|
103
|
+
"md": "Current average: **40 pts/sprint**. Improving reliability tooling could raise the ceiling, but also costs sprint capacity up front."
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "other_notes",
|
|
109
|
+
"type": "textarea",
|
|
110
|
+
"label": "Anything else I should factor in for Q3 planning?",
|
|
111
|
+
"placeholder": "team changes, external deadlines, tech debt priorities…"
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"note": true,
|
|
115
|
+
"allowPartial": false,
|
|
116
|
+
"autoClose": true,
|
|
117
|
+
"submitLabel": "Submit review"
|
|
118
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Auth feature — decisions needed",
|
|
3
|
+
"intro": "I'm about to implement authentication. Three decisions before I start. Hover chart points or select text to leave comments.",
|
|
4
|
+
"questions": [
|
|
5
|
+
{
|
|
6
|
+
"id": "provider",
|
|
7
|
+
"type": "single",
|
|
8
|
+
"label": "Which auth approach?",
|
|
9
|
+
"required": true,
|
|
10
|
+
"options": [
|
|
11
|
+
{ "value": "oauth", "label": "OAuth (GitHub + Google)", "description": "no password storage, needs provider setup" },
|
|
12
|
+
{ "value": "magic-link", "label": "Magic links", "description": "email-based, no passwords" },
|
|
13
|
+
{ "value": "password", "label": "Classic email + password", "description": "full control, more security surface" }
|
|
14
|
+
],
|
|
15
|
+
"other": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "scope",
|
|
19
|
+
"type": "multi",
|
|
20
|
+
"label": "Which surfaces need auth in this iteration?",
|
|
21
|
+
"options": ["web app", "REST API", "admin panel", "CLI"]
|
|
22
|
+
},
|
|
23
|
+
{ "id": "mfa", "type": "yesno", "label": "Include 2FA now (vs. a later iteration)?" },
|
|
24
|
+
{ "id": "priority", "type": "scale", "label": "How urgent is this feature?", "min": 1, "max": 5, "minLabel": "whenever", "maxLabel": "blocking" },
|
|
25
|
+
{ "id": "constraints", "type": "textarea", "label": "Any constraints I should know about?", "placeholder": "compliance, existing user table, …" }
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Dashboard layout — pick a direction",
|
|
3
|
+
"intro": "Two interactive mockups below. Click around, then answer. Select any text to leave inline comments.",
|
|
4
|
+
"questions": [
|
|
5
|
+
{
|
|
6
|
+
"id": "layout",
|
|
7
|
+
"type": "single",
|
|
8
|
+
"label": "Which layout direction?",
|
|
9
|
+
"required": true,
|
|
10
|
+
"blocks": [
|
|
11
|
+
{
|
|
12
|
+
"type": "html",
|
|
13
|
+
"html": "<!doctype html><html><body style=\"margin:0;font-family:system-ui;display:flex;gap:12px;padding:12px;background:#fff\"><div style=\"flex:1;border:2px solid #3b6ef6;border-radius:10px;padding:10px\"><b>A · sidebar</b><div style=\"display:flex;gap:6px;margin-top:8px\"><div style=\"width:60px;height:120px;background:#dbe4ff;border-radius:6px\"></div><div style=\"flex:1;height:120px;background:#f1f3f9;border-radius:6px\"></div></div></div><div style=\"flex:1;border:2px solid #999;border-radius:10px;padding:10px\"><b>B · topbar</b><div style=\"margin-top:8px\"><div style=\"height:24px;background:#dbe4ff;border-radius:6px\"></div><div style=\"height:90px;background:#f1f3f9;border-radius:6px;margin-top:6px\"></div></div></div></body></html>",
|
|
14
|
+
"height": 220
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"options": [
|
|
18
|
+
{ "value": "sidebar", "label": "A — sidebar navigation" },
|
|
19
|
+
{ "value": "topbar", "label": "B — topbar navigation" }
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{ "id": "density", "type": "scale", "label": "Information density?", "min": 1, "max": 5, "minLabel": "airy", "maxLabel": "dense" },
|
|
23
|
+
{ "id": "missing", "type": "textarea", "label": "Anything missing from both?" }
|
|
24
|
+
]
|
|
25
|
+
}
|