@lernapps/tooling 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +67 -2
  3. package/archetypes/shared/a11y.ts +38 -0
  4. package/archetypes/shared/hooks/pre-commit +22 -0
  5. package/archetypes/shared/hooks/pre-push +4 -0
  6. package/archetypes/shared/i18n.ts +25 -0
  7. package/archetypes/shared/install-hooks.ts +63 -0
  8. package/archetypes/shared/playwright.ts +54 -0
  9. package/archetypes/shared/preset.ts +81 -0
  10. package/archetypes/shared/storage.ts +167 -0
  11. package/archetypes/shared/tsconfig.json +27 -0
  12. package/check/validation-report.v1.schema.json +116 -0
  13. package/dist/a11y.mjs +30 -0
  14. package/dist/check/rules/accessible.mjs +18 -0
  15. package/dist/check/rules/app-content-guide.mjs +69 -0
  16. package/dist/check/rules/dependency-licence.mjs +82 -0
  17. package/dist/check/rules/entry-fitness-matches.mjs +22 -0
  18. package/dist/check/rules/entry-links-resolve.mjs +44 -0
  19. package/dist/check/rules/explainer-readable-without-js.mjs +66 -0
  20. package/dist/check/rules/links-resolve.mjs +10 -0
  21. package/dist/check/rules/lockfile-matches.mjs +57 -0
  22. package/dist/check/rules/no-request-before-click.mjs +17 -0
  23. package/dist/check/rules/no-tracking.mjs +17 -0
  24. package/dist/check/rules/own-data-only.mjs +66 -0
  25. package/dist/check/rules/pages-reachable.mjs +25 -0
  26. package/dist/check/rules/usable-at-360px.mjs +19 -0
  27. package/dist/check-cv4I6CCH.mjs +28 -0
  28. package/dist/cli.mjs +3118 -0
  29. package/dist/i18n.mjs +11 -0
  30. package/dist/lint.mjs +528 -0
  31. package/dist/plan-DWKayEnY.mjs +75 -0
  32. package/dist/playwright.mjs +47 -0
  33. package/dist/preset.mjs +60 -0
  34. package/dist/skills/lernapps-app/SKILL.md +49 -0
  35. package/dist/skills/lernapps-cli/SKILL.md +156 -0
  36. package/dist/skills/lernapps-cli/references/platform-rules.md +258 -0
  37. package/dist/skills/lernapps-commit/SKILL.md +39 -0
  38. package/dist/skills/lernapps-content-growth/SKILL.md +33 -0
  39. package/dist/skills/lernapps-content-questions/SKILL.md +133 -0
  40. package/dist/skills/lernapps-content-questions/references/question-types.md +69 -0
  41. package/dist/skills/lernapps-content-research/SKILL.md +50 -0
  42. package/dist/skills/lernapps-content-research/references/sources.md +16 -0
  43. package/dist/skills/lernapps-exercise-patterns/SKILL.md +74 -0
  44. package/dist/skills/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  45. package/dist/skills/lernapps-exercise-patterns/references/chemistry.md +16 -0
  46. package/dist/skills/lernapps-exercise-patterns/references/computer-science.md +13 -0
  47. package/dist/skills/lernapps-exercise-patterns/references/figures.md +10 -0
  48. package/dist/skills/lernapps-exercise-patterns/references/history.md +13 -0
  49. package/dist/skills/lernapps-exercise-patterns/references/mathematics.md +19 -0
  50. package/dist/skills/lernapps-exercise-patterns/references/page-structures.md +8 -0
  51. package/dist/skills/lernapps-exercise-patterns/references/physics.md +18 -0
  52. package/dist/skills/lernapps-exercise-patterns/references/success.md +28 -0
  53. package/dist/skills/lernapps-explainer/SKILL.md +33 -0
  54. package/dist/skills/lernapps-explainer/references/blocks.md +83 -0
  55. package/dist/skills/lernapps-explainer/references/components.md +66 -0
  56. package/dist/skills/lernapps-explainer/references/exercises.md +115 -0
  57. package/dist/skills/lernapps-explainer/references/rules.md +285 -0
  58. package/dist/skills/lernapps-explainer/references/runtime.md +79 -0
  59. package/dist/skills/lernapps-explainer/references/structure.md +24 -0
  60. package/dist/skills/lernapps-explainer-design/SKILL.md +57 -0
  61. package/dist/skills/lernapps-explainer-design/references/rules.md +75 -0
  62. package/dist/skills/lernapps-explainer-self-assessment/SKILL.md +93 -0
  63. package/dist/skills/lernapps-github/SKILL.md +102 -0
  64. package/dist/skills/lernapps-interactive/SKILL.md +141 -0
  65. package/dist/skills/lernapps-interactive/references/frame.md +30 -0
  66. package/dist/skills/lernapps-interactive-design/SKILL.md +58 -0
  67. package/dist/skills/lernapps-listing/SKILL.md +44 -0
  68. package/dist/skills/lernapps-listing/references/keeping-updated.md +33 -0
  69. package/dist/skills/lernapps-quiz/SKILL.md +100 -0
  70. package/dist/skills/lernapps-quiz-design/SKILL.md +48 -0
  71. package/dist/status-CXoQBgfU.mjs +76 -0
  72. package/dist/storage.mjs +113 -0
  73. package/generator/app/.agents/skills/app-content/SKILL.md +63 -0
  74. package/generator/app/.github/ISSUE_TEMPLATE/inhaltsfehler.yml +25 -0
  75. package/generator/app/.github/workflows/pages.yml +61 -0
  76. package/generator/app/LICENSE +21 -0
  77. package/generator/app/renovate.json +4 -0
  78. package/generator/architecture.ts +212 -0
  79. package/generator/create.ts +462 -0
  80. package/generator/init.ts +186 -0
  81. package/generator/update.ts +429 -0
  82. package/guidance/AGENTS.md +26 -0
  83. package/guidance/increment-template.md +194 -0
  84. package/guidance/plan-front-matter.v1.schema.json +36 -0
  85. package/guidance/plan-template.md +233 -0
  86. package/guidance/subagent-brief.md +25 -0
  87. package/guidance/workflow-rules.md +109 -0
  88. package/package.json +133 -4
  89. package/review/verdict.v1.schema.json +134 -0
  90. package/skills/archetypes/lernapps-explainer/SKILL.md +33 -0
  91. package/skills/archetypes/lernapps-explainer/references/blocks.md +83 -0
  92. package/skills/archetypes/lernapps-explainer/references/components.md +66 -0
  93. package/skills/archetypes/lernapps-explainer/references/exercises.md +115 -0
  94. package/skills/archetypes/lernapps-explainer/references/rules.md +285 -0
  95. package/skills/archetypes/lernapps-explainer/references/runtime.md +79 -0
  96. package/skills/archetypes/lernapps-explainer/references/structure.md +24 -0
  97. package/skills/archetypes/lernapps-explainer-design/SKILL.md +57 -0
  98. package/skills/archetypes/lernapps-explainer-design/references/rules.md +75 -0
  99. package/skills/archetypes/lernapps-explainer-self-assessment/SKILL.md +93 -0
  100. package/skills/archetypes/lernapps-interactive/SKILL.md +141 -0
  101. package/skills/archetypes/lernapps-interactive/references/frame.md +30 -0
  102. package/skills/archetypes/lernapps-interactive-design/SKILL.md +58 -0
  103. package/skills/archetypes/lernapps-quiz/SKILL.md +100 -0
  104. package/skills/archetypes/lernapps-quiz-design/SKILL.md +48 -0
  105. package/skills/content/lernapps-content-questions/SKILL.md +133 -0
  106. package/skills/content/lernapps-content-questions/references/question-types.md +69 -0
  107. package/skills/content/lernapps-content-research/SKILL.md +50 -0
  108. package/skills/content/lernapps-content-research/references/sources.md +16 -0
  109. package/skills/content/lernapps-exercise-patterns/SKILL.md +74 -0
  110. package/skills/content/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  111. package/skills/content/lernapps-exercise-patterns/references/chemistry.md +16 -0
  112. package/skills/content/lernapps-exercise-patterns/references/computer-science.md +13 -0
  113. package/skills/content/lernapps-exercise-patterns/references/figures.md +10 -0
  114. package/skills/content/lernapps-exercise-patterns/references/history.md +13 -0
  115. package/skills/content/lernapps-exercise-patterns/references/mathematics.md +19 -0
  116. package/skills/content/lernapps-exercise-patterns/references/page-structures.md +8 -0
  117. package/skills/content/lernapps-exercise-patterns/references/physics.md +18 -0
  118. package/skills/content/lernapps-exercise-patterns/references/success.md +28 -0
  119. package/skills/process/lernapps-app/SKILL.md +49 -0
  120. package/skills/process/lernapps-commit/SKILL.md +39 -0
  121. package/skills/process/lernapps-content-growth/SKILL.md +33 -0
  122. package/skills/process/lernapps-github/SKILL.md +102 -0
  123. package/skills/process/lernapps-listing/SKILL.md +44 -0
  124. package/skills/process/lernapps-listing/references/keeping-updated.md +33 -0
  125. package/skills/tooling/lernapps-cli/SKILL.md +156 -0
  126. package/skills/tooling/lernapps-cli/references/platform-rules.md +258 -0
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: lernapps-interactive
3
+ description: Use in Code of a lernapps.net interactive app whenever you write or change its core, inputs, user interface, data, playthroughs, frame or arc42 architecture, or a build, playthrough or architecture check fails. What you write, the core's contract, the playthrough format, the frame and full-screen play, the architecture, and the technical rules.
4
+ license: MIT
5
+ ---
6
+
7
+ # Interactive app
8
+
9
+ - Runtime: `@lernapps/app-templates` (`runtime/interactive/`); leave it untouched.
10
+ - `create` writes a small example app: replace it with the planned parts.
11
+
12
+ ## What you write
13
+
14
+ - `src/app.yaml` (schema `interactive.v1.schema.json`): what it does, how to play, competencies, languages, routes,
15
+ optional background sections. Rendered as the static start page and the app page `app/`.
16
+ - Routes: `app/#<id>`; a seed: `app/?seed=<n>#<route>`, else random.
17
+ - `src/core/`, `src/ui/` (root component), `src/data/`, `src/messages/`, `src/playthroughs/`, `src/main.ts`
18
+ (`startInteractive(core, App)`), and the app's part of `docs/arc42/`.
19
+
20
+ ## Read when
21
+
22
+ - [references/frame.md](references/frame.md): before you build a control in the heading line, a wider frame,
23
+ full-screen play, keys or focus.
24
+
25
+ ## Gotchas
26
+
27
+ - The generated `src/core/index.ts`, `src/ui/App.vue` and playthroughs follow the contract below: read them before you
28
+ replace them. The types are exported by `@lernapps/app-templates/interactive`.
29
+ - Test a timer by ticks in a playthrough; never wait real time.
30
+ - The arc42 hook fails on new code without a block: `git add` the new files and describe them. Never take back
31
+ architecture to get past the hook.
32
+ - A check names an `interactive-*` rule: read its section under "Rules" below before you fix.
33
+
34
+ ## Core, components, data, playthroughs
35
+
36
+ ### Core
37
+
38
+ - `src/core/index.ts`: pure TypeScript, no DOM; the state is plain JSON.
39
+ - Exports `start(seed, route)`, `step(state, input)`, and `tick(state, dt)` if it moves on its own.
40
+ - The runtime owns state and clock and calls `tick(state, 20)` every 20 ms.
41
+ - Randomness only from the seed; never `Math.random` or the clock.
42
+
43
+ ### Inputs
44
+
45
+ - `{ kind: "key", key }` (`KeyboardEvent.key`) or `{ kind: "action", name, value? }` (pointer, touch).
46
+ - The runtime turns keydown into key inputs; the root component emits `input` (an action or a key).
47
+ - Unknown kinds and ignored keys: return the same state object (Tab keeps moving the focus).
48
+
49
+ ### Components
50
+
51
+ - `src/ui/`: show the `state` prop; turn actions into inputs.
52
+ - Vue and TypeScript. The component rules apply to them and their imports: `vue-component-no-network`,
53
+ `vue-component-no-html-injection`, `vue-component-imports`, `vue-component-browser-globals`.
54
+ - Learner texts from `src/messages/<language>.json` through `translator` (`@lernapps/tooling/i18n`), never strings
55
+ in code (`learner-text-german`).
56
+ - Announce changes with `announce` (`@lernapps/tooling/a11y`); reduced motion with `prefersReducedMotion`.
57
+
58
+ ### Data
59
+
60
+ - `src/data/`, own format, imported by the core.
61
+
62
+ ### Playthroughs
63
+
64
+ - `src/playthroughs/<name>.yaml`: `seed`, `route`, `steps`.
65
+ - A step: `keys` (short form) or `inputs`, then `ticks` (20 ms each), at least one of them; it expects a part of the
66
+ state, an announcement, or both. No time passes except the named ticks.
67
+ - The build plays each twice against the core and fails on differing plays or a wrong state. The end-to-end test
68
+ plays the same in the browser, desktop and 360 px.
69
+ - Expect only what the steps decide.
70
+
71
+ ### Storage
72
+
73
+ - `createStorage` (`storage-through-wrapper`, skill `lernapps-cli`).
74
+
75
+ ## Architecture (arc42)
76
+
77
+ - `docs/arc42/`, arc42 DSL (`@doctc/arc42`), English, minimal.
78
+ - `create` copies the generic part and the interactive extension; `update` replaces them.
79
+ - Write only between `<!-- app: begin … -->` and `<!-- app: end … -->`; nothing outside.
80
+ - Chapter 5: each part of core, UI, data as a level-3 heading in section `core`, `ui` or `data`, with `parent`,
81
+ `path` and a diagram of the block and its parts. Each new leaf block on a deployment node in chapter 7.
82
+ - Concepts, decisions (canvas or DOM), declared accessibility with reasons: in the sections at the chapter ends.
83
+ - 1–2 sentences per block or decision: responsibility, reason; nothing the code says.
84
+ - Update with every change, same commit as the code.
85
+ - Pre-commit `arc42 diff --staged` fails on: block changed without prose (or the reverse); new `src/` code no block
86
+ claims and not in `.arc42ignore`. It reads staged files: `git add` new files.
87
+ - Review hint (code under an interface's path changed): warning; read and update if needed.
88
+ - Accept a finding with `ARC42_CONSISTENT` only for a shown consistency finding judged intended, with a note in the
89
+ plan. Never preset it (e.g. `$(git rev-parse HEAD)`): a bypass like `--no-verify`.
90
+ - Unclaimed new code is never accepted: give it a block, or list config in `.arc42ignore`.
91
+ - `lernapps check` runs `arc42 validate --strict` on the working tree: any error, warning or hint fails.
92
+ - Your work; no creator checkpoint.
93
+
94
+ ## Rules
95
+
96
+ ### `interactive-app-valid`: The description and the playthroughs validate
97
+
98
+ ```rule
99
+ id: interactive-app-valid
100
+ scope: archetype:interactive
101
+ severity: error
102
+ ```
103
+
104
+ - `src/app.yaml` and every playthrough valid against their schemas; German first, every language complete.
105
+ - Unique ids; at least one playthrough; each step expects a state or an announcement; playthrough routes exist.
106
+ - Build names each problem with file and line.
107
+
108
+ ### `interactive-core-contract`: The core keeps its contract
109
+
110
+ ```rule
111
+ id: interactive-core-contract
112
+ scope: archetype:interactive
113
+ severity: error
114
+ ```
115
+
116
+ - `src/core/index.ts` exports `start(seed, route)`, `step(state, input)`; `tick(state, dt)` as a function if it
117
+ moves on its own.
118
+ - Every route starts; nothing throws; same seed, route, inputs, ticks → same states.
119
+
120
+ ### `interactive-playthroughs-pass`: Every playthrough plays as written
121
+
122
+ ```rule
123
+ id: interactive-playthroughs-pass
124
+ scope: archetype:interactive
125
+ severity: error
126
+ ```
127
+
128
+ - After each step the state has the expected fields; the browser shows the expected announcement.
129
+ - Failure → fix core or playthrough, whichever is wrong; never delete a playthrough.
130
+
131
+ ### `interactive-architecture-current`: The architecture is valid and current
132
+
133
+ ```rule
134
+ id: interactive-architecture-current
135
+ scope: archetype:interactive
136
+ severity: error
137
+ ```
138
+
139
+ - `docs/arc42/`: generic part and extension as `create`/`update` wrote them, unchanged outside the app sections.
140
+ - App part describes the code: every part of `src/` has its block, every block its code.
141
+ - `arc42 validate --strict` and `arc42 diff --staged` pass; the review checks it says what the code does.
@@ -0,0 +1,30 @@
1
+ # Frame and full-screen game
2
+
3
+ ## Frame
4
+
5
+ - App page: header (language switch only; none with one language), `<main>` (heading line: the title as h1 and a
6
+ slot beside it; `<noscript>` note, route links, `.interactive-app` mount), footer (imprint, privacy). At most
7
+ `--page-max-width` wide, 44rem by default.
8
+ - A control in the heading line: `startInteractive(core, App, { title: Controls })`. The runtime mounts it into the
9
+ slot, with the root component's props (`state`, `lang`) and `input` event. Never hide or rebuild the h1. Without
10
+ `title` the slot stays hidden.
11
+ - A wider frame: `--page-max-width` (e.g. `60rem`) in the app's own `:root` rule; it widens header, page and
12
+ footer. Never override the runtime's selectors.
13
+ - Start page: own static page, no script; the app page never changes it.
14
+
15
+ ## Full-screen while playing
16
+
17
+ - Own overlay only: root element class from state (e.g. `state.phase === "playing"`), `position: fixed; inset: 0`,
18
+ page background. Leave runtime markup and CSS.
19
+ - Way out: visible button ("Pause"); Escape ends the overlay as a core input. Time limit or other loss → entry
20
+ `limits`.
21
+ - Browser full screen (`element.requestFullscreen()`): optional, only after a click, via template ref; overlay works
22
+ without it. Browser globals only in `onMounted` (`vue-component-browser-globals`).
23
+
24
+ ## Keys and focus
25
+
26
+ - Runtime gives keys to the core only when focus is not on a link, button, form field.
27
+ - Play area focusable (`tabindex="0"`, `aria-label`); focus it via template ref (`area.value?.focus()`) when play
28
+ starts. Focus visible.
29
+ - Space and arrows: runtime prevents default only for state-changing keys. Let the core take them while playing, or
30
+ `@keydown.space.prevent` (and arrows) on the play area.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: lernapps-interactive-design
3
+ description: Use in Explore right after choosing the `interactive` archetype - how the content of a lernapps.net interactive app maps onto core, user interface, data and playthroughs, which the plan then applies.
4
+ license: MIT
5
+ ---
6
+
7
+ # Designing an interactive app
8
+
9
+ ## What an interactive app is
10
+
11
+ - The learner's doing is the content: play, train, work in one app page. A static start page without script says
12
+ what it is.
13
+ - The code is yours. The runtime renders the frame, owns state and clock, and feeds inputs to your core.
14
+ - Write in "Content method" one line per part below; the architecture in Code follows it.
15
+
16
+ ## Can and cannot
17
+
18
+ - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/interactive/README.md>.
19
+ Read it before this skill's mapping, if you have not yet.
20
+
21
+ ## Parts
22
+
23
+ 1. **Core:** pure TypeScript, no DOM; the state is plain JSON. It starts from a seed and a route, takes inputs,
24
+ and moves on with ticks if time matters. Randomness only from the seed: same seed, route and inputs → same
25
+ states.
26
+ 2. **User interface:** Vue components show the state and turn actions into inputs. They keep no game state of
27
+ their own. Render as DOM, SVG or canvas.
28
+ 3. **Data:** the content (levels, tasks, texts) as data files the core imports. A new level is a data change.
29
+ 4. **Playthroughs:** one per behaviour to keep, timing included: seed, route, inputs, ticks, the state expected. They
30
+ are the proof that the core works; the build plays each twice, the browser once.
31
+ 5. **Routes:** one per mode or level the entry may link to (`app/#<id>`).
32
+
33
+ ## Decide
34
+
35
+ - Inputs: which keys, which buttons or touch actions. Every action works by keyboard.
36
+ - Timing: time limits and moving parts are ticks of the core, never the clock.
37
+ - Storage: small (at most 100 kB), the learning state only; no settings dialog.
38
+ - Libraries: bundled from `dependencies`, open licence; never a CDN.
39
+ - Accessibility: WCAG 2.1 AA and 360 px are the default. A deviation the idea needs (a time limit) goes into the
40
+ entry's `limits`, in German.
41
+ - Look and feel: as the creator chose in Explore.
42
+ - Languages: German; each declared language complete; learner texts in message files, never in code.
43
+
44
+ ## Gotchas
45
+
46
+ - "Low stimulation" means no overload, not no fun: a game may look like a game (bold colours, a real board). No
47
+ flashing; calm motion, less with reduced motion; sound off by default. The start page stays calm.
48
+ - A timer is a tick of the core with a playthrough that tests the end of time, not `setTimeout` in a component.
49
+
50
+ ## `start-page-explains`: The start page explains the app
51
+
52
+ ```rule
53
+ id: start-page-explains
54
+ scope: archetype:interactive
55
+ severity: hint
56
+ ```
57
+
58
+ - The static start page says what learners train, for whom, and how to begin.
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: lernapps-quiz
3
+ description: Use in Code of a lernapps.net quiz whenever you write or change the question bank src/quiz.json, add a language, or a build or runtime test of the quiz fails. What you write, how the runtime shows and tests the bank, languages, and the quiz's technical rules. The question types and how to write good questions are in lernapps-content-questions.
4
+ license: MIT
5
+ ---
6
+
7
+ # Quiz
8
+
9
+ - You write `src/quiz.json` and, for the content of its questions, the image files in `src/images/`. Engine, question
10
+ types, feedback, scoring, order, accessibility and the no-JS page come from the runtime `@lernapps/app-templates`.
11
+ - Schema: `node_modules/@lernapps/app-templates/runtime/quiz/quiz.v1.schema.json`.
12
+ - `create` writes the example bank "Naturwunder der Welt": replace it with the planned questions.
13
+ - The fields of each question type and how to write good questions: skill `lernapps-content-questions`.
14
+
15
+ ## Gotchas
16
+
17
+ - The build validates the bank; the runtime's tests then answer every question in the browser. A runtime test that
18
+ fails while the bank validates is a template bug (skill `lernapps-cli`).
19
+
20
+ ## Runtime
21
+
22
+ ### Build and page
23
+
24
+ - Build reads, validates, renders every question into `index.html`, with the content it shows (`material`), and
25
+ carries the images of `src/images/` to `images/`.
26
+ - No JS: a worksheet; all questions, then solutions with background and links.
27
+ - JS: one question at a time, right or wrong shown; then each option's `info` (right ones and the choice marked),
28
+ the explanation, the links. Score and solutions at the end.
29
+ - Order shuffled by `?seed=42` (same link, same order). Deep link to a question: `#frage-<id>`.
30
+
31
+ ### Storage
32
+
33
+ - Stores nothing, unless `"rememberLastResult": true`: then the last score stays on the device.
34
+
35
+ ### Tests
36
+
37
+ - From the runtime (`e2e/quiz.e2e.ts`), run by `lernapps check`. Per question: deep link, a right and a wrong answer,
38
+ every `info`, explanation and links shown. Also full score and the no-JS page.
39
+ - Each further language: its no-JS page (questions, solutions, switch) and one answered question in that language.
40
+ - New runtime features or fixes: `lernapps update` (skill `lernapps-cli`).
41
+
42
+ ### A runtime test fails
43
+
44
+ - Bank validates (build passes) but a runtime test fails = template bug: act as skill `lernapps-cli` says.
45
+ - Never change the runtime in `node_modules` (`quiz-only-data`). Go on with the questions.
46
+ - A question shows an image or a table with `material`: skill `lernapps-content-questions`, its reference question-types.
47
+
48
+ ### Languages
49
+
50
+ - German; more with `"languages": ["de", "en"]`, German first (runtime texts: de, en).
51
+ - Then every learner text is a map with each language: title, intro, source titles; per question text, options,
52
+ `info`, items, pairs, unit, explanation, link titles.
53
+ - Without `languages`: German strings.
54
+ - Link `url`: one address, or a map per language (own Wikipedia).
55
+ - Build errors, one line each, e.g.
56
+ `questions[1].explanation (en) (question "totes-meer"): the translation is missing; write the text as a map: { de: …, en: … }`;
57
+ undeclared language: `… is not a language of the app; declare it in languages in src/quiz.json, or remove it`;
58
+ `languages[0]: German comes first`.
59
+ - Pages: German `index.html`, others `<language>/index.html`, with `lang`, `hreflang`, a no-JS language switch.
60
+
61
+ ```json
62
+ {
63
+ "id": "totes-meer",
64
+ "type": "true-false",
65
+ "text": { "de": "Im Toten Meer kann man nicht untergehen.", "en": "You cannot sink in the Dead Sea." },
66
+ "answer": true,
67
+ "explanation": {
68
+ "de": "Das Wasser ist so salzig, dass ein Mensch an der Oberfläche treibt.",
69
+ "en": "The water is so salty that a person floats on the surface."
70
+ },
71
+ "links": [
72
+ { "title": { "de": "Totes Meer (Wikipedia)", "en": "Dead Sea (Wikipedia)" }, "url": "https://de.wikipedia.org/wiki/Totes_Meer" }
73
+ ]
74
+ }
75
+ ```
76
+
77
+ ## Rules
78
+
79
+ ### `quiz-only-data`: Write only the question bank and its images
80
+
81
+ ```rule
82
+ id: quiz-only-data
83
+ scope: archetype:quiz
84
+ severity: error
85
+ ```
86
+
87
+ - Change only `src/quiz.json` and add image files to `src/images/`. `index.html`, `src/main.ts`, `e2e/quiz.e2e.ts`,
88
+ config as generated (`keep-the-preset`).
89
+ - Bank cannot say it → "Where I had to guess", never code around the runtime.
90
+
91
+ ### `quiz-stable-ids`: Keep the ids
92
+
93
+ ```rule
94
+ id: quiz-stable-ids
95
+ scope: archetype:quiz
96
+ severity: warning
97
+ ```
98
+
99
+ - Short, telling `id` ("grand-canyon"); keep it when the text changes (shared links `#frage-<id>`).
100
+ - New question, new id; never reuse a removed one.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: lernapps-quiz-design
3
+ description: Use in Explore right after choosing the `quiz` archetype - how the content of a lernapps.net quiz maps onto rounds, question types and patterns, which the plan then applies.
4
+ license: MIT
5
+ ---
6
+
7
+ # Designing a quiz
8
+
9
+ ## What a quiz is
10
+
11
+ - One page of questions with options and feedback. The runtime shows one question at a time, then each option's
12
+ background, the explanation and links; the score at the end. Without JavaScript: a worksheet with solutions.
13
+ - You will write the question bank `src/quiz.json` and, for what a question shows, image files in `src/images/`;
14
+ no code (`quiz-only-data`).
15
+
16
+ ## Can and cannot
17
+
18
+ - The README of the template says it: <https://raw.githubusercontent.com/lernapps/app-templates/main/quiz/README.md>.
19
+ Read it before this skill's mapping, if you have not yet.
20
+
21
+ ## Map the content
22
+
23
+ - A chapter → a round: the questions of one chapter, next to each other in the bank.
24
+ - A competency → one or more questions.
25
+ - The bank is the shared material: each fact in one question.
26
+ - A pattern → one question type with a fixed form of text, options and background, varied over a round's facts.
27
+ - Not expressible as a question → no code: note it under "Where I had to guess"; an issue at
28
+ <https://github.com/lernapps/app-templates/issues> if other quizzes need it.
29
+
30
+ ## Question types
31
+
32
+ | `type` | The learner |
33
+ |---|---|
34
+ | `single-choice` | chooses one option |
35
+ | `multiple-choice` | chooses every correct option |
36
+ | `true-false` | judges a statement |
37
+ | `number` | types a number, within a tolerance |
38
+ | `ordering` | puts items in their fixed order |
39
+ | `matching` | matches left to right |
40
+
41
+ - Which pattern fits which competency: skill `lernapps-exercise-patterns`.
42
+
43
+ ## Decide
44
+
45
+ - Languages: German; English as a second language is supported. Each declared language complete.
46
+ - Keep the last score on the device (`rememberLastResult`) or nothing. Keeping it → the entry says
47
+ `fitness.storage: device`.
48
+ - Order: shuffled per seed; a link with `?seed=42` gives every learner the same order.
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: lernapps-content-questions
3
+ description: Use in Code whenever you write or review questions with options and feedback for a lernapps.net app - the question bank of a quiz, or the quiz-type exercises of an explainer. The fields of the six question types, and how to write one clear question, options a learner could believe, feedback that explains, further reading, numbers with unit and rounding, and how to check every fact.
4
+ license: MIT
5
+ ---
6
+
7
+ # Writing questions
8
+
9
+ - Read [references/question-types.md](references/question-types.md) before you write the first question of a type:
10
+ the fields of each type, the same in a quiz and in an explainer.
11
+ - Write all questions of a round, then check every fact against its linked page, then commit.
12
+
13
+ ## Gotchas
14
+
15
+ - Read every page you link before you commit: the meant article (no "Begriffsklärung"), saying what question and
16
+ options say.
17
+ - Never guess an address. Never fill a fact from memory.
18
+ - Link resolution is the check's job: no scraper, script or API loop over the links.
19
+
20
+ ## `quiz-bank-valid`: The question bank validates
21
+
22
+ ```rule
23
+ id: quiz-bank-valid
24
+ scope: [archetype:quiz, archetype:explainer]
25
+ severity: error
26
+ ```
27
+
28
+ - Valid against the schema. Build also checks: exactly one correct in single choice, at least one in multiple
29
+ choice; unique ids and options.
30
+ - Broken bank: one line per problem (position, id); fix in `src/quiz.json`. Explainer exercise: named by file and
31
+ block path.
32
+
33
+
34
+ ## `quiz-clear-question`: One clear question at a time
35
+
36
+ ```rule
37
+ id: quiz-clear-question
38
+ scope: [archetype:quiz, archetype:explainer]
39
+ severity: warning
40
+ ```
41
+
42
+ - One thing per question, answerable before reading the options.
43
+ - Positive; avoid "nicht", never two negations. No trick questions.
44
+ - Plain, short sentences in every language (`learner-text-german`).
45
+
46
+ ## `quiz-plausible-options`: Options a learner could believe
47
+
48
+ ```rule
49
+ id: quiz-plausible-options
50
+ scope: [archetype:quiz, archetype:explainer]
51
+ severity: warning
52
+ ```
53
+
54
+ - Wrong options are real things of the same kind (a river for a river), with true background.
55
+ - Options alike in length and form. No "Alle genannten", "Keine davon" or jokes. Three or four options.
56
+
57
+ ## `quiz-feedback-explains`: Background and explanation say why
58
+
59
+ ```rule
60
+ id: quiz-feedback-explains
61
+ scope: [archetype:quiz, archetype:explainer]
62
+ severity: hint
63
+ ```
64
+
65
+ - Every option has an `info` of 1–3 sentences about the option, true either way ("Der Nil fließt durch mehrere
66
+ Länder Afrikas und mündet in Ägypten ins Mittelmeer."). A wrong option's `info` also says why it does not fit.
67
+ - `explanation`: 1–3 sentences why the answer is right; for true-false, number, ordering and matching also the
68
+ background.
69
+ - `number`: typical wrong numbers as `mistakes` (`answer`, `message`). Any question: an optional `hint`, not the
70
+ answer.
71
+ - A wrong answer's `message` (and an exercise component's `reason`) says what does not fit and where to look, never
72
+ the solution itself: the solution comes after the answer, with "Lösung" or the tutor.
73
+
74
+ ## `quiz-further-reading`: Every question links to further reading
75
+
76
+ ```rule
77
+ id: quiz-further-reading
78
+ scope: archetype:quiz
79
+ severity: warning
80
+ ```
81
+
82
+ - At least one link per question, best the German Wikipedia (`https://de.wikipedia.org/wiki/...`).
83
+ - `title` names the page ("Uluru (Wikipedia)").
84
+ - HTTP 429 → tell the creator which; mark the facts "not checked" in the plan; go on.
85
+
86
+ ## `quiz-own-words`: Write in your own words
87
+
88
+ ```rule
89
+ id: quiz-own-words
90
+ scope: archetype:quiz
91
+ severity: warning
92
+ ```
93
+
94
+ - Take facts, never sentences: Wikipedia is CC BY-SA (copying needs attribution and relicenses).
95
+ - `info` and `explanation`: new, shorter, plainer, for the app's school year. Sources in `sources`
96
+ (`third-party-licence`).
97
+
98
+ ## `quiz-number-precision`: Numbers with unit and rounding
99
+
100
+ ```rule
101
+ id: quiz-number-precision
102
+ scope: [archetype:quiz, archetype:explainer]
103
+ severity: warning
104
+ ```
105
+
106
+ - The text says how exact the answer must be ("Bis zu 100 m daneben zählt noch als richtig"); `tolerance` matches
107
+ it.
108
+ - The unit goes into `unit`, not into the answer.
109
+ - Sources differ → the tolerance covers them.
110
+
111
+ ## `quiz-fitting-type`: The type that fits the question
112
+
113
+ ```rule
114
+ id: quiz-fitting-type
115
+ scope: [archetype:quiz, archetype:explainer]
116
+ severity: hint
117
+ ```
118
+
119
+ - One fact among things of a kind: `single-choice`; several facts: `multiple-choice`; estimate a size: `number`;
120
+ compare sizes or dates: `ordering`; connect: `matching`; judge a statement: `true-false`.
121
+ - Mix the types. The type must accept every answer the text allows (`ordering` only for a fixed order).
122
+
123
+ ## `quiz-answers-checked`: Check every fact
124
+
125
+ ```rule
126
+ id: quiz-answers-checked
127
+ scope: archetype:quiz
128
+ severity: hint
129
+ ```
130
+
131
+ - Check every marked option, number and `info` against the linked article before you commit.
132
+ - A source does not open → say so in the plan, mark it "not checked"; never fill it from memory.
133
+ - Learners report errors through `.github/ISSUE_TEMPLATE/inhaltsfehler.yml`.
@@ -0,0 +1,69 @@
1
+ # Question types
2
+
3
+ | `type` | You write |
4
+ |---|---|
5
+ | `single-choice` | `options`: exactly one `"correct": true`; `info` each, `link` where useful |
6
+ | `multiple-choice` | `options`: at least one correct; `info` each, `link` where useful |
7
+ | `true-false` | `answer` (true or false) |
8
+ | `number` | `answer`, `tolerance` (0 = exact), `unit` if any; the learner may type a comma or a point |
9
+ | `ordering` | `items` in the right order; the page mixes them |
10
+ | `matching` | `pairs` as they belong; 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
+
12
+ - Every question: `id`, `text`, `explanation`, at least one link in `links`. Optional quiz `sources`.
13
+ - Types without options carry their background in `explanation`.
14
+ - Optional `material`: what the question shows between its text and its answers, a list of blocks: `text` (restricted
15
+ Markdown), `formula`, `figure`, `labelled-figure`, `table`, `quote`, `code`. A `figure` is `image: images/<name>.svg`
16
+ (or `.png`, `.jpg`, `.webp`; the file is in `src/images/`) or drawn from numbers (`draw`), with `alt` (what it
17
+ shows), `caption` (what to look at) and, for an image, `source` and `licence` (`third-party-licence`). Use it where
18
+ the question needs the content (what does the image show, what does the table say); not as decoration. The build
19
+ fails for a missing file, a text missing in a language, raw HTML or a link to a page of the app.
20
+ - Optional `examples: { accepted, rejected }`: options and items by index from 0 or German text; numbers as number or
21
+ as typed (`"12,5"`; point = decimal mark: `8900`, never `8.900`). Build checks them; learners never see them.
22
+ Mistakes and wrong options' `info` already count as rejected.
23
+
24
+ ```json
25
+ {
26
+ "id": "ring",
27
+ "type": "single-choice",
28
+ "text": "Welche Form zeigt das Bild?",
29
+ "material": [
30
+ {
31
+ "type": "figure",
32
+ "image": "images/kreis.svg",
33
+ "alt": "Ein blauer Kreis mit einem weißen Kreis in der Mitte",
34
+ "caption": "Zwei Kreise mit demselben Mittelpunkt.",
35
+ "source": "eigene Zeichnung",
36
+ "licence": "CC0-1.0"
37
+ }
38
+ ],
39
+ "options": [
40
+ { "text": "Ein Ring", "correct": true, "info": "Ein Ring liegt zwischen zwei Kreisen mit demselben Mittelpunkt." },
41
+ { "text": "Eine Ellipse", "correct": false, "info": "Eine Ellipse hat zwei Brennpunkte." }
42
+ ],
43
+ "explanation": "Die weiße Fläche in der Mitte macht aus der Kreisscheibe einen Ring.",
44
+ "links": [{ "title": "Kreisring (Wikipedia)", "url": "https://de.wikipedia.org/wiki/Kreisring" }]
45
+ }
46
+ ```
47
+
48
+ ```json
49
+ {
50
+ "id": "grand-canyon",
51
+ "type": "single-choice",
52
+ "text": "Welcher Fluss hat den Grand Canyon in den USA geformt?",
53
+ "options": [
54
+ {
55
+ "text": "Colorado",
56
+ "correct": true,
57
+ "info": "Der Colorado ist der größte Fluss im Südwesten Nordamerikas. Er ist gut 2300 km lang.",
58
+ "link": { "title": "Colorado River (Wikipedia)", "url": "https://de.wikipedia.org/wiki/Colorado_River" }
59
+ },
60
+ {
61
+ "text": "Nil",
62
+ "correct": false,
63
+ "info": "Der Nil fließt durch mehrere Länder Afrikas und mündet in Ägypten ins Mittelmeer. Mit rund 6650 km gilt er als längster Fluss der Erde."
64
+ }
65
+ ],
66
+ "explanation": "Der Grand Canyon ist eine steile Schlucht in Arizona, etwa 450 km lang. Der Colorado hat sie über Millionen von Jahren in das Gestein gegraben.",
67
+ "links": [{ "title": "Grand Canyon (Wikipedia)", "url": "https://de.wikipedia.org/wiki/Grand_Canyon" }]
68
+ }
69
+ ```
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: lernapps-content-research
3
+ description: Use in Explore whenever you need to know what a lernapps.net app teaches - school year, Lehrplan, competencies, sources - even if the creator only names a topic; in the first version and in each increment that adds a chapter. How to use the Lehrplan as orientation, write competencies as "Ich kann …", verify sources by opening them, and keep the creator's material private. For every archetype.
4
+ license: MIT
5
+ ---
6
+
7
+ # Content research
8
+
9
+ - A filled-in content guide `.agents/skills/app-content/SKILL.md` comes first: its decisions stand; research only
10
+ the gaps.
11
+ - Content comes from the curriculum, the creator and sources you opened, never from memory.
12
+ - The questions to the creator are the plan's interview. Read every file the creator gives you.
13
+
14
+ ## 1. Lehrplan
15
+
16
+ - Orientation for grade and order, not a condition. None found → say so once; go on.
17
+ - Only the Land's official document (Kerncurriculum, Lehrplan, Bildungsplan, Rahmenlehrplan) from the ministry or
18
+ state institute. No publisher, schoolbook or portal. No Land known → KMK-Bildungsstandards.
19
+ - Download and read it yourself.
20
+ - Cite it under "Notes": title, issuer, year, address; page and unit (Inhaltsfeld, Lernbereich, Kompetenz).
21
+ - The creator's material differs → follow the material; say so in one sentence.
22
+
23
+ ## 2. Competencies
24
+
25
+ - One per line: "Ich kann …" with one observable verb (berechnen, zuordnen, erklären, unterscheiden, ablesen,
26
+ zeichnen). Never "verstehen" or "kennen".
27
+ - Yes: "Ich kann die Stromstärke in einem Reihenstromkreis berechnen."
28
+ - No: "Ich verstehe den elektrischen Strom."
29
+ - Group them into chapters, in the order of the Lehrplan or the material. Many chapters are still one app.
30
+ - Write them under "Notes". Show them at the checkpoint "research".
31
+
32
+ ## 3. Second sources
33
+
34
+ - Per competency one article or video (serlo.org, a channel the creator trusts, Wikipedia).
35
+ - Read [references/sources.md](references/sources.md) before you choose, cite or rely on a source.
36
+
37
+ ## 4. The creator's material and privacy
38
+
39
+ - The creator's material stays local: never commit or quote it. Only the competencies derived from it go into the
40
+ repo.
41
+ - No learner's name, class, school, grades, picture, or one learner's goal such as a test date
42
+ (`no-learner-data-in-texts`). School year, school type and Lehrplan may stay.
43
+
44
+ ## Gotchas
45
+
46
+ - Read the primary source before you write a fact. A secondary text that seems to fit is no proof.
47
+ - Several sources disagree → report the disagreement to the creator. Never bend a fact to fit the plan.
48
+ - Never guess a Lehrplan unit, a wording or an id (video, article, unit number): look it up or leave it out, and
49
+ mark it unchecked.
50
+ - HTTP 429 or a site down → tell the creator which; mark it "not checked"; go on. No scraper, no loop.
@@ -0,0 +1,16 @@
1
+ # Verifying a second source
2
+
3
+ ## Check by opening
4
+
5
+ 1. It loads: no error, no empty page, no redirect to a start or search page.
6
+ 2. It is the article or video itself: no search result, category, list or disambiguation.
7
+ 3. It covers exactly this competency: resistance for "Ich kann den Widerstand berechnen", not electricity in
8
+ general.
9
+
10
+ ## Rules
11
+
12
+ - No weak matches. Nothing fits → leave it out and say so under "Notes".
13
+ - Video: check channel and title through the platform's metadata (YouTube: oEmbed), never through a search result.
14
+ - A video loads only after a click (`no-request-before-click`).
15
+ - Note per source: address, exact title, "verified".
16
+ - Take facts, never sentences. Name source and licence of what you take (`third-party-licence`).