@bytesbybrandon/living-docs 0.2.1 → 0.3.1
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/README.md +6 -4
- package/docs/guide/cli.md +61 -0
- package/docs/guide/document-model.md +117 -0
- package/docs/guide/guarantees.md +31 -0
- package/docs/guide/mcp.md +47 -0
- package/docs/guide/pipeline.md +36 -0
- package/docs/guide/reactive-workflow.md +21 -0
- package/docs/guide/style-tokens.md +60 -0
- package/docs/guide/timeline.md +75 -0
- package/package.json +14 -2
- package/samples/agent-skills-audit.json +38 -1
- package/samples/end-of-harness-engineering.json +30 -7
- package/samples/harness-engineering.json +32 -2
- package/src/axi/cli.js +53 -7
- package/src/export/video.js +150 -0
- package/src/ingest/cues.js +81 -0
- package/src/ingest/index.js +9 -3
- package/src/ingest/style.js +57 -0
- package/src/mcp/server.js +32 -8
- package/src/model/markdown.js +7 -2
- package/src/model/schema.js +64 -12
- package/src/model/validate.js +82 -4
- package/src/render/blocks.js +9 -5
- package/src/render/index.js +16 -5
- package/src/render/style.js +1 -1
- package/src/render/svg.js +13 -16
- package/src/render/themes/hud.js +18 -7
- package/src/render/themes/variants.js +43 -0
- package/src/render/timeline.js +304 -0
package/README.md
CHANGED
|
@@ -10,8 +10,10 @@ Ships an AXI CLI and a stdio MCP server over the same core.
|
|
|
10
10
|
|
|
11
11
|
### Key Features
|
|
12
12
|
|
|
13
|
-
* **
|
|
13
|
+
* **Themes:** `paper-light` for papers and reports, `paper-dark` for reading notes and essays, `hud` for repo audits and system snapshots. Curated looks (`field-notes`, `editorial`, `blueprint`) sit on them, and `ingest --draft` designs a look and accent from the source itself.
|
|
14
14
|
* **Generated visuals:** diagrams and charts render as inline SVG from a compact spec, and the console hero uses a seeded graph layout.
|
|
15
|
+
* **Living timeline:** cues highlight the source's own sentences, light up the figure parts they describe, count numbers, type text, and scroll the video frame. Motion stays inside each block, so figures and text stay flat and legible. Drafted docs get cues automatically. See [Timeline and video](docs/guide/timeline.md).
|
|
16
|
+
* **Video export:** `render --format mp4|webm|gif` records the timeline frame by frame, with optional Playwright and ffmpeg.
|
|
15
17
|
* **Figure motion:** `draw`, `reveal`, and `steps` animate a generated figure with scoped CSS, then freeze for print and reduced motion. See [Document model](docs/guide/document-model.md).
|
|
16
18
|
* **Per-source style tokens:** palette, seed color, type pairing, density, and figure treatment adapt a theme without arbitrary CSS. See [Style tokens](docs/guide/style-tokens.md).
|
|
17
19
|
* **One self-contained file:** inline CSS, inline SVG, no network assets, and print rules. See [Guarantees](docs/guide/guarantees.md).
|
|
@@ -21,7 +23,7 @@ Ships an AXI CLI and a stdio MCP server over the same core.
|
|
|
21
23
|
|
|
22
24
|
* **Language:** JavaScript on Node.js 20 or newer, ECMAScript modules.
|
|
23
25
|
* **Rendering:** no UI framework and no build step; blocks, SVG, and theme CSS are plain JavaScript.
|
|
24
|
-
* **Dependencies:** `@modelcontextprotocol/sdk` for the MCP server and `unpdf` for PDF text extraction.
|
|
26
|
+
* **Dependencies:** `@modelcontextprotocol/sdk` for the MCP server and `unpdf` for PDF text extraction. Video export uses the optional `playwright` package and `ffmpeg`.
|
|
25
27
|
* **Tests:** the Node.js built-in test runner.
|
|
26
28
|
|
|
27
29
|
### Table of Contents
|
|
@@ -48,7 +50,7 @@ Install the package globally or run it without installing.
|
|
|
48
50
|
|
|
49
51
|
1. **Install from npm:**
|
|
50
52
|
```bash
|
|
51
|
-
npm install -g
|
|
53
|
+
npm install -g living-docs-axi
|
|
52
54
|
```
|
|
53
55
|
2. **Or clone the repository:**
|
|
54
56
|
```bash
|
|
@@ -83,7 +85,7 @@ node bin/living-docs-axi.js render docs/note.model.json --theme paper-dark -o do
|
|
|
83
85
|
node bin/living-docs-axi.js preview docs
|
|
84
86
|
```
|
|
85
87
|
|
|
86
|
-
With the published package, use `npx -y
|
|
88
|
+
With the published package, use `npx -y living-docs-axi` for each command.
|
|
87
89
|
|
|
88
90
|
Detailed references:
|
|
89
91
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CLI reference
|
|
2
|
+
|
|
3
|
+
The `living-docs-axi` command follows the AXI principles: compact TOON-style output, a content-first home view, and `help[]` next-step lines.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
living-docs-axi home: themes, built docs, next steps
|
|
7
|
+
living-docs-axi themes theme list with when to use each
|
|
8
|
+
living-docs-axi schema [--block figure] block fields and types
|
|
9
|
+
living-docs-axi ingest <path|url|-> outline, or --section <n|id> for one section
|
|
10
|
+
living-docs-axi ingest <path> --draft write a model, with a drafted timeline, from the source
|
|
11
|
+
living-docs-axi render <model.json> validate and write HTML, or --format mp4|webm|gif for video
|
|
12
|
+
living-docs-axi validate <model.json> validation only
|
|
13
|
+
living-docs-axi preview [dir] serve built docs with an index
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Flags
|
|
17
|
+
|
|
18
|
+
| Flag | Purpose |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| `--theme <name>` | `paper-light`, `paper-dark`, `hud`, or a curated look: `field-notes`, `editorial`, `blueprint`. With `--draft`, omitted means the source picks |
|
|
21
|
+
| `--seed <hex>` | with `--draft`: accent seed, overriding the one derived from the title |
|
|
22
|
+
| `-o`, `--out <file>` | output path |
|
|
23
|
+
| `--section <n\|id>` | ingest one section |
|
|
24
|
+
| `--max-chars <n>` | cap section text, default 12000 |
|
|
25
|
+
| `--full` | disable truncation |
|
|
26
|
+
| `--stdout` | print HTML instead of writing a file |
|
|
27
|
+
| `--url <url>` | ingest a URL |
|
|
28
|
+
| `--text <text>` | ingest inline text |
|
|
29
|
+
| `--port <n>` | preview port, default 4600 |
|
|
30
|
+
| `--no-open` | do not open a browser |
|
|
31
|
+
| `--static` | draft without timeline cues |
|
|
32
|
+
| `--format <f>` | `html` (default), `mp4`, `webm`, or `gif` |
|
|
33
|
+
| `--size <WxH>` | video stage, default `1080x1350` |
|
|
34
|
+
| `--fps <n>` | video frames per second, default 30 |
|
|
35
|
+
| `--scale <n>` | device pixel ratio for the stage, default 1 |
|
|
36
|
+
|
|
37
|
+
## Exit codes
|
|
38
|
+
|
|
39
|
+
| Code | Meaning |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| 0 | success |
|
|
42
|
+
| 1 | invalid model or runtime failure |
|
|
43
|
+
| 2 | usage error, including unknown flags |
|
|
44
|
+
|
|
45
|
+
Errors are structured on standard output.
|
|
46
|
+
Unknown flags fail loud instead of being ignored.
|
|
47
|
+
|
|
48
|
+
## Examples
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx -y living-docs-axi themes
|
|
52
|
+
npx -y living-docs-axi ingest samples/source/harness-notes.md --draft -o docs/draft.model.json
|
|
53
|
+
npx -y living-docs-axi render docs/draft.model.json --theme paper-dark -o docs/draft.html
|
|
54
|
+
npx -y living-docs-axi preview docs --no-open
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## See also
|
|
58
|
+
|
|
59
|
+
- [Pipeline](pipeline.md)
|
|
60
|
+
- [Document model](document-model.md)
|
|
61
|
+
- [Timeline and video](timeline.md)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Document model
|
|
2
|
+
|
|
3
|
+
A model is `{ schemaVersion: 1, theme?, meta, blocks }`.
|
|
4
|
+
Validation is strict: unknown fields, unknown block types, and unresolved references fail with an exact path.
|
|
5
|
+
|
|
6
|
+
## Meta
|
|
7
|
+
|
|
8
|
+
`meta` accepts `title`, `subtitle`, `kicker`, `runningHead`, `author`, `affiliation`, `date`, `stamps`, `abstract`, `indexTerms`, `footer`, `accent`, and `style`.
|
|
9
|
+
`style` carries the [style tokens](style-tokens.md).
|
|
10
|
+
|
|
11
|
+
## Blocks
|
|
12
|
+
|
|
13
|
+
| Block | Purpose |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `prose` | body text with inline markdown and `[[1]]` footnote refs |
|
|
16
|
+
| `heading` | numbered section (`level: 2`) or subsection (`level: 3`) |
|
|
17
|
+
| `figure` | generated diagram or chart, auto-numbered |
|
|
18
|
+
| `table` | rule-based table with small-caps head |
|
|
19
|
+
| `algorithm` | numbered pseudocode with an optional highlighted line |
|
|
20
|
+
| `callout` | `takeaway`, `note`, or `warn` aside |
|
|
21
|
+
| `stats` | row of headline numbers |
|
|
22
|
+
| `list`, `quote`, `code` | supporting text blocks |
|
|
23
|
+
| `image` | supplied file, inlined as a data URI |
|
|
24
|
+
| `footnotes` | footnote list printed at the foot |
|
|
25
|
+
| `ticker` | one-line console status strip |
|
|
26
|
+
| `graphScene` | console hero: tabs, prompt, graph, active-node card |
|
|
27
|
+
| `panels` | console grid with 13 panel kinds |
|
|
28
|
+
|
|
29
|
+
## Figures
|
|
30
|
+
|
|
31
|
+
A figure takes either a `diagram` spec or a `chart` spec.
|
|
32
|
+
Diagrams place nodes and edges on a 1000-unit canvas, with optional groups and notes.
|
|
33
|
+
Charts accept `line`, `scatter`, `bar`, and `steps` series, with ticks, bounds, legend, and annotations.
|
|
34
|
+
Both render as inline SVG, so no image assets are required.
|
|
35
|
+
|
|
36
|
+
`ingest --draft` never writes figures.
|
|
37
|
+
It drafts text, lists, stats, and a timeline from the source, so every figure is authored into the model by hand or by an agent.
|
|
38
|
+
Run `living-docs-axi schema --block figure` for every nested field.
|
|
39
|
+
|
|
40
|
+
### Diagram
|
|
41
|
+
|
|
42
|
+
Nodes sit at fixed `x` and `y` positions on a canvas that is 1000 units wide by default.
|
|
43
|
+
There is no auto layout, so choose positions that leave room for labels.
|
|
44
|
+
Node ids must be unique, and every edge and group member must name an existing node id.
|
|
45
|
+
Node `kind` is `box`, `accent`, `plain`, `dashed`, or `stack`.
|
|
46
|
+
Edge `route` is `straight` or `elbow`.
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"type": "figure",
|
|
51
|
+
"id": "segments",
|
|
52
|
+
"caption": "Appends go to the active segment. Sealed segments stay read-only.",
|
|
53
|
+
"spec": "diagram",
|
|
54
|
+
"span": "page",
|
|
55
|
+
"motion": "draw",
|
|
56
|
+
"diagram": {
|
|
57
|
+
"width": 1000,
|
|
58
|
+
"height": 360,
|
|
59
|
+
"nodes": [
|
|
60
|
+
{ "id": "writer", "label": "writer", "sub": "append", "x": 40, "y": 150, "w": 160, "h": 64 },
|
|
61
|
+
{ "id": "dir", "label": "segment directory", "x": 280, "y": 150, "w": 200, "h": 64, "kind": "accent" },
|
|
62
|
+
{ "id": "hot", "label": "active segment", "x": 580, "y": 60, "w": 180, "h": 64 },
|
|
63
|
+
{ "id": "cold", "label": "sealed segments", "x": 580, "y": 240, "w": 180, "h": 64, "kind": "dashed" }
|
|
64
|
+
],
|
|
65
|
+
"edges": [
|
|
66
|
+
{ "from": "writer", "to": "dir", "label": "publish" },
|
|
67
|
+
{ "from": "dir", "to": "hot", "route": "elbow" },
|
|
68
|
+
{ "from": "dir", "to": "cold", "route": "elbow" }
|
|
69
|
+
],
|
|
70
|
+
"groups": [{ "label": "segment store", "nodes": ["hot", "cold"] }],
|
|
71
|
+
"notes": ["Sealing copies no payload."]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Chart
|
|
77
|
+
|
|
78
|
+
Chart `kind` is `line`, `scatter`, `bar`, or `steps`.
|
|
79
|
+
A series carries `points` of `{ x, y }`, or `values` and `labels` for bars.
|
|
80
|
+
Series `tone` is `accent`, `ink`, `muted`, `kept`, or `rejected`.
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"type": "figure",
|
|
85
|
+
"caption": "Lookup probes grow with segment count.",
|
|
86
|
+
"spec": "chart",
|
|
87
|
+
"chart": {
|
|
88
|
+
"kind": "line",
|
|
89
|
+
"xLabel": "segments",
|
|
90
|
+
"yLabel": "probes",
|
|
91
|
+
"series": [
|
|
92
|
+
{ "name": "nacre", "tone": "accent", "points": [{ "x": 1, "y": 1 }, { "x": 32, "y": 32 }, { "x": 128, "y": 128 }] }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Use an `image` block instead when the graphic already exists as a raster or SVG file.
|
|
99
|
+
|
|
100
|
+
### Motion
|
|
101
|
+
|
|
102
|
+
`motion` is optional and accepts `none`, `draw`, `reveal`, or `steps`.
|
|
103
|
+
Motion is scoped CSS on the generated SVG: edges draw, marks fade in, and bars grow.
|
|
104
|
+
Print and `prefers-reduced-motion` freeze the final frame, and content stays visible while the animation runs.
|
|
105
|
+
|
|
106
|
+
## Console blocks
|
|
107
|
+
|
|
108
|
+
`graphScene` accepts a title, meta chips, tabs, a prompt line, a graph payload, an action strip, and a status line.
|
|
109
|
+
The graph layout is seeded, so the same model produces the same scene.
|
|
110
|
+
`panels` holds numbered panels with one of 13 kinds: `repo`, `bars`, `list`, `radar`, `tree`, `log`, `heat`, `big`, `spark`, `code`, `hist`, `metrics`, and `diff`.
|
|
111
|
+
|
|
112
|
+
Other themes render console blocks as annotated cards, so a model can switch themes without losing content.
|
|
113
|
+
|
|
114
|
+
## See also
|
|
115
|
+
|
|
116
|
+
- [Pipeline](pipeline.md)
|
|
117
|
+
- [Style tokens](style-tokens.md)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Guarantees
|
|
2
|
+
|
|
3
|
+
## One file per document
|
|
4
|
+
|
|
5
|
+
CSS, SVG, and the console runtime are inlined.
|
|
6
|
+
No CDN, fonts, or remote images are loaded.
|
|
7
|
+
|
|
8
|
+
## Deterministic output
|
|
9
|
+
|
|
10
|
+
Identical model and theme produce identical bytes, including generated SVG ids, graph layout, and derived palette values.
|
|
11
|
+
|
|
12
|
+
## Curated styling
|
|
13
|
+
|
|
14
|
+
`meta.style` only accepts known palettes, type pairings, densities, and figure treatments.
|
|
15
|
+
Accent colors are contrast corrected.
|
|
16
|
+
No arbitrary CSS is injected.
|
|
17
|
+
|
|
18
|
+
## Escaped content
|
|
19
|
+
|
|
20
|
+
Document text is HTML escaped.
|
|
21
|
+
Only `http(s)`, `mailto:`, `#`, and relative URLs survive as links.
|
|
22
|
+
|
|
23
|
+
## Print ready
|
|
24
|
+
|
|
25
|
+
Paper themes ship `@page` rules and keep figures, tables, algorithms, and callouts unbroken across pages.
|
|
26
|
+
Figure motion freezes to its final frame in print and under reduced-motion preferences.
|
|
27
|
+
|
|
28
|
+
## Known limits
|
|
29
|
+
|
|
30
|
+
PDF ingestion depends on the optional `unpdf` package and reports a typed error when it is unavailable.
|
|
31
|
+
There is no visual regression suite and no per-theme versioning.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# MCP server
|
|
2
|
+
|
|
3
|
+
The package ships a stdio MCP server over the same core as the CLI.
|
|
4
|
+
|
|
5
|
+
## Published package
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mcpServers": {
|
|
10
|
+
"living-docs": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": ["-y", "-p", "living-docs-axi", "living-docs-mcp"]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Local checkout
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"living-docs": {
|
|
24
|
+
"command": "node",
|
|
25
|
+
"args": ["<absolute-checkout>/bin/living-docs-mcp.js"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tools
|
|
32
|
+
|
|
33
|
+
| Tool | Purpose |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `living_docs_themes` | list the themes (three structural bases plus curated looks) and what each is best for |
|
|
36
|
+
| `living_docs_schema` | block fields, or one block in detail |
|
|
37
|
+
| `living_docs_ingest` | outline a source, optionally draft a model with timeline cues (`static` skips them) |
|
|
38
|
+
| `living_docs_render` | validate and write HTML, or `format` mp4, webm, or gif, from a model, a model path, or a source |
|
|
39
|
+
| `living_docs_preview` | serve built docs and return the URL |
|
|
40
|
+
|
|
41
|
+
`living_docs_render` accepts a model object, a model path, or a source to draft from.
|
|
42
|
+
Tools return compact text, and errors are marked with `isError`.
|
|
43
|
+
|
|
44
|
+
## See also
|
|
45
|
+
|
|
46
|
+
- [CLI reference](cli.md)
|
|
47
|
+
- [Document model](document-model.md)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Pipeline
|
|
2
|
+
|
|
3
|
+
The engine turns one source into one self-contained HTML document.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
source -> ingest -> outline + normalized blocks
|
|
7
|
+
|
|
|
8
|
+
+-> --draft -> valid document model
|
|
9
|
+
|
|
|
10
|
+
+-> author a richer model against the schema
|
|
11
|
+
|
|
|
12
|
+
render --theme -> single HTML file
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Ingest
|
|
16
|
+
|
|
17
|
+
`ingest` accepts a file path (Markdown, plain text, HTML, or PDF), a URL, inline text, or standard input.
|
|
18
|
+
It returns an outline with section ids, titles, and word counts.
|
|
19
|
+
Large sources stay bounded: read the outline, then pull one section at a time with `--section <n|id>`.
|
|
20
|
+
|
|
21
|
+
## Draft models
|
|
22
|
+
|
|
23
|
+
`ingest --draft` is the zero-judgment path.
|
|
24
|
+
It writes a document model that validates and renders immediately.
|
|
25
|
+
An author then adds figures, charts, callouts, stats, and console panels against the schema.
|
|
26
|
+
|
|
27
|
+
## Render
|
|
28
|
+
|
|
29
|
+
`render` validates the model, resolves style tokens, and writes one file with inline CSS, inline SVG, and the console runtime.
|
|
30
|
+
The file loads no fonts, images, or scripts from the network.
|
|
31
|
+
|
|
32
|
+
## See also
|
|
33
|
+
|
|
34
|
+
- [CLI reference](cli.md)
|
|
35
|
+
- [Document model](document-model.md)
|
|
36
|
+
- [Style tokens](style-tokens.md)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Reactive workflow
|
|
2
|
+
|
|
3
|
+
An optional reactive skill wraps the same pipeline: intake, outline, theme and style plan, model authoring, validation, render, human review, and finalize.
|
|
4
|
+
It calls the CLI and does not reimplement rendering.
|
|
5
|
+
|
|
6
|
+
## Boundary
|
|
7
|
+
|
|
8
|
+
The skill is maintained separately from this package.
|
|
9
|
+
`src/model/schema.js` and the AXI commands are the stable engine surface.
|
|
10
|
+
|
|
11
|
+
## Plan and review
|
|
12
|
+
|
|
13
|
+
The workflow holds two human gates.
|
|
14
|
+
The first approves the theme, style tokens, sections, and figures.
|
|
15
|
+
The second reviews the rendered page.
|
|
16
|
+
Model revisions are bounded at four attempts before the run ends in an error state.
|
|
17
|
+
|
|
18
|
+
## See also
|
|
19
|
+
|
|
20
|
+
- [CLI reference](cli.md)
|
|
21
|
+
- [Style tokens](style-tokens.md)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Style tokens
|
|
2
|
+
|
|
3
|
+
`meta.style` adapts a theme to its source without accepting arbitrary CSS.
|
|
4
|
+
Every choice is curated and validated, so the page stays coherent, printable, and deterministic.
|
|
5
|
+
|
|
6
|
+
| Token | Values | Effect |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| `palette` | `default`, `ember`, `ocean`, `moss`, `graphite`, `ink`, `plum` | curated accent family |
|
|
9
|
+
| `seed` | hex color, for example `#2f6f8f` | derives the accent, tinted surfaces, and figure fills; lightness is corrected until the accent clears WCAG contrast against the page |
|
|
10
|
+
| `type` | papers: `classic`, `editorial`, `technical`; console: `mono`, `hybrid`, `terminal` | curated font stacks, no web fonts |
|
|
11
|
+
| `density` | `compact`, `normal`, `roomy` | body size, leading, figure margins, panel height |
|
|
12
|
+
| `figure` | `outline`, `solid`, `minimal` | diagram fill and stroke; `minimal` also drops chart gridlines |
|
|
13
|
+
| `layout` | `columns`, `single` | paper themes only: two columns by default, or one reading column for code and wide tables |
|
|
14
|
+
|
|
15
|
+
`meta.accent` remains available as a direct accent override.
|
|
16
|
+
Invalid tokens fail validation at `meta.style`.
|
|
17
|
+
|
|
18
|
+
## Looks and designed drafts
|
|
19
|
+
|
|
20
|
+
Three themes set the structure: `paper-light`, `paper-dark`, and `hud`.
|
|
21
|
+
Curated looks sit on a structure with their own palette and type: `field-notes` and `editorial` on `paper-light`, `blueprint` on `paper-dark`.
|
|
22
|
+
A look is only a palette and a short stylesheet, so blocks, figures, timelines, and print behave exactly like the base theme.
|
|
23
|
+
|
|
24
|
+
`ingest --draft` designs the doc from its source.
|
|
25
|
+
Code-heavy sources get `blueprint`, papers get `paper-light`, long prose gets `editorial`, short notes get `field-notes`, and the rest get `paper-dark`.
|
|
26
|
+
Paper themes also get an accent seed derived from the title, and density follows length.
|
|
27
|
+
The draft writes these as ordinary `meta.style` tokens, so edit them freely.
|
|
28
|
+
Pass `--theme` or `--seed` to override the choice.
|
|
29
|
+
|
|
30
|
+
## Motion
|
|
31
|
+
|
|
32
|
+
Motion has two layers.
|
|
33
|
+
|
|
34
|
+
`figure.motion` animates one generated figure with `draw`, `reveal`, or `steps`.
|
|
35
|
+
It is scoped CSS on the SVG, freezes for print, and disables under `prefers-reduced-motion`.
|
|
36
|
+
The content stays visible while the animation runs.
|
|
37
|
+
|
|
38
|
+
The console theme also animates its graph, pulse, and clock.
|
|
39
|
+
Those animations are theme owned, not tokens.
|
|
40
|
+
|
|
41
|
+
## Example
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"meta": {
|
|
46
|
+
"title": "Example",
|
|
47
|
+
"style": {
|
|
48
|
+
"seed": "#2f6f8f",
|
|
49
|
+
"type": "editorial",
|
|
50
|
+
"density": "roomy",
|
|
51
|
+
"figure": "minimal"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## See also
|
|
58
|
+
|
|
59
|
+
- [Document model](document-model.md)
|
|
60
|
+
- [Guarantees](guarantees.md)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Timeline and video
|
|
2
|
+
|
|
3
|
+
A timeline makes a doc move in step with its own text.
|
|
4
|
+
Cues highlight a source sentence, light up the figure part it describes, count numbers up, type text out, and scroll the video frame to a block.
|
|
5
|
+
The same timeline plays on the live page and records to MP4, WebM, or GIF.
|
|
6
|
+
|
|
7
|
+
## Marks and ids
|
|
8
|
+
|
|
9
|
+
Wrap a sentence in any prose string, the abstract included, with `[[mark:id|text]]`.
|
|
10
|
+
Give any block an `id` so cues can point at it.
|
|
11
|
+
Ids use lowercase letters, digits, and hyphens, and must be unique.
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{ "type": "figure", "id": "loop", "caption": "...", "spec": "diagram", "diagram": { "nodes": [{ "id": "editor", "label": "4B editor", "x": 552, "y": 28 }] } }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Cues
|
|
18
|
+
|
|
19
|
+
`timeline.cues` is a list of `{ at, dur, do, target }`.
|
|
20
|
+
`at` and `dur` are seconds; `dur` defaults to 1.2.
|
|
21
|
+
|
|
22
|
+
| `do` | What it does |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `highlight` | Sweeps a highlighter across a mark or block, then leaves a faint underline. |
|
|
25
|
+
| `focus` | Outlines a block or part and dims its siblings. The glow stays inside the block. |
|
|
26
|
+
| `reveal` | Fades a block or part in at the cue time, without moving it. |
|
|
27
|
+
| `count` | Counts the numbers inside the target up from zero. |
|
|
28
|
+
| `type` | Types the target's text out. The full text keeps its space, so nothing reflows. |
|
|
29
|
+
| `camera` | Video only: scrolls the frame to a block or part, or back to `page`. The page stays flat at 100%; `zoom` is an opt-in that scales it. |
|
|
30
|
+
| `activate` | HUD only: glides the scene crosshair to a label. |
|
|
31
|
+
|
|
32
|
+
Targets are `mark:<id>`, `<blockId>`, `<blockId>/<part>`, or `page` for the camera.
|
|
33
|
+
A part is a diagram node id, a panel index such as `08`, or a scene label.
|
|
34
|
+
Validation rejects a cue whose target does not exist.
|
|
35
|
+
|
|
36
|
+
`timeline.duration` defaults to the last cue end plus 1.5 seconds.
|
|
37
|
+
`timeline.loop` restarts the live page when it ends; reveals, counts, and typing stay settled after the first pass.
|
|
38
|
+
On the live page, a block whose cue comes up while it is still below the fold waits, with its cues in order, until the reader scrolls to it.
|
|
39
|
+
|
|
40
|
+
## Drafted cues
|
|
41
|
+
|
|
42
|
+
`ingest --draft` writes a timeline from the source: up to four abstract sentences and five section leads are marked and highlighted in reading order, the frame scrolls to each lead, and stats count up.
|
|
43
|
+
Pass `--static` for a draft without cues.
|
|
44
|
+
Edit or replace the drafted cues like any other part of the model.
|
|
45
|
+
|
|
46
|
+
## Video
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
living-docs-axi render docs/notes.model.json --format mp4 -o docs/notes.mp4
|
|
50
|
+
living-docs-axi render docs/notes.model.json --format gif --size 1080x1350 --fps 30
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The renderer lays the doc out on a fixed stage, seeks the timeline frame by frame in headless Chromium, and pipes the frames to ffmpeg.
|
|
54
|
+
Every frame is a pure function of time, so two renders on one machine produce the same frames.
|
|
55
|
+
MP4 is the default for sharing; GIF is 720 wide at 15 fps for READMEs.
|
|
56
|
+
Video needs the optional `playwright` package with Chromium, and `ffmpeg` on `PATH` or in `LIVING_DOCS_FFMPEG`.
|
|
57
|
+
In a project, run `npm i -D playwright`; with npx, add it to the same call:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx -y -p living-docs-axi -p playwright living-docs-axi render notes.model.json --format mp4
|
|
61
|
+
npx playwright install chromium
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Driving a live doc from another page
|
|
65
|
+
|
|
66
|
+
A same-origin page that embeds a timed doc in an iframe can take over its clock through `window.__ld`.
|
|
67
|
+
`pause()` hands the clock to the host, and `seek(t)` then renders the frame at `t` seconds.
|
|
68
|
+
`play()` resumes from the last shown time, `replay()` restarts from zero, and `time()` reads the current time.
|
|
69
|
+
The home page of this site pins one doc and scrubs it as the reader scrolls.
|
|
70
|
+
The controls exist only on a live page; under reduced motion, in print, and in video capture the doc shows its final state or seeks per frame, so a host should check that `pause` is a function first.
|
|
71
|
+
|
|
72
|
+
## Accessibility and print
|
|
73
|
+
|
|
74
|
+
Under `prefers-reduced-motion`, print, or with scripts off, the page shows its final state: everything revealed, counted, and typed, with narrated sentences underlined.
|
|
75
|
+
Docs without a timeline ship no runtime.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytesbybrandon/living-docs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Turn a source document into a designed, self-contained living doc: academic paper, dark reading notes, or telemetry console. Ships an AXI CLI and an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"bin",
|
|
41
41
|
"src",
|
|
42
42
|
"samples",
|
|
43
|
+
"docs/guide",
|
|
43
44
|
"README.md",
|
|
44
45
|
"LICENSE"
|
|
45
46
|
],
|
|
@@ -47,12 +48,23 @@
|
|
|
47
48
|
"access": "public"
|
|
48
49
|
},
|
|
49
50
|
"scripts": {
|
|
50
|
-
"test": "node --test tests/cli.test.js tests/ingest.test.js tests/mcp.test.js tests/motion.test.js tests/render.test.js tests/site.test.js tests/style.test.js tests/validate.test.js",
|
|
51
|
+
"test": "node --test tests/cli.test.js tests/ingest.test.js tests/mcp.test.js tests/motion.test.js tests/render.test.js tests/site.test.js tests/style.test.js tests/timeline.test.js tests/validate.test.js",
|
|
51
52
|
"samples": "node scripts/build-samples.js",
|
|
52
53
|
"site": "node scripts/build-site.js"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
56
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
56
57
|
"unpdf": "^2.1.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"playwright": "^1.62.1"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"playwright": ">=1.40.0"
|
|
64
|
+
},
|
|
65
|
+
"peerDependenciesMeta": {
|
|
66
|
+
"playwright": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
57
69
|
}
|
|
58
70
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"blocks": [
|
|
13
13
|
{
|
|
14
|
+
"id": "scene",
|
|
14
15
|
"type": "graphScene",
|
|
15
16
|
"title": "AI CONFIGS / OPEN SOURCE",
|
|
16
17
|
"meta": ["SRC GITHUB", "5 TEAMS", "5 REPOS", "548.4K STARS", "$0"],
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
}
|
|
61
62
|
},
|
|
62
63
|
{
|
|
64
|
+
"id": "grid",
|
|
63
65
|
"type": "panels",
|
|
64
66
|
"columns": 4,
|
|
65
67
|
"items": [
|
|
@@ -256,6 +258,7 @@
|
|
|
256
258
|
"markdown": "This page is a single moment in a repository audit: one matched skill, its repository, and the run that surfaced it. Every number on the console is a fact about that snapshot, not a projection. The graph counts nodes and links across five repositories; the coverage grid marks which job families each repository actually covers."
|
|
257
259
|
},
|
|
258
260
|
{
|
|
261
|
+
"id": "totals",
|
|
259
262
|
"type": "stats",
|
|
260
263
|
"items": [
|
|
261
264
|
{ "label": "Repositories scanned", "value": "5", "note": "github" },
|
|
@@ -270,5 +273,39 @@
|
|
|
270
273
|
"title": "Reading the console",
|
|
271
274
|
"body": "Panels are independent: each one answers a different question about the same snapshot. The hero graph shows adjacency, not importance; the coverage grid is the only panel that scores completeness."
|
|
272
275
|
}
|
|
273
|
-
]
|
|
276
|
+
],
|
|
277
|
+
"timeline": {
|
|
278
|
+
"loop": true,
|
|
279
|
+
"duration": 16,
|
|
280
|
+
"cues": [
|
|
281
|
+
{ "at": 0.2, "dur": 0.6, "do": "reveal", "target": "grid/01" },
|
|
282
|
+
{ "at": 0.28, "dur": 0.6, "do": "reveal", "target": "grid/02" },
|
|
283
|
+
{ "at": 0.36, "dur": 0.6, "do": "reveal", "target": "grid/03" },
|
|
284
|
+
{ "at": 0.44, "dur": 0.6, "do": "reveal", "target": "grid/04" },
|
|
285
|
+
{ "at": 0.52, "dur": 0.6, "do": "reveal", "target": "grid/05" },
|
|
286
|
+
{ "at": 0.6000000000000001, "dur": 0.6, "do": "reveal", "target": "grid/06" },
|
|
287
|
+
{ "at": 0.6799999999999999, "dur": 0.6, "do": "reveal", "target": "grid/07" },
|
|
288
|
+
{ "at": 0.76, "dur": 0.6, "do": "reveal", "target": "grid/08" },
|
|
289
|
+
{ "at": 0.8400000000000001, "dur": 0.6, "do": "reveal", "target": "grid/09" },
|
|
290
|
+
{ "at": 0.9199999999999999, "dur": 0.6, "do": "reveal", "target": "grid/10" },
|
|
291
|
+
{ "at": 1, "dur": 0.6, "do": "reveal", "target": "grid/11" },
|
|
292
|
+
{ "at": 1.08, "dur": 0.6, "do": "reveal", "target": "grid/12" },
|
|
293
|
+
{ "at": 0.6, "dur": 1.6, "do": "count", "target": "grid/02" },
|
|
294
|
+
{ "at": 0.6, "dur": 1.6, "do": "count", "target": "grid/08" },
|
|
295
|
+
{ "at": 0.8, "dur": 1.6, "do": "count", "target": "grid/11" },
|
|
296
|
+
{ "at": 1, "dur": 2.4, "do": "type", "target": "grid/06" },
|
|
297
|
+
{ "at": 1.2, "dur": 2.2, "do": "type", "target": "grid/09" },
|
|
298
|
+
{ "at": 3, "dur": 1.4, "do": "activate", "target": "scene/spec-driven-development" },
|
|
299
|
+
{ "at": 3.6, "dur": 1.8, "do": "focus", "target": "grid/03" },
|
|
300
|
+
{ "at": 5.6, "dur": 1.4, "do": "activate", "target": "scene/code-review-and-quality" },
|
|
301
|
+
{ "at": 6.2, "dur": 1.8, "do": "focus", "target": "grid/07" },
|
|
302
|
+
{ "at": 8.2, "dur": 1.4, "do": "activate", "target": "scene/context-engineering" },
|
|
303
|
+
{ "at": 8.8, "dur": 1.8, "do": "focus", "target": "grid/12" },
|
|
304
|
+
{ "at": 10.8, "dur": 1.4, "do": "activate", "target": "scene/interview-me" },
|
|
305
|
+
{ "at": 11.4, "dur": 1.8, "do": "focus", "target": "grid/04" },
|
|
306
|
+
{ "at": 13.4, "dur": 1.4, "do": "camera", "target": "grid/08" },
|
|
307
|
+
{ "at": 13.6, "dur": 1.2, "do": "count", "target": "grid/08" },
|
|
308
|
+
{ "at": 14.9, "dur": 1, "do": "camera", "target": "page" }
|
|
309
|
+
]
|
|
310
|
+
}
|
|
274
311
|
}
|