rshow 0.0.0-stage → 0.0.2
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 +50 -2
- package/dist/main.js +8500 -0
- package/package.json +48 -4
- package/skills/rshow/SKILL.md +144 -0
- package/skills/rshow/reference/cli.md +263 -0
- package/skills/rshow/reference/dashboard.md +122 -0
- package/skills/rshow/reference/mockups.md +113 -0
- package/skills/rshow/reference/page-contract.md +83 -0
- package/skills/rshow/reference/pages.md +174 -0
- package/skills/rshow/reference/poster.md +137 -0
- package/skills/rshow/reference/project-page.md +132 -0
- package/skills/rshow/reference/reports.md +158 -0
- package/skills/rshow/reference/sketch.md +78 -0
- package/skills/rshow/reference/terminal.md +148 -0
- package/skills/rshow/reference/themes.md +139 -0
- package/skills/rshow-implement/SKILL.md +112 -0
- package/skills/rshow-implement/reference/compare.md +156 -0
- package/skills/rshow-implement/reference/handoff.md +125 -0
- package/skills/rshow-implement/reference/map.md +151 -0
- package/skills/rshow-slides/SKILL.md +136 -0
- package/skills/rshow-slides/reference/layouts.md +251 -0
- package/themes/default/dashboard.css +521 -0
- package/themes/default/dashboard.js +1390 -0
- package/themes/default/deck.css +586 -0
- package/themes/default/deck.js +741 -0
- package/themes/default/example/capture.ans +1 -0
- package/themes/default/example/dashboard.html +106 -0
- package/themes/default/example/demo.cast +14 -0
- package/themes/default/example/drawing.excalidraw +377 -0
- package/themes/default/example/index.html +311 -0
- package/themes/default/example/mockup-desktop.html +331 -0
- package/themes/default/example/mockup-platforms.html +742 -0
- package/themes/default/example/mockup.html +416 -0
- package/themes/default/example/page.html +153 -0
- package/themes/default/example/poster-figure.svg +58 -0
- package/themes/default/example/poster.html +181 -0
- package/themes/default/example/project.html +229 -0
- package/themes/default/example/report.html +404 -0
- package/themes/default/example/results.csv +61 -0
- package/themes/default/example/sketch.html +178 -0
- package/themes/default/example/teaser.svg +66 -0
- package/themes/default/example/terminal.html +231 -0
- package/themes/default/example/tui.html +223 -0
- package/themes/default/fonts/IBMPlexMono-Regular-Latin1.woff2 +0 -0
- package/themes/default/fonts/IBMPlexSans-Light-Latin1.woff2 +0 -0
- package/themes/default/fonts/IBMPlexSans-Regular-Latin1.woff2 +0 -0
- package/themes/default/fonts/IBMPlexSans-SemiBold-Latin1.woff2 +0 -0
- package/themes/default/fonts/OFL.txt +93 -0
- package/themes/default/fonts.css +63 -0
- package/themes/default/index.html +573 -0
- package/themes/default/mockup.css +1078 -0
- package/themes/default/mockup.js +1433 -0
- package/themes/default/mode.js +242 -0
- package/themes/default/page.css +320 -0
- package/themes/default/poster.css +480 -0
- package/themes/default/poster.js +223 -0
- package/themes/default/project.css +482 -0
- package/themes/default/project.js +116 -0
- package/themes/default/report.css +776 -0
- package/themes/default/report.js +427 -0
- package/themes/default/sketch.css +166 -0
- package/themes/default/sketch.js +681 -0
- package/themes/default/skins/adwaita.css +669 -0
- package/themes/default/skins/custom.css +596 -0
- package/themes/default/skins/egui.css +639 -0
- package/themes/default/skins/fluent.css +1093 -0
- package/themes/default/skins/fluent.js +458 -0
- package/themes/default/skins/mac.css +647 -0
- package/themes/default/skins/material.css +692 -0
- package/themes/default/skins/sketch.css +436 -0
- package/themes/default/skins/sketch.js +494 -0
- package/themes/default/skins/wire.css +561 -0
- package/themes/default/terminal.css +292 -0
- package/themes/default/terminal.js +433 -0
- package/themes/default/theme.json +149 -0
- package/themes/default/tokens.css +255 -0
- package/themes/default/tui.css +703 -0
- package/themes/default/tui.js +472 -0
- package/worker/index.js +6918 -0
- package/worker/migrations/0001_init.sql +52 -0
- package/worker/migrations/0002_blobs.sql +5 -0
- package/worker/migrations/0003_projects.sql +31 -0
- package/worker/migrations/0004_page_data_blob.sql +19 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Reports
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- The shape
|
|
6
|
+
- Skeleton
|
|
7
|
+
- Sections
|
|
8
|
+
- Figures and tables
|
|
9
|
+
- Cross-references
|
|
10
|
+
- Notes
|
|
11
|
+
- References
|
|
12
|
+
- Print
|
|
13
|
+
- Checks
|
|
14
|
+
|
|
15
|
+
A report is the reading shape: a long technical report or a paper preprint, on the same theme as a page and a deck.
|
|
16
|
+
`report.css` sets the look and `report.js` sets the numbering.
|
|
17
|
+
Both work with JavaScript off, so the document stays a readable paper that loses only the generated labels.
|
|
18
|
+
|
|
19
|
+
## The shape
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
report/index.html
|
|
23
|
+
report/figure.svg # optional, when a figure is not inline
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Link `fonts.css`, `tokens.css` and `report.css`, then `mode.js` in the head and `report.js` with `defer`.
|
|
27
|
+
`report.css` is self contained, so it needs no `page.css` beside it.
|
|
28
|
+
|
|
29
|
+
## Skeleton
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<!doctype html>
|
|
33
|
+
<html lang="en">
|
|
34
|
+
<head>
|
|
35
|
+
<meta charset="utf-8">
|
|
36
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
37
|
+
<title>Publishing a folder as an immutable artifact</title>
|
|
38
|
+
<link rel="stylesheet" href="/_themes/default@3/fonts.css">
|
|
39
|
+
<link rel="stylesheet" href="/_themes/default@3/tokens.css">
|
|
40
|
+
<link rel="stylesheet" href="/_themes/default@3/report.css">
|
|
41
|
+
<script src="/_themes/default@3/mode.js"></script>
|
|
42
|
+
<script defer src="/_themes/default@3/report.js"></script>
|
|
43
|
+
</head>
|
|
44
|
+
<body>
|
|
45
|
+
<div class="report">
|
|
46
|
+
|
|
47
|
+
<nav class="toc" aria-label="Contents"></nav>
|
|
48
|
+
|
|
49
|
+
<main>
|
|
50
|
+
<header class="report-head">
|
|
51
|
+
<h1>Publishing a folder as an immutable artifact</h1>
|
|
52
|
+
<p class="subtitle">One line that says what the report argues.</p>
|
|
53
|
+
<p class="authors">Dana Ruiz<sup>1</sup> and Tomas Oliveira<sup>2</sup></p>
|
|
54
|
+
<p class="affiliations"><sup>1</sup> rshow project, Berlin<br>
|
|
55
|
+
<sup>2</sup> University of Lisbon</p>
|
|
56
|
+
<p class="date">[PLACEHOLDER] date</p>
|
|
57
|
+
<p class="version">Preprint, version [PLACEHOLDER].</p>
|
|
58
|
+
</header>
|
|
59
|
+
|
|
60
|
+
<section class="abstract" id="abstract">
|
|
61
|
+
<h2 data-nonum data-notoc>Abstract</h2>
|
|
62
|
+
<p>Four to six sentences: the problem, the claim, the method and what a reader should do with it.</p>
|
|
63
|
+
</section>
|
|
64
|
+
|
|
65
|
+
<section id="sec-design">
|
|
66
|
+
<h2>Design</h2>
|
|
67
|
+
<p>Body text is 18px Plex Sans on a 1.6 line at about seventy characters.</p>
|
|
68
|
+
</section>
|
|
69
|
+
</main>
|
|
70
|
+
|
|
71
|
+
</div>
|
|
72
|
+
</body>
|
|
73
|
+
</html>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `nav.toc` sits first so the grid can put it in the left column, and `report.js` fills it.
|
|
77
|
+
Above 1056px the page is three columns: contents, text and notes.
|
|
78
|
+
Below it the contents collapses at the top and the notes collect at the end of the document.
|
|
79
|
+
|
|
80
|
+
## Sections
|
|
81
|
+
|
|
82
|
+
Numbering is generated, so never type a number into a heading.
|
|
83
|
+
|
|
84
|
+
- `<h2>` takes 1, 2, 3 and `<h3>` takes 1.1, 1.2.
|
|
85
|
+
- `data-nonum` keeps a heading out of the numbering, which an abstract and a references list use.
|
|
86
|
+
- `data-notoc` keeps a heading out of the contents.
|
|
87
|
+
- `data-break` on an `<h2>` starts a new page in print, and nothing else does.
|
|
88
|
+
- Headings are sentence case with no eyebrow above them, because the heading is the label.
|
|
89
|
+
|
|
90
|
+
## Figures and tables
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<figure id="fig-pipeline">
|
|
94
|
+
<svg viewBox="0 0 600 186" role="img" aria-label="What the diagram shows in one sentence.">
|
|
95
|
+
<text x="12" y="36" style="font-size: 16px; fill: var(--fg)">Folder</text>
|
|
96
|
+
</svg>
|
|
97
|
+
<figcaption>What to look at, and what it means.</figcaption>
|
|
98
|
+
</figure>
|
|
99
|
+
|
|
100
|
+
<figure class="table" id="tab-headers">
|
|
101
|
+
<table>
|
|
102
|
+
<caption>What the rows are.</caption>
|
|
103
|
+
<thead><tr><th scope="col">Response</th><th scope="col" class="num-cell">Share</th></tr></thead>
|
|
104
|
+
<tbody><tr><td>a versioned path</td><td class="num-cell">[PLACEHOLDER]</td></tr></tbody>
|
|
105
|
+
</table>
|
|
106
|
+
<figcaption>Where the numbers come from.</figcaption>
|
|
107
|
+
</figure>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`report.js` puts `Figure 1.` or `Table 1.` in front of the caption and counts in document order, so give every one an `id`.
|
|
111
|
+
Draw the figure as inline `<svg>` with the colours from tokens, and give it a `viewBox` so it scales.
|
|
112
|
+
An equation is `<div class="equation" id="eq-bytes">` with the formula inside, and `report.js` adds `(1)` at the end of the line.
|
|
113
|
+
Mark example data as example data in the caption, and never present a number you did not measure.
|
|
114
|
+
|
|
115
|
+
## Cross-references
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<p>The pipeline in <a class="ref" href="#fig-pipeline"></a> writes the record last.</p>
|
|
119
|
+
<p>The rule in <a class="ref" href="#sec-pins">the pin section</a> is one line.</p>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
A `.ref` link resolves to `Figure 1`, `Table 2`, `Equation 1`, `Section 2.1` or `Note 3` from the `id` it points at.
|
|
123
|
+
Text inside the link is a fallback for a reader without JavaScript, so write it when the sentence would otherwise lose its object.
|
|
124
|
+
|
|
125
|
+
## Notes
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<p>A republish sends only what changed.<span class="fn">A hash is the SHA-256 of the file bytes, so identical bytes are stored once.</span></p>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`report.js` turns the span into a raised number in the text and a note in the right margin.
|
|
132
|
+
On a narrow screen and in print the notes move to the end of the document.
|
|
133
|
+
Without JavaScript the note text stays in the sentence, which still reads.
|
|
134
|
+
|
|
135
|
+
## References
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<ol class="refs">
|
|
139
|
+
<li id="ref-tufte">Tufte, E. R. <em>The Visual Display of Quantitative Information</em>. Graphics Press, 1983.</li>
|
|
140
|
+
</ol>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Cite with `<a class="cite" href="#ref-tufte"></a>`, which becomes `[1]` and adds a back-link from the entry to every place it is cited.
|
|
144
|
+
List only references that exist and that you read, and print the full URL for a source that lives online.
|
|
145
|
+
|
|
146
|
+
## Print
|
|
147
|
+
|
|
148
|
+
Print is always light, one column, black on white, with 18mm margins on A4 and on Letter.
|
|
149
|
+
Figures and tables stay whole, `h2[data-break]` starts a page and the contents is dropped, because the page numbers navigate for it.
|
|
150
|
+
A URL after a link in the running text is printed in full, and the page number runs in the bottom margin where the browser supports page margin boxes.
|
|
151
|
+
Read the print preview before you publish, because a heading landing alone at the foot of a page is the one thing the CSS cannot see.
|
|
152
|
+
|
|
153
|
+
## Checks
|
|
154
|
+
|
|
155
|
+
- `rshow check <dir>` until it exits 0, then `rshow preview <dir>`.
|
|
156
|
+
- Read the report at 390px wide and at desktop width, in both modes.
|
|
157
|
+
- Print it once and read every page, then fix an orphan heading and a figure that split.
|
|
158
|
+
- Nothing on a report page is a slide: no 28px bullet list, no big number and no eyebrow.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Sketch
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- When a sketch
|
|
6
|
+
- Markup
|
|
7
|
+
- View and edit
|
|
8
|
+
- Save to the store
|
|
9
|
+
- Download and publish
|
|
10
|
+
- Ink and modes
|
|
11
|
+
- Checks
|
|
12
|
+
|
|
13
|
+
A sketch is a hand drawn figure from Excalidraw, read in the page and edited in place.
|
|
14
|
+
It is a guided kit rather than a fixed template: `sketch.css` is the bar around the canvas and `sketch.js` is the canvas.
|
|
15
|
+
Use it for an architecture drawing, a flow of systems or an idea that should look unfinished.
|
|
16
|
+
|
|
17
|
+
## When a sketch
|
|
18
|
+
|
|
19
|
+
Use a sketch when the drawing is the thought: boxes and arrows between services, a state machine, a rough plan of a page.
|
|
20
|
+
Use a mockup when the drawing is a screen a builder will reproduce, because a sketch has no frames, no states and no annotations to hand off.
|
|
21
|
+
A sketch is also the honest shape for a workshop, where a tidy drawing would end the conversation early.
|
|
22
|
+
|
|
23
|
+
## Markup
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<link rel="stylesheet" href="/_themes/default@3/fonts.css">
|
|
27
|
+
<link rel="stylesheet" href="/_themes/default@3/tokens.css">
|
|
28
|
+
<link rel="stylesheet" href="/_themes/default@3/sketch.css">
|
|
29
|
+
<script src="/_themes/default@3/mode.js"></script>
|
|
30
|
+
<script defer src="/_themes/default@3/sketch.js"></script>
|
|
31
|
+
...
|
|
32
|
+
<div class="sketch" data-src="drawing.excalidraw" data-store="sketch-main"></div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`data-src` is the `.excalidraw` file to read, relative to the page.
|
|
36
|
+
`data-store` is the store key that holds a saved copy.
|
|
37
|
+
Leave `data-store` off a sketch nobody edits.
|
|
38
|
+
|
|
39
|
+
`sketch.js` loads React, ReactDOM and Excalidraw from jsDelivr at exact versions.
|
|
40
|
+
0.17.6 is the last release with a UMD bundle, which is why the pinned version is old on purpose.
|
|
41
|
+
Never upgrade that pin by hand, because a newer Excalidraw needs a bundler and the page has none.
|
|
42
|
+
|
|
43
|
+
## View and edit
|
|
44
|
+
|
|
45
|
+
View mode is the default: read only, fitted to the drawing, with pan and zoom.
|
|
46
|
+
The bar over the canvas carries `Edit`, which opens the editor, `Save`, which writes the scene to the store and `Download`, which writes a `.excalidraw` file.
|
|
47
|
+
The canvas takes Excalidraw's own chrome from the theme tokens, so the selection handle and the active tool are the theme's accent and not Excalidraw's blue.
|
|
48
|
+
|
|
49
|
+
## Save to the store
|
|
50
|
+
|
|
51
|
+
`Save` writes the scene to `/_data/<key>`, which is the one network call a page may make.
|
|
52
|
+
A saved scene wins over the file when its `savedAt` is later than the file's `Last-Modified`, and the bar says which of the two the reader is looking at.
|
|
53
|
+
A public viewer cannot write, so the messages are literal: `Sign in to save` on 401 and 403, `Saving works once published` on 404 and a pointer at `Download` on 413.
|
|
54
|
+
The store holds 64 KiB per key, and a drawing over that limit is a drawing to download and commit.
|
|
55
|
+
|
|
56
|
+
The store is not a file in the version, so an edit made in the browser lives outside the artifact.
|
|
57
|
+
Say that to the person when they save, because it is the one thing about a sketch that surprises people.
|
|
58
|
+
|
|
59
|
+
## Download and publish
|
|
60
|
+
|
|
61
|
+
`Download` writes a `.excalidraw` file, and that file is the one that becomes the artifact.
|
|
62
|
+
Commit it next to the page, then `rshow publish <dir> --slug <slug> --label "sketch: <what changed>"` so the drawing travels in an immutable version.
|
|
63
|
+
That publish is also what makes `Save` work for a viewer, because the page now has a published origin.
|
|
64
|
+
|
|
65
|
+
## Ink and modes
|
|
66
|
+
|
|
67
|
+
The drawing is authored on paper, in Carbon white values.
|
|
68
|
+
In dark mode the ink inverts for the screen and inverts back on save or download, so a committed file keeps one palette and the store holds what the reader drew.
|
|
69
|
+
Never edit the ink by hand in the JSON, because the next save rewrites it.
|
|
70
|
+
|
|
71
|
+
With JavaScript off, or with the CDN blocked, the page keeps the file link and the text fallback, so a reader still learns what the figure is.
|
|
72
|
+
|
|
73
|
+
## Checks
|
|
74
|
+
|
|
75
|
+
- `rshow check <dir>` exits 0, and every CDN URL carries an exact version.
|
|
76
|
+
- `rshow preview <dir>`, then open the figure in both modes and read the ink at 100 percent.
|
|
77
|
+
- Edit, save, reload: the saved scene comes back and the bar names the store as its source.
|
|
78
|
+
- Download, diff the file against the committed one and publish only when the difference is the change you meant.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Terminal
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Three shapes
|
|
6
|
+
- The viewer
|
|
7
|
+
- ANSI captures
|
|
8
|
+
- Recordings
|
|
9
|
+
- Palettes
|
|
10
|
+
- The TUI kit
|
|
11
|
+
- A real ratatui app
|
|
12
|
+
- Checks
|
|
13
|
+
|
|
14
|
+
A terminal in a page is one of three things, and they are not interchangeable.
|
|
15
|
+
|
|
16
|
+
## Three shapes
|
|
17
|
+
|
|
18
|
+
| Shape | For | File |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| the viewer | a capture of a screen or a recording of a command, as evidence | `terminal.css`, `terminal.js` |
|
|
21
|
+
| the TUI kit | a drawing of a terminal user interface that does not exist yet | `tui.css`, `tui.js` |
|
|
22
|
+
| a real app | a ratatui tool that already builds and runs | Ratzilla plus `rshow publish --build` |
|
|
23
|
+
|
|
24
|
+
The viewer and the TUI kit are the theme's, and both are guided kits: the frame and the floor are given and the content is the work.
|
|
25
|
+
|
|
26
|
+
## The viewer
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<link rel="stylesheet" href="/_themes/default@3/fonts.css">
|
|
30
|
+
<link rel="stylesheet" href="/_themes/default@3/tokens.css">
|
|
31
|
+
<link rel="stylesheet" href="/_themes/default@3/terminal.css">
|
|
32
|
+
<script src="/_themes/default@3/mode.js"></script>
|
|
33
|
+
<script defer src="/_themes/default@3/terminal.js"></script>
|
|
34
|
+
...
|
|
35
|
+
<figure class="terminal" data-mode="ansi" data-src="capture.ans"
|
|
36
|
+
data-cols="100" data-rows="30" data-title="procview" data-palette="default"></figure>
|
|
37
|
+
<figure class="terminal" data-mode="cast" data-src="demo.cast"
|
|
38
|
+
data-title="rshow publish ./deck"></figure>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`terminal.js` loads only what a figure needs, from jsDelivr at exact versions: xterm.js for an ANSI capture and asciinema-player for a recording.
|
|
42
|
+
Never write either URL by hand, because `terminal.js` owns the pin and a second copy in the page is a version to keep in step.
|
|
43
|
+
Put the capture files next to the page, so they travel in the same immutable version.
|
|
44
|
+
Link the file below each figure, so a reader can download the evidence and check it.
|
|
45
|
+
|
|
46
|
+
## ANSI captures
|
|
47
|
+
|
|
48
|
+
An ANSI capture is one screen of a full screen program, on a fixed grid.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
tmux capture-pane -pet -p > capture.ans
|
|
52
|
+
tmux display -p '#{pane_width}x#{pane_height}'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Put the size that command prints into `data-cols` and `data-rows`, because a capture read at the wrong grid wraps in the wrong place.
|
|
56
|
+
A capture of a run with output is `script -q capture.ans -c "./tool --fast"` on a machine that has `script`.
|
|
57
|
+
The capture is read only: no stdin, no blinking cursor and no scrollback, because a terminal in a page is a picture of one and not a shell.
|
|
58
|
+
With JavaScript off or a library missing, the escapes are stripped and the screen is set as text, so the evidence still reads.
|
|
59
|
+
|
|
60
|
+
## Recordings
|
|
61
|
+
|
|
62
|
+
An asciinema recording is a real session with timing, and the player has a scrub bar.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
asciinema rec demo.cast -c "./tool --fast"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Keep it under about 30 seconds and put the interesting line in the first three, because a reader watches a recording twice at most.
|
|
69
|
+
`data-title` names what the recording does, so the figure needs no caption to say what it is.
|
|
70
|
+
A recording is a file in the folder, never a link to somebody else's player.
|
|
71
|
+
|
|
72
|
+
## Palettes
|
|
73
|
+
|
|
74
|
+
`data-palette` picks one of four sets of sixteen colours, and `terminal.css` owns all four.
|
|
75
|
+
|
|
76
|
+
| Palette | Ground |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `default` | the page ground, light or dark, with a neutral sixteen that holds on either |
|
|
79
|
+
| `dark` | a fixed dark ground, for a capture that is about being dark |
|
|
80
|
+
| `light` | a fixed light ground |
|
|
81
|
+
| `high-contrast` | black on white in a light page and white on black in a dark one |
|
|
82
|
+
|
|
83
|
+
The `default` set means one capture reads in both modes, so nothing has to be recorded twice.
|
|
84
|
+
At 360px the window frame scrolls inside its own box, so the page itself never scrolls sideways.
|
|
85
|
+
|
|
86
|
+
## The TUI kit
|
|
87
|
+
|
|
88
|
+
The kit draws a terminal user interface as cells, for the mockups that are a tool rather than a window, such as a git client, a log tail or a deploy console.
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<div class="tui" data-cols="100" data-rows="27" data-palette="default" data-depth="256">
|
|
92
|
+
<div class="tui-screen">
|
|
93
|
+
<div class="tui-body">
|
|
94
|
+
<div class="tui-line tui-dim">ledger, git</div>
|
|
95
|
+
<div class="tui-main">
|
|
96
|
+
<div class="tui-pane" data-title="branches" data-cols="24" data-lines="23">...</div>
|
|
97
|
+
<div class="tui-gap"></div>
|
|
98
|
+
<div class="tui-pane" data-title="commits" data-focus data-cols="38" data-lines="23">...</div>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="tui-statusbar">...</div>
|
|
101
|
+
<div class="tui-keys"><kbd>j</kbd> next <kbd>s</kbd> stage <kbd>q</kbd> quit</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Load it inside a mockup, after `mockup.css` and a skin: `tui.css` and then `tui.js` deferred.
|
|
108
|
+
The rules the kit is drawn by, all of them checked by `tui.js`:
|
|
109
|
+
|
|
110
|
+
- Cells, not pixels.
|
|
111
|
+
Type is one size, the line height is fixed and every block is a whole number of cells wide and lines tall.
|
|
112
|
+
A half cell is a bug.
|
|
113
|
+
- Below 80x24 the grid is replaced by a resize message, because a terminal that small asks to be resized.
|
|
114
|
+
- Exactly one pane has `data-focus`, and focus is a double frame and a bold title, so it survives a reader who cannot see colour.
|
|
115
|
+
- `Ctrl+C`, `Ctrl+Z` and `Ctrl+\` belong to the terminal, so a drawing that binds them teaches a reader something the app cannot keep.
|
|
116
|
+
- Every palette is legible at `data-depth="16"`, because a drawing that needs true colour will meet a printer.
|
|
117
|
+
|
|
118
|
+
Use `tui-gauge`, `tui-sparkline`, `tui-table` and `tui-dialog` instead of a picture of them.
|
|
119
|
+
Mark a placeholder branch name or commit hash the same way as any other placeholder.
|
|
120
|
+
`tui.js` reports what it cannot fix in the console with an `[rshow tui]` prefix, so read the console before you call the drawing done.
|
|
121
|
+
|
|
122
|
+
## A real ratatui app
|
|
123
|
+
|
|
124
|
+
When the tool already exists, publish the tool instead of a drawing of it.
|
|
125
|
+
Ratzilla draws a ratatui `Terminal` into a browser page through its DOM backend, so the same code that runs in a terminal runs at the link.
|
|
126
|
+
|
|
127
|
+
- Build to `dist` with trunk, such as `trunk build --release`.
|
|
128
|
+
Publish that build in one command.
|
|
129
|
+
- `rshow publish . --build "trunk build --release" --slug <slug>` runs the build in the folder and then uploads `<dir>/dist`, which is the `out` default.
|
|
130
|
+
- The build writes `index.html`, the JavaScript glue and a `.wasm`, and the host serves the wasm as `application/wasm` with no policy exception, because the page loads it from its own origin.
|
|
131
|
+
- Keep the wasm under 25 MiB per file, which is why the build is `--release` with debug symbols stripped and `opt-level = "z"` in the release profile when it is close.
|
|
132
|
+
- The content policy is `connect-src 'self'`, so the app reads its data from `/_data/<key>` or carries it in the wasm and fetches nothing from a third party.
|
|
133
|
+
- Publish the build and not the source tree, so `target/` and `node_modules/` never reach the host.
|
|
134
|
+
|
|
135
|
+
A real app is not a mockup: there are no states to draw and no annotations to hand off.
|
|
136
|
+
It is also the shape to prefer for a tool a person will actually use, because a Ratzilla page is the thing itself and a TUI kit is a drawing of it.
|
|
137
|
+
|
|
138
|
+
For the compare loop, `rshow compare` captures a terminal app through a `tmux:<session>:<pane>` entry in `map.screens`.
|
|
139
|
+
A browser build is captured through its URL.
|
|
140
|
+
Read `rshow-implement` for that loop, because it owns both the map and the compare.
|
|
141
|
+
|
|
142
|
+
## Checks
|
|
143
|
+
|
|
144
|
+
- `rshow check <dir>` exits 0, and every script URL carries an exact version.
|
|
145
|
+
- `rshow preview <dir>`, then read the figure at desktop width and at 360px, in both modes.
|
|
146
|
+
- For a real app, run the build locally first, then the published link.
|
|
147
|
+
Click every control that changes state.
|
|
148
|
+
- Report the `live-url` and say which of the three shapes the page holds.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Themes
|
|
2
|
+
|
|
3
|
+
A theme is a published artifact at `theme-<name>`, served at `/_themes/<name>@<n>/`, and it is always public.
|
|
4
|
+
Pages and decks link it and never copy it, so one token change can restyle every artifact that points at the new version.
|
|
5
|
+
Read this file when a five line override cannot carry the change.
|
|
6
|
+
|
|
7
|
+
## What ships
|
|
8
|
+
|
|
9
|
+
One theme ships in the rshow repo, `themes/default`, and it is IBM Carbon v11 on IBM Plex in two modes.
|
|
10
|
+
|
|
11
|
+
| Mode | Ground | Use |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| light, Carbon white `#ffffff` | `:root` in `tokens.css` | the default on a machine in light appearance |
|
|
14
|
+
| dark, Carbon g100 `#161616` | `prefers-color-scheme` and `[data-mode="dark"]` | the same deck, page and report on a dark ground |
|
|
15
|
+
|
|
16
|
+
One theme, two modes, system by default.
|
|
17
|
+
The light values sit on `:root`, the dark values appear twice, once for the system preference and once for `<html data-mode="dark">`.
|
|
18
|
+
`--chart-1` to `--chart-8` carry both palettes too.
|
|
19
|
+
`mode.js` reads the storage key `rshow-mode` (`light`, `dark` or `system`), sets `data-mode` on the document element and removes it for system.
|
|
20
|
+
It also mounts the toggle.
|
|
21
|
+
A deck shares the key: `t` cycles system, light and dark.
|
|
22
|
+
Print is always light.
|
|
23
|
+
The `paper` theme is no longer in the repo.
|
|
24
|
+
Its published versions stay online and immutable, so a page that pins `paper@<n>` keeps working.
|
|
25
|
+
|
|
26
|
+
`themes/DESIGN.md` holds the system itself: the palette roles, the type scale, the twelve layouts and the list of things this design never does.
|
|
27
|
+
Read it before you write a theme or a token override that is more than a colour swap.
|
|
28
|
+
|
|
29
|
+
## Files
|
|
30
|
+
|
|
31
|
+
| File | Holds |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `tokens.css` | every custom property, on `:root`, with no rules |
|
|
34
|
+
| `fonts.css` | the `@font-face` rules, pointing at `fonts/` |
|
|
35
|
+
| `fonts/` | the font files and their licence |
|
|
36
|
+
| `page.css` | the prose layout, the tables, the figures and the code block |
|
|
37
|
+
| `deck.css` | the 1280x720 canvas and the twelve slide layouts |
|
|
38
|
+
| `report.css` | the report layout: title block, contents column, side notes, print rules |
|
|
39
|
+
| `mode.js` | the mode from one storage key, plus the toggle button |
|
|
40
|
+
| `deck.js` | arrow keys, steps, notes, presenter view, the `t` key, print |
|
|
41
|
+
| `report.js` | section, figure and table numbering, cross-references, contents, notes, references |
|
|
42
|
+
| `theme.json` | the name and, for humans, the description and both mode token sets |
|
|
43
|
+
| `index.html` | the preview page, which shows a deck, a page and a report |
|
|
44
|
+
|
|
45
|
+
`theme.json` needs one field for the CLI, and the rest is for the person reading the repo.
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"name": "default",
|
|
50
|
+
"description": "IBM Carbon on IBM Plex, two modes, one accent, no decoration.",
|
|
51
|
+
"defaultMode": "system",
|
|
52
|
+
"modes": ["system", "light", "dark"],
|
|
53
|
+
"tokens": {"--space-05": "16px"},
|
|
54
|
+
"modeTokens": {
|
|
55
|
+
"light": {"--bg": "#ffffff", "--fg": "#161616", "--accent": "#0f62fe"},
|
|
56
|
+
"dark": {"--bg": "#161616", "--fg": "#f4f4f4", "--accent": "#78a9ff"}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`modeTokens` lists both sets so the file says what the theme does in each mode, and the CLI reads the name only.
|
|
62
|
+
|
|
63
|
+
The name is lowercase.
|
|
64
|
+
It starts with a letter or a digit and may hold hyphens.
|
|
65
|
+
It must not start with `theme-`, because the slug adds that.
|
|
66
|
+
|
|
67
|
+
## Make a preset
|
|
68
|
+
|
|
69
|
+
A preset is a small folder: a `theme.json` that extends a built-in theme, and a `fonts/` folder only when the brand brings its own type.
|
|
70
|
+
It changes token values and fonts.
|
|
71
|
+
It never renames a class or moves a layout.
|
|
72
|
+
|
|
73
|
+
Start with the brand inputs: the accent colour, the ground for light and for dark, and the font.
|
|
74
|
+
A logo is out of scope, because a logo belongs in the page and not in the theme.
|
|
75
|
+
|
|
76
|
+
1. Run `rshow theme new acme --dir ./themes`.
|
|
77
|
+
It writes `./themes/acme/theme.json` with `extends`, an empty `tokens` object and both modes filled with the base values of `--bg`, `--fg`, `--muted`, `--accent` and `--layer-01`.
|
|
78
|
+
2. Edit that `theme.json` and nothing else.
|
|
79
|
+
Change values, not names, and add a token only when the base theme already has it.
|
|
80
|
+
`tokens` holds values both modes share, such as `--font-sans`; `modeTokens.light` and `modeTokens.dark` hold the colours.
|
|
81
|
+
3. Add `fonts` when the brand brings a font, and put the files and their licence in `fonts/`.
|
|
82
|
+
One entry looks like `{"family": "Inter", "weight": 400, "style": "normal", "file": "fonts/Inter-Regular.woff2"}`.
|
|
83
|
+
Ship `OFL.txt`, `LICENSE`, `LICENSE.txt` or `LICENSE.md` beside the files, because a font without its licence warns.
|
|
84
|
+
4. Run `rshow theme check ./themes/acme` until it passes.
|
|
85
|
+
This is a hard gate and you never skip it: it names an unknown token, a bad colour value, and every text pair under 4.5:1 in light, in dark and in print.
|
|
86
|
+
5. Run `rshow theme preview ./themes/acme` and open the printed link.
|
|
87
|
+
Look at both modes, and at the deck, the page and the report.
|
|
88
|
+
6. Run `rshow theme publish ./themes/acme`.
|
|
89
|
+
It checks again, lays the preset over its base and publishes the built folder as `theme-acme`.
|
|
90
|
+
Read the `/_themes/acme@<n>/` line it prints.
|
|
91
|
+
7. Set `"theme": "acme@<n>"` in `~/.config/rshow/config.json`, or in the `rshow.json` of one folder to move that page alone.
|
|
92
|
+
|
|
93
|
+
## A full theme
|
|
94
|
+
|
|
95
|
+
1. Copy `themes/default` from the rshow repo into your own folder.
|
|
96
|
+
2. Change `name` in `theme.json` and leave every other file name alone.
|
|
97
|
+
3. Edit `tokens.css` first, from a documented system rather than from a feeling.
|
|
98
|
+
Copy the values in by hand and keep the role names, because a role is the interface.
|
|
99
|
+
4. Keep the class names.
|
|
100
|
+
`slide`, `title`, `section`, `statement`, `bullets`, `figure`, `figure-two`, `chart`, `table`, `code`, `two-col`, `quote` and `big-number` are the interface a deck writes against.
|
|
101
|
+
A theme that renames one breaks every deck that uses it.
|
|
102
|
+
5. Put the measured contrast ratios in a comment at the top of `tokens.css`.
|
|
103
|
+
6. Update `index.html` so it shows the new look at desktop width and at 360px, in both modes.
|
|
104
|
+
7. Run `rshow preview <theme dir>` and open the printed link, because the preview page links its own files by relative path and needs no host.
|
|
105
|
+
|
|
106
|
+
The preview page in the repo links `../deck.css` so a checkout previews with no network.
|
|
107
|
+
Keep those relative links in the repo and swap them for `/_themes/<name>@<n>/` links only in a page that lives on the host.
|
|
108
|
+
|
|
109
|
+
## Contrast
|
|
110
|
+
|
|
111
|
+
Text has to hold 4.5:1 against the ground it sits on, and that includes `--muted` and `--accent` as text.
|
|
112
|
+
Check every text pair in both modes, because one theme carries two grounds.
|
|
113
|
+
Check the print palette too, which is always light.
|
|
114
|
+
A ratio under 4.5:1 is a real defect, not a taste question, so darken the text or lighten the ground before publishing.
|
|
115
|
+
A support colour is a data mark and never text, because green on white is 3.4:1 and a mark is not a label.
|
|
116
|
+
|
|
117
|
+
## Publishing
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
rshow theme publish ./my-theme --label "carbon g100 on plex"
|
|
121
|
+
rshow theme list
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`theme publish` uploads the folder, sets the artifact public and prints `/_themes/<name>@<n>/`.
|
|
125
|
+
It needs a full-scope token, because the artifact goes public.
|
|
126
|
+
Without one it publishes the version and reports that it stayed private, and the link will 404 for everyone else until a person with a full-scope token runs it again.
|
|
127
|
+
`theme list` prints each theme artifact and the version it currently serves.
|
|
128
|
+
|
|
129
|
+
## Bumping a version
|
|
130
|
+
|
|
131
|
+
Every publish adds a version, and `@<n>` in a page pins one.
|
|
132
|
+
So publish the theme and read the new `<n>` from the printed line.
|
|
133
|
+
Then change the three or four links in each artifact that should follow.
|
|
134
|
+
Change the whole set of links in one page to the same `<n>` and never mix two versions in one page.
|
|
135
|
+
Leave a page on the old version when it is being presented this week, and move it after the talk.
|
|
136
|
+
A version is immutable, so an old `@<n>` keeps working and no page breaks while the theme is in progress.
|
|
137
|
+
|
|
138
|
+
A full theme is published the same way.
|
|
139
|
+
A preset is checked with `rshow theme check` before it is published, and the built folder is what goes up.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rshow-implement
|
|
3
|
+
description: Load before you implement or code a UI from an rshow mockup, design or an rshow link such as art.<domain>/<name>, when signed off wireframes or frozen tokens must become working code in your app and when a built app needs a side by side check against the design or where it drifted. Load it even for a quick question about it. Run rshow handoff to freeze the design and rshow compare to hold the build to it. Making the mockup belongs to rshow, slide decks belong to rshow-slides, visual direction belongs to frontend-design.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rshow implement
|
|
7
|
+
|
|
8
|
+
A design published on rshow is the contract, and the app repo is where it gets built.
|
|
9
|
+
`rshow handoff` freezes that design into a folder that does not move, and `rshow compare` holds the build to it.
|
|
10
|
+
The code moves toward the design, never the other way round.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
Copy this checklist into the reply and tick it as you go.
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
- [ ] handoff frozen into the app repo at a path the person agreed on
|
|
18
|
+
- [ ] HANDOFF.md read, spec.json read for the screen at hand
|
|
19
|
+
- [ ] tokens mapped in rshow.map.json
|
|
20
|
+
- [ ] components mapped in rshow.map.json
|
|
21
|
+
- [ ] one screen and one state built, url, tmux target or native screenshot in the map
|
|
22
|
+
- [ ] rshow compare --against <handoff-dir> --map rshow.map.json exits 0
|
|
23
|
+
- [ ] a review screen has its rubric filled in beside both images
|
|
24
|
+
- [ ] every state covered, not only the happy path
|
|
25
|
+
- [ ] report published and the person asked to review
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
1. Freeze the design.
|
|
29
|
+
Run `rshow handoff <slug>@v<n> --out <dir>`, or `rshow handoff <local-folder>` when the mockup is still local.
|
|
30
|
+
The folder it writes holds `HANDOFF.md`, `spec.json`, `tokens.json` and `baseline/`.
|
|
31
|
+
Put it in the app repo at a path the person agrees on and commit it next to the code.
|
|
32
|
+
Never work from a live link, because the next publish moves it.
|
|
33
|
+
2. Read the handoff before you write any code.
|
|
34
|
+
`HANDOFF.md` gives the immutable source, the screens, the states, the component table and the compare command.
|
|
35
|
+
`spec.json` gives the screen at hand its boxes, computed styles, flows, annotations and focus order.
|
|
36
|
+
A component the mockup marks `data-normative` is normative here, and its text, box and style must match.
|
|
37
|
+
Everything else is placeholder, so data, copy, names and images are free to change.
|
|
38
|
+
3. Map the tokens.
|
|
39
|
+
`tokens.json` is W3C DTCG 2025.10 with `$value` and `$type` on every token, grouped by name prefix, plus a `dark` group for the dark values.
|
|
40
|
+
Translate each token into the app's own system, such as a CSS variable, a Tailwind theme key, a Swift or Kotlin constant, a ratatui style.
|
|
41
|
+
Fill the `tokens` object in `rshow.map.json`, such as `"--accent": "theme.colors.accent"`.
|
|
42
|
+
Never hardcode a value that has a token, because a raw colour near a token colour comes back as drift.
|
|
43
|
+
4. Map the components.
|
|
44
|
+
Find the component the app already has before you write a new one.
|
|
45
|
+
Fill `components` in `rshow.map.json`, such as `"wf-button": "src/ui/Button.tsx"` or `"PrimaryButton": "src/ui/Button.tsx#primary"`.
|
|
46
|
+
Create a new component only when nothing fits, and say so in the reply.
|
|
47
|
+
5. Build one screen and one state at a time.
|
|
48
|
+
Fill `screens` with the dev url, a tmux target or a native capture, such as `"gallery": "http://localhost:5173/"`, `"cli": "tmux:mysession:0.1"` or `"desktop": "file:shots/desktop.png"`.
|
|
49
|
+
Compare that screen before you start the next one.
|
|
50
|
+
6. Run `rshow compare --against <handoff-dir> --map rshow.map.json` and fix until it exits 0.
|
|
51
|
+
Read the report at `<handoff-dir>/compare-report/index.html` and work through the mismatches before anything else.
|
|
52
|
+
Read a mismatch before you reach for a threshold, because a looser threshold hides a real difference.
|
|
53
|
+
Never loosen `--max-diff-ratio` or `--threshold` without asking the person.
|
|
54
|
+
7. A native desktop app has no DOM, so it compares through a screenshot.
|
|
55
|
+
An Electron, Tauri, egui, Qt, GTK or SwiftUI window takes `file:<path.png>` for a screenshot you took or `window:<app or title>` to capture the window itself on macOS.
|
|
56
|
+
The capture is scaled to the baseline width with a box filter so a Retina 2x shot lines up.
|
|
57
|
+
It is then diffed with the looser `--native-max-diff-ratio`, which defaults to 0.15.
|
|
58
|
+
The token colours of the normative components are checked against the dominant colours of the capture, in Lab, so a colour that is near a token but not on it is reported.
|
|
59
|
+
Such a screen reports `review` and the run still exits 0, unless the pixels or a token colour fail hard.
|
|
60
|
+
Open the baseline and the capture side by side, then fill in `compare-report/rubric-<screen>.md`.
|
|
61
|
+
It lists every state and every annotation note, plus each normative component with its text, colour, size and place.
|
|
62
|
+
List each line you could not tick for the person with the reason, because your eye is the check a native window cannot pass on its own.
|
|
63
|
+
8. Publish the report.
|
|
64
|
+
Run `rshow compare --against <handoff-dir> --map rshow.map.json --publish` and report the printed link.
|
|
65
|
+
Ask the person to review it, because their comments are the next tasks.
|
|
66
|
+
|
|
67
|
+
## Hard rules
|
|
68
|
+
|
|
69
|
+
- The design is the contract.
|
|
70
|
+
A box, a colour or a step that does not fit is a question for the person, not an edit to the design.
|
|
71
|
+
- Placeholders are free and normative values are not.
|
|
72
|
+
Keep the text, the box and the computed style of every normative component.
|
|
73
|
+
- Do not skip a state.
|
|
74
|
+
Empty, loading, error, long content and narrow width are part of the design.
|
|
75
|
+
A screen missing one of them is not done.
|
|
76
|
+
- An empty value in `rshow.map.json` is a component or a token nobody checks.
|
|
77
|
+
Fill it, or say why it stays empty.
|
|
78
|
+
- Keep the flows and the focus order that `spec.json` records.
|
|
79
|
+
- Every screen needs a url, a tmux target or a native capture in `screens`, because a screen without one is skipped and the report still passes.
|
|
80
|
+
- A `review` screen is not done when the rubric is empty.
|
|
81
|
+
Tick it beside both images, or say which lines you could not tick and why.
|
|
82
|
+
|
|
83
|
+
## Exit codes
|
|
84
|
+
|
|
85
|
+
| code | meaning | what to do |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| 0 | every screen matches, or a native screen is ready for review | publish the report and report the link |
|
|
88
|
+
| 2 | usage | the handoff folder, a flag or a url is wrong. Read `rshow compare --help` and fix the command |
|
|
89
|
+
| 5 | api | the host refused a `--publish` request. Read the message and retry once |
|
|
90
|
+
| 7 | compare failed | read each mismatch and the diff images, fix the build and run it again |
|
|
91
|
+
|
|
92
|
+
On 7, fix the build.
|
|
93
|
+
Never pass it with `--max-diff-ratio 1`, and never edit `baseline/` to make a screen pass.
|
|
94
|
+
|
|
95
|
+
## Reference files
|
|
96
|
+
|
|
97
|
+
- [handoff](reference/handoff.md) holds the frozen folder, `spec.json` field by field and the normative and placeholder rules.
|
|
98
|
+
Read it before you freeze a design or argue about a recorded box.
|
|
99
|
+
- [compare](reference/compare.md) holds every flag, the three checks, the report, the tmux path and the native path.
|
|
100
|
+
Read it when a compare run fails or a flag is not obvious.
|
|
101
|
+
- [map](reference/map.md) holds `rshow.map.json`, one example per stack and the empty value rule.
|
|
102
|
+
Read it before you write the map.
|
|
103
|
+
|
|
104
|
+
## Never
|
|
105
|
+
|
|
106
|
+
- Never change the design to match the code.
|
|
107
|
+
- Never build from a link that can move.
|
|
108
|
+
- Never hand edit `baseline/`, `tokens.json` or `spec.json`, because the next handoff overwrites them and a hand edit hides drift.
|
|
109
|
+
- Never loosen `--max-diff-ratio`, `--native-max-diff-ratio` or `--threshold` without a yes from the person.
|
|
110
|
+
- Never call a `review` screen done with an empty rubric or a line you did not look at.
|
|
111
|
+
- Never call a screen done on the happy path alone.
|
|
112
|
+
- Never publish the report as `public` without a yes, because it holds screenshots of unreleased work.
|