explico 0.13.1 → 0.14.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/CHANGELOG.md +879 -1
- package/README.md +200 -30
- package/dist/compiler/astro.d.ts +15 -2
- package/dist/compiler/astro.js +40 -11
- package/dist/compiler/cli-main.d.ts +43 -0
- package/dist/compiler/cli-main.js +392 -0
- package/dist/compiler/cli.d.ts +424 -9
- package/dist/compiler/cli.js +1289 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +105 -1
- package/dist/compiler/decks.d.ts +161 -0
- package/dist/compiler/decks.js +235 -0
- package/dist/compiler/exports/combined-html.d.ts +5 -1
- package/dist/compiler/exports/deck-fit.d.ts +55 -0
- package/dist/compiler/exports/deck-fit.js +90 -0
- package/dist/compiler/exports/export-chapters.d.ts +37 -6
- package/dist/compiler/exports/export-chapters.js +64 -5
- package/dist/compiler/exports/export-pages.d.ts +30 -3
- package/dist/compiler/exports/export-pages.js +24 -1
- package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/dist/compiler/exports/latex/cache.d.ts +78 -0
- package/dist/compiler/exports/latex/cache.js +129 -0
- package/dist/compiler/exports/latex/capture.d.ts +10 -1
- package/dist/compiler/exports/latex/capture.js +3 -1
- package/dist/compiler/exports/latex/compile.d.ts +13 -2
- package/dist/compiler/exports/latex/compile.js +12 -1
- package/dist/compiler/exports/latex/deck.d.ts +92 -0
- package/dist/compiler/exports/latex/deck.js +349 -0
- package/dist/compiler/exports/latex/document.d.ts +51 -6
- package/dist/compiler/exports/latex/document.js +71 -12
- package/dist/compiler/exports/latex/explico-common.sty +198 -0
- package/dist/compiler/exports/latex/explico.cls +13 -183
- package/dist/compiler/exports/latex/serialize.d.ts +60 -4
- package/dist/compiler/exports/latex/serialize.js +4 -2
- package/dist/compiler/exports/latex-export.d.ts +24 -2
- package/dist/compiler/exports/latex-export.js +107 -26
- package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
- package/dist/compiler/exports/markdown/serialize.js +85 -8
- package/dist/compiler/exports/markdown-export.d.ts +6 -1
- package/dist/compiler/exports/markdown-export.js +50 -11
- package/dist/compiler/exports/standalone-html.d.ts +10 -5
- package/dist/compiler/exports/standalone-html.js +3 -3
- package/dist/compiler/exports/static-tree.d.ts +38 -1
- package/dist/compiler/exports/static-tree.js +120 -4
- package/dist/compiler/knowledge-version.d.ts +26 -2
- package/dist/compiler/knowledge-version.js +27 -17
- package/dist/compiler/lesson-derivation.d.ts +143 -6
- package/dist/compiler/lesson-derivation.js +145 -13
- package/dist/compiler/manifest.d.ts +133 -4
- package/dist/compiler/manifest.js +359 -58
- package/dist/compiler/page-versions.d.ts +160 -0
- package/dist/compiler/page-versions.js +198 -0
- package/dist/compiler/render-diagnostics.d.ts +5 -1
- package/dist/compiler/resolution-report.d.ts +24 -6
- package/dist/compiler/resolution-report.js +22 -4
- package/dist/compiler/validate-content.d.ts +7 -0
- package/dist/compiler/validate-content.js +160 -0
- package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
- package/dist/curriculum/competency-graph.d.ts +54 -0
- package/dist/curriculum/competency-graph.js +41 -0
- package/dist/reference/base-library.d.mts +8 -0
- package/dist/reference/base-library.mjs +19 -0
- package/dist/reference/consistency.d.ts +8 -4
- package/dist/reference/consistency.js +76 -26
- package/dist/reference/deck-remark.d.mts +123 -0
- package/dist/reference/deck-remark.mjs +600 -0
- package/dist/reference/deck-source.d.ts +107 -0
- package/dist/reference/deck-source.js +140 -0
- package/dist/reference/decks-validate.d.ts +133 -0
- package/dist/reference/decks-validate.js +359 -0
- package/dist/reference/derived-entries.d.ts +5 -1
- package/dist/reference/diagram-fit.d.ts +1 -1
- package/dist/reference/figure-symbols.d.ts +23 -6
- package/dist/reference/figure-symbols.js +51 -15
- package/dist/reference/float-name.d.ts +43 -0
- package/dist/reference/float-name.js +58 -0
- package/dist/reference/folds-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-indices.js +5 -4
- package/dist/reference/gate-math.d.ts +29 -2
- package/dist/reference/gate-math.js +99 -18
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/lab-katex-validate.d.ts +10 -6
- package/dist/reference/lab-katex-validate.js +17 -9
- package/dist/reference/lab-math-scope.js +29 -4
- package/dist/reference/math-glyphs.d.mts +25 -0
- package/dist/reference/math-glyphs.mjs +189 -25
- package/dist/reference/page-notation.d.ts +22 -3
- package/dist/reference/page-notation.js +32 -10
- package/dist/reference/references.d.ts +14 -1
- package/dist/reference/references.js +13 -0
- package/dist/reference/registry-scope.d.mts +33 -0
- package/dist/reference/registry-scope.mjs +34 -0
- package/dist/reference/registry.js +29 -10
- package/dist/reference/rehype-deck.d.mts +6 -0
- package/dist/reference/rehype-deck.mjs +286 -0
- package/dist/reference/rehype-heading-anchors.d.mts +20 -0
- package/dist/reference/rehype-heading-anchors.mjs +48 -6
- package/dist/reference/remark-notation.mjs +249 -40
- package/dist/reference/source-lines.d.mts +12 -0
- package/dist/reference/source-lines.mjs +65 -0
- package/dist/reference/types.d.ts +28 -0
- package/dist/rules/catalog.d.ts +21 -4
- package/dist/rules/catalog.js +221 -2
- package/dist/rules/course-rules.d.ts +5 -1
- package/dist/rules/course-rules.js +17 -3
- package/dist/rules/course-rules.schema.json +12 -0
- package/dist/rules/in-effect.d.ts +13 -3
- package/dist/rules/in-effect.js +30 -7
- package/dist/rules/rules.schema.json +259 -1
- package/dist/rules/settings.d.ts +1 -1
- package/dist/session/PreferenceStore.d.ts +6 -0
- package/dist/session/PreferenceStore.js +18 -1
- package/dist/session/deck-memory.d.ts +116 -0
- package/dist/session/deck-memory.js +143 -0
- package/dist/session/reading-memory.d.ts +96 -0
- package/dist/session/reading-memory.js +133 -0
- package/docs/VERSIONING.md +21 -18
- package/docs/authoring/README.md +29 -9
- package/docs/authoring/agents.md +63 -16
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +588 -0
- package/docs/authoring/migrating.md +1045 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +54 -2
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +37 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
- package/docs/course-agent/skills/release-content/SKILL.md +24 -0
- package/docs/diagram-scaling.md +148 -0
- package/docs/privacy.md +59 -0
- package/package.json +8 -2
- package/src/compiler/astro.ts +60 -21
- package/src/compiler/cli-main.ts +469 -0
- package/src/compiler/cli.ts +1905 -16
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/course-config.ts +267 -0
- package/src/compiler/decks.ts +455 -0
- package/src/compiler/exports/deck-fit.ts +127 -0
- package/src/compiler/exports/export-chapters.ts +105 -6
- package/src/compiler/exports/export-pages.ts +46 -2
- package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/src/compiler/exports/latex/cache.ts +183 -0
- package/src/compiler/exports/latex/capture.ts +5 -2
- package/src/compiler/exports/latex/compile.ts +18 -0
- package/src/compiler/exports/latex/deck.ts +419 -0
- package/src/compiler/exports/latex/document.ts +117 -21
- package/src/compiler/exports/latex/explico-common.sty +198 -0
- package/src/compiler/exports/latex/explico.cls +13 -183
- package/src/compiler/exports/latex/serialize.ts +25 -21
- package/src/compiler/exports/latex/texlive-packages.txt +6 -2
- package/src/compiler/exports/latex-export.ts +187 -45
- package/src/compiler/exports/markdown/serialize.ts +118 -9
- package/src/compiler/exports/markdown-export.ts +56 -11
- package/src/compiler/exports/standalone-html.ts +8 -7
- package/src/compiler/exports/static-tree.ts +175 -3
- package/src/compiler/knowledge-version.ts +56 -21
- package/src/compiler/lesson-derivation.ts +282 -16
- package/src/compiler/manifest.ts +558 -63
- package/src/compiler/page-versions.ts +359 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +212 -0
- package/src/components/CourseContents.astro +124 -6
- package/src/components/CurriculumMap.astro +49 -1
- package/src/components/FloatIndex.astro +1 -1
- package/src/components/PartOverview.astro +51 -5
- package/src/components/assessments/AssessmentSet.astro +41 -15
- package/src/components/block-heading.ts +15 -6
- package/src/components/card-carry.ts +7 -4
- package/src/components/card-manager.ts +14 -2
- package/src/components/card-memory.ts +13 -9
- package/src/components/deck/DeckEnhancer.astro +13 -0
- package/src/components/deck/deck-context.ts +104 -0
- package/src/components/deck/deck-controller.ts +1287 -0
- package/src/components/deck/deck-map.ts +91 -0
- package/src/components/deck-lane.ts +163 -0
- package/src/components/diagram/Diagram.astro +131 -86
- package/src/components/disclosure/persisted-disclosure.ts +9 -1
- package/src/components/figure/Figure.astro +7 -2
- package/src/components/figure/FloatCaption.astro +5 -3
- package/src/components/fold/Fold.astro +2 -2
- package/src/components/notation/NotationFormula.astro +81 -11
- package/src/components/notation/NotationGlossary.astro +132 -1
- package/src/components/notation/NotationLayer.astro +15 -7
- package/src/components/starlight/AboutPanel.astro +186 -3
- package/src/components/starlight/CollapsibleSections.astro +24 -3
- package/src/components/starlight/DiagramEnhancer.astro +5 -1
- package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
- package/src/components/starlight/LayoutHeader.astro +17 -0
- package/src/components/starlight/LayoutPageTitle.astro +110 -0
- package/src/components/starlight/LayoutSidebar.astro +807 -21
- package/src/components/starlight/LayoutSocialIcons.astro +62 -6
- package/src/components/starlight/LessonExportActions.astro +27 -9
- package/src/components/starlight/LessonFooter.astro +59 -0
- package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
- package/src/components/starlight/TextSizeControl.astro +24 -13
- package/src/components/starlight/page-marks.ts +139 -0
- package/src/components/starlight/section-summary.ts +1 -1
- package/src/components/starlight/sidebar-editions.ts +245 -0
- package/src/components/table/Table.astro +15 -7
- package/src/content-config.ts +87 -1
- package/src/curriculum/competency-graph.ts +95 -0
- package/src/reference/base-library.mjs +19 -0
- package/src/reference/consistency.ts +126 -39
- package/src/reference/deck-remark.mjs +600 -0
- package/src/reference/deck-source.ts +273 -0
- package/src/reference/decks-validate.ts +604 -0
- package/src/reference/diagram-layout.ts +3 -1
- package/src/reference/figure-symbols.ts +108 -31
- package/src/reference/folds-validate.ts +1 -1
- package/src/reference/gate-indices.ts +5 -3
- package/src/reference/gate-math.ts +169 -25
- package/src/reference/lab-katex-validate.ts +30 -15
- package/src/reference/lab-math-scope.ts +34 -3
- package/src/reference/math-glyphs.mjs +189 -25
- package/src/reference/page-notation.ts +69 -15
- package/src/reference/references.ts +28 -0
- package/src/reference/registry-scope.mjs +34 -0
- package/src/reference/registry.ts +41 -11
- package/src/reference/rehype-deck.mjs +286 -0
- package/src/reference/rehype-heading-anchors.mjs +48 -6
- package/src/reference/remark-notation.mjs +249 -40
- package/src/reference/source-lines.mjs +65 -0
- package/src/reference/types.ts +28 -0
- package/src/rules/catalog.ts +257 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +54 -8
- package/src/session/PreferenceStore.ts +23 -0
- package/src/session/deck-memory.ts +263 -0
- package/src/session/reading-memory.ts +243 -0
- package/src/styles/deck.css +1150 -0
- package/src/styles/global.css +958 -27
- package/src/styles/zones.css +277 -0
- /package/src/{components → reference}/float-name.ts +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { PreferenceStore } from './PreferenceStore.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The one question explico asks a reader: may this course remember their
|
|
5
|
+
* reading in this browser? (`readingMemory` in the course settings.)
|
|
6
|
+
*
|
|
7
|
+
* **Reading memory** is what records what the reader did, across visits:
|
|
8
|
+
* which chapters they opened (the sidebar marks and the "changed since you
|
|
9
|
+
* last opened it" note, `page-marks.ts`), the cards they kept open on a page
|
|
10
|
+
* (`card-memory.ts`), the cards they carry from page to page
|
|
11
|
+
* (`card-carry.ts`), and where each deck stopped and which slides Present
|
|
12
|
+
* mode showed them (`deck-memory.ts`). It is kept only with the reader's yes.
|
|
13
|
+
* Without it — before they answer, after a no, or when the course turns the
|
|
14
|
+
* question off — nothing of their reading outlives the tab: no visit is
|
|
15
|
+
* recorded and no page is marked, and kept and carried cards and where a deck
|
|
16
|
+
* stopped live in the tab's session storage, so they still work until the tab
|
|
17
|
+
* is closed. The slides Present mode showed live there too before an answer,
|
|
18
|
+
* marked on the deck's page; a no clears them, and none is recorded after it.
|
|
19
|
+
*
|
|
20
|
+
* **Settings** are not reading memory: the theme, the text size, the panels'
|
|
21
|
+
* layout, a folded section or sidebar part, which edition a lesson's sidebar
|
|
22
|
+
* row opens, the "Carry cards" switch. The
|
|
23
|
+
* reader sets each of them, and they are kept because the reader set them,
|
|
24
|
+
* the exemption the ePrivacy rules give a preference the user asked for. They
|
|
25
|
+
* need no answer. Nothing explico stores is a cookie, and nothing leaves the
|
|
26
|
+
* browser.
|
|
27
|
+
*
|
|
28
|
+
* The answer itself is kept (storing a consent choice needs no consent), per
|
|
29
|
+
* course, for 13 months, after which the course asks again. A no deletes
|
|
30
|
+
* whatever reading memory the course had; "Forget what this course stored"
|
|
31
|
+
* (the `[?]` panel) deletes everything, the answer included.
|
|
32
|
+
*
|
|
33
|
+
* Storage goes through the `PreferenceStore` only. The pure half
|
|
34
|
+
* (`decodeAnswer`, `courseKeys`, …) is checked in Node by
|
|
35
|
+
* `tests/unit/reading-memory.test.ts`.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/** The reader's answer: yes, no, or not asked yet (or asked too long ago). */
|
|
39
|
+
type ReadingAnswer = 'yes' | 'no' | 'unasked';
|
|
40
|
+
/** The course's `readingMemory` setting: ask the reader, or never keep reading memory. */
|
|
41
|
+
type ReadingMemoryMode = 'ask' | 'off';
|
|
42
|
+
/** How long an answer stands before the course asks again: 13 months. */
|
|
43
|
+
declare const ANSWER_LIFETIME_DAYS = 396;
|
|
44
|
+
/** The event every part of the page listens to when the reader answers or forgets. */
|
|
45
|
+
declare const READING_MEMORY_EVENT = "explico:reading-memory";
|
|
46
|
+
interface ReadingMemoryChange {
|
|
47
|
+
readonly base: string;
|
|
48
|
+
readonly answer: ReadingAnswer;
|
|
49
|
+
}
|
|
50
|
+
/** Where a course keeps the reader's answer. */
|
|
51
|
+
declare function answerKey(base: string): string;
|
|
52
|
+
/** The stored answer's text. */
|
|
53
|
+
declare function encodeAnswer(yes: boolean, now: Date): string;
|
|
54
|
+
/** The answer a stored text holds on `now`: anything unreadable, or older than its lifetime, is not asked. */
|
|
55
|
+
declare function decodeAnswer(raw: string | null, now: Date): ReadingAnswer;
|
|
56
|
+
/**
|
|
57
|
+
* Where a course keeps, for each of its decks, the frame Present mode last
|
|
58
|
+
* stood on and the frames it showed (`deck-memory.ts`, `deck-controller.ts`).
|
|
59
|
+
*/
|
|
60
|
+
declare function deckPositionsKey(base: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* A key that is this course's reading memory: its visits, its kept and its
|
|
63
|
+
* carried cards, where its decks stopped and the slides they showed.
|
|
64
|
+
*/
|
|
65
|
+
declare function isReadingMemoryKey(key: string, base: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Every key this course stored, of the keys a store holds: its reading
|
|
68
|
+
* memory, its answer, its sections' and cards' per-page state, and the
|
|
69
|
+
* settings every explico course on this site shares, which forgetting this
|
|
70
|
+
* course resets too. Starlight's own theme key goes with them.
|
|
71
|
+
*/
|
|
72
|
+
declare function courseKeys(keys: readonly string[], base: string): string[];
|
|
73
|
+
/** The course's setting, from the element `ReadingMemoryNotice.astro` renders on every page. */
|
|
74
|
+
declare function readingMemoryMode(): ReadingMemoryMode;
|
|
75
|
+
/** The reader's answer for the course at `base`. */
|
|
76
|
+
declare function readingAnswer(base: string, now?: Date): ReadingAnswer;
|
|
77
|
+
/** Whether the course may keep the reader's reading memory: they said yes, and the course asks. */
|
|
78
|
+
declare function rememberReading(base: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Where reading memory goes: kept in the browser with the reader's yes, else
|
|
81
|
+
* the tab's session only. Read the session copy too when kept, so the cards
|
|
82
|
+
* of a visit that started before the yes are not lost.
|
|
83
|
+
*/
|
|
84
|
+
declare function readingMemoryStore(base: string): PreferenceStore;
|
|
85
|
+
/** Delete the course's reading memory from the browser (the tab's session copy stays). */
|
|
86
|
+
declare function forgetReadingMemory(base: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Record the reader's answer. A yes keeps the slides the tab recorded before
|
|
89
|
+
* it; a no deletes the course's reading memory, and those slides. Everything
|
|
90
|
+
* on the page is told.
|
|
91
|
+
*/
|
|
92
|
+
declare function answerReadingMemory(base: string, yes: boolean, now?: Date): void;
|
|
93
|
+
/** "Forget what this course stored": every key of the course, in the browser and the tab; the course asks again. */
|
|
94
|
+
declare function forgetCourse(base: string): void;
|
|
95
|
+
|
|
96
|
+
export { ANSWER_LIFETIME_DAYS, READING_MEMORY_EVENT, type ReadingAnswer, type ReadingMemoryChange, type ReadingMemoryMode, answerKey, answerReadingMemory, courseKeys, deckPositionsKey, decodeAnswer, encodeAnswer, forgetCourse, forgetReadingMemory, isReadingMemoryKey, readingAnswer, readingMemoryMode, readingMemoryStore, rememberReading };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBrowserPreferenceStore,
|
|
3
|
+
createSessionPreferenceStore
|
|
4
|
+
} from "./PreferenceStore.js";
|
|
5
|
+
import {
|
|
6
|
+
decodeDeckMemory,
|
|
7
|
+
encodeDeckMemory,
|
|
8
|
+
mergeDeckMemory,
|
|
9
|
+
withEveryDeckUnseen
|
|
10
|
+
} from "./deck-memory.js";
|
|
11
|
+
const ANSWER_LIFETIME_DAYS = 396;
|
|
12
|
+
const VERSION = 1;
|
|
13
|
+
const DAY = 24 * 60 * 60 * 1e3;
|
|
14
|
+
const READING_MEMORY_EVENT = "explico:reading-memory";
|
|
15
|
+
function answerKey(base) {
|
|
16
|
+
return `explico-reading-memory:${base}`;
|
|
17
|
+
}
|
|
18
|
+
function encodeAnswer(yes, now) {
|
|
19
|
+
return JSON.stringify({ v: VERSION, remember: yes, at: now.toISOString().slice(0, 10) });
|
|
20
|
+
}
|
|
21
|
+
function decodeAnswer(raw, now) {
|
|
22
|
+
if (!raw) return "unasked";
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = JSON.parse(raw);
|
|
26
|
+
} catch {
|
|
27
|
+
return "unasked";
|
|
28
|
+
}
|
|
29
|
+
if (!parsed || typeof parsed !== "object") return "unasked";
|
|
30
|
+
const { v, remember, at } = parsed;
|
|
31
|
+
if (v !== VERSION || typeof remember !== "boolean" || typeof at !== "string") return "unasked";
|
|
32
|
+
const given = Date.parse(`${at}T00:00:00Z`);
|
|
33
|
+
if (!Number.isFinite(given) || now.getTime() - given > ANSWER_LIFETIME_DAYS * DAY || given - now.getTime() > DAY) {
|
|
34
|
+
return "unasked";
|
|
35
|
+
}
|
|
36
|
+
return remember ? "yes" : "no";
|
|
37
|
+
}
|
|
38
|
+
const SHARED_SETTINGS = [
|
|
39
|
+
/^explico:display:/u,
|
|
40
|
+
/^explico:layout:/u,
|
|
41
|
+
/^explico-sidebar-groups$/u,
|
|
42
|
+
/^explico-sidebar-editions$/u,
|
|
43
|
+
/^explico:cards:carry$/u
|
|
44
|
+
];
|
|
45
|
+
function deckPositionsKey(base) {
|
|
46
|
+
return `explico:decks:${base}`;
|
|
47
|
+
}
|
|
48
|
+
function isReadingMemoryKey(key, base) {
|
|
49
|
+
return key === `explico-page-marks:${base}` || key === `explico:cards:carried:${base}` || key === deckPositionsKey(base) || key.startsWith(`explico:cards:${base}`) && !key.startsWith("explico:cards:carried:");
|
|
50
|
+
}
|
|
51
|
+
function courseKeys(keys, base) {
|
|
52
|
+
return keys.filter(
|
|
53
|
+
(key) => isReadingMemoryKey(key, base) || key === answerKey(base) || key.startsWith(`disclosure:${base}`) || key === "explico:cards:opened-at" || key === "starlight-theme" || key === "sl-sidebar-state" || SHARED_SETTINGS.some((pattern) => pattern.test(key))
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const local = createBrowserPreferenceStore();
|
|
57
|
+
const session = createSessionPreferenceStore();
|
|
58
|
+
function remove(store, key) {
|
|
59
|
+
if (store.remove) store.remove(key);
|
|
60
|
+
else store.set(key, "");
|
|
61
|
+
}
|
|
62
|
+
function readingMemoryMode() {
|
|
63
|
+
const element = document.querySelector("[data-explico-reading-memory]");
|
|
64
|
+
return element?.dataset.explicoReadingMemory === "off" ? "off" : "ask";
|
|
65
|
+
}
|
|
66
|
+
function readingAnswer(base, now = /* @__PURE__ */ new Date()) {
|
|
67
|
+
return decodeAnswer(local.get(answerKey(base)), now);
|
|
68
|
+
}
|
|
69
|
+
function rememberReading(base) {
|
|
70
|
+
return readingMemoryMode() === "ask" && readingAnswer(base) === "yes";
|
|
71
|
+
}
|
|
72
|
+
function readingMemoryStore(base) {
|
|
73
|
+
if (!rememberReading(base)) return session;
|
|
74
|
+
return {
|
|
75
|
+
get: (key) => local.get(key) ?? session.get(key),
|
|
76
|
+
set: (key, value) => local.set(key, value),
|
|
77
|
+
remove: (key) => {
|
|
78
|
+
remove(local, key);
|
|
79
|
+
remove(session, key);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function forgetReadingMemory(base) {
|
|
84
|
+
for (const key of local.keys?.() ?? []) if (isReadingMemoryKey(key, base)) remove(local, key);
|
|
85
|
+
}
|
|
86
|
+
function announce(base) {
|
|
87
|
+
window.dispatchEvent(
|
|
88
|
+
new CustomEvent(READING_MEMORY_EVENT, { detail: { base, answer: readingAnswer(base) } })
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
function keepShownSlides(base) {
|
|
92
|
+
const raw = session.get(deckPositionsKey(base));
|
|
93
|
+
if (!raw) return;
|
|
94
|
+
const kept = mergeDeckMemory(decodeDeckMemory(local.get(deckPositionsKey(base))), decodeDeckMemory(raw));
|
|
95
|
+
local.set(deckPositionsKey(base), encodeDeckMemory(kept));
|
|
96
|
+
}
|
|
97
|
+
function forgetShownSlides(base) {
|
|
98
|
+
const raw = session.get(deckPositionsKey(base));
|
|
99
|
+
if (raw) session.set(deckPositionsKey(base), encodeDeckMemory(withEveryDeckUnseen(decodeDeckMemory(raw))));
|
|
100
|
+
}
|
|
101
|
+
function answerReadingMemory(base, yes, now = /* @__PURE__ */ new Date()) {
|
|
102
|
+
local.set(answerKey(base), encodeAnswer(yes, now));
|
|
103
|
+
if (yes) {
|
|
104
|
+
keepShownSlides(base);
|
|
105
|
+
} else {
|
|
106
|
+
forgetReadingMemory(base);
|
|
107
|
+
forgetShownSlides(base);
|
|
108
|
+
}
|
|
109
|
+
announce(base);
|
|
110
|
+
}
|
|
111
|
+
function forgetCourse(base) {
|
|
112
|
+
for (const store of [local, session]) {
|
|
113
|
+
for (const key of courseKeys(store.keys?.() ?? [], base)) remove(store, key);
|
|
114
|
+
}
|
|
115
|
+
announce(base);
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
ANSWER_LIFETIME_DAYS,
|
|
119
|
+
READING_MEMORY_EVENT,
|
|
120
|
+
answerKey,
|
|
121
|
+
answerReadingMemory,
|
|
122
|
+
courseKeys,
|
|
123
|
+
deckPositionsKey,
|
|
124
|
+
decodeAnswer,
|
|
125
|
+
encodeAnswer,
|
|
126
|
+
forgetCourse,
|
|
127
|
+
forgetReadingMemory,
|
|
128
|
+
isReadingMemoryKey,
|
|
129
|
+
readingAnswer,
|
|
130
|
+
readingMemoryMode,
|
|
131
|
+
readingMemoryStore,
|
|
132
|
+
rememberReading
|
|
133
|
+
};
|
package/docs/VERSIONING.md
CHANGED
|
@@ -88,26 +88,29 @@ applies every intervening section in order.
|
|
|
88
88
|
|
|
89
89
|
## Cutting a release
|
|
90
90
|
|
|
91
|
+
Two judgment steps, then one command.
|
|
92
|
+
|
|
91
93
|
1. Decide the next version from the rules above and the `## [Unreleased]`
|
|
92
94
|
section of `CHANGELOG.md`.
|
|
93
|
-
2.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
the `
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
95
|
+
2. Complete the `## <previous> → Unreleased` section at the top of
|
|
96
|
+
`docs/authoring/migrating.md`, derived from the complete changelog entry you
|
|
97
|
+
are about to finalize: every consumer-owned surface that moved, exact edits
|
|
98
|
+
or commands, conditional steps, the checks to run; write explicit no-action
|
|
99
|
+
instructions when nothing in a downstream course needs to change. Give every
|
|
100
|
+
`rule N#` the entry names and every `is now vN` schema bump its own
|
|
101
|
+
coverage, in that phrasing — `check:release-migration` matches them
|
|
102
|
+
mechanically.
|
|
103
|
+
3. `pnpm release <x.y.z>` (`scripts/release.mjs`) does the rest: it refuses a
|
|
104
|
+
dirty tree, an empty `[Unreleased]` or a guide without the draft, then
|
|
105
|
+
renames the draft's heading to the version, dates the changelog entry and
|
|
106
|
+
fixes the compare links, bumps `package.json`, and runs
|
|
107
|
+
`check:release-migration`, the build, the tests and `pnpm pack --dry-run`
|
|
108
|
+
(the two shipped guides must be listed); a failed check puts the files back.
|
|
109
|
+
It stops at the diff; `--commit` commits and tags `v<x.y.z>` annotated
|
|
110
|
+
(with `push.followTags` on, a plain `git push` carries the tag; a
|
|
111
|
+
lightweight one never travels); `--dry-run` rehearses and restores.
|
|
112
|
+
4. Publish with the VS Code task **Explico: Publish to npm**: the maintainer's
|
|
113
|
+
step, behind the account's security key.
|
|
111
114
|
|
|
112
115
|
## When you change the engine
|
|
113
116
|
|
package/docs/authoring/README.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
Content rules for explico courses — strong recommendations for the people and
|
|
4
4
|
agents who write lessons, notation entries, and interactive figures.
|
|
5
5
|
|
|
6
|
+
A path these pages cite that starts with `playground/` is a file of the
|
|
7
|
+
playground course, which is not in the npm package: its source, at the engine's
|
|
8
|
+
latest release, is [downloadable](https://danieltuzes.github.io/explico/downloads/explico-playground-latest.zip) from https://danieltuzes.github.io/explico/start/, together with a full
|
|
9
|
+
course, credit-and-derivatives.
|
|
10
|
+
|
|
6
11
|
## What these are
|
|
7
12
|
|
|
8
13
|
A course built on explico is authored by many hands — lecturers, TAs, AI
|
|
@@ -102,7 +107,7 @@ speak in: what a part, a chapter, a section, and a subsection are, and which of
|
|
|
102
107
|
them an equation number counts.
|
|
103
108
|
|
|
104
109
|
Each rule has a stable ID — a letter for its area (`N` notation,
|
|
105
|
-
`V` visualizations, `C` versioning, `S` structure, `P` prose) plus a number — and this shape.
|
|
110
|
+
`V` visualizations, `C` versioning, `S` structure, `P` prose, `D` decks) plus a number — and this shape.
|
|
106
111
|
`X` is not one of them: it is reserved for the rules a course writes for itself
|
|
107
112
|
([Rules of your own](#rules-of-your-own)), so the engine never ships an `X`
|
|
108
113
|
rule and a course can number its own without waiting for a release.
|
|
@@ -230,9 +235,10 @@ of to the settings file.
|
|
|
230
235
|
| -------------------------------- | ---- | --------------------------------------------------------- |
|
|
231
236
|
| [notation.md](notation.md) | `N` | how math symbols are written and bound |
|
|
232
237
|
| [visualizations.md](visualizations.md) | `V` | diagrams, charts, interactive figures, randomness |
|
|
233
|
-
| [versioning.md](versioning.md) | `C` | the knowledge version
|
|
238
|
+
| [versioning.md](versioning.md) | `C` | the knowledge version, `content/CHANGELOG.md`, each page's own version |
|
|
234
239
|
| [structure-rules.md](structure-rules.md) | `S` | heading and float title length; part page paragraphs; tables and diagrams declared so they can be cited |
|
|
235
240
|
| [prose.md](prose.md) | `P` | how a lesson's sentences, terms, and equation lead-ins are worded |
|
|
241
|
+
| [deck.md](deck.md) | `D` | a lesson's deck: its frames, steps, notes and recalls, and what fits a frame |
|
|
236
242
|
| [components.md](components.md) | — | _catalog_: inline/block features available in a lesson body — tooltips, tables, figures, diagrams, memos, abbreviations, citations |
|
|
237
243
|
| [agents.md](agents.md) | — | _guide_: working on a course repo (with an AI agent) |
|
|
238
244
|
| [migrating.md](migrating.md) | — | _guide_: per-version steps when bumping the `explico` dep |
|
|
@@ -245,7 +251,7 @@ of to the settings file.
|
|
|
245
251
|
| ID | Element | Rule | Enforcement |
|
|
246
252
|
| --- | --- | --- | --- |
|
|
247
253
|
| [N2](notation.md#n2) | math | A reserved spelling is used only for its reserved meaning — settings: `reserved` = `["\\mathbb{N} — the natural numbers","\\mathbb{Z} — the integers","\\mathbb{R} — the reals","\\mathbb{C} — the complex numbers","\\mathbb{P} — probability","\\mathcal{N}(\\mu, \\sigma^2) — the normal distribution (mean, variance)","\\mathrm{d} — the differential"]` | Guide |
|
|
248
|
-
| [N4](notation.md#n4) | math, notation | One meaning per glyph; define once; `[[key]]` before first math | **Locked** — the notation layer is this rule — an unresolved glyph has no hover card and the render path needs every glyph bound. Script — `unresolved-glyph`, `glyph-unique-in-corpus` (warning), `weak-local` (info), `
|
|
254
|
+
| [N4](notation.md#n4) | math, notation | One meaning per glyph; define once; `[[key]]` before first math | **Locked** — the notation layer is this rule — an unresolved glyph has no hover card and the render path needs every glyph bound. Script — `unresolved-glyph`, `glyph-unique-in-corpus` (warning), `weak-local` (info), `definition-repeated` (warning), `meaning-repeated` (info), `explain-redundant` (info), `card-wants-demoting` (info) in [`gate-math.ts`](../../src/reference/gate-math.ts) `resolveInto`; [`consistency.ts`](../../src/reference/consistency.ts) `checkGlyphUniqueness`, `checkWeakLocal`, `checkDefinitionRepeated`, `checkMeaningRepeated`, `checkCardWantsDemoting` |
|
|
249
255
|
| [N5](notation.md#n5) | equation | Referenced display equations carry `\label{eq:key}` | Partial — `eq-key-unused` (info) in [`equations-validate.ts`](../../src/reference/equations-validate.ts) `validateEquations`. review: that a referenced-in-prose equation actually carries a label |
|
|
250
256
|
| [N8](notation.md#n8) | math, notation | A named operator is universal (shipped/course list) or explained — settings: `allow` = `[]`, `deny` = `[]` | Script — `operator-explained` (warning) in [`consistency.ts`](../../src/reference/consistency.ts) `checkOperatorExplained` |
|
|
251
257
|
| [N9](notation.md#n9) | prose, assessment, table | A quantity/unit/operator is typeset in `$…$`, never as plain text — settings: `allow` = `[]` | Script — `prose-notation`, `spelled-unit` in [`gate-prose-notation.ts`](../../src/reference/gate-prose-notation.ts) `gateProseNotation`, `gateProseNotationInAssessments` |
|
|
@@ -268,17 +274,18 @@ of to the settings file.
|
|
|
268
274
|
| [V4](visualizations.md#v4) | plot | Randomised figures expose an adjustable, deterministic seed | Guide |
|
|
269
275
|
| [V5](visualizations.md#v5) | plot | Axis ranges span the first 10 seeds at the current control values — settings: `seeds` = `10` | Guide |
|
|
270
276
|
| [V6](visualizations.md#v6) | plot | Every quantitative axis shows at least three labelled values — settings: `minLabels` = `3` | Guide |
|
|
271
|
-
| [V7](visualizations.md#v7) | plot | A figure’s picture fits on one screen — settings: `maxPercent` = `80` | Partial — `figure-too-tall` (warning) in [`figure-fit.ts`](../../src/reference/figure-fit.ts) `checkFigureFit`. review: any page or viewport the course’s Playwright suite does not open — the check runs in the browser, not in the build |
|
|
272
|
-
| [V8](visualizations.md#v8) | diagram | A diagram fits the lesson column — settings: `columnWidth` = `707` | Script — `dia-too-wide` (warning) in [`diagram-fit.ts`](../../src/reference/diagram-fit.ts) `oversizedDiagrams` |
|
|
277
|
+
| [V7](visualizations.md#v7) | plot | A figure’s picture fits on one screen _(chapter only)_ — settings: `maxPercent` = `80` | Partial — `figure-too-tall` (warning) in [`figure-fit.ts`](../../src/reference/figure-fit.ts) `checkFigureFit`. review: any page or viewport the course’s Playwright suite does not open — the check runs in the browser, not in the build |
|
|
278
|
+
| [V8](visualizations.md#v8) | diagram | A diagram fits the lesson column _(chapter only)_ — settings: `columnWidth` = `707` | Script — `dia-too-wide` (warning) in [`diagram-fit.ts`](../../src/reference/diagram-fit.ts) `oversizedDiagrams` |
|
|
273
279
|
| [C1](versioning.md#c1) | changelog | Every content change lands with a `content/CHANGELOG.md` entry | Guide |
|
|
274
280
|
| [C2](versioning.md#c2) | changelog | The knowledge version is semver over learning-facing content | Guide |
|
|
275
281
|
| [C3](versioning.md#c3) | changelog | `about.version` equals the newest changelog heading; a release moves both | Partial — `knowledge-version-mismatch` (warning), `knowledge-version-invalid` (warning), `knowledge-changelog-missing` (warning) in [`knowledge-version.ts`](../../src/compiler/knowledge-version.ts) `resolveKnowledgeVersion`. review: that the two edits landed in one commit — the build only ever sees the end state, so a release split across commits warns until the second half lands |
|
|
276
|
-
| [
|
|
282
|
+
| [C5](versioning.md#c5) | changelog | Each chapter and part page carries the release its content last changed in; `content/versions.json` is generated and committed | Partial — `page-versions-stale`, `page-versions-invalid` (warning) in [`page-versions.ts`](../../src/compiler/page-versions.ts) `syncPageVersions`, `readPageVersions`. review: which bullet of `## [Unreleased]` belongs to which page — every page changed while there is any bullet counts as not yet released; and a change to a lab, `content/domain/` or a part’s label, which changes the page’s PDF without changing its version |
|
|
283
|
+
| [S1](structure-rules.md#s1) | heading | No heading, short caption or short-note title over 65 characters _(chapter only)_ — settings: `maxLength` = `65` | Partial — `title-length` in [`gate-heading-length.ts`](../../src/reference/gate-heading-length.ts) `gateHeadingLength`. review: a lesson’s `frontmatter.title` — the gate scans the body only |
|
|
277
284
|
| [S2](structure-rules.md#s2) | part-page | A part page carries a `<PartBridge>` (earlier parts → this one) and a `<PartScope>` paragraph — settings: `bridgeMinWords` = `30`, `bridgeMaxWords` = `150`, `scopeMinWords` = `30`, `scopeMaxWords` = `150` | Partial — `part-page-paragraph` in [`gate-part-pages.ts`](../../src/reference/gate-part-pages.ts) `gatePartPages`. review: what each paragraph says — the gate cannot tell a bridge that links the parts from one that does not |
|
|
278
285
|
| [S3](structure-rules.md#s3) | table | A table is a `<Table id="…">`, never a raw Markdown/HTML table | Script — `raw-table-markdown` (warning), `raw-table-html` (warning) in [`raw-floats-validate.ts`](../../src/reference/raw-floats-validate.ts) `validateRawFloats` |
|
|
279
286
|
| [S4](structure-rules.md#s4) | diagram | A `<Diagram>` carries an `id` and sits where numbering can see it | Script — `diagram-unkeyed` (warning), `diagram-nested` (warning) in [`raw-floats-validate.ts`](../../src/reference/raw-floats-validate.ts) `validateRawFloats` |
|
|
280
|
-
| [S6](structure-rules.md#s6) | heading | Headings descend one level at a time, from `##` | Script — `heading-skip`, `heading-nested` in [`gate-heading-structure.ts`](../../src/reference/gate-heading-structure.ts) `gateHeadingStructure` |
|
|
281
|
-
| [S7](structure-rules.md#s7) | heading | A heading is followed by body content, never by another heading | Script — `heading-adjacent` in [`gate-heading-structure.ts`](../../src/reference/gate-heading-structure.ts) `gateHeadingStructure` |
|
|
287
|
+
| [S6](structure-rules.md#s6) | heading | Headings descend one level at a time, from `##` _(chapter only)_ | Script — `heading-skip`, `heading-nested` in [`gate-heading-structure.ts`](../../src/reference/gate-heading-structure.ts) `gateHeadingStructure` |
|
|
288
|
+
| [S7](structure-rules.md#s7) | heading | A heading is followed by body content, never by another heading _(chapter only)_ | Script — `heading-adjacent` in [`gate-heading-structure.ts`](../../src/reference/gate-heading-structure.ts) `gateHeadingStructure` |
|
|
282
289
|
| [S8](structure-rules.md#s8) | prose | Prefer `<Memo>` over a Starlight aside when the content needs an anchor, a caption or collapsing | Guide |
|
|
283
290
|
| [S9](structure-rules.md#s9) | plot, table, diagram | A float’s short caption names it; the long caption goes on from that name | Guide |
|
|
284
291
|
| [S10](structure-rules.md#s10) | part-page, plot, table, diagram, equation, notation | A page that is not a chapter explains its symbols but numbers nothing: it links a chapter’s float instead | **Locked** — a float needs a chapter number, and such a page has none — turning the rule off would not render one. Script — `non-chapter-float`, `non-chapter-local-notation`, `non-chapter-plain-text` in [`gate-non-chapter-pages.ts`](../../src/reference/gate-non-chapter-pages.ts) `gateNonChapterPages` |
|
|
@@ -291,6 +298,16 @@ of to the settings file.
|
|
|
291
298
|
| [P7](prose.md#p7) | prose | One claim per sentence; every logical link stated | Guide |
|
|
292
299
|
| [P8](prose.md#p8) | prose, math | Words for a relation match the math exactly ("proportional to") | Guide |
|
|
293
300
|
| [P9](prose.md#p9) | prose, equation | A display equation's lead-in says what it gives and where it comes from | Guide |
|
|
301
|
+
| [D1](deck.md#d1) | slide, heading | A deck is sections of frames: `##` a section, `###` a frame _(deck only)_ | **Locked** — a frame is the unit the deck page, Present mode and the PDF are built from — content outside one has no frame to show in. Script — `frame-depth`, `deck-loose-content`, `deck-empty` in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
302
|
+
| [D2](deck.md#d2) | slide | A frame fits its canvas in every step _(deck only)_ — settings: `maxWords` = `70`, `maxBullets` = `7` | Partial — `frame-dense` (warning), `frame-overflow` in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks`; [`deck-fit.ts`](../../src/compiler/exports/deck-fit.ts) `checkFrameFit`. review: the paper: a frame that fits its canvas on the web can still run over in the PDF, which the export reports as a warning naming the frame |
|
|
303
|
+
| [D3](deck.md#d3) | slide, prose | A frame makes one claim, and its title states it _(deck only)_ | Guide |
|
|
304
|
+
| [D4](deck.md#d4) | slide, prose | A frame with text carries speaker notes _(deck only)_ | Script — `frame-notes-missing` (warning) in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
305
|
+
| [D5](deck.md#d5) | slide, heading | A frame title fits one line _(deck only)_ — settings: `maxLength` = `50` | Script — `frame-title-length` in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
306
|
+
| [D6](deck.md#d6) | slide | A frame shows in at most `maxSteps` steps, each adding to the last _(deck only)_ — settings: `maxSteps` = `4` | Partial — `frame-steps` (warning) in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks`. review: that a later step contradicts nothing already shown |
|
|
307
|
+
| [D7](deck.md#d7) | slide, plot, table, diagram | A frame holds one figure, table or diagram _(deck only)_ | Script — `frame-floats` (warning) in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
308
|
+
| [D8](deck.md#d8) | slide, equation | Recall a chapter’s result; never retype it _(deck only)_ | Script — `frame-retyped` (warning) in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
309
|
+
| [D9](deck.md#d9) | slide, math, notation | A frame introduces at most `maxNewSymbols` symbols _(deck only)_ — settings: `maxNewSymbols` = `4` | Script — `frame-new-symbols` (info) in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
310
|
+
| [D10](deck.md#d10) | slide | A deck opens on its title and closes on what the student can now do _(deck only)_ | Guide |
|
|
294
311
|
|
|
295
312
|
_Element_ is what the rule is about; the first tag is primary. _Enforcement_ is
|
|
296
313
|
derived from the catalog: **Script** — every violation a check can see is
|
|
@@ -299,7 +316,9 @@ reported; **Partial** — checks exist and the rule says what they miss;
|
|
|
299
316
|
enforcement; **Locked** — the engine cannot run without it, so it has no
|
|
300
317
|
checkbox in the course settings. A `(warning)` / `(info)` code does not fail
|
|
301
318
|
the build. A rule with _settings_ takes them from `rules.<ID>` in the course
|
|
302
|
-
settings; the value shown is the default.
|
|
319
|
+
settings; the value shown is the default. A rule marked _chapter only_ or _deck
|
|
320
|
+
only_ is about one edition of a lesson ([deck.md](deck.md)); every other rule
|
|
321
|
+
holds for both.
|
|
303
322
|
|
|
304
323
|
A rule that has been retired is not listed here at all — see
|
|
305
324
|
[retired.md](retired.md).
|
|
@@ -320,5 +339,6 @@ next to the syntax it belongs to.
|
|
|
320
339
|
| [`content-schema`](structure.md#content-schemas) | notation, assessment, source, changelog | Every content file satisfies its collection’s schema. | `content-schema` in [`content-schema.ts`](../../src/compiler/content-schema.ts) `validateContentSchemas` |
|
|
321
340
|
| [`retired-keys`](structure.md#retired-keys) | changelog | No content file sets a key the engine has retired or cannot honour. | `retired-key`, `unsupported-key`, `ignored-key` (warning) in [`gate-retired-keys.ts`](../../src/reference/gate-retired-keys.ts) `findRetiredKeys`, `findUnsupportedKeys` |
|
|
322
341
|
| [`prop-text`](components.md#props-are-plain-text) | math, plot, diagram, table | A component’s quoted prop holds plain text, and prose holds no `{…}` expression. | `markup-in-prop`, `mdx-expression` in [`gate-prop-text.ts`](../../src/reference/gate-prop-text.ts) `findMarkupInProps`; [`gate-mdx-expression.ts`](../../src/reference/gate-mdx-expression.ts) `gateMdxExpressions` |
|
|
342
|
+
| [`decks`](deck.md#the-deck-file) | slide | A deck belongs to a lesson or a part, and recalls what its chapters number. _(deck only)_ | `deck-frontmatter`, `deck-outside-part`, `recall-unresolved`, `pause-invalid`, `deck-chapter-unknown`, `deck-chapter-repeated`, `deck-chapter-outside-part`, `deck-marker-misplaced`, `deck-check-no-chapter`, `deck-route-taken` in [`decks-validate.ts`](../../src/reference/decks-validate.ts) `validateDecks` |
|
|
323
343
|
|
|
324
344
|
<!-- RULES-INDEX:END -->
|
package/docs/authoring/agents.md
CHANGED
|
@@ -5,6 +5,13 @@ Guidance for an AI agent — or a person — editing a course repo built on
|
|
|
5
5
|
a repo-specific `AGENTS.md` at your course root for anything below that is
|
|
6
6
|
particular to your layout.
|
|
7
7
|
|
|
8
|
+
**Examples to start from.** Two working courses — the playground, which every
|
|
9
|
+
`playground/…` path in these docs refers to, and credit-and-derivatives, a full
|
|
10
|
+
course — are downloadable at their newest version from https://danieltuzes.github.io/explico/start/
|
|
11
|
+
(the playground at https://danieltuzes.github.io/explico/downloads/explico-playground-latest.zip;
|
|
12
|
+
[`sources.json`](https://danieltuzes.github.io/explico/downloads/sources.json) lists both, machine-readably). Download the
|
|
13
|
+
playground to see how a feature is wired before writing your own.
|
|
14
|
+
|
|
8
15
|
This is a guide, not a rule area. The enforceable rules are in
|
|
9
16
|
[`notation.md`](notation.md) (`N`), [`visualizations.md`](visualizations.md)
|
|
10
17
|
(`V`), [`versioning.md`](versioning.md) (`C`),
|
|
@@ -14,7 +21,10 @@ and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
|
14
21
|
|
|
15
22
|
## The loop
|
|
16
23
|
|
|
17
|
-
- **Read the rules in effect first
|
|
24
|
+
- **Read the rules in effect first, one rule at a time after that.**
|
|
25
|
+
`pnpm content rule <ID>` prints one rule whole: the entry as this course
|
|
26
|
+
has it and the page's own section with its example, about half a thousand
|
|
27
|
+
tokens. `pnpm --filter <course> content rules`
|
|
18
28
|
(or `build/rules-in-effect.md` after a `validate:content`) lists every rule
|
|
19
29
|
this course has *on*, grouped by the element it is about — prose, math,
|
|
20
30
|
equation, notation, heading, part-page, plot, diagram, table, assessment,
|
|
@@ -24,6 +34,9 @@ and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
|
24
34
|
checks and is therefore on you. Open a rule's page only when it is listed
|
|
25
35
|
there and you need the example. A rule that is not on the page is off for
|
|
26
36
|
this course (or does not exist): do not apply it, do not flag it in review.
|
|
37
|
+
For a deck, `content rules --edition deck` (or
|
|
38
|
+
`build/rules-in-effect-deck.md`) is the page: the `D` rules for frames, then
|
|
39
|
+
every rule a deck shares with a chapter ([deck.md](deck.md)).
|
|
27
40
|
A rule marked `waivable` there can be broken at one place with
|
|
28
41
|
`{/* explico-allow <ID>: <reason> */}` above the block — that is where the
|
|
29
42
|
reason for breaking a rule goes ([README.md § Waiving](README.md#waiving-a-rule-at-one-place)).
|
|
@@ -32,22 +45,53 @@ and a rule disagree, the engine wins — see [`README.md`](README.md).
|
|
|
32
45
|
and it is the one kind you may be asked to *add*
|
|
33
46
|
([README.md § Rules of your own](README.md#rules-of-your-own)) — never by
|
|
34
47
|
editing this folder.
|
|
35
|
-
- **Start from the CLI, not a file hunt.**
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
again; the second run is clean. `build/` is git-ignored — there is nothing
|
|
46
|
-
to commit from it.
|
|
47
|
-
- **Before handing work back:** `validate:content` (×2) → `astro check` →
|
|
48
|
+
- **Start from the CLI, not a file hunt.** Run it from the course package;
|
|
49
|
+
`pnpm content help` lists every verb, and every verb takes `--json` for the
|
|
50
|
+
whole report. Read what it prints before opening files. The table under
|
|
51
|
+
"The CLI" says which verb answers which question.
|
|
52
|
+
- **Validate once.** `pnpm --filter <course> validate:content` rewrites
|
|
53
|
+
`build/resolution/*` and passes on its first run; it fails only on a report
|
|
54
|
+
git tracks that it had to rewrite, so a course that commits `build/resolution/`
|
|
55
|
+
commits the rewritten files with the change, and a course whose `build/` is
|
|
56
|
+
git-ignored has nothing to commit from it.
|
|
57
|
+
- **Before handing work back:** `validate:content` → `astro check` →
|
|
48
58
|
`astro build`. `astro build` is the only step that runs every gate the CI
|
|
49
59
|
does.
|
|
50
60
|
|
|
61
|
+
## The CLI
|
|
62
|
+
|
|
63
|
+
The `content` CLI ships in the engine (`explico/compiler/cli-main`); a course's
|
|
64
|
+
`scripts/content.ts` is a three-line shim over it (migration step 14 of the
|
|
65
|
+
release that introduced it). Read-only except `new` and `init-agent`, and
|
|
66
|
+
`move`, `rename` and `fix`, which print a diff and change nothing without
|
|
67
|
+
`--write`.
|
|
68
|
+
|
|
69
|
+
| You want to know or do | Verb | It prints |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| how the course stands | `status` | counts, diagnostic totals, the agent surfaces' sizes, whether this file's procedures are installed |
|
|
72
|
+
| what is wrong, where | `diagnostics [info\|warning\|error]` | counts by code (with each code's rule) and by file; `--all`, `--code <c>`, `--lesson <id>`, `--changed` list the lines |
|
|
73
|
+
| what a lesson draws on | `context <lesson>` | its outcomes, notation, sources, diagnostics |
|
|
74
|
+
| which rules apply | `rules [--element …] [--enforcement guide]` | the rules this course has on, by element |
|
|
75
|
+
| one rule, whole | `rule <ID>` | the entry as this course has it and the page's section, example included |
|
|
76
|
+
| is this symbol defined already | `symbol <latex \| key>` | the shared card, each local entry with its lesson, each gloss with its card, near misses |
|
|
77
|
+
| will this expression build | `equation "<latex>" [--lesson <id>]` | each glyph's card, unresolved glyphs with where they are defined; exit 1 if the build would refuse it |
|
|
78
|
+
| what a lesson's math binds | `bindings <lesson>` | every span: bindings, unresolved glyphs, redundant `\explain` wraps |
|
|
79
|
+
| does it render | `check <lesson \| deck>… \| --changed` | schema, references, MDX → KaTeX; exit 1 on an error |
|
|
80
|
+
| what an upgrade needs | `migrate [--from <v>] [--to <v>]` | the migration guide's sections between two versions, oldest first |
|
|
81
|
+
| a local entry becomes shared | `move <lesson>:<key> [--to <key>] [--write]` | the new card and every copy and reference that changes, as a diff |
|
|
82
|
+
| rename a shared card | `rename <old> <new> [--write]` | the file and every reference, as a diff |
|
|
83
|
+
| the mechanical repairs | `fix <lesson> [--write]` | redundant `\explain` wraps unwrapped, as a diff |
|
|
84
|
+
| a draft to start from | `new lesson <id>`, `new deck <lesson \| part>`, `new term <key>` | the files it created; never overwrites |
|
|
85
|
+
| install these procedures | `init-agent [--write]` | the skills and the `rules-reviewer` agent copied into `.claude/`, a baseline `AGENTS.md` when the course has none |
|
|
86
|
+
|
|
87
|
+
The procedures — drafting a lesson, upgrading the engine, releasing the
|
|
88
|
+
course's content, reviewing a lesson against the guide-only rules — ship in
|
|
89
|
+
`node_modules/explico/docs/course-agent/`. `pnpm content init-agent --write`
|
|
90
|
+
installs them as project skills and a sub-agent; rerun it after an upgrade.
|
|
91
|
+
A course's own `AGENTS.md` should open by pointing here and then hold only
|
|
92
|
+
what is particular to the course; the shipped `docs/course-agent/AGENTS.md` is
|
|
93
|
+
that baseline, and `content status` says when the course file does not.
|
|
94
|
+
|
|
51
95
|
## Reading and running
|
|
52
96
|
|
|
53
97
|
- Grep for a symbol and open a line range; don't read a whole engine module out
|
|
@@ -150,8 +194,11 @@ then read the target package's
|
|
|
150
194
|
`node_modules/explico/docs/authoring/migrating.md`; the migration instructions
|
|
151
195
|
ship with the code they describe.
|
|
152
196
|
|
|
153
|
-
|
|
154
|
-
|
|
197
|
+
`pnpm content migrate` prints exactly the sections to apply, from the version
|
|
198
|
+
`package.json` pinned at HEAD to the one now installed, oldest first (`--from`
|
|
199
|
+
and `--to` override either end), and refuses when a section is missing; it is
|
|
200
|
+
the one or two sections an upgrade needs, not the whole forty-thousand-token
|
|
201
|
+
guide. Apply every section it prints. Follow required and conditional changes across `content/`,
|
|
155
202
|
`content/course.config.ts`, Astro/source wiring, course scripts, dependencies,
|
|
156
203
|
and generated files. Do not use `CHANGELOG.md` alone as the procedure and do not
|
|
157
204
|
assume that a release without a **Breaking** heading needs no work; each migration
|
|
@@ -376,6 +376,21 @@ sits outside the text flow, so the title keeps the whole line.
|
|
|
376
376
|
default) or `icon`, which leaves the corner label to the number and keeps
|
|
377
377
|
the word for a screen reader.
|
|
378
378
|
|
|
379
|
+
## In a deck
|
|
380
|
+
|
|
381
|
+
A lesson's deck, `<lesson>.deck.mdx` ([deck.md](deck.md)), has a few elements
|
|
382
|
+
of its own. None needs an import, and none works in a chapter's `.mdx`.
|
|
383
|
+
|
|
384
|
+
| Element | Notes | Doc |
|
|
385
|
+
| --- | --- | --- |
|
|
386
|
+
| `<Pause />` | A step: what follows appears on the next key press. `control`, `from`, `to` and `seconds` make the step move a lab's control instead; `highlight="key"` lights up a symbol | [deck.md § D6](deck.md#d6) |
|
|
387
|
+
| `<Notes>…</Notes>` | The frame's speaker notes: Markdown with math, terms and citations | [deck.md § D4](deck.md#d4) |
|
|
388
|
+
| `<Recall ref="eq-…" />` | The chapter's equation, figure (`fig-`), table (`tab-`) or diagram (`dia-`), with the chapter's number | [deck.md § D8](deck.md#d8) |
|
|
389
|
+
| `### Title [morph]` | The frame morphs from the one before, its shared symbols moving into place | [deck.md](deck.md) |
|
|
390
|
+
|
|
391
|
+
A question frame is a `###` frame holding `<AssessmentSet id="…" />` (imported
|
|
392
|
+
as in a chapter): the `id` picks one of the lesson's checks.
|
|
393
|
+
|
|
379
394
|
## Choosing between the "explain a term" options
|
|
380
395
|
|
|
381
396
|
From lightest to heaviest — pick the first one that's actually enough:
|