@lernapps/app-templates 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 (232) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +195 -2
  3. package/dist/appname-Bh23cUuz.mjs +12 -0
  4. package/dist/assessment-Dy359O1O.mjs +1696 -0
  5. package/dist/block-BK_ohsH1.mjs +82 -0
  6. package/dist/blocks-CxtCPAa5.mjs +149 -0
  7. package/dist/blocks.mjs +4 -0
  8. package/dist/check-CteIFN96.mjs +254 -0
  9. package/dist/content-DO6oEJxj.mjs +140 -0
  10. package/dist/contract-PONpxJtd.mjs +52 -0
  11. package/dist/e2e-CU0n_unV.mjs +89 -0
  12. package/dist/engine-CArxqizW.mjs +136 -0
  13. package/dist/explainer-e2e.mjs +1311 -0
  14. package/dist/explainer-islands.mjs +197 -0
  15. package/dist/explainer-plugin.mjs +2132 -0
  16. package/dist/explainer.mjs +1246 -0
  17. package/dist/html-mffkHGHh.mjs +89 -0
  18. package/dist/image-CspJVfyQ.mjs +21 -0
  19. package/dist/interactive-e2e.mjs +140 -0
  20. package/dist/interactive-plugin.mjs +242 -0
  21. package/dist/interactive.mjs +75 -0
  22. package/dist/load-RosvaPZf.mjs +16976 -0
  23. package/dist/needs-BzEahJ6X.mjs +97 -0
  24. package/dist/pages-9RaaomoO.mjs +81 -0
  25. package/dist/questions-e2e.mjs +1 -0
  26. package/dist/questions-engine.mjs +3 -0
  27. package/dist/questions.mjs +6 -0
  28. package/dist/quiz-DnW-xtCh.mjs +70 -0
  29. package/dist/quiz-e2e.mjs +174 -0
  30. package/dist/quiz-plugin.mjs +266 -0
  31. package/dist/quiz.mjs +246 -0
  32. package/dist/render-D5kwkNt1.mjs +507 -0
  33. package/dist/render-DqHOJyHK.mjs +146 -0
  34. package/dist/render-GS1Htlu8.mjs +545 -0
  35. package/dist/result-D_mmCVwN.mjs +180 -0
  36. package/dist/tasks-DADUYy52.mjs +74 -0
  37. package/dist/validate-BDwL7Su3.mjs +1076 -0
  38. package/dist/validate-Bxy9NfB8.mjs +146 -0
  39. package/dist/vue-DO1m6q1R.mjs +40 -0
  40. package/dist/vue-code-BkJjW_I_.mjs +320 -0
  41. package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
  42. package/docs/arc42/02-constraints.arc42.md +228 -0
  43. package/docs/arc42/03-system-context.arc42.md +118 -0
  44. package/docs/arc42/04-solution-strategy.arc42.md +47 -0
  45. package/docs/arc42/05-building-blocks.arc42.md +307 -0
  46. package/docs/arc42/06-runtime-view.arc42.md +98 -0
  47. package/docs/arc42/07-deployment-view.arc42.md +160 -0
  48. package/docs/arc42/08-concepts.arc42.md +123 -0
  49. package/docs/arc42/09-decisions.arc42.md +246 -0
  50. package/docs/arc42/10-quality-requirements.arc42.md +155 -0
  51. package/docs/arc42/11-risks.arc42.md +113 -0
  52. package/docs/arc42/12-glossary.arc42.md +162 -0
  53. package/docs/arc42/architecture-evidence.md +395 -0
  54. package/explainer/.arc42ignore +3 -0
  55. package/explainer/README.md +54 -0
  56. package/explainer/_gitignore +5 -0
  57. package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
  58. package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
  59. package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
  60. package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
  61. package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
  62. package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
  63. package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
  64. package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
  65. package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
  66. package/explainer/e2e/explainer.e2e.ts +3 -0
  67. package/explainer/index.html +11 -0
  68. package/explainer/package.json +18 -0
  69. package/explainer/playwright.config.ts +1 -0
  70. package/explainer/src/app.yaml +20 -0
  71. package/explainer/src/components/ProzentFeld.test.ts +30 -0
  72. package/explainer/src/components/ProzentFeld.ts +121 -0
  73. package/explainer/src/components/ProzentFeld.vue +84 -0
  74. package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
  75. package/explainer/src/main.ts +4 -0
  76. package/explainer/src/prozent/chapter.yaml +18 -0
  77. package/explainer/src/prozent/grundwert.yaml +115 -0
  78. package/explainer/src/prozent/prozentsatz.yaml +99 -0
  79. package/explainer/src/prozent/prozentwert.yaml +119 -0
  80. package/explainer/tsconfig.json +1 -0
  81. package/explainer/vite.config.ts +4 -0
  82. package/interactive/.arc42ignore +5 -0
  83. package/interactive/README.md +28 -0
  84. package/interactive/_gitignore +4 -0
  85. package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
  86. package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
  87. package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
  88. package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
  89. package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
  90. package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
  91. package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
  92. package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
  93. package/interactive/e2e/interactive.e2e.ts +3 -0
  94. package/interactive/index.html +11 -0
  95. package/interactive/package.json +18 -0
  96. package/interactive/playwright.config.ts +1 -0
  97. package/interactive/src/app.yaml +28 -0
  98. package/interactive/src/core/index.ts +101 -0
  99. package/interactive/src/data/lessons.json +4 -0
  100. package/interactive/src/env.d.ts +6 -0
  101. package/interactive/src/main.ts +6 -0
  102. package/interactive/src/messages/de.json +12 -0
  103. package/interactive/src/playthroughs/grundreihe.yaml +33 -0
  104. package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
  105. package/interactive/src/ui/App.vue +85 -0
  106. package/interactive/tsconfig.json +1 -0
  107. package/interactive/vite.config.ts +4 -0
  108. package/package.json +143 -4
  109. package/quiz/README.md +31 -0
  110. package/quiz/_gitignore +5 -0
  111. package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
  112. package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
  113. package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
  114. package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
  115. package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
  116. package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
  117. package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
  118. package/quiz/e2e/quiz.e2e.ts +3 -0
  119. package/quiz/index.html +11 -0
  120. package/quiz/package.json +18 -0
  121. package/quiz/playwright.config.ts +1 -0
  122. package/quiz/src/images/berge-ordnen.jpg +0 -0
  123. package/quiz/src/images/everest-hoehe.jpg +0 -0
  124. package/quiz/src/images/galapagos.jpg +0 -0
  125. package/quiz/src/images/grand-canyon.jpg +0 -0
  126. package/quiz/src/images/totes-meer.jpg +0 -0
  127. package/quiz/src/images/uluru.jpg +0 -0
  128. package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
  129. package/quiz/src/main.ts +4 -0
  130. package/quiz/src/quiz.json +312 -0
  131. package/quiz/tsconfig.json +1 -0
  132. package/quiz/vite.config.ts +4 -0
  133. package/runtime/explainer/assessment-client.ts +478 -0
  134. package/runtime/explainer/assessment-page.ts +448 -0
  135. package/runtime/explainer/assessment.ts +393 -0
  136. package/runtime/explainer/check-page.ts +520 -0
  137. package/runtime/explainer/components/exercise.ts +409 -0
  138. package/runtime/explainer/components/props.ts +230 -0
  139. package/runtime/explainer/components/read.ts +428 -0
  140. package/runtime/explainer/content.ts +277 -0
  141. package/runtime/explainer/e2e.ts +1488 -0
  142. package/runtime/explainer/exercises.ts +326 -0
  143. package/runtime/explainer/explainer.css +1283 -0
  144. package/runtime/explainer/explainer.ts +838 -0
  145. package/runtime/explainer/explainer.v1.schema.json +1165 -0
  146. package/runtime/explainer/expression.ts +407 -0
  147. package/runtime/explainer/fraction.ts +107 -0
  148. package/runtime/explainer/generated/comparator.ts +31 -0
  149. package/runtime/explainer/generated/question.ts +165 -0
  150. package/runtime/explainer/generated/soundness.ts +280 -0
  151. package/runtime/explainer/generated/texts.ts +257 -0
  152. package/runtime/explainer/generated/types.ts +103 -0
  153. package/runtime/explainer/generated/values.ts +136 -0
  154. package/runtime/explainer/islands.ts +281 -0
  155. package/runtime/explainer/load.ts +457 -0
  156. package/runtime/explainer/messages/de.json +200 -0
  157. package/runtime/explainer/messages/en.json +200 -0
  158. package/runtime/explainer/messages.ts +13 -0
  159. package/runtime/explainer/needs.ts +122 -0
  160. package/runtime/explainer/open-task.ts +235 -0
  161. package/runtime/explainer/outline.ts +306 -0
  162. package/runtime/explainer/plugin.ts +488 -0
  163. package/runtime/explainer/position.ts +62 -0
  164. package/runtime/explainer/prompt.ts +75 -0
  165. package/runtime/explainer/render.ts +686 -0
  166. package/runtime/explainer/result.ts +238 -0
  167. package/runtime/explainer/routes.ts +119 -0
  168. package/runtime/explainer/schema.ts +140 -0
  169. package/runtime/explainer/scope.ts +87 -0
  170. package/runtime/explainer/stuck.ts +57 -0
  171. package/runtime/explainer/tasks.ts +109 -0
  172. package/runtime/explainer/tutor.ts +469 -0
  173. package/runtime/explainer/tutorpage.ts +669 -0
  174. package/runtime/explainer/video.ts +123 -0
  175. package/runtime/interactive/contract.ts +121 -0
  176. package/runtime/interactive/e2e.ts +190 -0
  177. package/runtime/interactive/interactive.css +82 -0
  178. package/runtime/interactive/interactive.ts +115 -0
  179. package/runtime/interactive/interactive.v1.schema.json +146 -0
  180. package/runtime/interactive/load.ts +188 -0
  181. package/runtime/interactive/messages/de.json +14 -0
  182. package/runtime/interactive/messages/en.json +14 -0
  183. package/runtime/interactive/messages.ts +11 -0
  184. package/runtime/interactive/playthrough.v1.schema.json +143 -0
  185. package/runtime/interactive/plugin.ts +266 -0
  186. package/runtime/interactive/render.ts +126 -0
  187. package/runtime/quiz/e2e.ts +233 -0
  188. package/runtime/quiz/engine.ts +242 -0
  189. package/runtime/quiz/messages/de.json +23 -0
  190. package/runtime/quiz/messages/en.json +23 -0
  191. package/runtime/quiz/plugin.ts +150 -0
  192. package/runtime/quiz/quiz.css +154 -0
  193. package/runtime/quiz/quiz.ts +56 -0
  194. package/runtime/quiz/quiz.v1.schema.json +72 -0
  195. package/runtime/quiz/render.ts +173 -0
  196. package/runtime/quiz/validate.ts +108 -0
  197. package/runtime/shared/appname.ts +16 -0
  198. package/runtime/shared/blocks/block.ts +162 -0
  199. package/runtime/shared/blocks/blocks.css +190 -0
  200. package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
  201. package/runtime/shared/blocks/code.ts +26 -0
  202. package/runtime/shared/blocks/figures.ts +49 -0
  203. package/runtime/shared/blocks/image.ts +25 -0
  204. package/runtime/shared/blocks/index.ts +13 -0
  205. package/runtime/shared/blocks/messages/de.json +4 -0
  206. package/runtime/shared/blocks/messages/en.json +4 -0
  207. package/runtime/shared/blocks/render.ts +134 -0
  208. package/runtime/shared/blocks/validate.ts +165 -0
  209. package/runtime/shared/content.ts +197 -0
  210. package/runtime/shared/examples.ts +20 -0
  211. package/runtime/shared/html.ts +10 -0
  212. package/runtime/shared/languages.ts +94 -0
  213. package/runtime/shared/page.css +101 -0
  214. package/runtime/shared/pages.ts +114 -0
  215. package/runtime/shared/questions/e2e.ts +115 -0
  216. package/runtime/shared/questions/engine.ts +209 -0
  217. package/runtime/shared/questions/index.ts +39 -0
  218. package/runtime/shared/questions/messages/de.json +26 -0
  219. package/runtime/shared/questions/messages/en.json +26 -0
  220. package/runtime/shared/questions/question.ts +433 -0
  221. package/runtime/shared/questions/question.v1.schema.json +346 -0
  222. package/runtime/shared/questions/questions.css +192 -0
  223. package/runtime/shared/questions/render.ts +255 -0
  224. package/runtime/shared/questions/validate.ts +518 -0
  225. package/runtime/shared/schema.ts +44 -0
  226. package/runtime/shared/text/check.ts +68 -0
  227. package/runtime/shared/text/formula.ts +69 -0
  228. package/runtime/shared/text/markdown.ts +185 -0
  229. package/runtime/shared/text/speech.ts +39 -0
  230. package/runtime/shared/text/text.v1.schema.json +34 -0
  231. package/runtime/shared/vue-code.ts +395 -0
  232. package/runtime/shared/vue.ts +38 -0
