@lernapps/tooling 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +8 -10
- package/dist/skills/lernapps-cli/SKILL.md +1 -1
- package/dist/skills/lernapps-content-questions/references/question-types.md +1 -1
- package/dist/skills/lernapps-exercise-patterns/references/figures.md +1 -0
- package/dist/skills/lernapps-explainer/SKILL.md +2 -0
- package/generator/create.ts +8 -6
- package/generator/init.ts +2 -11
- package/guidance/AGENTS.md +2 -0
- package/guidance/increment-template.md +2 -1
- package/guidance/plan-template.md +2 -2
- package/guidance/workflow-rules.md +2 -2
- package/package.json +2 -2
- package/skills/archetypes/lernapps-explainer/SKILL.md +2 -0
- package/skills/content/lernapps-content-questions/references/question-types.md +1 -1
- package/skills/content/lernapps-exercise-patterns/references/figures.md +1 -0
- package/skills/tooling/lernapps-cli/SKILL.md +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -809,7 +809,7 @@ const SCREENSHOTS_OPTIONS = {
|
|
|
809
809
|
},
|
|
810
810
|
width: {
|
|
811
811
|
type: "string",
|
|
812
|
-
default: "
|
|
812
|
+
default: "360"
|
|
813
813
|
},
|
|
814
814
|
desktop: {
|
|
815
815
|
type: "boolean",
|
|
@@ -846,8 +846,8 @@ which shows the figures with their page, in the folder --out. The folder is empt
|
|
|
846
846
|
|
|
847
847
|
Options:
|
|
848
848
|
--out <dir> the folder of the images (default screenshots)
|
|
849
|
-
--width <px> the width of the images in pixels (default
|
|
850
|
-
--desktop also images 1280 px wide; every image is then named with its width (01-index-
|
|
849
|
+
--width <px> the width of the images in pixels (default 360, a phone)
|
|
850
|
+
--desktop also images 1280 px wide; every image is then named with its width (01-index-360.png,
|
|
851
851
|
01-index-1280.png, 01-index-figure-1-1280.png)
|
|
852
852
|
-h, --help print this help
|
|
853
853
|
`;
|
|
@@ -1445,7 +1445,7 @@ Run it in the folder lernapps init prepared, from the tooling init installed:
|
|
|
1445
1445
|
It needs git, and the npm registry for the npm install that follows. The app then depends on the version of
|
|
1446
1446
|
@lernapps/tooling that created it, and its workflows use the actions of that version's tag.
|
|
1447
1447
|
|
|
1448
|
-
It writes, besides the template: package.json named after the folder (its prepare script, lernapps hooks,
|
|
1448
|
+
It writes, besides the template: package.json named after the short name given to init (the folder's name without init) (its prepare script, lernapps hooks,
|
|
1449
1449
|
installs the git hooks; for an explainer and an interactive app also vue-tsc and typescript, with which lernapps
|
|
1450
1450
|
check type-checks its Vue components; for an interactive app also @doctc/arc42, which checks its architecture),
|
|
1451
1451
|
for an interactive app its architecture docs/arc42/ (the generic part and the interactive extension of app-templates,
|
|
@@ -1527,7 +1527,7 @@ function contents(dir) {
|
|
|
1527
1527
|
if (name === ".git" || name === "skills-lock.json" && skills.size > 0) return [];
|
|
1528
1528
|
if (name === "node_modules" || name === "package-lock.json") return [];
|
|
1529
1529
|
if (name === "package.json" && readJson(join(dir, name)).lernapps?.init === true) return [];
|
|
1530
|
-
if (name === ".vibe") return
|
|
1530
|
+
if (name === ".vibe") return existsSync(join(dir, ".vibe/plans")) ? within(PLANS, (file) => PLAN_NAME.test(file)) : [];
|
|
1531
1531
|
if ((name === ".agents" || name === ".claude") && skills.size > 0) return within(name, (folder) => folder === "skills").concat(existsSync(join(dir, name, "skills")) ? within(`${name}/skills`, (skill) => skills.has(skill)) : []);
|
|
1532
1532
|
return [name];
|
|
1533
1533
|
});
|
|
@@ -1691,7 +1691,7 @@ function create(args) {
|
|
|
1691
1691
|
if (positionals.length > 1) throw new UsageError(`one <dir> at most, not ${positionals.join(" ")}`);
|
|
1692
1692
|
const dir = resolve(positionals[0] ?? ".");
|
|
1693
1693
|
const found = contents(dir);
|
|
1694
|
-
if (found.length > 0) throw new CreateError(`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`);
|
|
1694
|
+
if (found.length > 0) throw new CreateError(`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, .vibe/ (the first version's plan .vibe/plans/01-<short name>.md, and its sketches) and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`);
|
|
1695
1695
|
const plan = confirmedPlan(dir, archetype, values.plan);
|
|
1696
1696
|
const architecture = ARCHITECTURE_ARCHETYPES.includes(archetype);
|
|
1697
1697
|
if (!existsSync(join(templates.root, archetype, "package.json"))) throw new CreateError(`${templates.root} has no template ${archetype}/ (version ${templates.version})`);
|
|
@@ -1711,7 +1711,7 @@ function create(args) {
|
|
|
1711
1711
|
if (architecture) writeArchitecture(dir, templates.root, archetype, templates.version);
|
|
1712
1712
|
else rmSync(join(dir, ".arc42ignore"), { force: true });
|
|
1713
1713
|
const app = readJson(join(dir, "package.json"));
|
|
1714
|
-
const name = packageName(dir);
|
|
1714
|
+
const name = initialised?.lernapps?.init === true && typeof initialised.name === "string" ? initialised.name : packageName(dir);
|
|
1715
1715
|
app.name = name;
|
|
1716
1716
|
app.scripts = {
|
|
1717
1717
|
...app.scripts,
|
|
@@ -1860,8 +1860,6 @@ function syncSkills(dir, exclude) {
|
|
|
1860
1860
|
...filters.length > 0 ? ["--exclude", ...filters] : []
|
|
1861
1861
|
], (message) => new CreateError(message), dir);
|
|
1862
1862
|
}
|
|
1863
|
-
/** A package name from the folder's name: lower case, letters, digits and hyphens. */
|
|
1864
|
-
const slug = (dir) => basename(dir).toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "app";
|
|
1865
1863
|
function init(args) {
|
|
1866
1864
|
const { values, positionals } = parseArgs({
|
|
1867
1865
|
args,
|
|
@@ -1881,7 +1879,7 @@ function init(args) {
|
|
|
1881
1879
|
const addon = values.addon;
|
|
1882
1880
|
const repository = ensureRepository(dir);
|
|
1883
1881
|
writeJson(join(dir, "package.json"), {
|
|
1884
|
-
name
|
|
1882
|
+
name,
|
|
1885
1883
|
version: "0.0.0",
|
|
1886
1884
|
private: true,
|
|
1887
1885
|
lernapps: { init: true }
|
|
@@ -44,7 +44,7 @@ a submission they declare something about.
|
|
|
44
44
|
(`…-figure-<n>.png`): a page image is scaled down, its details are not readable. `--desktop` adds 1280 px images.
|
|
45
45
|
Options: `npx --no -- lernapps screenshots --help`. The folder ignores itself in git, so a later check never sees it.
|
|
46
46
|
- Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
|
|
47
|
-
(`import { chromium } from "playwright"`), at
|
|
47
|
+
(`import { chromium } from "playwright"`), at 360 px width, and take `page.screenshot({ fullPage: true })` of each
|
|
48
48
|
state the creator should see, from a short script outside the app.
|
|
49
49
|
|
|
50
50
|
## A check fails
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| `true-false` | `answer` (true or false) |
|
|
8
8
|
| `number` | `answer`, `tolerance` (0 = exact), `unit` if any; the learner may type a comma or a point |
|
|
9
9
|
| `ordering` | `items` in the right order; the page mixes them |
|
|
10
|
-
| `matching` | `pairs` as they belong
|
|
10
|
+
| `matching` | `pairs` as they belong, each pair an object `{ left, right }`; the page mixes the right side. `distractors` (1 to 4): wrong right entries that match no left one. `pairsFrom: material` instead of `pairs` takes them from the `labelled-figure` in `material` (marker left, text right; the figure needs `legend: false`) |
|
|
11
11
|
|
|
12
12
|
- Every question: `id`, `text`, `explanation`, at least one link in `links`. Optional quiz `sources`.
|
|
13
13
|
- Types without options carry their background in `explanation`.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- Bundled; nothing from other servers before a click (`no-request-before-click`); others' images with source and
|
|
6
6
|
licence (`third-party-licence`).
|
|
7
7
|
- Works at 360 px: trees top to bottom; too wide → table, or split by stage.
|
|
8
|
+
- Check each in its own image of `npx --no -- lernapps screenshots`, not in the page image.
|
|
8
9
|
- Same conventions (colours, labels, units, orientation) across the app; write them into the guide, "Figures".
|
|
9
10
|
- The same figures work in a quiz question (`material`, skill `lernapps-content-questions`): an image of `src/images/` with
|
|
10
11
|
`alt`, `caption`, `source` and `licence`.
|
|
@@ -28,6 +28,8 @@ license: MIT
|
|
|
28
28
|
|
|
29
29
|
- A build problem is one line `file:line: place (language): what to do`. Fix where it points.
|
|
30
30
|
- Headings are `section` blocks, never Markdown headings.
|
|
31
|
+
- YAML: quote a text that has `: ` in it or looks like a number (`"8."`, `"01000001"`, `"0"`). Unquoted, YAML reads a map or a
|
|
32
|
+
number: the build stops, or the digits change. A table cell, a header cell too, is a text and never empty.
|
|
31
33
|
- A new chapter: a folder with `chapter.yaml`, listed in `src/app.yaml`, each page listed in `chapter.yaml`.
|
|
32
34
|
- `selfAssessment` in a `chapter.yaml`: written in Commit, skill
|
|
33
35
|
`lernapps-explainer-self-assessment`. An exercise it names renamed or moved → change the reference too.
|
package/generator/create.ts
CHANGED
|
@@ -57,7 +57,7 @@ Run it in the folder lernapps init prepared, from the tooling init installed:
|
|
|
57
57
|
It needs git, and the npm registry for the npm install that follows. The app then depends on the version of
|
|
58
58
|
@lernapps/tooling that created it, and its workflows use the actions of that version's tag.
|
|
59
59
|
|
|
60
|
-
It writes, besides the template: package.json named after the folder (its prepare script, lernapps hooks,
|
|
60
|
+
It writes, besides the template: package.json named after the short name given to init (the folder's name without init) (its prepare script, lernapps hooks,
|
|
61
61
|
installs the git hooks; for an explainer and an interactive app also vue-tsc and typescript, with which lernapps
|
|
62
62
|
check type-checks its Vue components; for an interactive app also @doctc/arc42, which checks its architecture),
|
|
63
63
|
for an interactive app its architecture docs/arc42/ (the generic part and the interactive extension of app-templates,
|
|
@@ -174,9 +174,9 @@ function contents(dir: string): string[] {
|
|
|
174
174
|
if (name === "node_modules" || name === "package-lock.json") return [];
|
|
175
175
|
if (name === "package.json" && readJson(join(dir, name)).lernapps?.init === true) return [];
|
|
176
176
|
if (name === ".vibe") {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
);
|
|
177
|
+
// the planning folder: the plans are checked (a first version has one), what the planning leaves beside them stays
|
|
178
|
+
// (the sketches of the plan, .vibe/sketches/)
|
|
179
|
+
return existsSync(join(dir, PLANS)) ? within(PLANS, (file) => PLAN_NAME.test(file)) : [];
|
|
180
180
|
}
|
|
181
181
|
if ((name === ".agents" || name === ".claude") && skills.size > 0) {
|
|
182
182
|
return within(name, (folder) => folder === "skills").concat(
|
|
@@ -384,7 +384,7 @@ export function create(args: string[]): number {
|
|
|
384
384
|
const found = contents(dir);
|
|
385
385
|
if (found.length > 0) {
|
|
386
386
|
throw new CreateError(
|
|
387
|
-
`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, the first version's plan .vibe/plans/01-<short name>.md and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`,
|
|
387
|
+
`${dir} is not empty (${found.slice(0, 5).join(", ")}${found.length > 5 ? ", ..." : ""}): create the app in an empty folder; only .git, .vibe/ (the first version's plan .vibe/plans/01-<short name>.md, and its sketches) and what lernapps init wrote (its skills, package.json, package-lock.json and node_modules) may be there`,
|
|
388
388
|
);
|
|
389
389
|
}
|
|
390
390
|
const plan = confirmedPlan(dir, archetype, values.plan);
|
|
@@ -416,7 +416,9 @@ export function create(args: string[]): number {
|
|
|
416
416
|
else rmSync(join(dir, ".arc42ignore"), { force: true });
|
|
417
417
|
|
|
418
418
|
const app = readJson(join(dir, "package.json"));
|
|
419
|
-
|
|
419
|
+
// the short name the creator gave `lernapps init` stays the app's name; without init, the folder names it
|
|
420
|
+
const name =
|
|
421
|
+
initialised?.lernapps?.init === true && typeof initialised.name === "string" ? initialised.name : packageName(dir);
|
|
420
422
|
app.name = name;
|
|
421
423
|
// npm install installs the hooks of this package, in the app's own repository only (lernapps hooks); the
|
|
422
424
|
// template needs no prepare script of its own, which would install them in app-templates
|
package/generator/init.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { spawnSync } from "node:child_process";
|
|
9
9
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
|
-
import {
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
12
|
import { parseArgs, type ParseArgsOptionsConfig } from "node:util";
|
|
13
13
|
import { UsageError } from "../src/usage.ts";
|
|
14
14
|
import { PLANS } from "../src/plan.ts";
|
|
@@ -121,15 +121,6 @@ function syncSkills(dir: string, exclude: string[]): void {
|
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
/** A package name from the folder's name: lower case, letters, digits and hyphens. */
|
|
125
|
-
const slug = (dir: string) =>
|
|
126
|
-
basename(dir)
|
|
127
|
-
.toLowerCase()
|
|
128
|
-
.normalize("NFKD")
|
|
129
|
-
.replace(/[̀-ͯ]/g, "")
|
|
130
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
131
|
-
.replace(/^-+|-+$/g, "") || "app";
|
|
132
|
-
|
|
133
124
|
export function init(args: string[]): number {
|
|
134
125
|
const { values, positionals } = parseArgs({ args, options: INIT_OPTIONS, strict: true, allowPositionals: true });
|
|
135
126
|
if (values.help) {
|
|
@@ -150,7 +141,7 @@ export function init(args: string[]): number {
|
|
|
150
141
|
const addon = values.addon;
|
|
151
142
|
const repository = ensureRepository(dir);
|
|
152
143
|
writeJson(join(dir, "package.json"), {
|
|
153
|
-
name
|
|
144
|
+
name,
|
|
154
145
|
version: "0.0.0",
|
|
155
146
|
private: true,
|
|
156
147
|
lernapps: { init: true },
|
package/guidance/AGENTS.md
CHANGED
|
@@ -15,6 +15,8 @@ Learning app for lernapps.net: static, runs in the browser, collects nothing, ac
|
|
|
15
15
|
|
|
16
16
|
- Read guidance and skills from the file, in full. Never use a fetch tool that summarises.
|
|
17
17
|
- Push only the branch the current plan names. A push to `main` publishes.
|
|
18
|
+
- Tick a box only after you did what it says, and only as far as it says. A box you did in part stays open, with a line
|
|
19
|
+
saying what is missing.
|
|
18
20
|
- Never `--no-verify`. Never edit `prePushFailures` or `failedChecks`.
|
|
19
21
|
- Never edit a `lernapps-*` skill: `lernapps update` replaces them. The app's own skills (`app-content`, `app-*`)
|
|
20
22
|
take precedence; app rules go there.
|
|
@@ -100,7 +100,7 @@ questions. -->
|
|
|
100
100
|
`lernapps-<archetype>-design` says, choose its pattern with skill `lernapps-exercise-patterns` (both loaded
|
|
101
101
|
in Explore), and say why the guide's patterns do not fit.
|
|
102
102
|
- [ ] Each new component or interactive exercise: a sketch (static SVG or image, or the steps). Words alone are not
|
|
103
|
-
enough.
|
|
103
|
+
enough. Keep sketch files in `.vibe/sketches/`.
|
|
104
104
|
- [ ] Show the creator, short: goal, new competencies by chapter, slices; in plain words what learners see and do,
|
|
105
105
|
what is new. At most 2 questions.
|
|
106
106
|
- [ ] **Checkpoint:** confirm the plan and the content method. Stop and wait for an explicit yes. Changes → change,
|
|
@@ -138,6 +138,7 @@ cannot. Something new goes into the guide in the slice that adds it. -->
|
|
|
138
138
|
- [ ] The content guide describes the app as it is now (`app-content-matches`). `grep -c "FILL IN"
|
|
139
139
|
.agents/skills/app-content/SKILL.md` prints 0.
|
|
140
140
|
- [ ] `npx --no -- lernapps check` passes.
|
|
141
|
+
- [ ] Look at `npx --no -- lernapps screenshots --desktop`, each figure in its own image.
|
|
141
142
|
- [ ] Every box of Explore, Plan and Code ticked.
|
|
142
143
|
- [ ] Set `phase: commit`: change the value line (`grep '^phase:'` prints `phase: commit`).
|
|
143
144
|
No checkpoint here: set it before you ask or report anything, then start Commit in the same message.
|
|
@@ -133,7 +133,7 @@ questions. -->
|
|
|
133
133
|
- [ ] Write the Code tasks under "Code": pages or screens, their content, what each shows. Each ends in a commit.
|
|
134
134
|
After the first task that shows real content: the task "Show the creator a first look (`early-preview`)".
|
|
135
135
|
- [ ] Each screen, component or interactive exercise: a sketch (static SVG or image, or the steps with what
|
|
136
|
-
learners see after each). Words alone are not enough.
|
|
136
|
+
learners see after each). Words alone are not enough. Keep sketch files in `.vibe/sketches/`, which `create` leaves alone.
|
|
137
137
|
- [ ] Show the creator, short: goal, competencies by chapter, entry draft, tasks, sketches; the content method in
|
|
138
138
|
plain words (what learners see and do, what it cannot do). At most 2 questions.
|
|
139
139
|
- [ ] **Checkpoint:** confirm the plan and the content method, with the sketches shown. Stop and wait for an
|
|
@@ -175,7 +175,7 @@ checks and cannot; how a later agent adds a chapter. Becomes the content guide i
|
|
|
175
175
|
- [ ] The content guide matches what was built (`app-content-matches`).
|
|
176
176
|
- [ ] `npx --no -- lernapps check` passes.
|
|
177
177
|
- [ ] Look at a screenshot of every screen and state (start, each mode, pause, end), desktop and 360 px. Compare
|
|
178
|
-
each with the confirmed sketches.
|
|
178
|
+
each with the confirmed sketches; each figure in its own image (`npx --no -- lernapps screenshots --desktop`).
|
|
179
179
|
- [ ] Every box of Explore, Plan and Code ticked.
|
|
180
180
|
- [ ] Set `phase: commit`: change the value line (`grep '^phase:'` prints `phase: commit`).
|
|
181
181
|
No checkpoint here: set it before you ask or report anything, then start Commit in the same message.
|
|
@@ -60,8 +60,8 @@ severity: hint
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
- In Code, as soon as the first screen or page shows real content: send the creator a short "Zwischenstand".
|
|
63
|
-
- Show screenshots, desktop and 360 px. On the creator's machine also the
|
|
64
|
-
background.
|
|
63
|
+
- Show screenshots, desktop and 360 px (`npx --no -- lernapps screenshots --desktop`). On the creator's machine also the
|
|
64
|
+
address of `npm run dev`, started in the background.
|
|
65
65
|
- No checkpoint, no question: go on in the same message. The creator may stop you or ask for a change.
|
|
66
66
|
- Example: "Zwischenstand: So sieht die erste Seite aus. Ich baue weiter; sag Bescheid, wenn etwas nicht passt."
|
|
67
67
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lernapps/tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared tooling of the lernapps.net apps and sites: the CLI lernapps, site actions, Renovate preset, guidance for building apps; documentation at https://lernapps.net/tooling/",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
117
|
"@doctc/arc42": "0.38.0",
|
|
118
|
-
"@lernapps/site": "github:lernapps/lernapps.github.io#
|
|
118
|
+
"@lernapps/site": "github:lernapps/lernapps.github.io#15473cb8e782c69b2a38d45208bbe7eaf8a6c698",
|
|
119
119
|
"@types/node": "26.6.5",
|
|
120
120
|
"ajv": "8.20.0",
|
|
121
121
|
"vite-plus": "1.4.0"
|
|
@@ -28,6 +28,8 @@ license: MIT
|
|
|
28
28
|
|
|
29
29
|
- A build problem is one line `file:line: place (language): what to do`. Fix where it points.
|
|
30
30
|
- Headings are `section` blocks, never Markdown headings.
|
|
31
|
+
- YAML: quote a text that has `: ` in it or looks like a number (`"8."`, `"01000001"`, `"0"`). Unquoted, YAML reads a map or a
|
|
32
|
+
number: the build stops, or the digits change. A table cell, a header cell too, is a text and never empty.
|
|
31
33
|
- A new chapter: a folder with `chapter.yaml`, listed in `src/app.yaml`, each page listed in `chapter.yaml`.
|
|
32
34
|
- `selfAssessment` in a `chapter.yaml`: written in Commit, skill
|
|
33
35
|
`lernapps-explainer-self-assessment`. An exercise it names renamed or moved → change the reference too.
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| `true-false` | `answer` (true or false) |
|
|
8
8
|
| `number` | `answer`, `tolerance` (0 = exact), `unit` if any; the learner may type a comma or a point |
|
|
9
9
|
| `ordering` | `items` in the right order; the page mixes them |
|
|
10
|
-
| `matching` | `pairs` as they belong
|
|
10
|
+
| `matching` | `pairs` as they belong, each pair an object `{ left, right }`; the page mixes the right side. `distractors` (1 to 4): wrong right entries that match no left one. `pairsFrom: material` instead of `pairs` takes them from the `labelled-figure` in `material` (marker left, text right; the figure needs `legend: false`) |
|
|
11
11
|
|
|
12
12
|
- Every question: `id`, `text`, `explanation`, at least one link in `links`. Optional quiz `sources`.
|
|
13
13
|
- Types without options carry their background in `explanation`.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- Bundled; nothing from other servers before a click (`no-request-before-click`); others' images with source and
|
|
6
6
|
licence (`third-party-licence`).
|
|
7
7
|
- Works at 360 px: trees top to bottom; too wide → table, or split by stage.
|
|
8
|
+
- Check each in its own image of `npx --no -- lernapps screenshots`, not in the page image.
|
|
8
9
|
- Same conventions (colours, labels, units, orientation) across the app; write them into the guide, "Figures".
|
|
9
10
|
- The same figures work in a quiz question (`material`, skill `lernapps-content-questions`): an image of `src/images/` with
|
|
10
11
|
`alt`, `caption`, `source` and `licence`.
|
|
@@ -44,7 +44,7 @@ a submission they declare something about.
|
|
|
44
44
|
(`…-figure-<n>.png`): a page image is scaled down, its details are not readable. `--desktop` adds 1280 px images.
|
|
45
45
|
Options: `npx --no -- lernapps screenshots --help`. The folder ignores itself in git, so a later check never sees it.
|
|
46
46
|
- Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
|
|
47
|
-
(`import { chromium } from "playwright"`), at
|
|
47
|
+
(`import { chromium } from "playwright"`), at 360 px width, and take `page.screenshot({ fullPage: true })` of each
|
|
48
48
|
state the creator should see, from a short script outside the app.
|
|
49
49
|
|
|
50
50
|
## A check fails
|