pageship 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/cli.mjs +15 -5
  2. package/dist/skills/pageship/SKILL.md +1 -1
  3. package/dist/skills/pageship-chart/SKILL.md +18 -2
  4. package/dist/skills/pageship-code-block/SKILL.md +1 -1
  5. package/dist/skills/pageship-decision-record/SKILL.md +5 -1
  6. package/dist/skills/pageship-diagram/SKILL.md +16 -14
  7. package/dist/skills/pageship-diagram/references/check-diagram.js +3 -2
  8. package/dist/skills/pageship-docs/SKILL.md +32 -8
  9. package/dist/skills/pageship-docs/references/axe.js +34 -0
  10. package/dist/skills/pageship-docs/references/check.md +35 -8
  11. package/dist/skills/pageship-docs/references/design.md +38 -18
  12. package/dist/skills/pageship-docs/references/html-validate-rules.mjs +326 -0
  13. package/dist/skills/pageship-docs/references/html-validate.json +13 -0
  14. package/dist/skills/pageship-docs/references/palette.mjs +791 -0
  15. package/dist/skills/pageship-docs/references/plain-default.md +1 -1
  16. package/dist/skills/pageship-explainer/SKILL.md +13 -5
  17. package/dist/skills/pageship-interaction/SKILL.md +7 -5
  18. package/dist/skills/pageship-interaction/references/pointer.md +3 -0
  19. package/dist/skills/pageship-interaction/references/step-through.md +10 -25
  20. package/dist/skills/pageship-key-figures/SKILL.md +1 -1
  21. package/dist/skills/pageship-media/SKILL.md +2 -2
  22. package/dist/skills/pageship-motion/SKILL.md +31 -28
  23. package/dist/skills/pageship-motion/references/figure-motion.js +252 -0
  24. package/dist/skills/pageship-motion/references/figure-motion.md +294 -0
  25. package/dist/skills/pageship-plan/SKILL.md +3 -3
  26. package/dist/skills/pageship-report/SKILL.md +5 -1
  27. package/dist/skills/pageship-review-report/SKILL.md +5 -1
  28. package/dist/skills/pageship-slide-deck/SKILL.md +5 -3
  29. package/dist/skills/pageship-slide-deck/references/engine.md +1 -1
  30. package/dist/skills/pageship-spec/SKILL.md +5 -1
  31. package/dist/skills/pageship-table/SKILL.md +5 -3
  32. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -705,7 +705,7 @@ async function updateWorkspaceAddress(baseUrl, action, options = {}) {
705
705
  credentials: options.token ? "omit" : "include",
706
706
  headers: options.token ? { Authorization: `Bearer ${options.token}` } : void 0,
707
707
  redirect: "error",
708
- cache: "no-store",
708
+ cache: "default",
709
709
  throwOnError: false,
710
710
  signal: options.signal ? AbortSignal.any([timeout, options.signal]) : timeout
711
711
  });
@@ -742,6 +742,16 @@ function requestOptions(baseUrl, options) {
742
742
  throwOnError: false
743
743
  };
744
744
  }
745
+ /**
746
+ * A change keeps the browser's default cache mode. Chromium skips its preflight cache for a
747
+ * `no-store` request, and no browser caches a change's response anyway.
748
+ */
749
+ function changeOptions(baseUrl, options) {
750
+ return {
751
+ ...requestOptions(baseUrl, options),
752
+ cache: "default"
753
+ };
754
+ }
745
755
  function record(value) {
746
756
  return typeof value === "object" && value !== null && !Array.isArray(value);
747
757
  }
@@ -861,7 +871,7 @@ async function getDocumentContent(baseUrl, id, options = {}) {
861
871
  throw new Error("Invalid document content response.");
862
872
  }