@@ -0,0 +1,518 @@
1
+ # Building Blocks
2
+
3
+ The interactive archetype's extension of the generic architecture (`docs/arc42/` at the root of
4
+ `lernapps/app-templates`): an app whose doing is the content, with a static start page, one app page on which the
5
+ shell runs the app's deterministic core and shows its state with the app's Vue components, and hash routes for modes
6
+ and levels. The runtime `runtime/interactive/` ships the build step, the pages, the shell and the end-to-end tests; the
7
+ creator writes the description, the core, the UI, the data, the messages and the playthroughs, and `src/main.ts`, which
8
+ calls `startInteractive`. It reuses the explainer's component rules; the tutor handoff, task numbers, exercise contract
9
+ and the examples check are not built for it (its playthroughs take the examples' role). Only the start page reads
10
+ without JavaScript. An interactive app adds its own blocks below `bb-interactive-core`, `bb-interactive-ui` and
11
+ `bb-interactive-data`: an app gets this architecture as a copy, and writes its own part between the markers
12
+ `<!-- app: begin … -->` and `<!-- app: end … -->` in it (here inside the sections of the core, the UI and the data and
13
+ at the end of each chapter), which the tooling keeps when it replaces the rest. The creator's assistant follows the
14
+ skill `lernapps-interactive` (`if-skills`).
15
+
16
+ ## Level 1 (interactive app)
17
+
18
+ ```arc42
19
+ :::diagram
20
+ id: building-blocks-interactive-level-1
21
+ view: building-block
22
+ notation: mermaid
23
+ :::
24
+ ```
25
+
26
+ ```mermaid
27
+ flowchart TB
28
+ subgraph bb-runtime["Shared runtime"]
29
+ bb-component-rules["Component rules"]
30
+ end
31
+ bb-tooling["Tooling helpers"]
32
+ bb-archetype-runtime["Interactive runtime"]
33
+ bb-interactive-description["Description"]
34
+ bb-interactive-core["Core"]
35
+ bb-interactive-ui["UI"]
36
+ bb-interactive-data["Data"]
37
+ bb-interactive-messages["Messages"]
38
+ bb-interactive-playthroughs["Playthroughs"]
39
+ bb-archetype-runtime -->|"if-shared-runtime"| bb-runtime
40
+ bb-archetype-runtime -->|"if-component-rules"| bb-component-rules
41
+ bb-archetype-runtime -->|"if-preset"| bb-tooling
42
+ bb-interactive-core -->|"if-interactive-data"| bb-interactive-data
43
+ bb-interactive-ui -->|"if-messages"| bb-interactive-messages
44
+ bb-interactive-ui -->|"if-a11y"| bb-tooling
45
+ bb-interactive-ui -->|"if-translator"| bb-tooling
46
+ ```
47
+
48
+ ## Level 2: the interactive runtime
49
+
50
+ ```arc42
51
+ :::diagram
52
+ id: building-blocks-interactive-runtime
53
+ view: building-block
54
+ notation: mermaid
55
+ :::
56
+ ```
57
+
58
+ ```mermaid
59
+ flowchart TB
60
+ subgraph bb-archetype-runtime["Interactive runtime"]
61
+ bb-build["Build step"]
62
+ bb-validation["Description validation"]
63
+ bb-render["Page rendering"]
64
+ bb-shell["Shell"]
65
+ bb-e2e["End-to-end tests"]
66
+ bb-runtime-texts["Runtime texts"]
67
+ end
68
+ bb-interactive-description["Description"]
69
+ bb-interactive-core["Core"]
70
+ bb-interactive-ui["UI"]
71
+ bb-interactive-playthroughs["Playthroughs"]
72
+ bb-tooling["Tooling helpers"]
73
+ bb-build -->|"if-archetype-content"| bb-interactive-description
74
+ bb-build -->|"if-playthrough-format"| bb-interactive-playthroughs
75
+ bb-build -->|"if-core-contract"| bb-interactive-core
76
+ bb-validation -->|"if-archetype-content"| bb-interactive-description
77
+ bb-validation -->|"if-playthrough-format"| bb-interactive-playthroughs
78
+ bb-validation -->|"if-runtime-texts"| bb-runtime-texts
79
+ bb-render -->|"if-archetype-content"| bb-interactive-description
80
+ bb-render -->|"if-runtime-texts"| bb-runtime-texts
81
+ bb-shell -->|"if-core-contract"| bb-interactive-core
82
+ bb-shell -->|"if-root-component"| bb-interactive-ui
83
+ bb-e2e -->|"if-archetype-content"| bb-interactive-description
84
+ bb-e2e -->|"if-playthrough-format"| bb-interactive-playthroughs
85
+ bb-e2e -->|"if-state-property"| bb-shell
86
+ bb-e2e -->|"if-test-clock"| bb-shell
87
+ bb-e2e -->|"if-runtime-texts"| bb-runtime-texts
88
+ bb-e2e -->|"if-a11y"| bb-tooling
89
+ ```
90
+
91
+ ## Interactive runtime
92
+
93
+ Built. The runtime of every interactive app, which the app does not change: it builds the pages, runs the build
94
+ checks, starts the app's core and UI in the browser and brings the end-to-end tests.
95
+
96
+ ```arc42
97
+ :::building-block
98
+ id: bb-archetype-runtime
99
+ title: Interactive runtime
100
+ path: runtime/interactive
101
+ technology: TypeScript, Vite plugin, Vue
102
+ requires: if-shared-runtime, if-preset, if-component-rules
103
+ implements: concept-archetype-extension
104
+ :::
105
+ ```
106
+
107
+ ### Build step
108
+
109
+ Built. The plugin `interactive()` reads `src/app.yaml` and the playthroughs, runs the component rules on the UI, loads
110
+ the core in a Vite server of its own and checks its exports and that every route starts, plays every playthrough
111
+ against the core twice, each step's inputs through `step` and then its ticks through `tick(state, 20)`, and fails when
112
+ the two plays differ or a state differs from the expected one, and only then writes the start page, the app page and
113
+ the 404 page. No time passes but the ticks a step names. An app's code has no size limit (`dec-no-size-limit`).
114
+
115
+ ```arc42
116
+ :::building-block
117
+ id: bb-build
118
+ title: Build step
119
+ parent: bb-archetype-runtime
120
+ path: runtime/interactive/plugin.ts
121
+ technology: Vite plugin
122
+ requires: if-archetype-content, if-playthrough-format, if-core-contract, if-component-rules
123
+ implements: concept-playthroughs, concept-determinism
124
+ :::
125
+ ```
126
+
127
+ #### Build plugin interface
128
+
129
+ The app's vite.config.ts adds `interactive()` to the tooling preset; that is the only way the app enters the build.
130
+
131
+ ```arc42
132
+ :::interface
133
+ id: if-build-plugin
134
+ title: interactive() Vite plugin
135
+ provider: bb-build
136
+ protocol: TypeScript import, @lernapps/app-templates/interactive/plugin
137
+ path: runtime/interactive/plugin.ts
138
+ :::
139
+ ```
140
+
141
+ ### Description validation
142
+
143
+ Built. Validates `src/app.yaml` and every playthrough against their JSON schemas, then German first, complete
144
+ languages, unique ids, at least one playthrough, each step expecting something, and known routes; one line per
145
+ problem with file and line.
146
+
147
+ ```arc42
148
+ :::building-block
149
+ id: bb-validation
150
+ title: Description validation
151
+ parent: bb-archetype-runtime
152
+ path: runtime/interactive/load.ts
153
+ technology: Ajv, JSON Schema, YAML
154
+ requires: if-archetype-content, if-playthrough-format, if-runtime-texts
155
+ :::
156
+ ```
157
+
158
+ ### Page rendering
159
+
160
+ Built. Renders, in each language, the start page (what the app does, the link into the app, the routes, how to play,
161
+ competencies, background sections, a `<noscript>` note and no script) and the app page (title, `<noscript>` note with
162
+ a link back, the routes as anchor links, and the element the shell mounts into, carrying the route ids).
163
+
164
+ ```arc42
165
+ :::building-block
166
+ id: bb-render
167
+ title: Page rendering
168
+ parent: bb-archetype-runtime
169
+ path: runtime/interactive/render.ts
170
+ technology: TypeScript, HTML
171
+ requires: if-archetype-content, if-runtime-texts
172
+ implements: concept-readable-without-js, concept-hash-routes, concept-accessibility
173
+ :::
174
+ ```
175
+
176
+ #### Pages interface
177
+
178
+ Learners, teachers and parents read the start page at `lernapps.net/<repo>/` and play at
179
+ `app/?seed=<n>#<route>`; the catalog entry's topics link to the routes.
180
+
181
+ ```arc42
182
+ :::interface
183
+ id: if-pages
184
+ title: Start page and app page app/?seed=<n>#<route>
185
+ provider: bb-render
186
+ protocol: HTML pages over HTTPS (query and hash)
187
+ path: runtime/interactive/render.ts
188
+ :::
189
+ ```
190
+
191
+ ### Shell
192
+
193
+ Built. `startInteractive(core, root)` mounts the root component on the app page and holds the core's state; it takes
194
+ the seed from `?seed=<n>` (else a random one) and the route from the hash (else the first route), starts the core
195
+ again on a new route, calls `tick(state, 20)` every 20 ms when the core has `tick`, and routes typed inputs to `step`
196
+ (`dec-typed-input`): every key typed on the page as a key input, except on links, buttons and form fields or with
197
+ Ctrl, Alt or Meta, and every input the root component emits as `input` (an action, or a key it stands for). When the
198
+ end-to-end tests' clock is on the page (`if-test-clock`), it starts no interval and steps the ticks the tests ask for.
199
+
200
+ The app page has a heading line: the h1, the app's title, and a slot beside it, hidden and empty. An app that wants a
201
+ small control there (help, sound off) passes a component as `startInteractive(core, App, { title })`; the shell
202
+ mounts it into the slot with the props `state` and `lang` and the same `input` event as the root component, and shows
203
+ the slot. The header of both pages holds the language switch and nothing else, and an app with one language has none:
204
+ the title is the h1, and the way back to the catalog is the platform's. The frame of the header, the page and the
205
+ footer is as wide as the custom property `--page-max-width` (default `44rem`), which an app sets in its own
206
+ `:root` rule.
207
+
208
+ ```arc42
209
+ :::building-block
210
+ id: bb-shell
211
+ title: Shell
212
+ parent: bb-archetype-runtime
213
+ path: runtime/interactive/interactive.ts
214
+ technology: TypeScript, Vue, DOM events
215
+ requires: if-core-contract, if-root-component
216
+ implements: concept-core-and-shell, concept-hash-routes, concept-determinism
217
+ :::
218
+ ```
219
+
220
+ #### Start interface
221
+
222
+ The app's `src/main.ts` imports the runtime's style, the core and the root component and calls `startInteractive`.
223
+
224
+ ```arc42
225
+ :::interface
226
+ id: if-start
227
+ title: startInteractive(core, root, options?)
228
+ provider: bb-shell
229
+ protocol: TypeScript import, @lernapps/app-templates/interactive
230
+ path: runtime/interactive/interactive.ts
231
+ :::
232
+ ```
233
+
234
+ #### Test clock
235
+
236
+ Before the client module runs, the end-to-end tests put an object on the page as the global `lernappsClock`; the
237
+ shell then starts no interval and gives that object `tick(count)`, which calls the shell's own tick `count` times. No
238
+ time passes in the browser but the ticks a playthrough step names, as in the build. Only the tests set it.
239
+
240
+ ```arc42
241
+ :::interface
242
+ id: if-test-clock
243
+ title: lernappsClock, the end-to-end tests' clock
244
+ provider: bb-shell
245
+ protocol: global object with tick(count)
246
+ path: runtime/interactive/contract.ts
247
+ :::
248
+ ```
249
+
250
+ #### State property
251
+
252
+ The shell mirrors the state on the app's element as `lernappsState`, which the end-to-end tests read.
253
+
254
+ ```arc42
255
+ :::ignore H020 the state property, the test clock and the core contract are all defined in contract.ts, the runtime's one contract module
256
+ :::
257
+ :::interface
258
+ id: if-state-property
259
+ title: lernappsState on the app element
260
+ provider: bb-shell
261
+ protocol: DOM property
262
+ path: runtime/interactive/contract.ts
263
+ :::
264
+ ```
265
+
266
+ ### End-to-end tests
267
+
268
+ Built. `interactiveTests()` checks the start page and the app page without JavaScript in every language and plays
269
+ every playthrough's steps in the browser on the test clock (`if-test-clock`): a key input pressed on the keyboard, an
270
+ action emitted as `input` by the root component, as the component itself does, then the step's ticks; after each step
271
+ it compares the state and the polite announcement, at desktop width and 360 px.
272
+
273
+ ```arc42
274
+ :::building-block
275
+ id: bb-e2e
276
+ title: End-to-end tests
277
+ parent: bb-archetype-runtime
278
+ path: runtime/interactive/e2e.ts
279
+ technology: Playwright
280
+ requires: if-archetype-content, if-playthrough-format, if-state-property, if-test-clock, if-runtime-texts, if-a11y
281
+ implements: concept-playthroughs
282
+ :::
283
+ ```
284
+
285
+ #### Tests interface
286
+
287
+ The app's `e2e/interactive.e2e.ts` only calls `interactiveTests()`.
288
+
289
+ ```arc42
290
+ :::interface
291
+ id: if-e2e-tests
292
+ title: interactiveTests()
293
+ provider: bb-e2e
294
+ protocol: TypeScript import, @lernapps/app-templates/interactive/e2e
295
+ path: runtime/interactive/e2e.ts
296
+ :::
297
+ ```
298
+
299
+ ### Runtime texts
300
+
301
+ Built. The runtime's own learner texts in German and English; an app may declare only these languages.
302
+
303
+ ```arc42
304
+ :::building-block
305
+ id: bb-runtime-texts
306
+ title: Runtime texts
307
+ parent: bb-archetype-runtime
308
+ path: runtime/interactive/messages.ts
309
+ technology: JSON per language
310
+ implements: concept-languages
311
+ :::
312
+ ```
313
+
314
+ #### Runtime texts interface
315
+
316
+ The pages, the validation and the tests take the runtime's texts by key and language.
317
+
318
+ ```arc42
319
+ :::interface
320
+ id: if-runtime-texts
321
+ title: Runtime texts by language
322
+ provider: bb-runtime-texts
323
+ protocol: TypeScript import, JSON
324
+ path: runtime/interactive/messages
325
+ :::
326
+ ```
327
+
328
+ ## Description
329
+
330
+ Built in the template: `src/app.yaml` says what the start page shows, the languages and the routes.
331
+
332
+ ```arc42
333
+ :::building-block
334
+ id: bb-interactive-description
335
+ title: Description
336
+ technology: YAML
337
+ path: interactive/src/app.yaml
338
+ :::
339
+ ```
340
+
341
+ ### App description interface
342
+
343
+ The interactive archetype's content: the build, the validation, the pages and the tests read the app's description
344
+ only through this schema.
345
+
346
+ ```arc42
347
+ :::interface
348
+ id: if-archetype-content
349
+ title: app.yaml (interactive.v1 schema)
350
+ provider: bb-interactive-description
351
+ protocol: YAML, JSON Schema
352
+ path: runtime/interactive/interactive.v1.schema.json
353
+ :::
354
+ ```
355
+
356
+ ## Core
357
+
358
+ Built in the template. The app's logic, pure TypeScript without DOM, deterministic by its seed, its state plain JSON,
359
+ so that it can be played and tested in Node and in the browser alike; it reads the app's data.
360
+
361
+ ```arc42
362
+ :::building-block
363
+ id: bb-interactive-core
364
+ title: Core
365
+ technology: TypeScript
366
+ requires: if-interactive-data
367
+ implements: concept-core-and-shell, concept-determinism
368
+ path: interactive/src/core
369
+ :::
370
+ ```
371
+
372
+ ### Core contract
373
+
374
+ The core exports `start(seed, route)`, `step(state, input)` and, when the app moves on its own, `tick(state, dt)`.
375
+ The input is typed and extensible (`dec-typed-input`): `{ kind: "key", key }` with the key as `KeyboardEvent.key`, or
376
+ `{ kind: "action", name, value? }` for what the learner does with the pointer or by touch; a core handles the kinds it
377
+ knows and returns the state unchanged for any other, so new kinds can come.
378
+
379
+ ```arc42
380
+ :::ignore H020 the core contract, the state property and the test clock are all defined in contract.ts, the runtime's one contract module
381
+ :::
382
+ :::interface
383
+ id: if-core-contract
384
+ title: Core contract start, step, tick
385
+ provider: bb-interactive-core
386
+ protocol: TypeScript module exports
387
+ path: runtime/interactive/contract.ts
388
+ :::
389
+ ```
390
+
391
+ <!-- app: begin core -->
392
+ <!-- app: end core -->
393
+
394
+ ## UI
395
+
396
+ Built in the template. Vue components that show the state and translate the device's input (keys, pointer, touch, …)
397
+ into inputs; free in how they render (DOM, SVG, canvas). They may remember something through the small storage; the
398
+ template does not.
399
+
400
+ ```arc42
401
+ :::building-block
402
+ id: bb-interactive-ui
403
+ title: UI
404
+ technology: Vue single-file components
405
+ requires: if-a11y, if-translator, if-messages
406
+ implements: concept-component-rules, concept-accessibility
407
+ path: interactive/src/ui
408
+ :::
409
+ ```
410
+
411
+ ### Root component
412
+
413
+ The root component takes the props `state` and `lang` and emits `input` with an input (an action, or a key).
414
+
415
+ ```arc42
416
+ :::ignore H014 the contract has no file of its own: its props are set in runtime/interactive/interactive.ts (if-start's file), the component is the app's
417
+ :::
418
+ :::interface
419
+ id: if-root-component
420
+ title: Root component (state, lang, input)
421
+ provider: bb-interactive-ui
422
+ protocol: Vue props and events
423
+ :::
424
+ ```
425
+
426
+ <!-- app: begin ui -->
427
+ <!-- app: end ui -->
428
+
429
+ ## Data
430
+
431
+ Built in the template. The app's content as data in its own format (lessons, texts with their faulty versions).
432
+
433
+ ```arc42
434
+ :::building-block
435
+ id: bb-interactive-data
436
+ title: Data
437
+ technology: JSON
438
+ path: interactive/src/data
439
+ :::
440
+ ```
441
+
442
+ ### App data
443
+
444
+ The core imports the data files as JSON modules, so they are bundled and checked with the core.
445
+
446
+ ```arc42
447
+ :::interface
448
+ id: if-interactive-data
449
+ title: Data files (JSON imports)
450
+ provider: bb-interactive-data
451
+ protocol: JSON module import
452
+ path: interactive/src/data
453
+ :::
454
+ ```
455
+
456
+ <!-- app: begin data -->
457
+ <!-- app: end data -->
458
+
459
+ ## Messages
460
+
461
+ Built in the template. The app's learner texts by language, read through the translator.
462
+
463
+ ```arc42
464
+ :::building-block
465
+ id: bb-interactive-messages
466
+ title: Messages
467
+ technology: JSON
468
+ implements: concept-languages
469
+ path: interactive/src/messages
470
+ :::
471
+ ```
472
+
473
+ ### Message files
474
+
475
+ The UI imports one message file per language and hands it to the translator.
476
+
477
+ ```arc42
478
+ :::interface
479
+ id: if-messages
480
+ title: Message files by language
481
+ provider: bb-interactive-messages
482
+ protocol: JSON module import
483
+ path: interactive/src/messages
484
+ :::
485
+ ```
486
+
487
+ ## Playthroughs
488
+
489
+ Built in the template. Playthroughs as data: a seed, a route and steps of inputs (`keys` as the short form of key
490
+ inputs, or `inputs`) and ticks that pass after them, with the state or announcement expected after each step. The
491
+ template's playthrough lets a letter go late and starts a round with the action `again`.
492
+
493
+ ```arc42
494
+ :::building-block
495
+ id: bb-interactive-playthroughs
496
+ title: Playthroughs
497
+ technology: YAML
498
+ implements: concept-playthroughs
499
+ path: interactive/src/playthroughs
500
+ :::
501
+ ```
502
+
503
+ ### Playthrough format
504
+
505
+ The build and the end-to-end tests read playthroughs in this format.
506
+
507
+ ```arc42
508
+ :::interface
509
+ id: if-playthrough-format
510
+ title: Playthrough (playthrough.v1 schema)
511
+ provider: bb-interactive-playthroughs
512
+ protocol: YAML, JSON Schema
513
+ path: runtime/interactive/playthrough.v1.schema.json
514
+ :::
515
+ ```
516
+
517
+ <!-- app: begin -->
518
+ <!-- app: end -->
@@ -0,0 +1,58 @@
1
+ # Runtime View
2
+
3
+ The interactive archetype's own scenarios, besides the generic ones.
4
+
5
+ ## Playing on the app page
6
+
7
+ The learner opens `app/`, possibly with `?seed=<n>` and `#<route>`. `src/main.ts` calls `startInteractive`, which
8
+ takes the seed from the address (else a random one) and the route from the hash (else the first route), starts the
9
+ core and mounts the root component with the state and the page's language. Components translate any device input
10
+ (pointer, touch, …) into typed inputs for `step` (`dec-typed-input`): the shell gives every key typed on the page to
11
+ `step` as a key input, except keys on links, buttons and form fields or with Ctrl, Alt or Meta, and steps every input
12
+ the root component emits as `input`; a key that changes the state loses its default. When the core
13
+ has `tick`, the shell calls it every 20 ms. A new route in the hash starts the core again with the same seed and marks
14
+ the current route link. The components only show the state, take their texts through the translator and announce
15
+ changes through the live region.
16
+
17
+ ```arc42
18
+ :::runtime-scenario
19
+ id: scenario-play
20
+ title: Playing on the app page (input, ticks, route change)
21
+ trigger: The learner opens the app page, gives an input, or follows a route link
22
+ involves: bb-render, bb-shell, bb-interactive-core, bb-interactive-data, bb-interactive-ui, bb-interactive-messages, bb-tooling
23
+ :::
24
+ ```
25
+
26
+ ## Building with the playthroughs
27
+
28
+ The `interactive()` plugin validates `src/app.yaml` and the playthroughs, runs the component rules on the UI, loads
29
+ the core in a Vite server of its own, checks its exports and that every route starts, and plays every playthrough
30
+ twice, each step's inputs and then its ticks, comparing the two plays and the expected states, before it writes the start page and the app
31
+ page with the runtime's texts.
32
+
33
+ ```arc42
34
+ :::runtime-scenario
35
+ id: scenario-interactive-build
36
+ title: Building with the playthroughs
37
+ trigger: The creator, a git hook or CI runs the build
38
+ involves: bb-build, bb-validation, bb-component-rules, bb-interactive-description, bb-interactive-core, bb-interactive-playthroughs, bb-render, bb-runtime-texts
39
+ :::
40
+ ```
41
+
42
+ ## Browser playthroughs
43
+
44
+ `interactiveTests()` checks the start page and the app page without JavaScript in every language, then opens each
45
+ playthrough at `app/?seed=<seed>#<route>` on the test clock, gives its inputs (keys pressed on the keyboard, actions
46
+ emitted by the root component) and its ticks, and compares, after each step, the state read from `lernappsState` and the announcement of the polite live region.
47
+
48
+ ```arc42
49
+ :::runtime-scenario
50
+ id: scenario-browser-playthroughs
51
+ title: Browser playthroughs in the end-to-end tests
52
+ trigger: The pre-push hook or CI runs lernapps check --pre-push
53
+ involves: bb-e2e, bb-interactive-description, bb-interactive-playthroughs, bb-shell, bb-interactive-core, bb-interactive-ui, bb-runtime-texts, bb-tooling
54
+ :::
55
+ ```
56
+
57
+ <!-- app: begin -->
58
+ <!-- app: end -->
@@ -0,0 +1,35 @@
1
+ # Deployment View
2
+
3
+ Where the interactive archetype's blocks run, below the generic nodes.
4
+
5
+ ## Interactive build
6
+
7
+ The build step with its checks and the end-to-end tests run in CI and, through the same hooks, on the creator's
8
+ machine; the app's description, code, data and playthroughs are built and played there.
9
+
10
+ ```arc42
11
+ :::deployment-node
12
+ id: dn-interactive-build
13
+ title: Interactive build
14
+ type: container
15
+ parent: dn-ci-runner
16
+ hosts: bb-interactive-description, bb-interactive-core, bb-interactive-ui, bb-interactive-data, bb-interactive-messages, bb-interactive-playthroughs
17
+ :::
18
+ ```
19
+
20
+ ## Interactive app page
21
+
22
+ The shell, the core and the UI run in the learner's browser on the app page.
23
+
24
+ ```arc42
25
+ :::deployment-node
26
+ id: dn-interactive-app-page
27
+ title: Interactive app page
28
+ type: container
29
+ parent: dn-learner-browser
30
+ hosts: bb-shell, bb-interactive-core, bb-interactive-ui, bb-interactive-data, bb-interactive-messages
31
+ :::
32
+ ```
33
+
34
+ <!-- app: begin -->
35
+ <!-- app: end -->
@@ -0,0 +1,52 @@
1
+ # Cross-cutting Concepts
2
+
3
+ The interactive archetype's concepts, besides the generic ones.
4
+
5
+ ## Core and shell
6
+
7
+ The core is the app's logic in pure TypeScript without DOM, its state plain JSON, exported as `start(seed, route)`,
8
+ `step(state, input)` and optionally `tick(state, dt)`. The input is typed and extensible: a key, a pointer or touch
9
+ action, and other kinds later; the components translate any device input into such inputs (`dec-typed-input`). The
10
+ shell keeps the state, feeds it inputs and ticks and hands it to the components, which only show it, so the same core
11
+ runs in Node at build and in the browser.
12
+
13
+ ```arc42
14
+ :::concept
15
+ id: concept-core-and-shell
16
+ title: Core and shell
17
+ category: structure
18
+ :::
19
+ ```
20
+
21
+ ## Playthroughs
22
+
23
+ A playthrough is data: a seed, a route and steps of inputs, each with the state (a part of it) or the announcement
24
+ expected after them. The build plays it against the core, the end-to-end tests give the same inputs in the browser,
25
+ so behaviour is specified once and checked in both places. A step can let n ticks pass after its inputs; in the build
26
+ and in the browser no other time passes, so a real-time core is checked deterministically. The core's property tests
27
+ over fixed seeds are not built yet.
28
+
29
+ ```arc42
30
+ :::concept
31
+ id: concept-playthroughs
32
+ title: Playthroughs as data
33
+ category: testing
34
+ :::
35
+ ```
36
+
37
+ ## Hash routes
38
+
39
+ Modes and levels are routes declared in `src/app.yaml`, reached as `app/#<id>` from anchor links on the start page and
40
+ the app page. The shell starts the core with the route of the address (else the first) and again on every new route,
41
+ so an entry's topics can point to a route and `entry-links-resolve` can check it.
42
+
43
+ ```arc42
44
+ :::concept
45
+ id: concept-hash-routes
46
+ title: Hash routes
47
+ category: navigation
48
+ :::
49
+ ```
50
+
51
+ <!-- app: begin -->
52
+ <!-- app: end -->