rshow 0.0.4 → 0.0.6

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/dist/main.js CHANGED
@@ -13,7 +13,7 @@ import process from "node:process";
13
13
  // src/version.ts
14
14
  import { readFileSync } from "node:fs";
15
15
  import { fileURLToPath } from "node:url";
16
- var VERSION = true ? "0.0.4" : versionFromPackage();
16
+ var VERSION = true ? "0.0.6" : versionFromPackage();
17
17
 
18
18
  // src/binary.ts
19
19
  var ASSET_MANIFEST = "assets.json";
@@ -969,6 +969,7 @@ commands:
969
969
  delete <slug> --yes delete an artifact
970
970
  login [--url u] save the API token for this account
971
971
  logout [--url u] remove the saved token for a server
972
+ completion <shell> print a completion script for bash, zsh or fish
972
973
 
973
974
  global:
974
975
  --json print the API reply JSON
@@ -1243,6 +1244,19 @@ var LOGOUT_USAGE = `usage: rshow logout [--url u]
1243
1244
 
1244
1245
  Removes the token this server has from every store that holds it: the macOS
1245
1246
  Keychain, the Linux keyring and the 0600 credentials file.`;
1247
+ var COMPLETION_USAGE = `usage: rshow completion <bash|zsh|fish>
1248
+
1249
+ Prints a completion script for that shell on stdout. It lists every command
1250
+ and its long options, and it completes files and folders for the commands that
1251
+ take one. It is static: a completion never calls the API.
1252
+
1253
+ load it once per machine:
1254
+ bash rshow completion bash > ~/.local/share/bash-completion/completions/rshow
1255
+ zsh rshow completion zsh > ~/.local/share/zsh/site-functions/_rshow
1256
+ (that folder must be on $fpath, before compinit)
1257
+ fish rshow completion fish > ~/.config/fish/completions/rshow.fish
1258
+
1259
+ The curl installer writes all three, and an npm install runs one of them.`;
1246
1260
  var PROJECT_USAGE = `usage: rshow project <create|list|show|share|delete> [options]
1247
1261
 
1248
1262
  project create <slug> [--title t] [--description d]
@@ -8388,7 +8402,8 @@ var USAGE = {
8388
8402
  pin: PIN_USAGE,
8389
8403
  delete: DELETE_USAGE,
8390
8404
  login: LOGIN_USAGE,
8391
- logout: LOGOUT_USAGE
8405
+ logout: LOGOUT_USAGE,
8406
+ completion: COMPLETION_USAGE
8392
8407
  };
8393
8408
  var WHEN = {
8394
8409
  ok: "the work was done.",
@@ -8716,6 +8731,328 @@ async function run18(argv, ctx) {
8716
8731
  ctx.out.line(`wrote ${path24.join(out, "exit-codes.md")}`);
8717
8732
  }
8718
8733
 
8734
+ // src/commands/completion.ts
8735
+ var SHELLS = ["bash", "zsh", "fish"];
8736
+ var GLOBAL_OPTIONS = [
8737
+ { name: "--json", description: "print the API reply JSON" },
8738
+ { name: "--help", description: "show this help" },
8739
+ { name: "--version", description: "print rshow <version>" }
8740
+ ];
8741
+ var SKILL_TARGETS2 = ["claude", "pi", "codex"];
8742
+ var SPECS = {
8743
+ publish: { usage: PUBLISH_USAGE, path: true },
8744
+ check: { usage: CHECK_USAGE, path: true },
8745
+ handoff: { usage: HANDOFF_USAGE, path: true },
8746
+ compare: { usage: COMPARE_USAGE },
8747
+ preview: { usage: PREVIEW_USAGE, path: true },
8748
+ config: { usage: CONFIG_USAGE, path: true },
8749
+ init: { usage: INIT_USAGE },
8750
+ doctor: { usage: DOCTOR_USAGE, path: true },
8751
+ theme: { usage: THEME_USAGE },
8752
+ "theme new": { usage: THEME_NEW_USAGE },
8753
+ "theme check": { usage: THEME_CHECK_USAGE, path: true },
8754
+ "theme preview": { usage: THEME_PREVIEW_USAGE, path: true },
8755
+ "theme publish": { usage: THEME_PUBLISH_USAGE, path: true },
8756
+ "theme list": { usage: THEME_LIST_USAGE },
8757
+ skills: { usage: SKILLS_USAGE },
8758
+ "skills install": { usage: SKILLS_INSTALL_USAGE, choices: SKILL_TARGETS2 },
8759
+ "skills uninstall": { usage: SKILLS_UNINSTALL_USAGE, choices: SKILL_TARGETS2 },
8760
+ "skills status": { usage: SKILLS_STATUS_USAGE, choices: SKILL_TARGETS2 },
8761
+ project: { usage: PROJECT_USAGE },
8762
+ "project create": { usage: PROJECT_CREATE_USAGE },
8763
+ "project list": { usage: PROJECT_LIST_USAGE },
8764
+ "project show": { usage: PROJECT_SHOW_USAGE },
8765
+ "project share": { usage: PROJECT_SHARE_USAGE },
8766
+ "project delete": { usage: PROJECT_DELETE_USAGE },
8767
+ tag: { usage: TAG_USAGE },
8768
+ list: { usage: LIST_USAGE },
8769
+ show: { usage: SHOW_USAGE },
8770
+ share: { usage: SHARE_USAGE },
8771
+ pin: { usage: PIN_USAGE },
8772
+ delete: { usage: DELETE_USAGE },
8773
+ login: { usage: LOGIN_USAGE },
8774
+ logout: { usage: LOGOUT_USAGE },
8775
+ completion: { usage: COMPLETION_USAGE, choices: [...SHELLS] }
8776
+ };
8777
+ function optionsOf(usage) {
8778
+ const out = [];
8779
+ for (const found of usageLine(usage).matchAll(/--([a-z][a-z0-9-]*)(?:\s+([^[\]\s|]+))?/g)) {
8780
+ out.push({ name: `--${found[1]}`, value: found[2] });
8781
+ }
8782
+ return out;
8783
+ }
8784
+ function summaryOf2(name) {
8785
+ const words = name.split(" ");
8786
+ const parent = SPECS[words[0]];
8787
+ const text = words.length === 1 || parent === void 0 ? GENERAL_USAGE : parent.usage;
8788
+ for (const line of text.split("\n")) {
8789
+ if (!/^ {2}\S/.test(line)) continue;
8790
+ const parts2 = line.trim().split(/ {2,}/);
8791
+ const spec = (parts2[0] ?? "").split(" ");
8792
+ if (spec[0] !== words[0]) continue;
8793
+ if (words.length === 2 && spec[1] !== words[1]) continue;
8794
+ if (parts2.length > 1) return parts2.slice(1).join(" ").trim();
8795
+ let index = 1;
8796
+ while (index < spec.length && /^(?:<[^>]+>|\[[^\]]*\]|--?\S+)$/.test(spec[index])) index += 1;
8797
+ const summary = spec.slice(index).join(" ").trim();
8798
+ return summary.startsWith("[") ? "" : summary;
8799
+ }
8800
+ return "";
8801
+ }
8802
+ function specs() {
8803
+ return Object.entries(SPECS).map(([name, entry]) => ({
8804
+ words: name.split(" "),
8805
+ options: optionsOf(entry.usage),
8806
+ path: entry.path === true,
8807
+ choices: entry.choices ?? [],
8808
+ summary: summaryOf2(name)
8809
+ }));
8810
+ }
8811
+ function childrenOf(all, parent) {
8812
+ return all.filter((spec) => spec.words.length === 2 && spec.words[0] === parent);
8813
+ }
8814
+ function quoted2(text) {
8815
+ return `'${text.replace(/'/g, "'\\''")}'`;
8816
+ }
8817
+ function described(name, summary) {
8818
+ return quoted2(summary === "" ? name : `${name}:${summary}`);
8819
+ }
8820
+ function bashScript() {
8821
+ const all = specs();
8822
+ const top = all.filter((spec) => spec.words.length === 1);
8823
+ const arms = all.map((spec) => {
8824
+ const key2 = quoted2(spec.words.join(" "));
8825
+ const children = childrenOf(all, spec.words[0]);
8826
+ const names = spec.options.map((option) => option.name);
8827
+ const values = spec.options.filter((option) => option.value !== void 0).map((option) => option.name);
8828
+ const parts2 = [];
8829
+ const choices = spec.words.length === 1 && children.length > 0 ? children.map((child) => child.words[1]) : spec.choices;
8830
+ if (choices.length > 0) parts2.push(`choices='${choices.join(" ")}'`);
8831
+ if (names.length > 0) parts2.push(`opts="$opts ${names.join(" ")}"`);
8832
+ if (values.length > 0) parts2.push(`vals='${values.join(" ")}'`);
8833
+ if (spec.path) parts2.push("paths=1");
8834
+ return ` ${key2}) ${parts2.length === 0 ? ":" : parts2.join("; ")} ;;`;
8835
+ });
8836
+ return [
8837
+ "# bash completion for rshow, printed by `rshow completion bash`.",
8838
+ "# Load it with",
8839
+ "# rshow completion bash > ~/.local/share/bash-completion/completions/rshow",
8840
+ "",
8841
+ `_rshow_commands='${top.map((spec) => spec.words[0]).join(" ")}'`,
8842
+ `_rshow_options='${GLOBAL_OPTIONS.map((option) => option.name).join(" ")}'`,
8843
+ "",
8844
+ "_rshow() {",
8845
+ " local cur prev cmd sub key word opts vals paths choices i",
8846
+ " COMPREPLY=()",
8847
+ ' cur="${COMP_WORDS[COMP_CWORD]}"',
8848
+ " prev=''",
8849
+ ' if [ "$COMP_CWORD" -gt 0 ]; then',
8850
+ ' prev="${COMP_WORDS[COMP_CWORD-1]}"',
8851
+ " fi",
8852
+ "",
8853
+ " i=1",
8854
+ ' while [ "$i" -lt "$COMP_CWORD" ]; do',
8855
+ ' word="${COMP_WORDS[i]}"',
8856
+ ' case "$word" in',
8857
+ " -*) ;;",
8858
+ " *)",
8859
+ ' if [ -z "$cmd" ]; then',
8860
+ ' cmd="$word"',
8861
+ ' elif [ -z "$sub" ]; then',
8862
+ ' sub="$word"',
8863
+ " fi",
8864
+ " ;;",
8865
+ " esac",
8866
+ " i=$((i + 1))",
8867
+ " done",
8868
+ "",
8869
+ ' if [ -z "$cmd" ]; then',
8870
+ ' COMPREPLY=( $(compgen -W "$_rshow_commands $_rshow_options" -- "$cur") )',
8871
+ " return 0",
8872
+ " fi",
8873
+ "",
8874
+ ' key="$cmd"',
8875
+ ' if [ -n "$sub" ]; then',
8876
+ ' key="$cmd $sub"',
8877
+ " fi",
8878
+ "",
8879
+ ' opts="$_rshow_options"',
8880
+ " vals=''",
8881
+ " paths=''",
8882
+ " choices=''",
8883
+ ' case "$key" in',
8884
+ ...arms,
8885
+ " *) return 0 ;;",
8886
+ " esac",
8887
+ "",
8888
+ " # A flag that takes a value completes nothing: the value is a slug or a",
8889
+ " # folder, and this script never asks the API.",
8890
+ ' if [ -n "$vals" ]; then',
8891
+ ' case " $vals " in',
8892
+ ' *" $prev "*) return 0 ;;',
8893
+ " esac",
8894
+ " fi",
8895
+ "",
8896
+ ' case "$cur" in',
8897
+ " -*)",
8898
+ ' COMPREPLY=( $(compgen -W "$opts" -- "$cur") )',
8899
+ " return 0",
8900
+ " ;;",
8901
+ " esac",
8902
+ "",
8903
+ ' if [ -n "$choices" ]; then',
8904
+ ' COMPREPLY=( $(compgen -W "$choices" -- "$cur") )',
8905
+ " return 0",
8906
+ " fi",
8907
+ ' if [ -n "$paths" ]; then',
8908
+ ' COMPREPLY=( $(compgen -f -- "$cur") )',
8909
+ " return 0",
8910
+ " fi",
8911
+ " return 0",
8912
+ "}",
8913
+ "",
8914
+ "complete -F _rshow rshow"
8915
+ ].join("\n");
8916
+ }
8917
+ function zshArguments(spec) {
8918
+ const parts2 = GLOBAL_OPTIONS.map((option) => quoted2(`${option.name}[${option.description}]`));
8919
+ for (const option of spec.options) {
8920
+ parts2.push(quoted2(option.value === void 0 ? option.name : `${option.name}=`));
8921
+ }
8922
+ if (spec.choices.length > 0) parts2.push(quoted2(`*: :(${spec.choices.join(" ")})`));
8923
+ else if (spec.path) parts2.push(quoted2("*:file or folder:_files"));
8924
+ return `_arguments ${parts2.join(" ")}`;
8925
+ }
8926
+ function zshScript() {
8927
+ const all = specs();
8928
+ const top = all.filter((spec) => spec.words.length === 1);
8929
+ const groups = top.filter((spec) => childrenOf(all, spec.words[0]).length > 0);
8930
+ const arms = all.map((spec) => {
8931
+ const children = childrenOf(all, spec.words[0]);
8932
+ const key2 = quoted2(spec.words.join(" "));
8933
+ if (spec.words.length === 1 && children.length > 0) {
8934
+ const subs = children.map((child) => ` ${described(child.words[1], child.summary)}`);
8935
+ return [
8936
+ ` ${key2})`,
8937
+ " subs=(",
8938
+ ...subs,
8939
+ " )",
8940
+ ` _describe -t commands ${quoted2(`${spec.words[0]} command`)} subs`,
8941
+ " ;;"
8942
+ ].join("\n");
8943
+ }
8944
+ return ` ${key2}) ${zshArguments(spec)} ;;`;
8945
+ });
8946
+ return [
8947
+ "#compdef rshow",
8948
+ "",
8949
+ "# Completion for rshow, printed by `rshow completion zsh`.",
8950
+ "# Load it with",
8951
+ "# rshow completion zsh > ~/.local/share/zsh/site-functions/_rshow",
8952
+ "# and keep that folder on $fpath, before compinit.",
8953
+ "",
8954
+ "_rshow() {",
8955
+ " local -a commands subs groups",
8956
+ " local state key",
8957
+ "",
8958
+ " groups=(",
8959
+ ...groups.map((spec) => ` ${quoted2(spec.words[0])}`),
8960
+ " )",
8961
+ "",
8962
+ " _arguments -C \\",
8963
+ ...GLOBAL_OPTIONS.map((option) => ` ${quoted2(`${option.name}[${option.description}]`)} \\`),
8964
+ " '1: :->command' \\",
8965
+ " '*:: :->args' && return 0",
8966
+ "",
8967
+ " case $state in",
8968
+ " command)",
8969
+ " commands=(",
8970
+ ...top.map((spec) => ` ${described(spec.words[0], spec.summary)}`),
8971
+ " )",
8972
+ " _describe -t commands 'rshow command' commands",
8973
+ " ;;",
8974
+ " args)",
8975
+ " key=$words[1]",
8976
+ " if (( $groups[(Ie)$words[1]] )); then",
8977
+ " case $words[2] in",
8978
+ " ''|-*) ;;",
8979
+ ' *) key="$words[1] $words[2]" ;;',
8980
+ " esac",
8981
+ " fi",
8982
+ " case $key in",
8983
+ ...arms,
8984
+ " esac",
8985
+ " ;;",
8986
+ " esac",
8987
+ "}",
8988
+ "",
8989
+ "# Sourced from a shell that runs compinit as well as autoloaded from $fpath.",
8990
+ "if (( $+functions[compdef] )); then",
8991
+ " compdef _rshow rshow",
8992
+ "fi"
8993
+ ].join("\n");
8994
+ }
8995
+ function fishScript() {
8996
+ const all = specs();
8997
+ const top = all.filter((spec) => spec.words.length === 1);
8998
+ const condition = (words) => words.map((word) => `__fish_seen_subcommand_from ${word}`).join("; and ");
8999
+ const lines = [
9000
+ "# fish completion for rshow, printed by `rshow completion fish`.",
9001
+ "# Load it with",
9002
+ "# rshow completion fish > ~/.config/fish/completions/rshow.fish",
9003
+ "",
9004
+ "complete -c rshow -f",
9005
+ "",
9006
+ "# commands"
9007
+ ];
9008
+ for (const spec of top) {
9009
+ const summary = spec.summary === "" ? "" : ` -d ${quoted2(spec.summary)}`;
9010
+ lines.push(`complete -c rshow -n __fish_use_subcommand -a ${quoted2(spec.words[0])}${summary}`);
9011
+ }
9012
+ for (const spec of all.filter((entry) => entry.words.length === 2)) {
9013
+ const parent = spec.words[0];
9014
+ const siblings = childrenOf(all, parent).map((child) => child.words[1]);
9015
+ const summary = spec.summary === "" ? "" : ` -d ${quoted2(spec.summary)}`;
9016
+ lines.push(
9017
+ `complete -c rshow -n ${quoted2(
9018
+ `__fish_seen_subcommand_from ${parent}; and not __fish_seen_subcommand_from ${siblings.join(" ")}`
9019
+ )} -a ${quoted2(spec.words[1])}${summary}`
9020
+ );
9021
+ }
9022
+ lines.push("", "# options");
9023
+ for (const option of GLOBAL_OPTIONS) {
9024
+ lines.push(`complete -c rshow -l ${option.name.slice(2)} -d ${quoted2(option.description)}`);
9025
+ }
9026
+ for (const spec of all) {
9027
+ const seen = quoted2(condition(spec.words));
9028
+ for (const option of spec.options) {
9029
+ const value = option.value === void 0 ? "" : " -r";
9030
+ lines.push(`complete -c rshow -n ${seen} -l ${option.name.slice(2)}${value}`);
9031
+ }
9032
+ if (spec.choices.length > 0) lines.push(`complete -c rshow -n ${seen} -a ${quoted2(spec.choices.join(" "))}`);
9033
+ else if (spec.path) lines.push(`complete -c rshow -n ${seen} -F`);
9034
+ }
9035
+ return lines.join("\n");
9036
+ }
9037
+ function script(shell) {
9038
+ if (shell === "bash") return bashScript();
9039
+ if (shell === "zsh") return zshScript();
9040
+ return fishScript();
9041
+ }
9042
+ function isShell(value) {
9043
+ return SHELLS.includes(value);
9044
+ }
9045
+ async function run19(argv, ctx) {
9046
+ const args = parseCommandArgs(argv, {}, 0, 1, COMPLETION_USAGE);
9047
+ const shell = args.positionals[0];
9048
+ if (shell === void 0) {
9049
+ throw new UsageError(`completion needs a shell: bash, zsh or fish (try: ${usageLine(COMPLETION_USAGE)})`);
9050
+ }
9051
+ if (!isShell(shell)) throw new UsageError(`unknown shell: ${shell} (use bash, zsh or fish)`);
9052
+ ctx.out.raw(script(shell));
9053
+ return EXIT.ok;
9054
+ }
9055
+
8719
9056
  // src/commands/login.ts