863
873
  async function restoreDocumentRevision(baseUrl, id, input, options = {}) {
864
- const request = requestOptions(baseUrl, options);
874
+ const request = changeOptions(baseUrl, options);
865
875
  const { data: received, response, error } = await documentsRestore({
866
876
  ...request,
867
877
  path: { id },
@@ -891,7 +901,7 @@ async function restoreDocumentRevision(baseUrl, id, input, options = {}) {
891
901
  }
892
902
  async function updateDocumentVisibility(baseUrl, id, visibility, options = {}) {
893
903
  const { data: received, response, error } = await documentsUpdateVisibility({
894
- ...requestOptions(baseUrl, options),
904
+ ...changeOptions(baseUrl, options),
895
905
  path: { id },
896
906
  body: { visibility }
897
907
  });
@@ -913,7 +923,7 @@ async function publishDocument(baseUrl, input, options = {}) {
913
923
  if (input.action) {
914
924
  if (!(await getDocumentLimits(baseUrl, options)).publicationActions.includes(input.action)) throw new DocumentRequestError("publication_action_unsupported", "This server does not support explicit publication actions. Ask the operator to update the server. No HTML was uploaded.", 400);
915
925
  }
916
- const request = requestOptions(baseUrl, options);
926
+ const request = changeOptions(baseUrl, options);
917
927
  const { data: received, response, error } = await documentsCreate({
918
928
  ...request,
919
929
  headers: {
@@ -1412,7 +1422,7 @@ function commandLine(command, args) {
1412
1422
  }
1413
1423
  //#endregion
1414
1424
  //#region package.json
1415
- var version = "0.3.0";
1425
+ var version = "0.4.0";
1416
1426
  //#endregion
1417
1427
  //#region src/publish.ts
1418
1428
  const execute = promisify(execFile);
@@ -3,7 +3,7 @@ name: pageship
3
3
  description: Publish an HTML file to Pageship and manage what is published. Use when the user asks to publish, share or get a link to a document, update its published copy, change its visibility, list, inspect history, download or restore published documents, or sign in to Pageship. To write, edit, rename or move a document, load pageship-docs instead.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Pageship
@@ -3,12 +3,12 @@ name: pageship-chart
3
3
  description: Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for charts in a Pageship HTML document, loaded by a pageship- kind skill before it draws a chart.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Chart
10
10
 
11
- A chart answers one question about the source's numbers at a glance. You draw it as inline SVG on an honest scale, with every value the reader needs printed on the page, never with a chart library or Mermaid.
11
+ A chart answers one question about the source's numbers at a glance. You draw it as inline SVG on an honest scale, with every value the reader needs printed on the page, never with a chart library or Mermaid, and it plays once from its initial state to its values when it scrolls into view.
12
12
 
13
13
  Unless another pageship- skill loaded this one, start as [pageship-docs says](../pageship-docs/SKILL.md#starting-at-a-kind-or-pattern-skill).
14
14
 
@@ -85,6 +85,22 @@ Write static SVG markup with the coordinates computed as you write. For each val
85
85
 
86
86
  Buttons that highlight or filter series show every series by default.
87
87
 
88
+ ## 5. Play the entrance
89
+
90
+ Load `pageship-motion` before the first chart: [its playback rules](../pageship-motion/SKILL.md#2-build-it-so-the-still-page-tells-the-whole-story) own when a chart plays, its pace, its controls and reduced motion. The markup you wrote in step 4 is the end state; the entrance starts from each mark's initial state and ends on that markup.
91
+
92
+ | Form | Entrance |
93
+ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
94
+ | Vertical bars, histogram bins | Bars grow up from the baseline to their height; each printed value fades in with its bar. |
95
+ | Horizontal bars | Bars grow from the left axis to their length, top to bottom. |
96
+ | Line chart | Each line draws from left to right; a point and its value appear as the line reaches it; the direct label appears at the end. |
97
+ | Share bar | The parts fill in from left to right, one after the next, each to its share. |
98
+ | Scatter plot, dot plot | Dots appear in order of the horizontal axis, left to right. |
99
+ | Small multiples | Every small chart plays its own form's entrance at the same time, on the same clock. |
100
+ | Target, forecast and other lines | Appear in full when the series they belong to finishes. |
101
+
102
+ [The reference script](../pageship-motion/references/figure-motion.md) shows bars that grow and a line that draws; the other forms scale each mark's size or opacity the same way.
103
+
88
104
  ## Colours
89
105
 
90
106
  Colour the chart in the stylesheet, with `fill` and `stroke`, from [the look's colour variables](../pageship-docs/references/design.md#the-looks-colour-variables) and no other colour:
@@ -3,7 +3,7 @@ name: pageship-code-block
3
3
  description: Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for code in a Pageship HTML document, such as source code, commands, configuration or logs, loaded by a pageship- kind skill before the first code block.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Code block
@@ -3,7 +3,7 @@ name: pageship-decision-record
3
3
  description: HTML decision records, as the second step of pageship-docs. For any request to record, write, regenerate, edit or move a decision, load pageship-docs first; load this skill first only when the user names it.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Decision record
@@ -29,6 +29,10 @@ Build one comparison of the options:
29
29
  - Every option gets a value on every point: what the source says about that option on that point, in its units and wording. Where the source says nothing, write "Not stated", never a value you would have to infer, such as "low" for an option whose cost the source never gives.
30
30
  - Keep the source's order of options, and mark the chosen one in words.
31
31
 
32
+ ## Figures
33
+
34
+ Beyond the comparison table, a decision record's figures come from the numbers behind the context and from the consequences, such as a table of the consequences when most share fields such as standing and who acts. When the source gives a number for every option on one point, such as cost, a chart of that point beside the table is a candidate figure.
35
+
32
36
  ## Order
33
37
 
34
38
  1. **Title and decision.** An `h1` naming what was decided, then at once the decision in one or two sentences in the source's words, and a line with its status and the date, owner and scope the source gives.
@@ -3,7 +3,7 @@ name: pageship-diagram
3
3
  description: Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for diagrams in a Pageship HTML document, such as a process, a timeline, a system map or states, loaded by a pageship- kind skill before it draws a diagram.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Diagram
@@ -16,16 +16,16 @@ Unless another pageship- skill loaded this one, start as [pageship-docs says](..
16
16
 
17
17
  Write down the reader's question the figure answers, in a few words, and take the row closest to it.
18
18
 
19
- | The reader asks | Diagram | Drawn with |
20
- | ----------------------------------------------- | --------------------------------------- | ---------------------------------- |
21
- | What happens next, and where does it branch? | Flowchart, top to bottom | SVG, with a [step-through][steps] |
22
- | Who hands what to whom, in what order? | Swimlane or sequence | SVG, with a [step-through][steps] |
23
- | When did each thing happen, and how far apart? | [Timeline](references/svg.md#timelines) | SVG, always |
24
- | What states can it be in, and what moves it on? | State diagram | SVG, [computed][layout] when large |
25
- | What connects to what? | System map or dependency graph | SVG, [computed][layout] when large |
26
- | What is part of what? | Tree or nested boxes | SVG |
19
+ | The reader asks | Diagram | Drawn with |
20
+ | ----------------------------------------------- | --------------------------------------- | ----------------------------------- |
21
+ | What happens next, and where does it branch? | Flowchart, top to bottom | SVG, played as a [sequence][motion] |
22
+ | Who hands what to whom, in what order? | Swimlane or sequence | SVG, played as a [sequence][motion] |
23
+ | When did each thing happen, and how far apart? | [Timeline](references/svg.md#timelines) | SVG, played as a [sequence][motion] |
24
+ | What states can it be in, and what moves it on? | State diagram | SVG, [computed][layout] when large |
25
+ | What connects to what? | System map or dependency graph | SVG, [computed][layout] when large |
26
+ | What is part of what? | Tree or nested boxes | SVG |
27
27
 
28
- A process or a change over time of three to eight steps gets the [step-through][steps], unless its layout is computed.
28
+ Every diagram plays once when it scrolls into view, by `pageship-motion`. A process, a path or events in time play as a [sequence][motion]: a marker travels the path, or the stages or events appear in order, and the reader has the controls. Every other diagram, a computed layout included, is a graphic that builds in: its nodes appear, then its connectors draw. A Mermaid figure, which Mermaid draws at load, holds still.
29
29
 
30
30
  ## 2. Fit the limits
31
31
 
@@ -52,7 +52,7 @@ Content you merge or move stays in the document, in a figure or the text beside
52
52
  - With SVG, follow [the SVG rules](references/svg.md).
53
53
  - With a computed layout, follow [the computed layout steps][layout].
54
54
  - With Mermaid, follow [the Mermaid rules][mermaid].
55
- - For a process or change over time laid out by hand, add [the step-through][steps].
55
+ - Load `pageship-motion` before the first SVG figure. A process, a path or events in time laid out by hand plays as a [sequence][motion]: each node and connector carries the `data-step` that brings it in, and an ordered list of the steps with their values follows the drawing. Any other SVG figure builds in as a graphic: the nodes appear, then the connectors draw.
56
56
 
57
57
  Every figure, however drawn:
58
58
 
@@ -78,8 +78,10 @@ When the source sorts the nodes into two to four named groups, such as the team
78
78
 
79
79
  ## Check
80
80
 
81
- - In a browser, run [check-diagram.js](references/check-diagram.js) in the page at 1280px and at 390px wide, for example `agent-browser eval "$(cat <this skill's folder>/references/check-diagram.js)"`. It returns a list of problems with every SVG you drew or computed. Fix each one and run it again until the list is empty. A line starting with "note" is a crossing to remove if you can.
82
- - For a step-through, run [its check](../pageship-interaction/references/step-through.md#check).
81
+ Run the browser steps with [the check's browser tool](../pageship-docs/references/check.md#checks-in-a-browser).
82
+
83
+ - Run [check-diagram.js](references/check-diagram.js) in the page at 1280px and at 390px wide. In `html_preview`, the copy's `load` listener runs `const problems = <the file's text>` and logs `JSON.stringify(problems)`. In agent-browser, run `agent-browser eval "$(cat <this skill's folder>/references/check-diagram.js)"`. It returns a list of problems with every SVG you drew or computed. Fix each one and run it again until the list is empty. A line starting with "note" is a crossing to remove if you can.
84
+ - For every SVG figure, run [the motion check](../pageship-motion/SKILL.md#check).
83
85
  - For Mermaid, look at the screenshot at both widths and confirm every node and label is readable, no two lines run together, and no line runs through a node or a label.
84
86
  - Without a browser, check your layout plan by arithmetic as [the SVG rules](references/svg.md#plan-the-layout) say.
85
87
 
@@ -87,6 +89,6 @@ When the source sorts the nodes into two to four named groups, such as the team
87
89
 
88
90
  The structure you introduced includes the form you chose for each figure and why, and any merges, splits or overviews. When a graph over the hand-drawn limits went to Mermaid instead of a computed layout, say why.
89
91
 
90
- [steps]: ../pageship-interaction/references/step-through.md
92
+ [motion]: ../pageship-motion/SKILL.md
91
93
  [mermaid]: references/mermaid.md
92
94
  [layout]: references/computed-layout.md
@@ -1,6 +1,7 @@
1
1
  // Checks every hand-drawn diagram in the open page against the pageship-diagram rules.
2
- // Run the whole file in the page, for example with `agent-browser eval "$(cat check-diagram.js)"`
3
- // or Playwright's `page.evaluate`. It returns a list of problems; an empty list passes.
2
+ // Run the whole file in the page, for example with `agent-browser eval "$(cat check-diagram.js)"`,
3
+ // or in html_preview as `const problems = <this file>` in a load listener that logs them.
4
+ // It returns a list of problems; an empty list passes.
4
5
  // Mermaid diagrams are skipped: Mermaid lays them out itself.
5
6
  (() => {
6
7
  const problems = [];
@@ -3,13 +3,15 @@ name: pageship-docs
3
3
  description: First step for any document people read, such as a report, plan, spec, explainer, review, decision record or slide deck, in HTML or Markdown. Load it before any other pageship- skill. Use when the user asks for one of these documents, asks to regenerate, redesign, edit, rename, move or copy an HTML source file, or asks to record whether they want HTML or Markdown.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.3.0"
6
+ version: "0.4.0"
7
7
  ---
8
8
 
9
9
  # Pageship documents
10
10
 
11
11
  The result is Markdown or one standalone HTML source file. You never publish yourself; you hand the file to the `pageship` skill, which does.
12
12
 
13
+ When your task says you write the file for `pageship-docs`, you are the subagent of [step 4 in a subagent](#step-4-in-a-subagent): start at step 4 with the format, kind and path it gives. Otherwise, when you can start a subagent, as in Claude Code, Codex and T3 Code, run steps 1 to 3 yourself and send step 4 to one subagent, for a new file and an edit alike. The sources, skill text and check output then stay in its context, not yours. Without subagents, run every step yourself.
14
+
13
15
  ## 1. Settle the format
14
16
 
15
17
  Take the first rule that applies.
@@ -35,7 +37,7 @@ For Markdown, go to step 3.
35
37
  | Decision record | What was decided, the options and the consequences | `pageship-decision-record` |
36
38
  | Slide deck | Slides to present from a browser | `pageship-slide-deck` |
37
39
 
38
- Load the skill of the kind that fits. When none fits exactly, or its skill is not installed, use the closest installed kind and tell the user which.
40
+ Pick the kind that fits. Step 4 loads its skill. When none fits exactly, or its skill is not installed, use the closest installed kind and tell the user which.
39
41
 
40
42
  ## 3. Choose the path
41
43
 
@@ -43,25 +45,47 @@ A new file goes at the path the user names, or else where the project keeps such
43
45
 
44
46
  ## 4. Write the file
45
47
 
48
+ When you send this step to a subagent, follow [step 4 in a subagent](#step-4-in-a-subagent).
49
+
46
50
  For Markdown, write one file by the [content rules](references/content.md) alone, then hand over.
47
51
 
48
- For HTML, the kind skill gives the parts, the order and its own rules, which win over this skeleton:
52
+ For HTML, load the kind skill. It gives the parts, the order and its own rules, which win over this skeleton:
49
53
 
50
54
  1. **Gather.** Read the request, every file it points to and the project's glossary. Where the kind asks for an **inventory**, list every item of the source in its order and words, until an item covers every sentence of the source. Done when you can point to where each fact you plan to write comes from.
51
55
  2. **Sort.** Put every statement of the source into exactly one of the kind's parts.
52
- 3. **Write.** One file by the [content rules](references/content.md), the [file rules](references/file.md) and the [design rules](references/design.md), in the kind's order, under its headings or the closest glossary terms. A part the source leaves empty keeps its heading and one line saying the source gives none. Done when every sorted statement, or every inventory item, is in the file.
53
- 4. **Check.** Run [the check](references/check.md), with the checks the kind and pattern skills add.
56
+ 3. **Figures.** For each section, ask whether a figure carries its point better than prose: a chart, a table, a diagram or key figures. Wherever one does, use it, in the form [the design rules](references/design.md#the-form-of-each-figure) give. Technical or complex content, such as a mechanism, a set of numbers or a comparison of several items, gets a figure and prose. The prose beside each figure says what it shows and why it matters, as the source puts it. Before drawing the first chart, graphic or sequence diagram, load `pageship-motion`, which plays each one as it scrolls into view. Done when you can name, for each section, the figures it gets, or that prose carries its point better.
57
+ 4. **Write.** One file by the [content rules](references/content.md), the [file rules](references/file.md) and the [design rules](references/design.md), in the kind's order, under its headings or the closest glossary terms. A part the source leaves empty keeps its heading and one line saying the source gives none. Done when every sorted statement, or every inventory item, is in the file.
58
+ 5. **Check.** Run [the check](references/check.md), with the checks the kind and pattern skills add.
54
59
 
55
60
  Then hand over. Your final message lists, however briefly you otherwise reply:
56
61
 
57
62
  - the file's path;
58
63
  - the structure you added that the source didn't have, as [the check lists it](references/check.md#the-structure-you-added);
59
64
  - the open questions, marking the ones you added;
60
- - the checks that ran and the ones you skipped;
65
+ - the checks that ran and the ones you skipped, and which tool ran [the browser checks](references/check.md#checks-in-a-browser), or that none did;
61
66
  - what the kind and pattern skills add to this list.
62
67
 
63
- For an HTML file, end the hand-over with the next step for publishing. When the user asked in this conversation to publish this document, or accepted an offer to, load `pageship` and publish it. Otherwise, when the `pageship` skill is installed, offer to publish the file through it; for a file with a document marker, offer to publish the change as a new revision of its document.
68
+ As the subagent, end at the list. Otherwise, for an HTML file, end the hand-over with the next step for publishing. When the user asked in this conversation to publish this document, or accepted an offer to, load `pageship` and publish it. Otherwise, when the `pageship` skill is installed, offer to publish the file through it; for a file with a document marker, offer to publish the change as a new revision of its document.
69
+
70
+ ## Step 4 in a subagent
71
+
72
+ Start one subagent and give it:
73
+
74
+ - the user's request, word for word, and every source that lives only in this conversation, such as pasted text or an answer the user gave, quoted in full;
75
+ - each source file by absolute path, the file being edited, renamed, moved or copied included. The subagent reads them;
76
+ - the format and the path from steps 1 to 3 and, for HTML, the kind or lone pattern skill;
77
+ - this instruction: "You write the file for `pageship-docs`. Load it and the skill named here, and follow step 4 and its hand-over. The format, kind and path are settled. Put each question you would ask the user into the open questions. Your final message is the full hand-over list; I handle publishing."
78
+
79
+ Wait for its final message. When it lacks the hand-over list, ask the subagent for the list.
80
+
81
+ When the list has "Fresh reading still to run", the subagent couldn't start a reader of its own:
82
+
83
+ 1. Start a new subagent that has not seen this conversation and give it only the reader task the list gives, word for word. Wait for its answer.
84
+ 2. Bring its quotes to the writer. When you can continue the writing subagent, send it the quotes in full. Otherwise start a new subagent with the file's path, each source file by absolute path, the kind skill, the quotes in full and this instruction: "You write the file for `pageship-docs`. Load it and the skill named here. The file is written; the quotes below are its fresh reading. Fix each one as the skill's check says, then run the rest of the check again. Your final message is the full hand-over list; I handle publishing."
85
+ 3. Its new list replaces the first. Done when the list you relay has no "Fresh reading still to run".
86
+
87
+ Relay the list to the user in full, open questions included, then, for an HTML file, end with the next step for publishing as step 4 says.
64
88
 
65
89
  ## Starting at a kind or pattern skill
66
90
 
67
- When the user named a kind skill, or named a pattern skill and asked for just that pattern, write HTML unless the request names another format, and start at step 3. A lone pattern is the file's main content, under an `h1`, with no parts to sort. In every other case, start at step 1.
91
+ The subagent always starts at step 4. Otherwise, when the user named a kind skill, or named a pattern skill and asked for just that pattern, write HTML unless the request names another format, and start at step 3. A lone pattern is the file's main content, under an `h1`, with no parts to sort. In every other case, start at step 1.
@@ -0,0 +1,34 @@
1
+ // Runs axe-core's WCAG 2 A and AA rules on the page and logs one line per problem, with the
2
+ // element and how to fix it. Run with `agent-browser eval --stdin < axe.js`, which also prints the
3
+ // lines, or paste into a <script> at the end of <body> for html_preview, which shows the log.
4
+ // The promise stays the script's value, which agent-browser eval waits for and prints.
5
+ // oxlint-disable-next-line typescript/no-floating-promises
6
+ (async () => {
7
+ // Added before the page's load event, the script delays it, so html_preview waits for axe-core.
8
+ if (!window.axe) {
9
+ const script = document.createElement("script");
10
+ script.src = "https://cdn.jsdelivr.net/npm/axe-core@4.14.0/axe.min.js";
11
+ script.integrity = "sha384-lFUXB8tI4BaTE1bqxH9eeAXON2NH1qsdAhs7S5L++nUNP5QOy+hwr0C3TYEJUEl0";
12
+ script.crossOrigin = "anonymous";
13
+ document.head.append(script);
14
+ await new Promise((resolve, reject) => {
15
+ script.onload = resolve;
16
+ script.onerror = () => reject(new Error("axe-core didn't load"));
17
+ });
18
+ }
19
+ if (document.readyState !== "complete") {
20
+ await new Promise((resolve) => addEventListener("load", resolve, { once: true }));
21
+ }
22
+ const { violations } = await window.axe.run(document, {
23
+ runOnly: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"],
24
+ });
25
+ const problems = violations.flatMap((violation) =>
26
+ violation.nodes.map(
27
+ (node) =>
28
+ `axe ${violation.id}: ${node.target.join(" ")}: ${node.failureSummary.replace(/\s+/g, " ")}`,
29
+ ),
30
+ );
31
+ for (const problem of problems) console.log(problem);
32
+ console.log(`axe: ${problems.length} problems`);
33
+ return problems;
34
+ })();
@@ -2,25 +2,52 @@
2
2
 
3
3
  Run these checks on the finished file and fix what they find.
4
4
 
5
- The files a check makes, such as screenshots, PDFs and scripts, are scratch: save them by absolute path in the system temporary folder, never in the project, and delete them, wherever they landed, once the check is done.
5
+ The files a check makes, such as screenshots, PDFs, scripts and edited copies of the file, are scratch: save them by absolute path in the system temporary folder, never in the project, and delete them, wherever they landed, once the check is done.
6
6
 
7
7
  ## Checks that need no browser
8
8
 
9
- - Every `<script src>` and `<link rel="stylesheet">` tag matches a tag in the [file rules](file.md) exactly: the same URL, `integrity` and `crossorigin="anonymous"`. A script or stylesheet inside the file as a `data:` URL matches none. A hosted font matches by its address instead: a stylesheet link to `https://fonts.googleapis.com/css2?family=...`, with no `integrity`. A font preload (`rel="preload" as="font"`) needs no match.
10
- - No relative paths load anything: search for `src="` and `url(` and confirm each one is `https://`, `data:` or a `#fragment`.
9
+ Run the linter, html-validate with the config and rules in this folder:
10
+
11
+ ```sh
12
+ npx --yes html-validate@11.17.0 --config <pageship-docs folder>/references/html-validate.json <file>
13
+ ```
14
+
15
+ It reports HTML errors, accessibility problems such as a missing `lang` or `alt` or a skipped heading level, and breaks of three rules: [one standalone file](file.md#one-standalone-file) and [trusted libraries only](file.md#trusted-libraries-only) in the file rules, and **Height** in [the design rules](design.md#base-rules-every-file-meets). Fix each problem it reports and run it again. Done when it reports nothing. When `npx` can't run, such as without Node or network, check the file against those three rules by reading it, and say in the hand-over that the linter didn't run.
16
+
17
+ Then:
18
+
11
19
  - The file uses nothing on the sandbox list in the file rules.
12
20
  - The marker is as the file rules say: the same last line as before, or none at all.
13
21
  - Every number, name and date in the file appears in the source. Each gap is an open question.
14
- - Light and dark each set every variable in [the design rules](design.md#the-looks-colour-variables), each colour clears its floor, `--accent-2` sits as far from `--accent` as the table says, and both accents colour something on screen.
22
+ - Light and dark each set every variable in [the design rules](design.md#the-looks-colour-variables), and each colour clears its floor: `node <pageship-docs folder>/references/palette.mjs --check <file>` lists each one that doesn't. Without Node, compare each value with its floor yourself. Both accents colour something on screen.
15
23
 
16
24
  ## Checks in a browser
17
25
 
18
- Use a browser tool when you have one, such as `agent-browser` or Playwright; without one, skip this section. Open the file from disk and:
26
+ These checks, and the browser steps of the kind and pattern skills, are required whenever you have a browser tool. Use the first one you have:
27
+
28
+ 1. **`html_preview`**, in T3 Code. Pass the file's text as `html`, with a `width` and an `appearance`. It returns a screenshot of the whole page and the console output. A file over 512 KB is too large for it: use agent-browser.
29
+ 2. **agent-browser**, in every other harness. `agent-browser open file://<the file's absolute path>`, then `set viewport <width> 800`, `set media light` or `set media dark`, `screenshot <path>`, `console` and `errors`. A step's input uses `click`, `press` and `focus`, and a step's script runs with `eval`.
30
+ 3. **Neither.** Skip this section and the skills' browser steps, and take the step a skill gives for a missing browser, where it gives one.
19
31
 
20
- - At 1280px and at 390px wide, confirm the page doesn't scroll sideways: `document.documentElement.scrollWidth` is no larger than `clientWidth`.
21
- - Look at a screenshot at each width, in light and in dark. Fix overlapping, clipped or unreadable content.
32
+ Some states take an edited copy of the file:
33
+
34
+ - **axe-core in `html_preview`**: at the end of `<body>`, add a `<script>` holding the text of `<pageship-docs folder>/references/axe.js`. Every preview of the file uses a copy with it.
35
+ - **Dark in `html_preview`**, which doesn't set the colour scheme: change every `prefers-color-scheme: dark` to `prefers-color-scheme: light`, add `<style>:root { color-scheme: dark }</style>` at the end of `<head>`, and pass `appearance: "dark"`.
36
+ - **Reduced motion in `html_preview`**: swap `prefers-reduced-motion: reduce` and `prefers-reduced-motion: no-preference` everywhere. In agent-browser, `set media light reduced-motion`.
37
+ - **Print, in both tools**, which can't emulate it: swap `print` and `screen` in every media query, in `@media` rules and `matchMedia` calls alike, so `@media print` reads `@media screen`.
38
+ - **Input and scripts in `html_preview`**: at the end of `<body>`, add a `<script>` with a `load` listener that takes the steps and logs each result with `console.log`. Click with `element.click()`, which also stands for Enter or Space on a button; press a key with `element.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true, cancelable: true }))`; hover with a `pointerover` event the same way. A script can't press Tab: log each control's `tabIndex`, which is `0` for every control in the tab order, then focus each one in document order with `element.focus()` and log `document.activeElement`. The screenshot shows the page after the listener ran.
39
+ - **A fragment in `html_preview`**, such as `#slide-3`: the copy's first script runs `history.replaceState(null, "", "#slide-3")`.
40
+
41
+ `html_preview` takes its screenshot right after the page loads, before timers and animations run their course, so a figure that plays in view at load may show its initial state or part of its playback; `pageship-motion`'s check covers its end state. A step that waits, such as letting playback run, takes the skill's step for a missing browser, or is skipped where the skill gives none.
42
+
43
+ At 1280px and at 390px wide, each in light and in dark:
44
+
45
+ - Confirm the page doesn't scroll sideways: `document.documentElement.scrollWidth` is no larger than `clientWidth`.
46
+ - Look at the screenshot. Fix overlapping, clipped or unreadable content.
22
47
  - Read the console. Fix every error, including failed integrity checks.
23
- - Use every control by keyboard and confirm it works and shows focus.
48
+ - Run axe-core, which checks accessibility in the rendered page, such as the contrast of each piece of text against what is really behind it. In agent-browser, run `agent-browser eval --stdin < <pageship-docs folder>/references/axe.js`; in `html_preview`, read the lines the copy's script logs. Fix each problem it lists.
49
+
50
+ Then use every control by keyboard and confirm it works and shows focus. Done when, at both widths in both colour schemes, the page doesn't scroll sideways, the screenshot shows nothing overlapping, clipped or unreadable, the console shows no error, and axe-core lists no problem, and every control works by keyboard and shows focus.
24
51
 
25
52
  ## Claims
26
53
 
@@ -2,45 +2,63 @@
2
2
 
3
3
  ## Who sets the look
4
4
 
5
- Take the look from the first source that has one:
5
+ Settle the look and its colours yourself, from the first source that has one:
6
6
 
7
7
  1. The user's explicit visual instructions.
8
8
  2. The project's design system: its tokens, stylesheets or brand guide.
9
- 3. An installed design skill: one in your list of available skills, not a skill file found elsewhere on disk. Prefer Anthropic's `frontend-design`, then the Taste Skill stack (`design-taste-frontend` and its companion skills). Follow its guidance on type, colour values and character. When it asks questions or offers options, take its default and keep going.
9
+ 3. An installed design skill: one in your list of available skills, not a skill file found elsewhere on disk. Prefer Anthropic's `frontend-design`, then the Taste Skill stack (`design-taste-frontend` and its companion skills). Follow its guidance on type and character. When it asks questions or offers options, take its default and keep going.
10
10
  4. Otherwise, copy [the plain default](plain-default.md).
11
11
 
12
- Whatever sets the look, these rules own structure, density, reading width, print, the colour count below and the [file rules](file.md). A design skill's one-accent or colour-lock rule shapes the values it picks, but the colour count here wins whatever a design skill says about accents: two accents, four series colours and three status colours. A document is for reading: leave out the landing-page parts a design skill may suggest, such as hero banners, decorative sections, marketing copy and entrance animations.
12
+ Whatever sets the look, these rules own structure, density, reading width, print, the colours below and the [file rules](file.md). The colours here win whatever a design skill says about palettes or accents: two accents, four series colours and three status colours, from [the palette calculator](#the-palette-calculator). A document is for reading: leave out the landing-page parts a design skill may suggest, such as hero banners, decorative sections, marketing copy, and entrance animations on text and sections. Figures move only as `pageship-motion` says.
13
13
 
14
14
  ## The look's colour variables
15
15
 
16
- Every source file sets these fourteen variables in `:root`, once for light and once more under `@media (prefers-color-scheme: dark)`. The look's source fills their values: a design system from its tokens, a design skill from the palette it chooses, the plain default as written. Each takes a plain colour value: hex, `rgb()`, `hsl()`, `oklch()`, or `light-dark()` of those. Pattern skills colour their parts from these variables and no other colour.
16
+ Every source file sets these fourteen variables in `:root`, once for light and once more under `@media (prefers-color-scheme: dark)`. [The palette calculator](#the-palette-calculator) fills their values, unless the user gives the colours or the project's design system has colour tokens: then those fill them. Each takes a plain colour value: hex, `rgb()`, `hsl()`, `oklch()`, or `light-dark()` of those. Pattern skills colour their parts from these variables and no other colour.
17
17
 
18
- | Variable | Colours | Floor against `--bg` |
19
- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
20
- | `--bg` | The page background. | |
21
- | `--fg` | Text. | 4.5:1 |
22
- | `--muted` | Secondary text: meta lines, captions, axis labels, connector labels. | 4.5:1 |
23
- | `--line` | Hairlines: rules, table borders, frames, gridlines. | |
24
- | `--surface` | Tinted panels: callouts, code blocks, caption strips, diagram nodes. | |
25
- | `--accent` | The first accent: the title area, section headings, callout bars, focus outlines and the focus of each figure. | 3:1 |
26
- | `--accent-2` | The second accent: links, the title rule and quote bars. In each theme, at least 60° from the first in OKLCH hue, so it stands out from the first accent and from the page. | 4.5:1 |
27
- | `--series-1` to `--series-4` | Chart series and diagram node categories, in this order. Four hues apart from each other and from the accents. | 3:1 |
28
- | `--good`, `--warn`, `--bad` | A status the source gives, such as on track, at risk and blocked: green, amber and red tuned to the look. | 3:1 |
18
+ | Variable | Colours | Floor against `--bg` |
19
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------- |
20
+ | `--bg` | The page background. | |
21
+ | `--fg` | Text. | 4.5:1 |
22
+ | `--muted` | Secondary text: meta lines, captions, axis labels, connector labels. | 4.5:1 |
23
+ | `--line` | Hairlines: rules, table borders, frames, gridlines. | |
24
+ | `--surface` | Tinted panels: callouts, code blocks, caption strips, diagram nodes. | |
25
+ | `--accent` | The first accent: the title area, section headings, callout bars, focus outlines and the focus of each figure. | 4.5:1 |
26
+ | `--accent-2` | The second accent: links, the title rule and quote bars. | 4.5:1 |
27
+ | `--series-1` to `--series-4` | Chart series and diagram node categories, in this order. Four hues apart from each other and from the accents. | 3:1 |
28
+ | `--good`, `--warn`, `--bad` | A status the source gives, such as on track, at risk and blocked: green, amber and red tuned to the look. | 3:1 |
29
29
 
30
- Spend colour by the 60-30-10 rule: the neutrals fill most of the page, the first accent carries the look, and the second accent is the small share that stands out. Both accents colour something a reader sees in every source file, as the table places them. The first accent meets 4.5:1 where it colours text, such as headings.
30
+ Spend colour by the 60-30-10 rule: the neutrals fill most of the page, the first accent carries the look, and the second accent is the small share that stands out. Both accents colour something a reader sees in every source file, as the table places them.
31
31
 
32
32
  A status the source gives shows in the source's words, in an element with `data-status="good"`, `"warn"` or `"bad"` that carries the matching colour on a dot, border or bar beside the words; the words stay `--fg`. The words are the element's own text, or a `.status` label inside it when the element holds more, such as a card. Rate it only as the source's word does: good for done or on track, warn for at risk, bad for blocked, late or missed. Any other status, such as in progress or not started, stays `--muted` with no `data-status`.
33
33
 
34
+ ## The palette calculator
35
+
36
+ [palette.mjs](palette.mjs) writes all fourteen variables for light and dark, each at its floor. The accents are what it gives. Make each choice below yourself, from the topic and the source.
37
+
38
+ - **Seed** (`--seed`): the project's brand colour when it has one, otherwise a colour you pick for the topic: hex, `rgb()`, `hsl()` or `oklch()`, with hues in degrees.
39
+ - **Number of colours** (`--colours`, 1 to 5): the hues the colour system sets: 1 for a calm look of one hue, more for a livelier one. Hues 1 and 2 become the accents, hues 3 to 5 the first series colours, and the calculator picks the rest. With 1, the second accent is a shade of the first.
40
+ - **Gap** (`--gap`): degrees between hues. Leave it out to space the hues evenly. A small gap, such as 30, gives neighbouring hues; a large one, contrasting hues.
41
+ - **Preset** (`--preset`), in place of the number and the gap: `split-complementary` (three hues at 0°, 150° and 210°) or `rectangle` (four at 0°, 60°, 180° and 240°).
42
+ - **Neutral tint** (`--tint`): how much of the seed's hue the background, text and lines carry: `none`, `subtle` (the default) or `strong`.
43
+
44
+ ```sh
45
+ node <pageship-docs folder>/references/palette.mjs --seed '#0d9488' --colours 3 --gap 40
46
+ node <pageship-docs folder>/references/palette.mjs --seed '#0d9488' --preset split-complementary --tint none
47
+ ```
48
+
49
+ It prints the `:root` block for light and the one for dark. Put their declarations in the look's light and dark root rules, in place of any colour values there. Without Node, keep [the plain default](plain-default.md)'s colours.
50
+
34
51
  ## Base rules every file meets
35
52
 
36
53
  - **Light and dark.** Both themes follow the system setting through `prefers-color-scheme`.
37
54
  - **Contrast.** Text meets WCAG AA: 4.5:1 for body text, 3:1 for large text, icons and control borders. Each colour variable meets its floor in the table above, in light and in dark.
38
55
  - **Reading width.** Prose lines hold about 70 characters (`max-width: 70ch` on prose).
39
56
  - **Type size.** Body text is at least 16px. Nothing a reader needs is smaller than 13px, including captions, table text, labels and code.
57
+ - **Height.** Content sets each part's height, or a length in `rem` or `px`. Previews frame the page at its full height, so a height that follows the window (`vh`, `svh`, `lvh`, `dvh`) grows with the frame.
40
58
  - **Phone width.** At 390px wide the page never scrolls sideways and keeps at least 12px of side padding, so no text or figure frame touches the screen's edge. Wide content scrolls inside its own box: a `<div class="scroll">` (`overflow-x: auto`) around a diagram or chart, the `.table-scroll` box `pageship-table` gives, or a code block's own `pre`.
41
59
  - **Print.** A print stylesheet shows all content, expands anything collapsed (`details::details-content { content-visibility: visible }`), hides controls, prints dark text on white, and avoids breaking inside figures, table rows and callouts.
42
60
  - **Links and controls.** Hovering a link or control changes how it looks, such as a thicker underline or a tinted background, and keyboard focus shows a visible outline. Every control is a native interactive element. Before adding one, load `pageship-interaction`.
43
- - **Motion.** Nothing moves until the reader acts. Under `prefers-reduced-motion: reduce`, nothing animates and every state shows in full. Before making anything move, load `pageship-motion`.
61
+ - **Motion.** Every chart, graphic and sequence plays once when it scrolls into view and stops on its end state, which its markup holds; everything else holds still until the reader acts. Under `prefers-reduced-motion: reduce`, nothing plays on its own and every state shows in full. Before drawing a chart, a graphic or a sequence, or making anything else move, load `pageship-motion`.
44
62
  - **Headings.** One `h1`, then levels in order. The document has a `lang` attribute and a `title`.
45
63
 
46
64
  ## The form of each figure
@@ -57,4 +75,6 @@ Take each figure's form from what the reader wants of it. Before writing a form
57
75
  | The lines of code the text is about | Code block | `pageship-code-block` |
58
76
  | An image, video or audio the source gives | Media | `pageship-media` |
59
77
  | Items with one attribute each, or steps in one line with no branch whose timing doesn't matter | List | |
60
- | One or two relationships, or two or three numbers that aren't parts of a whole | Sentence | |
78
+ | A single relationship, or one or two numbers, that a figure would only repeat | Sentence | |
79
+
80
+ A point that fits a figure's row and the list or sentence row takes the figure, with the list or sentence as the prose beside it.