@lernapps/app-templates 0.0.0-stage → 0.1.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/LICENSE +22 -0
- package/README.md +195 -2
- package/dist/appname-Bh23cUuz.mjs +12 -0
- package/dist/assessment-By2GGTJC.mjs +1696 -0
- package/dist/block-BK_ohsH1.mjs +82 -0
- package/dist/blocks-BmRrD7UY.mjs +149 -0
- package/dist/blocks.mjs +4 -0
- package/dist/check-BkEl-m-F.mjs +254 -0
- package/dist/content-cYBPYg_J.mjs +140 -0
- package/dist/contract-PONpxJtd.mjs +52 -0
- package/dist/e2e-BiMI-pCL.mjs +89 -0
- package/dist/engine-BqF2Vffn.mjs +136 -0
- package/dist/explainer-e2e.mjs +1297 -0
- package/dist/explainer-islands.mjs +197 -0
- package/dist/explainer-plugin.mjs +2131 -0
- package/dist/explainer.mjs +1246 -0
- package/dist/html-mffkHGHh.mjs +89 -0
- package/dist/image-CspJVfyQ.mjs +21 -0
- package/dist/interactive-e2e.mjs +140 -0
- package/dist/interactive-plugin.mjs +242 -0
- package/dist/interactive.mjs +75 -0
- package/dist/load-C-0hUaSC.mjs +16947 -0
- package/dist/needs-BzEahJ6X.mjs +97 -0
- package/dist/pages-9RaaomoO.mjs +81 -0
- package/dist/questions-e2e.mjs +1 -0
- package/dist/questions-engine.mjs +3 -0
- package/dist/questions.mjs +6 -0
- package/dist/quiz-BKc8JYtC.mjs +70 -0
- package/dist/quiz-e2e.mjs +174 -0
- package/dist/quiz-plugin.mjs +266 -0
- package/dist/quiz.mjs +246 -0
- package/dist/render-BJey0bwl.mjs +540 -0
- package/dist/render-BL6fV_NI.mjs +507 -0
- package/dist/render-DpRO_RKm.mjs +146 -0
- package/dist/result-_eQcamoz.mjs +180 -0
- package/dist/tasks-DADUYy52.mjs +74 -0
- package/dist/validate-COaZso7u.mjs +1072 -0
- package/dist/validate-CxtdeQ5S.mjs +146 -0
- package/dist/vue-DO1m6q1R.mjs +40 -0
- package/dist/vue-code-BkJjW_I_.mjs +320 -0
- package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
- package/docs/arc42/02-constraints.arc42.md +228 -0
- package/docs/arc42/03-system-context.arc42.md +118 -0
- package/docs/arc42/04-solution-strategy.arc42.md +47 -0
- package/docs/arc42/05-building-blocks.arc42.md +307 -0
- package/docs/arc42/06-runtime-view.arc42.md +98 -0
- package/docs/arc42/07-deployment-view.arc42.md +160 -0
- package/docs/arc42/08-concepts.arc42.md +123 -0
- package/docs/arc42/09-decisions.arc42.md +246 -0
- package/docs/arc42/10-quality-requirements.arc42.md +155 -0
- package/docs/arc42/11-risks.arc42.md +113 -0
- package/docs/arc42/12-glossary.arc42.md +162 -0
- package/docs/arc42/architecture-evidence.md +395 -0
- package/explainer/.arc42ignore +3 -0
- package/explainer/README.md +54 -0
- package/explainer/_gitignore +5 -0
- package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
- package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
- package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
- package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
- package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
- package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
- package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
- package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
- package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
- package/explainer/e2e/explainer.e2e.ts +3 -0
- package/explainer/index.html +11 -0
- package/explainer/package.json +18 -0
- package/explainer/playwright.config.ts +1 -0
- package/explainer/src/app.yaml +20 -0
- package/explainer/src/components/ProzentFeld.test.ts +30 -0
- package/explainer/src/components/ProzentFeld.ts +121 -0
- package/explainer/src/components/ProzentFeld.vue +84 -0
- package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
- package/explainer/src/main.ts +4 -0
- package/explainer/src/prozent/chapter.yaml +18 -0
- package/explainer/src/prozent/grundwert.yaml +115 -0
- package/explainer/src/prozent/prozentsatz.yaml +99 -0
- package/explainer/src/prozent/prozentwert.yaml +119 -0
- package/explainer/tsconfig.json +1 -0
- package/explainer/vite.config.ts +4 -0
- package/interactive/.arc42ignore +5 -0
- package/interactive/README.md +28 -0
- package/interactive/_gitignore +4 -0
- package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
- package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
- package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
- package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
- package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
- package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
- package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
- package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
- package/interactive/e2e/interactive.e2e.ts +3 -0
- package/interactive/index.html +11 -0
- package/interactive/package.json +18 -0
- package/interactive/playwright.config.ts +1 -0
- package/interactive/src/app.yaml +28 -0
- package/interactive/src/core/index.ts +101 -0
- package/interactive/src/data/lessons.json +4 -0
- package/interactive/src/env.d.ts +6 -0
- package/interactive/src/main.ts +6 -0
- package/interactive/src/messages/de.json +12 -0
- package/interactive/src/playthroughs/grundreihe.yaml +33 -0
- package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
- package/interactive/src/ui/App.vue +85 -0
- package/interactive/tsconfig.json +1 -0
- package/interactive/vite.config.ts +4 -0
- package/package.json +144 -4
- package/quiz/README.md +31 -0
- package/quiz/_gitignore +5 -0
- package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
- package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
- package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
- package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
- package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
- package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
- package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
- package/quiz/e2e/quiz.e2e.ts +3 -0
- package/quiz/index.html +11 -0
- package/quiz/package.json +18 -0
- package/quiz/playwright.config.ts +1 -0
- package/quiz/src/images/berge-ordnen.jpg +0 -0
- package/quiz/src/images/everest-hoehe.jpg +0 -0
- package/quiz/src/images/galapagos.jpg +0 -0
- package/quiz/src/images/grand-canyon.jpg +0 -0
- package/quiz/src/images/totes-meer.jpg +0 -0
- package/quiz/src/images/uluru.jpg +0 -0
- package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
- package/quiz/src/main.ts +4 -0
- package/quiz/src/quiz.json +312 -0
- package/quiz/tsconfig.json +1 -0
- package/quiz/vite.config.ts +4 -0
- package/runtime/explainer/assessment-client.ts +478 -0
- package/runtime/explainer/assessment-page.ts +446 -0
- package/runtime/explainer/assessment.ts +393 -0
- package/runtime/explainer/check-page.ts +520 -0
- package/runtime/explainer/components/exercise.ts +409 -0
- package/runtime/explainer/components/props.ts +230 -0
- package/runtime/explainer/components/read.ts +428 -0
- package/runtime/explainer/content.ts +277 -0
- package/runtime/explainer/e2e.ts +1474 -0
- package/runtime/explainer/exercises.ts +324 -0
- package/runtime/explainer/explainer.css +1283 -0
- package/runtime/explainer/explainer.ts +838 -0
- package/runtime/explainer/explainer.v1.schema.json +1165 -0
- package/runtime/explainer/expression.ts +407 -0
- package/runtime/explainer/fraction.ts +107 -0
- package/runtime/explainer/generated/comparator.ts +31 -0
- package/runtime/explainer/generated/question.ts +165 -0
- package/runtime/explainer/generated/soundness.ts +280 -0
- package/runtime/explainer/generated/texts.ts +257 -0
- package/runtime/explainer/generated/types.ts +103 -0
- package/runtime/explainer/generated/values.ts +136 -0
- package/runtime/explainer/islands.ts +281 -0
- package/runtime/explainer/load.ts +457 -0
- package/runtime/explainer/messages/de.json +200 -0
- package/runtime/explainer/messages/en.json +200 -0
- package/runtime/explainer/messages.ts +13 -0
- package/runtime/explainer/needs.ts +122 -0
- package/runtime/explainer/open-task.ts +235 -0
- package/runtime/explainer/outline.ts +299 -0
- package/runtime/explainer/plugin.ts +488 -0
- package/runtime/explainer/position.ts +62 -0
- package/runtime/explainer/prompt.ts +75 -0
- package/runtime/explainer/render.ts +686 -0
- package/runtime/explainer/result.ts +238 -0
- package/runtime/explainer/routes.ts +119 -0
- package/runtime/explainer/schema.ts +140 -0
- package/runtime/explainer/scope.ts +87 -0
- package/runtime/explainer/stuck.ts +57 -0
- package/runtime/explainer/tasks.ts +109 -0
- package/runtime/explainer/tutor.ts +469 -0
- package/runtime/explainer/tutorpage.ts +669 -0
- package/runtime/explainer/video.ts +123 -0
- package/runtime/interactive/contract.ts +121 -0
- package/runtime/interactive/e2e.ts +190 -0
- package/runtime/interactive/interactive.css +82 -0
- package/runtime/interactive/interactive.ts +115 -0
- package/runtime/interactive/interactive.v1.schema.json +146 -0
- package/runtime/interactive/load.ts +188 -0
- package/runtime/interactive/messages/de.json +14 -0
- package/runtime/interactive/messages/en.json +14 -0
- package/runtime/interactive/messages.ts +11 -0
- package/runtime/interactive/playthrough.v1.schema.json +143 -0
- package/runtime/interactive/plugin.ts +266 -0
- package/runtime/interactive/render.ts +126 -0
- package/runtime/quiz/e2e.ts +233 -0
- package/runtime/quiz/engine.ts +242 -0
- package/runtime/quiz/messages/de.json +23 -0
- package/runtime/quiz/messages/en.json +23 -0
- package/runtime/quiz/plugin.ts +150 -0
- package/runtime/quiz/quiz.css +154 -0
- package/runtime/quiz/quiz.ts +56 -0
- package/runtime/quiz/quiz.v1.schema.json +72 -0
- package/runtime/quiz/render.ts +173 -0
- package/runtime/quiz/validate.ts +108 -0
- package/runtime/shared/appname.ts +16 -0
- package/runtime/shared/blocks/block.ts +162 -0
- package/runtime/shared/blocks/blocks.css +190 -0
- package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
- package/runtime/shared/blocks/code.ts +26 -0
- package/runtime/shared/blocks/figures.ts +49 -0
- package/runtime/shared/blocks/image.ts +25 -0
- package/runtime/shared/blocks/index.ts +13 -0
- package/runtime/shared/blocks/messages/de.json +4 -0
- package/runtime/shared/blocks/messages/en.json +4 -0
- package/runtime/shared/blocks/render.ts +134 -0
- package/runtime/shared/blocks/validate.ts +165 -0
- package/runtime/shared/content.ts +197 -0
- package/runtime/shared/examples.ts +20 -0
- package/runtime/shared/html.ts +10 -0
- package/runtime/shared/languages.ts +94 -0
- package/runtime/shared/page.css +101 -0
- package/runtime/shared/pages.ts +114 -0
- package/runtime/shared/questions/e2e.ts +115 -0
- package/runtime/shared/questions/engine.ts +209 -0
- package/runtime/shared/questions/index.ts +39 -0
- package/runtime/shared/questions/messages/de.json +26 -0
- package/runtime/shared/questions/messages/en.json +26 -0
- package/runtime/shared/questions/question.ts +430 -0
- package/runtime/shared/questions/question.v1.schema.json +342 -0
- package/runtime/shared/questions/questions.css +192 -0
- package/runtime/shared/questions/render.ts +247 -0
- package/runtime/shared/questions/validate.ts +518 -0
- package/runtime/shared/schema.ts +44 -0
- package/runtime/shared/text/check.ts +68 -0
- package/runtime/shared/text/formula.ts +69 -0
- package/runtime/shared/text/markdown.ts +185 -0
- package/runtime/shared/text/text.v1.schema.json +34 -0
- package/runtime/shared/vue-code.ts +395 -0
- 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 -->
|