8720
9057
  import process21 from "node:process";
8721
9058
  async function hiddenLine() {
@@ -8773,7 +9110,7 @@ function reasonOf(err) {
8773
9110
  const lines = text.split("\n").map((part) => part.trim()).filter((part) => part !== "");
8774
9111
  return lines.at(-1) ?? "";
8775
9112
  }
8776
- async function run19(argv, ctx, platform = process21.platform) {
9113
+ async function run20(argv, ctx, platform = process21.platform) {
8777
9114
  const args = parseCommandArgs(argv, { url: { type: "string" } }, 0, 0, LOGIN_USAGE);
8778
9115
  const settings = await ctx.config();
8779
9116
  const given = (stringValue(args, "url") ?? "").trim();
@@ -8802,7 +9139,7 @@ async function run19(argv, ctx, platform = process21.platform) {
8802
9139
 
8803
9140
  // src/commands/logout.ts
8804
9141
  import process22 from "node:process";
8805
- async function run20(argv, ctx, platform = process22.platform) {
9142
+ async function run21(argv, ctx, platform = process22.platform) {
8806
9143
  const args = parseCommandArgs(argv, { url: { type: "string" } }, 0, 0, LOGOUT_USAGE);
8807
9144
  const settings = await ctx.config();
8808
9145
  const given = (stringValue(args, "url") ?? "").trim();
@@ -8837,8 +9174,9 @@ var COMMANDS = {
8837
9174
  share: { usage: SHARE_USAGE, run: run11 },
8838
9175
  pin: { usage: PIN_USAGE, run: run12 },
8839
9176
  delete: { usage: DELETE_USAGE, run: run13 },
8840
- login: { usage: LOGIN_USAGE, run: run19 },
8841
- logout: { usage: LOGOUT_USAGE, run: run20 },
9177
+ login: { usage: LOGIN_USAGE, run: run20 },
9178
+ logout: { usage: LOGOUT_USAGE, run: run21 },
9179
+ completion: { usage: COMPLETION_USAGE, run: run19 },
8842
9180
  // Kept out of the general help: the docs site runs it, a person rarely does.
8843
9181
  docs: { usage: DOCS_USAGE, run: run18 }
8844
9182
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rshow",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Publish static artifacts to rshow",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rslib.github.io/rshow",
@@ -47,8 +47,13 @@ Copy this checklist into the reply and tick it as you go.
47
47
  The only exceptions are `/_themes/...` and `/_data/...`.
48
48
  - Link the theme, never copy it.
49
49
  The stylesheet links and `mode.js` in the head all carry the same `<name>@<n>` version.
50
- - Override tokens in one `:root` block, five declarations at most.
51
- No selectors, no rules, no `!important`.
50
+ - The theme is the base, not a cage.
51
+ A page may carry one inline `<style>` block with its own classes and its own layouts when the content needs them.
52
+ Own CSS takes colour, type and space from the theme tokens with `var(--...)`, so light, dark, print and a theme swap keep working.
53
+ A hard-coded colour sits inside a figure only.
54
+ - Own CSS adds a class and never restyles a theme class globally.
55
+ Scope a new deck layout as `.slide.<name>` and scope a page part under its own class name, and use no `!important`.
56
+ - A token override still goes in one `:root` block, with no limit on the declarations.
52
57
  - Keep the script and the styles inline.
53
58
  Add a framework only when the page needs one.
54
59
  - `connect-src` is `'self'`.
@@ -64,9 +69,10 @@ Copy this checklist into the reply and tick it as you go.
64
69
  Print `[PLACEHOLDER]` and say so in the footer.
65
70
  - The look is IBM Carbon on IBM Plex, and every colour has one job.
66
71
  `themes/DESIGN.md` in the rshow repo holds the system, the type scale and the layout set.
67
- - Fixed templates carry decks, reports, posters, project pages and dashboards, so the sections are set and the content is the work.
72
+ - Documented templates carry decks, reports, posters, project pages and dashboards, so the markup is documented and the content is the work.
73
+ The markup is the starting point, and a page adds its own parts with its own classes when it needs them.
68
74
  - Guided kits carry mockups, sketches and TUIs, so the kit gives you a frame, a floor and a checklist and the drawing is the work.
69
- Starting a kit at its highest fidelity is the same mistake as decorating a fixed template.
75
+ Starting a kit at its highest fidelity is the same mistake as decorating a documented template.
70
76
 
71
77
  ## Audience
72
78
 
@@ -11,7 +11,7 @@
11
11
  - Checks
12
12
 
13
13
  A results dashboard is the page a reader works in rather than reads: a filter bar, a summary, small multiples and the table of rows behind them.
14
- It is a fixed template, so the four blocks are set and the data is the work.
14
+ It is a documented template, so the four blocks are the starting point and the data is the work, and a page may add its own parts with its own classes.
15
15
  `dashboard.css` sets the look and `dashboard.js` reads the data, draws the chart and keeps the view in the link.
16
16
 
17
17
  ## What it is for
@@ -13,15 +13,17 @@
13
13
  - Look at it
14
14
 
15
15
  A mockup is a drawing of a product that does not exist yet, so it follows that product and not rshow.
16
- Decks, reports, posters, project pages and dashboards are fixed templates, while a mockup is a guided kit: the kit gives you a frame, a floor and a checklist, and the drawing is the work.
16
+ Decks, reports, posters, project pages and dashboards are documented templates, while a mockup is a guided kit: the kit gives you a frame, a floor and a checklist, and the drawing is the work.
17
17
  `themes/MOCKUPS.md` in the rshow repo holds the kit itself, and this file is what to do with it.
18
18
 
19
19
  ## A guided kit
20
20
 
21
- - Start in `wire` every time, because a tidy drawing invites a room to argue about the colour of a button instead of the order of the steps.
22
- - Move to `sketch` when the room is too polite about a finished looking picture.
23
- - Move to a platform skin only when the look of the product is the decision.
21
+ - Pick the skin from the question.
22
+ - Use `wire` when the flow or the order of the layout is the question, because a tidy drawing invites a room to argue about the colour of a button instead of the order of the steps.
23
+ - Use `sketch` for an early rough idea, or when the room is too polite about a finished looking picture.
24
+ - Use a platform skin, or `tui` and `terminal` for a terminal, when the look is the decision or the person asks for the look.
24
25
  - Keep the inventing to layout, spacing, hierarchy and the order of steps.
26
+ Own CSS inside a screen is allowed for the part the kit lacks, and it takes colour from the `--mk-*` and theme tokens so a skin swap and dark mode still read.
25
27
  Data, copy, names and prices are placeholders and say so.
26
28
 
27
29
  ## Markup
@@ -108,6 +110,7 @@ Never present invented data as if somebody measured it.
108
110
 
109
111
  - `rshow check <dir>` exits 0, then `rshow preview <dir>`.
110
112
  - Look at the canvas, the focus view and Play mode, in both modes, at desktop width and at 360px.
113
+ - Press `?` on the page for the keys: `w` `a` `s` `d` or the arrows pan, `[` `]` step between screens, `Enter` opens one, `1` to `9` pick a state, so tell the person about that list.
111
114
  - Switch the skin in the toolbar and check the drawing still reads.
112
115
  - Print puts one artboard on a page with no tool chrome, which is what a review meeting wants on paper.
113
116
  - `rshow publish <dir> --slug <slug> --label "<what changed>"`, then read `rshow-implement` before anybody writes code from it.
@@ -71,9 +71,11 @@ Every link carries the same version on purpose, because a mixed version renders
71
71
  ```
72
72
 
73
73
  `page.css` gives you `lede`, `table`, `num-cell`, `muted`, `small` and `mono`, plus the heading, list, figure, table and code rules.
74
- Use them and keep your own CSS to the one `:root` block.
74
+ The theme is the base, not a cage.
75
+ Use these classes first, and add a class of your own in one inline `<style>` block when the page needs a part the theme does not carry.
76
+ Own CSS takes colour, type and space from the tokens with `var(--...)`, and it never restyles a theme class globally.
75
77
  There is no card class, no label class and no number tile.
76
- A page that needs one is usually a page with a table it has not written yet.
78
+ A page that needs one writes it, and a page that needs only a table writes the table.
77
79
 
78
80
  The theme carries both modes, so the same page reads on white and on g100 with nothing in the page itself.
79
81
 
@@ -96,8 +98,8 @@ Print is always light, whatever the screen was.
96
98
 
97
99
  ## Token overrides
98
100
 
99
- Override a token instead of writing rules.
100
- Five declarations cover most restyling.
101
+ Override a token instead of restyling a theme class.
102
+ A few declarations cover most restyling, and there is no limit on how many.
101
103
 
102
104
  ```html
103
105
  <style>:root{
@@ -11,7 +11,7 @@
11
11
  - Checks
12
12
 
13
13
  A poster is one sheet that prints from the browser, in the same theme as a page, a report and a project page.
14
- It is a fixed template, so the sheet, the columns and the print are set and the blocks are the work.
14
+ It is a documented template, so the sheet, the columns and the print are set and the blocks are the starting point, and a page may add its own parts with its own classes.
15
15
  `poster.css` sets the look and `poster.js` sets the scale, the QR code and the one page print.
16
16
 
17
17
  ## The sheet
@@ -11,7 +11,7 @@
11
11
  - Checks
12
12
 
13
13
  A project page is the landing page of a paper, and it uses the same theme as a page, a report and a poster.
14
- It is a fixed template, so the sections are set and the content is the work.
14
+ It is a documented template, so the sections are the starting point and the content is the work, and a page may add its own parts with its own classes.
15
15
  `project.css` sets the look and `project.js` does one thing, the copy button on the BibTeX entry.
16
16
 
17
17
  A project page is not a project.
@@ -11,7 +11,7 @@
11
11
  - Checks
12
12
 
13
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.
14
+ It is a guided kit rather than a documented template: `sketch.css` is the bar around the canvas and `sketch.js` is the canvas.
15
15
  Use it for an architecture drawing, a flow of systems or an idea that should look unfinished.
16
16
 
17
17
  ## When a sketch
@@ -6,8 +6,8 @@ description: Load before you build or revise a talk, deck or presentation. Load
6
6
  # rshow slides
7
7
 
8
8
  A deck is a folder with one `index.html` in it, published to `https://art.example.com/<slug>/`.
9
- It links the deck half of a published theme, so the folder holds no CSS, no font and no script of its own.
10
- The theme does the layout, and the deck only picks a layout per slide.
9
+ It links the deck half of a published theme, so the folder holds no copy of the theme, no font and no script of its own.
10
+ The theme does the layout, and the deck picks a layout per slide or adds one of its own in an inline `<style>` block.
11
11
  The look is IBM Carbon on IBM Plex, and `themes/DESIGN.md` in the rshow repo holds the whole system.
12
12
 
13
13
  ## 1. Outline first
@@ -23,6 +23,7 @@ A topic on its own is not a slide.
23
23
  - Open with a `title` slide and close with a `title` slide or a `big-number` that says what to do next.
24
24
  - Put one `section` slide before each move in the argument.
25
25
  - Give the evidence slides the layout that carries the claim: `figure`, `chart`, `table` or `figure-two` for a research or systems talk.
26
+ - Name the layout of each line in the outline, including any layout the deck adds for itself.
26
27
  - In a research talk the figure, the plot and the table are the hero.
27
28
  The title says what the evidence shows and the type stays out of the way.
28
29
  - Say which slide carries the headline number, and put the number in it once.
@@ -71,11 +72,12 @@ Replace `<name>@<n>` with the `theme` value that `rshow config <dir>` prints, wh
71
72
 
72
73
  The three stylesheet links and the script carry the same `<n>` on purpose, because a mixed version renders somewhere between two designs.
73
74
  The deck needs no `mode.js`, because `deck.js` reads the same key and `t` does the same work.
74
- Override a token in one `:root` block after the theme links when the deck needs its own accent, and keep it to a few declarations.
75
+ Override a token in one `:root` block after the theme links when the deck needs its own accent, with no limit on the declarations.
76
+ An inline `<style>` block after the theme links may also carry a layout of the deck's own, as section 3 says.
75
77
 
76
78
  ## 3. Layouts
77
79
 
78
- Every slide is a `<section class="slide ...">`, and the second class is one of twelve.
80
+ Every slide is a `<section class="slide ...">`, and the second class is one of twelve or one the deck adds.
79
81
 
80
82
  - `title` for the opener, `section` for a divider and `statement` for one claim set large.
81
83
  - `bullets` for a takeaway title and at most five short points.
@@ -89,8 +91,11 @@ A bullets slide puts its points under the title at 28px with a 1.4 line, five at
89
91
  A figure slide starts at the top and lets the figure take the rest.
90
92
  A figure is `<figure>` with a `figcaption`, and two figures are `<div class="pair">` with two `<figure>` inside.
91
93
  A big number is `<p class="value">` plus `<p class="caption">`, and the value is a short statement with the figure inside it, never a bare digit.
92
- Do not invent a thirteenth layout and do not write the layout CSS yourself, because the theme owns it and a copy drifts.
93
- [layouts](reference/layouts.md) holds one markup example per layout. Read it before you write a slide that is not `title`, `bullets` or `section`.
94
+ The twelve layouts are a starting set and not a ceiling.
95
+ Invent a layout when none of them carries the claim, such as an annotated figure, a figure with a callout, a diagram built in HTML or SVG, a timeline, a before and after or a comparison grid.
96
+ Give it a short class name and put its CSS in the deck's own `<style>` block, scoped to `.slide.<name>` and taken from the tokens.
97
+ Vary the rhythm: do not run more than three text slides (`two-col` or `bullets`) in a row, and turn a text slide that explains a figure into an annotated figure.
98
+ [layouts](reference/layouts.md) holds one markup example per layout and one worked example of your own layout. Read it before you write a slide that is not `title`, `bullets` or `section`.
94
99
 
95
100
  ## 4. Notes and steps
96
101
 
@@ -99,13 +104,16 @@ Do not invent a thirteenth layout and do not write the layout CSS yourself, beca
99
104
  It is what you say, not what the room reads.
100
105
  - Press `n` for the notes window, which also names the next slide.
101
106
  - Press `p` for the presenter view: the current slide, the next slide, the notes and an elapsed timer, kept in step with the deck.
102
- - Put `class="step"` on an `<li>` to reveal it one press later.
107
+ - Put `class="step"` on any element inside a slide to reveal it one press later, because `deck.js` selects every `.step` in the slide.
108
+ That is how a diagram builds up in steps.
103
109
  - Every step is a reveal, so a slide with four steps needs four presses.
104
110
  Five is the ceiling before the slide drags.
105
111
  - Press `f` for fullscreen and arrows or space to advance.
106
112
  Press `Ctrl` and `P` for a print sheet when someone wants a pdf.
107
113
  - Press `t` to cycle the mode: system, light, dark, with the mode shown in the counter for a moment.
108
114
  The choice is remembered for every rshow document and print is always light.
115
+ - On a phone held upright the deck reads as a stack of slides, each one reflowed to the width of the screen at phone sizes with a rule and an `n / total` label between slides, and a `Present` button goes back to one slide at a time.
116
+ `Esc` comes back to reading, and the arrows, space and a `#n` link work in both.
109
117
 
110
118
  ## 5. Check, preview, publish
111
119
 
@@ -132,5 +140,6 @@ Publish again after a fix instead of making a second slug, because the link in t
132
140
  - Never use a hairline rule as decoration.
133
141
  - Never use Inter, Space Grotesk, Geist, Fraunces or Instrument Serif as the gesture.
134
142
  - Never use gradient text, glass, a large shadow or an emoji.
135
- - Never animate a slide in, because a reveal is the only motion a deck needs.
143
+ - Never animate a slide in for decoration.
144
+ Motion is allowed when it explains something, such as a step that builds a diagram or a short transition that shows a change.
136
145
  - Never invent a number and never present example data without saying so in the caption.