explico 0.11.1 → 0.13.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 +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +15 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +300 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +66 -8
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +14 -22
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +8 -10
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figure-symbols.ts +117 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +275 -23
- package/src/reference/render-lab-math.ts +40 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,1295 @@ under **Breaking** below; a PATCH never breaks.
|
|
|
14
14
|
|
|
15
15
|
## [Unreleased]
|
|
16
16
|
|
|
17
|
+
## [0.13.0] - 2026-10-07
|
|
18
|
+
|
|
19
|
+
### Breaking
|
|
20
|
+
|
|
21
|
+
- **A float's caption has no chain icon, and an equation's Copy LaTeX
|
|
22
|
+
button moved to its bottom border.** The toolbar on a float's number
|
|
23
|
+
(Added, below) copies the link instead. `a.float-caption__anchor` is gone
|
|
24
|
+
from `FloatCaption.astro` (figures, diagrams) and `Table.astro`, and
|
|
25
|
+
`button.keyed-equation__copy` is now a child of `.keyed-equation` rather
|
|
26
|
+
than of `.keyed-equation__controls`. Course CSS or browser tests that
|
|
27
|
+
target either need the new place: hover the number, then use
|
|
28
|
+
`a.float-toolbar__link` (it carries the same `data-copy-link` name).
|
|
29
|
+
|
|
30
|
+
- **A course with `lessonExports.standaloneHtml` on needs
|
|
31
|
+
`canonicalBaseUrl`** once its landing page or a part's page links anywhere
|
|
32
|
+
else in the course, which a splash hero's actions always do. Those pages
|
|
33
|
+
are exported now (below), and an exported page that links out without the
|
|
34
|
+
base fails the build, as a lesson always did. Set
|
|
35
|
+
`lessonExports.canonicalBaseUrl` to the deployed course root.
|
|
36
|
+
|
|
37
|
+
- **Astro 7.3, Starlight 0.42 and `@astrojs/react` 7.** The exact
|
|
38
|
+
`peerDependencies` pins move: `astro` 7.2.7 → 7.3.5, `@astrojs/starlight`
|
|
39
|
+
0.41.9 → 0.42.4, `@astrojs/react` 6.0.4 → 7.0.0 and
|
|
40
|
+
`@astrojs/markdown-remark` 7.2.4 → 7.3.1. A course moves the same four in
|
|
41
|
+
its own `package.json`, together: Starlight 0.42 requires `astro` 7.2.10
|
|
42
|
+
and `@astrojs/markdown-remark` 7.3.0 or later. What moved upstream that a
|
|
43
|
+
course can depend on:
|
|
44
|
+
- Starlight 0.42 drops support for browsers older than Chrome 116,
|
|
45
|
+
Safari 17 and Firefox 125.
|
|
46
|
+
- Its mobile menu is a `#starlight__sidebar` popover opened by a plain
|
|
47
|
+
`button.sl-menu-button`: the `<starlight-menu-button>` wrapper, its
|
|
48
|
+
`aria-expanded` and `body[data-mobile-menu-expanded]` are gone. Course
|
|
49
|
+
CSS or scripts that target them match nothing; use `.sl-menu-button`
|
|
50
|
+
and `:popover-open` (`body:has(#starlight__sidebar:popover-open)`).
|
|
51
|
+
- Starlight's unused top-level `tagline` option is removed (a splash
|
|
52
|
+
page's `hero.tagline` is unaffected).
|
|
53
|
+
- `@astrojs/react` 7 removes the `babel` option. A course that passes
|
|
54
|
+
`react({ babel: … })` moves those plugins to `@rolldown/plugin-babel`
|
|
55
|
+
in `vite.plugins`.
|
|
56
|
+
- `astro build` now prints `[WARN] [content] The collection "i18n" does
|
|
57
|
+
not exist or is empty` (twice). It is harmless: Starlight silences it
|
|
58
|
+
through `console.warn`, which Astro 7.3's logger no longer goes
|
|
59
|
+
through.
|
|
60
|
+
|
|
61
|
+
- **A page that is not a chapter no longer downloads on its own** (D8),
|
|
62
|
+
reversing the per-page downloads added earlier in this cycle (no release
|
|
63
|
+
wrote them, but a site deployed from `main` has): the build stops
|
|
64
|
+
writing `downloads/index.html` (the landing page),
|
|
65
|
+
`downloads/<part>/index.html` (a part's page), `downloads/glossary.html`,
|
|
66
|
+
`downloads/curriculum-map.html` and `downloads/figures-and-tables.html`.
|
|
67
|
+
Their content is in `downloads/part/<dir>.html` (a part's page, then its
|
|
68
|
+
chapters) and `downloads/course.html` (all of them). A link to one of the
|
|
69
|
+
old files now 404s; point it at the part's or the course's file. The
|
|
70
|
+
Download menu lists the scopes that contain the page: "This chapter" on a
|
|
71
|
+
chapter, "This part" on a chapter or its part's page, "Whole course" on
|
|
72
|
+
every page, each with the chapter's, part's or course's name; the course
|
|
73
|
+
file is saved under the course's name (`explico-playground-motion.html`).
|
|
74
|
+
A download's accessible name names its scope ("Download this chapter as
|
|
75
|
+
standalone HTML", "… this part …", "… the whole course …"). During
|
|
76
|
+
`astro dev` only a chapter's HTML builds on request.
|
|
77
|
+
|
|
78
|
+
- **`editorialStatus` is retired.** Lessons are reviewed continuously, so
|
|
79
|
+
the draft / in-review / reviewed flag never meant a page was finished; it
|
|
80
|
+
only put a label in front of readers. No collection reads it now and
|
|
81
|
+
nothing shows it: the part page's chapter list, the notation card, the
|
|
82
|
+
glossary entry, the reference list and the citation card lose their
|
|
83
|
+
status label. What a course changes:
|
|
84
|
+
- **Delete the key from every content file.** A page, notation entry,
|
|
85
|
+
abbreviation, competency, assessment, source or track that still sets
|
|
86
|
+
it fails the build with `retired-key`, once per file, with the file and
|
|
87
|
+
line. The check is the new `retired-keys` invariant
|
|
88
|
+
(`reference/gate-retired-keys.ts`), reported under `curriculum` so a
|
|
89
|
+
course's own `validate:content` script fails on it unchanged. In a JSON
|
|
90
|
+
record the key is often the last one, so deleting its line leaves a
|
|
91
|
+
trailing comma.
|
|
92
|
+
- **The manifest schema is now v29**: `lessons[].status`, the
|
|
93
|
+
`editorialStatus` of the notation definitions under `lessons[]` and
|
|
94
|
+
`pages[]`, and the `status` of `notation.definitions[]` and
|
|
95
|
+
`notation.bundles[]` are removed.
|
|
96
|
+
- **The `content` CLI:** `content status` no longer counts drafts
|
|
97
|
+
(`--json` loses `draftDebt`), `content context` loses `lesson.status`,
|
|
98
|
+
and `content new lesson` / `content new term` no longer write the key.
|
|
99
|
+
A course's own `scripts/content.ts` that prints `report.draftDebt` or
|
|
100
|
+
`report.lesson.status` must stop: `tsx` does not type-check, so
|
|
101
|
+
`report.draftDebt.lessons` throws at run time.
|
|
102
|
+
- **Diagnostic codes:** `review-state` and `alignment-review-state` are
|
|
103
|
+
removed with the checks that compared review states. The unrelated
|
|
104
|
+
check that shared `review-state`, a lesson that `teaches` but declares
|
|
105
|
+
no `assumptions`, now reports `missing-assumptions`.
|
|
106
|
+
- **Exports:** `EditorialStatus` and the `status` field of
|
|
107
|
+
`SharedNotationDefinitionInput`, `NotationLessonInput`, the notation
|
|
108
|
+
definition records and `NotationPageBundle` (`explico/reference/types`);
|
|
109
|
+
`LessonDefinition.status` and `SourceDefinition.editorialStatus`
|
|
110
|
+
(`explico/curriculum/validation`); the per-definition `editorialStatus`
|
|
111
|
+
of `NotationLayer`. A course test that builds these inputs drops
|
|
112
|
+
`status`.
|
|
113
|
+
- **CSS hooks:** `.notation-status`, `.glossary-status`,
|
|
114
|
+
`.citation-status` and `.citation-panel-status` no longer exist, and a
|
|
115
|
+
glossary entry's header has two columns, not three.
|
|
116
|
+
|
|
117
|
+
- **`estimateBoxSize` is gone from `explico/reference/diagram-layout`.**
|
|
118
|
+
Diagram boxes are measured now (Changed, below); `nodeBoxSize` takes the
|
|
119
|
+
label and the formula's measured box (`measureFormula`) in its place.
|
|
120
|
+
- **A quoted prop holding `$…$`, `[[…]]` or `[@…]` fails
|
|
121
|
+
`validate:content`** (`markup-in-prop`, invariant `prop-text`). A prop
|
|
122
|
+
reaches the page as plain text, so `short="Speed $v$"` showed its dollars
|
|
123
|
+
in the caption line, the preview card and the "Figures and tables" page,
|
|
124
|
+
and a `[[…]]` or `[@…]` printed as typed; meanwhile the math gate demanded
|
|
125
|
+
a notation entry for the symbol. Write a symbol in a prop in Unicode or
|
|
126
|
+
words, and reference or cite from the prose next to the component. The
|
|
127
|
+
math gates no longer read prop strings. None of the four courses on the
|
|
128
|
+
maintainer's machine has such a prop.
|
|
129
|
+
- **A second `\label{eq:…}` in one display block fails `validate:content`**
|
|
130
|
+
(`eq-label-repeated`). A `$$…$$` block is one numbered equation: only its
|
|
131
|
+
first label named it, and a `[[eq-…]]` to a later one failed with "no
|
|
132
|
+
display equation on the page carries" a label the block visibly holds.
|
|
133
|
+
Give each equation you refer to its own block.
|
|
134
|
+
- **A notation key that starts with a reference prefix fails where it is
|
|
135
|
+
defined.** `[[eq-…]]`, `[[tab-…]]`, `[[fig-…]]`, `[[dia-…]]`, `[[ex-…]]`,
|
|
136
|
+
`[[check-…]]`, `[[sec-…]]` and `[[memo-…]]` are routed by prefix before
|
|
137
|
+
notation keys are looked at, so an entry keyed `ex-ante` or `eq-fake` could
|
|
138
|
+
never be referenced, and its use failed with a float error that never said
|
|
139
|
+
the key was a notation entry. The registry now reports `invalid-key` at
|
|
140
|
+
the definition, naming the prefixes, and `content new term` refuses such
|
|
141
|
+
a key. None of the four courses on the maintainer's machine has one.
|
|
142
|
+
- **A worked-example set or a knowledge check inside a memo or a short
|
|
143
|
+
note fails rule S6** (`heading-nested`). Its own `<h2>` landed under the
|
|
144
|
+
memo's `<h6>`, the heading order jumped, and "On this page" never listed
|
|
145
|
+
it, with no diagnostic. None of the courses on the maintainer's machine
|
|
146
|
+
has one.
|
|
147
|
+
- **A `<Table>` holding two tables fails `validate:content`**
|
|
148
|
+
(`tab-several-tables`). The page showed both under one number and
|
|
149
|
+
caption, and the PDF, LaTeX and Markdown exports kept only the first,
|
|
150
|
+
silently. None of the courses on the maintainer's machine has one.
|
|
151
|
+
- **A citation in a link's text fails `validate:content`**
|
|
152
|
+
(`citation-in-link`). `[as measured in [@id]](https://…)` printed the
|
|
153
|
+
citation as typed on the page and in every export, while the manifest
|
|
154
|
+
counted the source as cited. The lesson's sources are now read the way
|
|
155
|
+
the page reads them, and the message says to cite after the link. None of
|
|
156
|
+
the courses on the maintainer's machine has one.
|
|
157
|
+
- **Rule N23: an index is part of the symbol**
|
|
158
|
+
(`docs/authoring/notation.md#n23`). A subscript on a symbol must be
|
|
159
|
+
explained by the indexed symbol's own entry (`latex: v_0`), a family entry
|
|
160
|
+
whose index runs (`latex: x_k` explains `x_1`, `x_{k+1}`), or an index entry
|
|
161
|
+
for the subscript (`latex: "{}_0"`, Added below); a card on the base alone
|
|
162
|
+
no longer passes. Arithmetic on an index letter with its own card passes
|
|
163
|
+
(`X_{t-1}`), and a subscript on an operator or a bracket is not an index
|
|
164
|
+
(`\sum_{i=1}`). `validate:content` fails with four errors
|
|
165
|
+
(`gate-indices.ts`), in a lesson body located and once per form per page
|
|
166
|
+
(per letter for `index-range`), in a shared formula once per formula:
|
|
167
|
+
`index-explained` (a digit, a label or a base-library `i`, `e`, `d`
|
|
168
|
+
explained by nothing), `index-swallowed` (`\explain{key}{v_x}` where `key`'s
|
|
169
|
+
`latex` has no index), `index-range` (a running index — a lowercase letter
|
|
170
|
+
not marked `fixedIndex` — whose set is stated neither as `range` on its card
|
|
171
|
+
or its family entry nor after a `\quad` on the first display line that uses
|
|
172
|
+
it) and `derived-key-taken`. Notation formulas and assessments get the first
|
|
173
|
+
two from `validate:content` too; lab math (`renderLabMath`) and `<Diagram>`
|
|
174
|
+
formulas fail `astro build` with the same findings as they render. A course
|
|
175
|
+
fixes each form, or waives one place in a lesson body with `{/*
|
|
176
|
+
explico-allow N23: <reason> */}`; `rules.N23.enabled: false` turns all of it
|
|
177
|
+
off. `docs/authoring/migrating.md` has the one-pass migration.
|
|
178
|
+
- **An indexed entry no longer lends its card to other symbols** (rule N4).
|
|
179
|
+
An entry with a fixed index — digits or a `\mathrm{…}` label, `v_0`,
|
|
180
|
+
`H_0`, `T_{\mathrm{opt}}` — lent its card to the bare base and to every
|
|
181
|
+
other index: `H_1` opened "Null hypothesis". It lends to nothing now. A
|
|
182
|
+
family entry (`\alpha_i`) lent its card to the bare symbol (`\alpha`, a
|
|
183
|
+
different object); it lends only to its own instances now. A function form
|
|
184
|
+
still lends by its head: `D(0,t)` explains a bare `D`, and `V_0(1_t)`
|
|
185
|
+
explains `V_0(1_2)` but no longer a bare `V`. A symbol that had a card only
|
|
186
|
+
by borrowing one fails `unresolved-glyph`, and the message names the
|
|
187
|
+
indexed entry with that base: give it its own entry, or an
|
|
188
|
+
`\explain{key}{\alpha}` where it really is the family's shorthand. An
|
|
189
|
+
entry with a superscript only (`j^{(m)}`) still lends to its base.
|
|
190
|
+
- **The manifest schema is now v31 (additive)**: the `notation` bundle of
|
|
191
|
+
`lessons[]` and `pages[]` gains `derived`, the derived cards (Added below)
|
|
192
|
+
its body math uses; a notation definition record carries `reads`, `range`,
|
|
193
|
+
`fixedIndex` and an index entry's `formulaTemplate` when they are set; a
|
|
194
|
+
bundle definition carries `range`. `diagnostics.math` carries the N23
|
|
195
|
+
codes.
|
|
196
|
+
- **`resolveMathGlyphs` resolves an indexed symbol differently**, which
|
|
197
|
+
changes a card a reader sees without a content edit; a course records it
|
|
198
|
+
in its own changelog (rule C1). Under a power or a mark, a whole form
|
|
199
|
+
still wins (`v_0^{2}` is `v_0` squared; Fixed, below). An instance takes
|
|
200
|
+
its family's card ahead of a plain entry for its base (`x_1` opens the
|
|
201
|
+
`x_k` card, not the `x` card), through a font-styled family too
|
|
202
|
+
(`\mathbf{v}_k` explains `\mathbf{v}_1`), and only through a family whose
|
|
203
|
+
index has the same shape — the same number of comma-separated slots, and
|
|
204
|
+
no fixed label in a running slot (`x_{\mathrm{e}}` is not an instance of
|
|
205
|
+
`x_k`). The whole instance is one target. Two families on one base that
|
|
206
|
+
both fit an instance fail `ambiguous-base-fallback`, as two lending
|
|
207
|
+
entries did before.
|
|
208
|
+
- **Rule S5 is retired into rule N4, and `CourseConfig.conventions` is no
|
|
209
|
+
longer read.** Its check (`convention-single-definition`) matched one
|
|
210
|
+
finance course's wording and one key per course, and never fired in any
|
|
211
|
+
course. A `conventions` block now does nothing and warns
|
|
212
|
+
`config-deprecated-key`; the type keeps it as a deprecated `unknown` until
|
|
213
|
+
the next MINOR. `CourseConventions` is gone, and `runConsistencyChecks`
|
|
214
|
+
no longer takes `catalog` or `conventions`. Rule N4 says how to write a
|
|
215
|
+
convention instead: on its notation entry, `meaning` names the other
|
|
216
|
+
choice and the body says how to convert.
|
|
217
|
+
|
|
218
|
+
### Added
|
|
219
|
+
|
|
220
|
+
- **A toolbar on every float's number.** Hovering or focusing the number of
|
|
221
|
+
an equation, a figure, a table or a diagram shows Pin and Dock just above
|
|
222
|
+
it and Copy link just below it, none of them over the number. Pin and
|
|
223
|
+
Dock keep the float's own reference card, pinned next to the float or
|
|
224
|
+
docked beside the article; Copy link copies the float's named link, as
|
|
225
|
+
the chain icon did. A click on the number itself still only puts its
|
|
226
|
+
anchor in the address bar. An equation's Copy LaTeX sits on its bottom
|
|
227
|
+
border, under the number, or slid along the border in an equation too
|
|
228
|
+
short for both, and shows while the equation is hovered. A touch screen
|
|
229
|
+
has no toolbar. The toolbar is `components/float-toolbar.ts`; it opens
|
|
230
|
+
the card through the new `keepCardFor(layer, anchor, mode)` in
|
|
231
|
+
`card-manager.ts`, and a card source can name an item's own anchor
|
|
232
|
+
(`CardSource.ownAnchor`), so a card pinned from a number comes back after
|
|
233
|
+
a reload like any kept card.
|
|
234
|
+
|
|
235
|
+
- **A docked card widens from its right edge, and a width menu sizes
|
|
236
|
+
them all.** A card beside the article has a handle along its right edge:
|
|
237
|
+
drag it, or focus it and use the arrow keys (Shift for bigger steps);
|
|
238
|
+
Home or a double click gives the card back the column's width. It may
|
|
239
|
+
reach past the "On this page" rail: the rail then goes under the cards
|
|
240
|
+
(`data-card-over-rail` on `<html>`), and its `>>>` collapses it. Once a
|
|
241
|
+
reader has resized a card, a width menu joins the switch at the top of
|
|
242
|
+
the side column: Default, Wide (65 characters a line) or Very wide (90),
|
|
243
|
+
counted in the card's own text so they follow the text size; it lists a
|
|
244
|
+
size only when it fits beside the article with both panels collapsed. A
|
|
245
|
+
size applies to every docked card and the next ones; a card resized by
|
|
246
|
+
hand reads "Custom". The width is remembered with the card, and the
|
|
247
|
+
size per reader (`card-side.ts`, `card-manager.ts`, `HoverPanel.astro`,
|
|
248
|
+
`card-memory.ts`).
|
|
249
|
+
- **A lab's picture is in the built page, or the build says so** (rule
|
|
250
|
+
V3). A lab draws its plot in the browser, after the page loads; until
|
|
251
|
+
then the page held an empty box, so a reference card from another page,
|
|
252
|
+
print without JavaScript and the HTML export had no picture. The lab's
|
|
253
|
+
wrapper now draws its default picture at build time and hands it to the
|
|
254
|
+
island as children, which the island shows until it has drawn its own
|
|
255
|
+
(the playground's `content/labs/still-plot.ts` shows the pattern). The
|
|
256
|
+
build warns about a figure whose picture is an island with nothing drawn
|
|
257
|
+
in the built page: `lab-picture-undrawn`, a warning
|
|
258
|
+
(`reference/figure-pictures.ts`, run by `compiler/astro.ts`). A reference
|
|
259
|
+
card copies the build's picture until the island has drawn
|
|
260
|
+
(`FloatRefLayer.astro`, `cloneFigureBody`, which used to drop an
|
|
261
|
+
island's children), and `global.css` hides it the moment the live plot
|
|
262
|
+
in `.lab-chart-live` exists.
|
|
263
|
+
|
|
264
|
+
- **A text size on touch screens**: 100%, 90%, 80% or 70%, beside the
|
|
265
|
+
theme switch in the phone menu (and in the header of a tablet held wide).
|
|
266
|
+
A PC has the browser's zoom; a phone's text-size settings are buried in
|
|
267
|
+
its browser's menus. The choice scales the root font size
|
|
268
|
+
(`data-text-size` on `<html>`, `styles/global.css`), so the text, the
|
|
269
|
+
math, the spacing and the cards follow; it is remembered per reader and
|
|
270
|
+
applied before the page first paints, by an inline script that
|
|
271
|
+
`PreferenceStore.ts` builds (`inlineRootAttributeScript`), so storage is
|
|
272
|
+
still touched in that file alone. It shows only where there is no hover,
|
|
273
|
+
never in print, and a card's text keeps a 12 px floor
|
|
274
|
+
(`TextSizeControl.astro`, rendered by `LayoutSocialIcons.astro`, which a
|
|
275
|
+
course already wires as its `SocialIcons` override).
|
|
276
|
+
|
|
277
|
+
- **Carried cards stay on screen** (rules K2–K4). With carrying on, a kept
|
|
278
|
+
card — pinned, docked or moved — scrolls with its trigger until it
|
|
279
|
+
reaches the top edge of the window (under the header, and in the side
|
|
280
|
+
column under its controls row) or the bottom edge, then stays there,
|
|
281
|
+
and follows its trigger again once its place comes back. Cards at one
|
|
282
|
+
edge stack outward from it in the order they were opened, only those
|
|
283
|
+
over each other; when the cards held over each other are taller than the
|
|
284
|
+
window, the older ones collapse to their header row, and a click or the
|
|
285
|
+
keyboard's focus opens one again. A card opened from inside a held card
|
|
286
|
+
moves with it. `heldAt` in `card-placement.ts` is the rule, pure; the
|
|
287
|
+
card manager fixes a held card at its edge (`data-card-held="top"` or
|
|
288
|
+
`"bottom"`, `data-card-collapsed`) from one scroll listener, on only
|
|
289
|
+
while carrying is on and a card is kept. A held card does not print.
|
|
290
|
+
|
|
291
|
+
- **A "Carry cards" switch** (K1, D6–D8). It joins "Article left" in
|
|
292
|
+
the side column's controls row while the column is in use; otherwise it
|
|
293
|
+
shows alone at the article's top right, while a card is kept. Its
|
|
294
|
+
tooltip says what it does. It is off until a reader turns it on, and the
|
|
295
|
+
reader's choice is remembered (`card-carry.ts`, through
|
|
296
|
+
`PreferenceStore`). A course can start every reader with it on: the new
|
|
297
|
+
`cards.carry` course setting (`CourseConfig.cards`, `normalizeCards`),
|
|
298
|
+
default `false`. The manifest schema is now v26: `cards`, the course's
|
|
299
|
+
card settings with the defaults applied, which `LessonFooter.astro`
|
|
300
|
+
hands the page in a hidden `[data-explico-card-config]` element.
|
|
301
|
+
|
|
302
|
+
- **Carried cards come along to every page of the course** (K5, D9):
|
|
303
|
+
by a link, the sidebar, search, Next and Previous, Back and Forward, a
|
|
304
|
+
reload or a typed address. On the page a card was opened on it attaches
|
|
305
|
+
to its trigger again, at its place; anywhere else it is rebuilt from that
|
|
306
|
+
page, fetched once, and held at the window edge it was at, at the same
|
|
307
|
+
place across the window. A figure card brings its plot as it was drawn.
|
|
308
|
+
Closing a card ends its journey; turning carrying off closes the cards
|
|
309
|
+
from other pages. Each tab keeps its own carried set in session storage,
|
|
310
|
+
and every change also writes it as the course's last set in local
|
|
311
|
+
storage, which a tab with no set of its own (a new tab, a browser
|
|
312
|
+
restarted without its tabs) takes. A page the browser brings back from
|
|
313
|
+
its cache takes the set as another page left it. While cards from other
|
|
314
|
+
pages sit on the bottom edge, the page grows by their height, so its
|
|
315
|
+
Next and Previous links scroll clear of them. Card memory per page rests
|
|
316
|
+
while carrying is on. New: `CardSource.build(item, page)` and
|
|
317
|
+
`CardSource.awayItem(item, page)` in `card-manager.ts`, which every card
|
|
318
|
+
layer implements; `card-fetch.ts`, the fetch-once page cache that
|
|
319
|
+
`FloatRefLayer.astro` kept to itself until now; the carried set's
|
|
320
|
+
decoder in `card-carry.ts`; and `createSessionPreferenceStore` in
|
|
321
|
+
`PreferenceStore.ts`, still the one module that touches browser storage.
|
|
322
|
+
|
|
323
|
+
- **A page's own symbol, carried, says where it means what it says**
|
|
324
|
+
(K6, D4). Away from its page, its card opens with "Defined in
|
|
325
|
+
*‹page title›* · means this only there", and its definition link goes
|
|
326
|
+
back to that page. When the reader points at a symbol on the new page
|
|
327
|
+
whose notation entry has the same LaTeX, the carried card's arrow to it
|
|
328
|
+
is dashed and grey: the same letters, defined elsewhere. A shared
|
|
329
|
+
symbol's arrow to the same symbol on another page stays solid, and
|
|
330
|
+
pointing at a carried card shows the nearest such place on the page.
|
|
331
|
+
Notation entries carry `data-notation-scope` and `data-notation-latex`,
|
|
332
|
+
a notation card `data-card-scope` and `data-card-glyph`; a source tells
|
|
333
|
+
the manager a trigger's glyph (`CardSource.glyphOf`) and the triggers
|
|
334
|
+
with a glyph (`CardSource.lookalikes`), and the arrow overlay draws the
|
|
335
|
+
dashed kind (`ArrowOverlay.show(…, { lookalike: true })`,
|
|
336
|
+
`.explico-card-arrow.is-lookalike`).
|
|
337
|
+
|
|
338
|
+
- **With carrying on, every kept card links back to where it was opened**
|
|
339
|
+
(K7, D15): "Opened at § 2.1.1" beside its "Go to …", or "Opened at
|
|
340
|
+
(2.1.3)" when it was opened from inside a numbered equation, the worked
|
|
341
|
+
example or knowledge check it was in ("Opened at Example 1.2.1"), or
|
|
342
|
+
"Opened at the start" before a page's first section. A fold's bar and a
|
|
343
|
+
memo are no sections. With carrying off, a kept card stays by its
|
|
344
|
+
trigger and shows no such link. Its arrow says where that is (↑ ↓
|
|
345
|
+
on this page, → on another), and its tooltip says it in full: "Back to
|
|
346
|
+
where you opened this card: Projectile Range, § 2.1.1 From launch to
|
|
347
|
+
landing". The link is the section's or the equation's anchor, so it works
|
|
348
|
+
in a new tab and without JavaScript; with it, the page scrolls to the
|
|
349
|
+
trigger itself and lights it a moment (`.is-card-origin`), after loading
|
|
350
|
+
when the card was opened on another page. A card opened from inside
|
|
351
|
+
another goes back to where the outermost one was opened. The link is an
|
|
352
|
+
`a.hover-panel-action[data-card-opened-at]` the card manager adds; where
|
|
353
|
+
a card was opened travels in the carried set.
|
|
354
|
+
|
|
355
|
+
- **A carried card says whether it means the same everywhere** (K8,
|
|
356
|
+
plan §4). While carrying is on, a kept card shows, at the left of its
|
|
357
|
+
header's buttons, a globe — shared notation, citations, abbreviations,
|
|
358
|
+
numbered references — or a page and "this page", for one of a page's own
|
|
359
|
+
symbols; its tooltip says which. `HoverPanel.astro` renders the mark
|
|
360
|
+
(`[data-card-mark="global"|"page"]`), hidden until the manager shows it.
|
|
361
|
+
|
|
362
|
+
- **LaTeX source and PDF of every chapter** (`lessonExports.latex`). After
|
|
363
|
+
Astro's static build, each chapter's LaTeX folder is zipped to
|
|
364
|
+
`downloads/<slug>-latex.zip`: `main.tex`, explico's book class
|
|
365
|
+
`explico.cls`, the chapter as readable source (named environments for
|
|
366
|
+
memos, short notes, worked examples and knowledge checks; `\label` and
|
|
367
|
+
`\ref` for every cross-reference; the author's `\explain` markers kept
|
|
368
|
+
in the math, printed by the class), its figures, a `latexmkrc` and a
|
|
369
|
+
README. The same folder is compiled with `latexmk` to
|
|
370
|
+
`downloads/<slug>.pdf`, a tagged PDF 2.0 with each chapter's answer key
|
|
371
|
+
at its end. Under LuaLaTeX it is PDF/UA-2 with MathML for every formula
|
|
372
|
+
(veraPDF passes every playground chapter); pdfLaTeX tags less (no
|
|
373
|
+
MathML, table rules untagged, a box broken across pages leaves its
|
|
374
|
+
marked content unbalanced, which poppler reports as "Mismatched EMC
|
|
375
|
+
operator"), so its PDF claims no standard.
|
|
376
|
+
- **Numbers are LaTeX's own.** The class counts parts, chapters,
|
|
377
|
+
sections, equations, floats, worked examples and knowledge checks the
|
|
378
|
+
way the website does, so an edited download renumbers itself. When the
|
|
379
|
+
source is compiled unchanged, every printed number is checked against
|
|
380
|
+
the website's, and a difference fails the build.
|
|
381
|
+
- **Figures stay vector.** A lab or other figure a browser draws is
|
|
382
|
+
captured from the finished site with the course's own Playwright
|
|
383
|
+
Chromium and included as a vector PDF, its caption's live clause
|
|
384
|
+
filled in. explico's `<Diagram>` is drawn as TikZ from the layout Dagre
|
|
385
|
+
gave it, so LaTeX sets its text and math.
|
|
386
|
+
- **A float inside a memo or a worked example** is set where it stands
|
|
387
|
+
with the `float` package's `[H]` (`ExplicoHere` in `explico.cls`), so
|
|
388
|
+
tagging gives the float its own caption. The minipage and `\captionof`
|
|
389
|
+
used before passed PDF/UA-2 under TeX Live 2025, but TeX Live 2026 tags
|
|
390
|
+
the minipage as a Div, which leaves the caption mid-way through the
|
|
391
|
+
box's text (veraPDF, ISO 14289-2 rule 8.2.5.27). Without `float` the
|
|
392
|
+
class falls back to the minipage. CI needs `float` in its TeX Live
|
|
393
|
+
packages.
|
|
394
|
+
- **Reproducible.** The same source compiles to the same bytes, and two
|
|
395
|
+
builds write identical downloads. `main.tex` fixes TeX's random seed
|
|
396
|
+
before tagging loads (tagpdf names a structure namespace with random
|
|
397
|
+
digits) and sets the PDF's file identifier, which the engines would
|
|
398
|
+
derive from the output file's path; a captured figure's PDF carries the
|
|
399
|
+
course's content date, not the moment Chromium printed it. A figure's
|
|
400
|
+
alt text keeps its punctuation (`45°, where`), which its braces
|
|
401
|
+
protect.
|
|
402
|
+
- **Figure labels match the book.** A captured figure's SVG labels are
|
|
403
|
+
set in KaTeX's Computer Modern, which explico's stylesheet loads on
|
|
404
|
+
every page, so any machine draws the same figure, and they are sized
|
|
405
|
+
so the most common one prints at 9 pt (`\footnotesize`) once LaTeX
|
|
406
|
+
fits the figure to the page. An Observable Plot axis title moves clear
|
|
407
|
+
of its grown tick labels; no label grows into another. A figure that
|
|
408
|
+
still draws text in one of the machine's fonts is named in a warning.
|
|
409
|
+
- **Engine.** LuaLaTeX by default (TeX Live 2025 or later);
|
|
410
|
+
`EXPLICO_LATEX_ENGINE=pdflatex` switches to pdfLaTeX. In CI (`CI` set)
|
|
411
|
+
or with `EXPLICO_LATEX_STRICT=1`, a missing engine or browser fails the
|
|
412
|
+
build; elsewhere the build warns, still writes the source zips, and
|
|
413
|
+
leaves an uncaptured figure as a placeholder. explico ships the TeX
|
|
414
|
+
Live package list as `src/compiler/exports/latex/texlive-packages.txt`.
|
|
415
|
+
- `lessonExports.latexPaper` sets the paper size: `letter` (default,
|
|
416
|
+
LaTeX's own) or `a4`.
|
|
417
|
+
- **Each part and the course as a book** (plan step 6):
|
|
418
|
+
`downloads/part/<dir>-latex.zip` and `.pdf`, `downloads/course-latex.zip`
|
|
419
|
+
and `.pdf` (`bookSource`), with cells in the Download menu. A title page
|
|
420
|
+
from About (the course or part, the content version, the authors, the
|
|
421
|
+
website), the contents (parts, chapters, sections) and the lists of
|
|
422
|
+
figures, tables and diagrams that have entries; then each part, opening
|
|
423
|
+
on its own page (`\ExplicoPart`, numbered as on the website) followed by
|
|
424
|
+
its page's text and objectives, and its chapters in order; then the
|
|
425
|
+
appendices: the book's notation, in order of first appearance (a symbol
|
|
426
|
+
one chapter defines says so), and the course's abbreviations. A
|
|
427
|
+
reference between chapters is a `\ref`; each chapter keeps its own
|
|
428
|
+
reference list, numbered as on its page, its citation keys prefixed with
|
|
429
|
+
the chapter; its notation is in the appendix, and under its title only
|
|
430
|
+
the link to its live version. Every number in a book is checked against
|
|
431
|
+
the website. Contents and lists are black, their number columns wide
|
|
432
|
+
enough for `2.1` and `2.1.10`.
|
|
433
|
+
- **Every document compiles at once**, up to one per core. On the
|
|
434
|
+
playground's 8 cores the LaTeX step takes 31 s for its 7 documents, where
|
|
435
|
+
the 4 chapters alone took about 55 s one after another; the books add
|
|
436
|
+
79 s of compile time (parts 48 s, course 31 s), and the course book sets
|
|
437
|
+
the wall time. The build logs these times.
|
|
438
|
+
- **The manifest schema is now v27**: `lessonExports.latex` and
|
|
439
|
+
`lessonExports.latexPaper`, and every `assessmentContent` item carries
|
|
440
|
+
its `type`, a choice item's `options` and `correctOptionId`, and a
|
|
441
|
+
numeric item's `answer`.
|
|
442
|
+
- **Every part and the whole course download as one offline HTML file**
|
|
443
|
+
(`lessonExports.standaloneHtml`; `compiler/exports/combined-html.ts`):
|
|
444
|
+
`downloads/part/<dir>.html` is the part's page, then its chapters;
|
|
445
|
+
`downloads/course.html` is the landing page, the curriculum map, the
|
|
446
|
+
figures and tables, every part and the glossary last. Each opens with a
|
|
447
|
+
list of contents. They are assembled from the pages the build wrote, not
|
|
448
|
+
rendered again, so each page keeps its own notation, citation and
|
|
449
|
+
float-reference cards, labs and checks. Every id in a page gains the page
|
|
450
|
+
as a suffix (`eq-range--projectiles-projectile-range`), with every
|
|
451
|
+
reference to it (links, ARIA id lists, `for`, `popovertarget`,
|
|
452
|
+
`url(#…)`); a suffix keeps the `eq-`, `fig-` and `cite-` prefixes the card
|
|
453
|
+
layers read. A link to another page of the same file becomes a link into
|
|
454
|
+
it, so its hover preview works offline. A React island whose `prefix`
|
|
455
|
+
an earlier page used gets its own, with the ids React renders from it, so
|
|
456
|
+
hydration matches. Each page is a section with `content-visibility: auto`
|
|
457
|
+
and starts a new sheet when printed.
|
|
458
|
+
- The notation layers of a page share one card source, so a document
|
|
459
|
+
with several (each page's) serves every page's symbols; a citation
|
|
460
|
+
card finds its reference through the marker's link instead of building
|
|
461
|
+
`#cite-<n>`, so a file with several reference lists numbered from 1
|
|
462
|
+
shows the right one. A kept citation card is remembered by its
|
|
463
|
+
reference-list item, not its number.
|
|
464
|
+
- The print controller moved out of the header into the page's footer
|
|
465
|
+
(`PrintController.astro`, `print-controller.ts`), inside `<main>`: a
|
|
466
|
+
downloaded page keeps only `<main>`, and lost Ctrl+P's lab loading with
|
|
467
|
+
the header.
|
|
468
|
+
- **Markdown of every chapter, part and the course** (`lessonExports.markdown`;
|
|
469
|
+
`compiler/exports/markdown-export.ts`, `markdown/serialize.ts`), built with
|
|
470
|
+
the site (D2) from the same reading trees as the LaTeX export:
|
|
471
|
+
`downloads/<slug>-markdown.zip` holds `<name>-markdown/lesson.md` and its
|
|
472
|
+
`assets/`; `downloads/part/<dir>-markdown.zip` an `index.md` (the part's
|
|
473
|
+
page, then its contents) and one file per chapter
|
|
474
|
+
(`02-01-projectile-range.md`); `downloads/course-markdown.zip` an
|
|
475
|
+
`index.md`, each part's page and every chapter, with shared `assets/` and
|
|
476
|
+
relative links between the files. The Download menu gains a Markdown
|
|
477
|
+
column.
|
|
478
|
+
- GitHub's flavour with `$…$` and `$$…$$` math for remark-math, KaTeX or
|
|
479
|
+
MathJax, the author's `\explain` markers stripped. Headings keep their
|
|
480
|
+
numbers, a display equation its `\tag{…}`, each float its number and
|
|
481
|
+
captions, and every anchor an `<a id>`; a reference into the download
|
|
482
|
+
is a link into its file, any other goes to the website. A bar in table
|
|
483
|
+
math is `\vert`/`\Vert`, which a pipe table can hold. Memos, notes,
|
|
484
|
+
examples and checks are titled quotes, always open; Starlight's asides
|
|
485
|
+
are GitHub alerts (`[!NOTE]`, `[!TIP]`, `[!WARNING]`, `[!CAUTION]`).
|
|
486
|
+
Each chapter ends with its references, its notation and the answers to
|
|
487
|
+
its checks (D3).
|
|
488
|
+
- A figure a browser draws is a PNG at two device pixels per CSS pixel,
|
|
489
|
+
taken from the same clean page as its vector PDF; an image is the
|
|
490
|
+
site's own file; an explico `<Diagram>` is a PNG with its boxes and
|
|
491
|
+
arrows listed as text. The capture now also draws a diagram, and the
|
|
492
|
+
LaTeX and Markdown exports share one reading of the chapters and one
|
|
493
|
+
capture of their figures (`compiler/exports/export-chapters.ts`).
|
|
494
|
+
- New dependencies: `mdast-util-to-markdown`, `mdast-util-gfm-table`,
|
|
495
|
+
`mdast-util-math`, the versions Astro already installs.
|
|
496
|
+
- A part's page in print exports leaves out its generated stats line and
|
|
497
|
+
chapter list (the export's own contents replace them) and keeps its
|
|
498
|
+
objectives.
|
|
499
|
+
- **The manifest schema is now v28**: `lessonExports.markdown`.
|
|
500
|
+
- **`downloads/index.json`** lists every file the exports wrote, by its
|
|
501
|
+
path below `downloads/`, with its size in bytes
|
|
502
|
+
(`compiler/exports/download-index.ts`). The Download menu reads it.
|
|
503
|
+
- **Ctrl+P and Cmd+P load the labs before printing**, as the Print button
|
|
504
|
+
does: the page catches the shortcut, loads every lab that will be on
|
|
505
|
+
paper, and then opens the print dialog. A downloaded page keeps this.
|
|
506
|
+
The browser's own File → Print cannot wait, so a lab that never loaded
|
|
507
|
+
prints a one-line note saying how to include it.
|
|
508
|
+
|
|
509
|
+
- **Rule V7: a figure's picture fits on one screen.** The default slot of a
|
|
510
|
+
`<Figure>` (plot, key and tables) takes at most `maxPercent` of the
|
|
511
|
+
viewport height, 80% unless the course sets `rules.V7.maxPercent`, so the
|
|
512
|
+
reader sees the picture and its caption line together. The height is
|
|
513
|
+
only known in a laid-out page, so the check runs in a course's Playwright
|
|
514
|
+
suite: `explico/reference/figure-fit` exports `checkFigureFit(page,
|
|
515
|
+
{ maxPercent?, allow? })`, which opens folded figures, waits for islands
|
|
516
|
+
to hydrate and the height to settle, and returns a `figure-too-tall`
|
|
517
|
+
finding (warning) per picture over the budget; `lessonsWithFigures(manifest)`
|
|
518
|
+
lists the pages to open, and `allow` exempts a figure by anchor with a
|
|
519
|
+
stated reason. The rule page shows the test to add; the playground runs it
|
|
520
|
+
at a laptop and a phone viewport.
|
|
521
|
+
|
|
522
|
+
- **Rule V8: a diagram is no wider than the lesson column.** A `<Diagram>`
|
|
523
|
+
that lays out wider than `columnWidth` px (707 unless the course sets
|
|
524
|
+
`rules.V8.columnWidth`: the lesson column at a 1366px-wide window) gets a
|
|
525
|
+
`dia-too-wide` warning naming the lesson file and the diagram `id`. Only
|
|
526
|
+
the rendered page knows a diagram's width (a wrapper component's nodes
|
|
527
|
+
never reach the manifest walk), so `Diagram.astro` marks a diagram over
|
|
528
|
+
its limit with `data-diagram-too-wide`, `astro build` reports each mark
|
|
529
|
+
as it finishes (`oversizedDiagrams` in `explico/reference/diagram-fit`)
|
|
530
|
+
and writes them to `build/render-diagnostics.json`, and `astro dev`
|
|
531
|
+
prints the same warning as the page renders. `content warnings`,
|
|
532
|
+
`content diagnostics`, `content status`, `content context` and
|
|
533
|
+
`content check` list the last build's findings beside the manifest's,
|
|
534
|
+
under the `render:` source (`render:dia-too-wide`). `warnAboveWidth={false}`
|
|
535
|
+
still opts a diagram out, and a number in it still sets that diagram's
|
|
536
|
+
own limit.
|
|
537
|
+
|
|
538
|
+
- **Build-time measurement of a formula and of a label.**
|
|
539
|
+
`explico/reference/katex-measure` exports `measureFormula(latex, fontPx)`:
|
|
540
|
+
the width, height and depth of notation LaTeX as KaTeX lays it out, from
|
|
541
|
+
KaTeX's own layout tree and font metrics plus the widths `katex.css`
|
|
542
|
+
adds, each glyph rounded up to a whole pixel as Chromium on Linux draws
|
|
543
|
+
it. It is never narrower than Chromium's width and at most a few pixels
|
|
544
|
+
wider, which `tests/reference/katex-measure.test.ts` holds against 92
|
|
545
|
+
formulas measured in Chromium (`playground/scripts/measure-katex-widths.ts`).
|
|
546
|
+
`explico/reference/text-measure` exports `textWidth` and `wrapText`,
|
|
547
|
+
which measure text in DejaVu Sans, the widest common system font, from
|
|
548
|
+
an advance-width table generated from the font
|
|
549
|
+
(`scripts/gen-text-widths.mjs`). `renderNotationFormula` also returns the
|
|
550
|
+
`latex` it rendered, glyphs bound.
|
|
551
|
+
- **A page-local notation key that equals a shared one warns**
|
|
552
|
+
(`local-shadows-shared`). The local entry wins on its page, so
|
|
553
|
+
`[[motion.range]]` meant "Length of the field" there and "Range" in the
|
|
554
|
+
glossary and on every other page, and nothing said so. None of the
|
|
555
|
+
courses on the maintainer's machine has such a key.
|
|
556
|
+
- **`contentCheck` takes `lessons`, several ids each checked.** The
|
|
557
|
+
playground's `content check a b` checked `a` alone and exited 0 with `b`
|
|
558
|
+
silently ignored, so an agent could take both as passed; its wrapper now
|
|
559
|
+
passes every id, and `context`, `status`, `rules`, `warnings` and `new`
|
|
560
|
+
refuse an argument they do not take. A course's own `scripts/content.ts`
|
|
561
|
+
can do the same by passing `lessons: args.positionals`.
|
|
562
|
+
- **A symbol in a card from another lesson explains itself, even one this
|
|
563
|
+
page never uses.** The equation a `[[lesson/slug#eq-…]]` reference
|
|
564
|
+
previews brought its symbols along, but only those this page explained
|
|
565
|
+
opened a card: on "Projectile Range", ρ and φ in equation (1.1.3) of
|
|
566
|
+
"Position and Coordinate Systems" did nothing. Each now opens the card
|
|
567
|
+
that lesson gives it, read off the page the preview came from, and one of
|
|
568
|
+
that lesson's own symbols says "Defined in … · means this only there", as
|
|
569
|
+
a carried card always did (K6). Such a card is kept, remembered and
|
|
570
|
+
carried like any other: a shared symbol becomes the page's own card
|
|
571
|
+
wherever a page explains it. A kept card of a page's own symbol now names
|
|
572
|
+
the page it was read off in its carrying mark (K8), not the page it
|
|
573
|
+
was opened on. `card-fetch.ts` `markForeign` marks a card built from
|
|
574
|
+
another page (`data-card-from`, `data-card-from-slug`); nothing in a
|
|
575
|
+
course changes (`NotationLayer.astro`, `FloatRefLayer.astro`,
|
|
576
|
+
`card-manager.ts`).
|
|
577
|
+
- **Index entries and derived cards** (rule N23). A notation entry whose
|
|
578
|
+
`latex` is a subscript on an empty group (`"{}_0"`, `"{}_x"`, quoted in
|
|
579
|
+
YAML) explains that subscript on every symbol of the page that has a card of
|
|
580
|
+
its own: `\mathbf{v}_0` becomes one target with a **derived card**, composed
|
|
581
|
+
by the build (`derived-notation.mjs`) and keyed `<base>.sub.<index>`. Its
|
|
582
|
+
title is the index entry's new `reads` with `{base}` replaced by the base's
|
|
583
|
+
label ("Velocity vector evaluated at t = 0"; the default is "`<label>` of
|
|
584
|
+
`{base}`"), its summary the index entry's `meaning`, its formula the index
|
|
585
|
+
entry's `formula` with `{base}` bound to the base symbol, so the base's card
|
|
586
|
+
is one level deeper, and its units the base's. A derived card is never
|
|
587
|
+
listed; an index entry is listed with a square for the symbol (`\square_0`,
|
|
588
|
+
like an operator entry) and takes no `units`, `dimensionless`, `range` or
|
|
589
|
+
`fixedIndex` — the loader rejects them, and rule N19 skips it; `reads`
|
|
590
|
+
belongs to an index entry only, names the symbol with `{base}`, and is plain
|
|
591
|
+
prose (no `$`, `\` or backtick). A table header's screen-reader label reads
|
|
592
|
+
the derived title, so `v_x` and `v_y` columns differ. A whole form or a
|
|
593
|
+
family still wins over an index entry.
|
|
594
|
+
- **`range` and `fixedIndex` on a notation entry** (rule N23). `range` is
|
|
595
|
+
the set a running index letter runs over, as LaTeX (`"1, \\dots, n"`); the
|
|
596
|
+
card and the glossary show it as "Runs over …". `fixedIndex: true` says a
|
|
597
|
+
letter, as an index, is a label (a component, a size), or that an indexed
|
|
598
|
+
entry's index is fixed, so it is no family and lends nothing.
|
|
599
|
+
- **Derived cards wherever page math renders**: a lesson body, an
|
|
600
|
+
assessment, lab math and a `<Diagram>` formula; never a notation formula,
|
|
601
|
+
which resolves against its own card's table. A lab composes them when it
|
|
602
|
+
passes the table `labMathScope` returned to `renderLabMath` unchanged:
|
|
603
|
+
`labMathScope` ties the table to its page (`bindScopeToPage`), and
|
|
604
|
+
`renderLabMath` and `Diagram.astro` register the derived cards they use
|
|
605
|
+
(`registerPageDerivedNotation`), which `derivedNotationForPage` composes
|
|
606
|
+
for the page's payload. `renderNotationFormula` takes `{ derive }` and
|
|
607
|
+
returns `derived` and `indices`; `splitMixedContent` takes `{ derive,
|
|
608
|
+
derived }`.
|
|
609
|
+
- `resolveMathGlyphs` takes `derive` (page math sets it) and returns
|
|
610
|
+
`indices`, how each indexed symbol is explained, and `derived`, the derived
|
|
611
|
+
cards it used; an unresolved item carries `lenders`, the indexed entries
|
|
612
|
+
with its base, and a decoration `wholeFormExplicit`. `math-glyphs.mjs`
|
|
613
|
+
exports `derivedNotationKey`, `indexOfEntry`, `indexDisplayLatex`,
|
|
614
|
+
`entryHasIndex`, `baseSymbolLatex`, `derivedNotationLatex` and
|
|
615
|
+
`isRunningIndexLetter`; a glyph-table row may carry `fixedIndex`.
|
|
616
|
+
- **`accent-swallowed`** (rule N22, a warning): an `\explain{beta}{\hat{\beta}}`
|
|
617
|
+
around a decorated form counted as its whole form even though the `beta`
|
|
618
|
+
card never mentions the hat. It is reported now, the decoration twin of
|
|
619
|
+
N23's `index-swallowed` (`consistency.ts` `checkAccentExplained`).
|
|
620
|
+
|
|
621
|
+
### Changed
|
|
622
|
+
|
|
623
|
+
- **A symbol of a page's own has a card key scoped to its page**: the card
|
|
624
|
+
for `notation.local`'s `theta-star` on "The Optimal Launch Angle" is
|
|
625
|
+
`[data-card-key="notation:theta-star@projectiles/optimal-launch-angle"]`,
|
|
626
|
+
not `notation:theta-star`, so a carried card (K5) never stands for
|
|
627
|
+
another page's symbol of the same name (K6). A shared symbol's key
|
|
628
|
+
is unchanged. Browser tests that select a local symbol's card by its key
|
|
629
|
+
need the scoped form; the page's slug comes from `NotationLayer`'s new
|
|
630
|
+
`page` prop, which `LessonFooter.astro` passes. A card's memory saved
|
|
631
|
+
under the old key is not restored.
|
|
632
|
+
|
|
633
|
+
- **Every card layer registers on every course page**, with nothing of its
|
|
634
|
+
own to show or not, so a card carried in can be built there: the
|
|
635
|
+
citation and abbreviation layers no longer wait for a marker on the page,
|
|
636
|
+
the reference layer for a reference or a numbered float, and a page
|
|
637
|
+
without notation still renders the notation card's template, in a
|
|
638
|
+
hidden `.notation-layer`. The page's notation layers — the page's own and
|
|
639
|
+
the glossary's panel — share one card source. A symbol in a card cloned
|
|
640
|
+
from another page opens this page's card only for a shared symbol, never
|
|
641
|
+
for one of this page's own.
|
|
642
|
+
|
|
643
|
+
- **A reference card's "Go to …" link sits in a row of its own**,
|
|
644
|
+
`p.float-ref-panel-links`, which a kept card's "Opened at" link joins
|
|
645
|
+
(K7). Course CSS that placed `.float-ref-panel-jump` as a grid item of
|
|
646
|
+
`.float-ref-panel-body` targets the row instead.
|
|
647
|
+
|
|
648
|
+
- **The side controls row's switches share one class**,
|
|
649
|
+
`.explico-side-switch` (its knob `.explico-side-switch-knob`), which
|
|
650
|
+
replaces `.explico-keep-left` and `.explico-keep-left-switch`. Course CSS
|
|
651
|
+
that styled "Article left" by those names targets the new ones; the
|
|
652
|
+
`[data-keep-article-left]` hook is unchanged, and "Carry cards" has
|
|
653
|
+
`[data-carry-cards]`.
|
|
654
|
+
|
|
655
|
+
- **A reference card names its float by its number in the title**:
|
|
656
|
+
"Equation (1.1.3)", "Figure 2.2.1 · Range vs. launch angle explorer". The
|
|
657
|
+
column that repeated the number beside the content is gone, an equation's
|
|
658
|
+
too, so the content takes the card's width, and the "Go to …" link no
|
|
659
|
+
longer repeats the number either: "Go to the equation in Position and
|
|
660
|
+
Coordinate Systems", "Go to the table". A course's browser test that reads
|
|
661
|
+
the link by its old name ("Go to figure 2.1.1", "Go to equation (1.1.3)")
|
|
662
|
+
needs the new one; `[data-panel-number]` moved into the title and keeps
|
|
663
|
+
its text, except an equation's, which reads "Equation (1.1.3)" instead of
|
|
664
|
+
"(1.1.3)" (`FloatRefLayer.astro`).
|
|
665
|
+
- **A figure card's picture is 80% of its width in the article**, and the
|
|
666
|
+
card is as wide as the picture: the caption wraps under it instead of
|
|
667
|
+
widening the card. A figure from another page is laid out unseen in this
|
|
668
|
+
page's article and measured there (`FloatRefLayer.astro`,
|
|
669
|
+
`figureCardWidth`).
|
|
670
|
+
- **Every card's text is 14 px** (`--sl-text-sm`, the article's caption
|
|
671
|
+
size). The notation card alone was 90% of the article's text, 14.4 px;
|
|
672
|
+
its units line is now 13 px (`--sl-text-xs`), a step below the text
|
|
673
|
+
(`NotationLayer.astro`).
|
|
674
|
+
- **"Keep the article left" reads "Article left"**, so it and the width
|
|
675
|
+
menu fit one row at the top of a 1920 px window's side column; its
|
|
676
|
+
tooltip still says it in full. The switch keeps
|
|
677
|
+
`[data-keep-article-left]`, inside a new row, `.explico-side-controls`,
|
|
678
|
+
which now holds the fixed position.
|
|
679
|
+
- **A heading's chain icon shows on hover in a narrow window too.** Below
|
|
680
|
+
`50em` it used to show on every heading, a rule meant for phones that a
|
|
681
|
+
narrow PC window matched as well. It now shows on every heading only on a
|
|
682
|
+
touch screen (`hover: none`); with a mouse it appears on hover at any
|
|
683
|
+
width (`styles/global.css`).
|
|
684
|
+
- **A card's footer links are outline buttons in the site's accent
|
|
685
|
+
colour.** "Go to the full definition", "Go to the source", "Go to the
|
|
686
|
+
reference list", "Go to the glossary" and a reference card's "Go to …"
|
|
687
|
+
lose their underline and take a hairline border, tinted on hover. The
|
|
688
|
+
card layer sits outside the article, so these links never got the site's
|
|
689
|
+
link colour and showed the browser's default blue. They are still links,
|
|
690
|
+
with the shared class `hover-panel-action` (`HoverPanel.astro`). A link
|
|
691
|
+
inside a card's text keeps its underline.
|
|
692
|
+
|
|
693
|
+
- **The header's download link is a Download menu** (`LessonExportActions.astro`).
|
|
694
|
+
The Download button opens a native popover listing the scopes that
|
|
695
|
+
contain the page, one row each ("This chapter", "This part", "Whole
|
|
696
|
+
course", with the chapter's, part's or course's name), and the formats in
|
|
697
|
+
columns (HTML, and a chapter's PDF and LaTeX source with
|
|
698
|
+
`lessonExports.latex`), each with its size from `downloads/index.json`; a
|
|
699
|
+
download the build did not write is left out. The Print button stays
|
|
700
|
+
beside it. A link's accessible name names its scope and format
|
|
701
|
+
("Download this chapter as standalone HTML"); the button is "Download
|
|
702
|
+
this page". During `astro dev` every cell but a chapter's HTML says it is
|
|
703
|
+
built when the site is deployed.
|
|
704
|
+
|
|
705
|
+
- **Every page offers the print button and the Download menu**, not only
|
|
706
|
+
the chapters: the landing page, each part's page, the glossary and every
|
|
707
|
+
other page in the manifest's `pages` (`LayoutSocialIcons.astro`). Such a
|
|
708
|
+
page downloads as part of its part's and the course's files (see
|
|
709
|
+
Breaking). Ctrl+P on those pages now also gets the print preparation:
|
|
710
|
+
links moved onto `canonicalBaseUrl`, off-screen figures drawn. The print
|
|
711
|
+
button's accessible name says "this page" instead of "this lesson"
|
|
712
|
+
("Print or save this page as PDF"), and the group's is "Page exports".
|
|
713
|
+
The `lessonExports` setting keeps its name.
|
|
714
|
+
|
|
715
|
+
- **A diagram's boxes are sized from what they hold.** A node is as wide
|
|
716
|
+
as its formula or its label, whichever is wider, plus an inset. The label
|
|
717
|
+
is measured in DejaVu Sans and wrapped evenly to a box of at most 220px;
|
|
718
|
+
the formula is measured from KaTeX's layout at the size it renders
|
|
719
|
+
(KaTeX's own 1.21em of the 13.6px label; `katex.css` is unlayered, so the
|
|
720
|
+
component's `font-size: 1em` for it never applied and is gone) and never
|
|
721
|
+
wraps, so a wide one widens its box and the label wraps to it. Each glyph
|
|
722
|
+
counts as the wider of the two ways a browser draws it: hinted at a
|
|
723
|
+
whole-pixel size and rounded, as Chromium on Linux does, or at its exact
|
|
724
|
+
advance, as macOS and iOS do. Glyphs KaTeX has no metrics for (`\iint`,
|
|
725
|
+
`\iiint`, `\oiint`, …) are measured too. The height follows from the
|
|
726
|
+
lines of text and the formula's own height. Before, the box was
|
|
727
|
+
estimated from the formula's character count alone, ignoring the label,
|
|
728
|
+
so a label could wrap past its box or spill out of it in a wide system
|
|
729
|
+
font. A node's `width` without a `height` now takes effect: the label
|
|
730
|
+
wraps inside it and the height follows (both used to be needed). A
|
|
731
|
+
`width` narrower than the node's formula, or a `height` shorter than what
|
|
732
|
+
it holds, is raised to fit; either used to cut the formula off. A
|
|
733
|
+
diagram wider than its V8 limit is laid out again with its labels wrapped
|
|
734
|
+
narrower, down to 120px boxes, before it is reported. Diagrams change
|
|
735
|
+
size, so screenshots of them need re-shooting. The node label carries
|
|
736
|
+
`text-wrap: balance`.
|
|
737
|
+
|
|
738
|
+
- **`<Diagram warnAboveWidth>` defaults to the course's column (rule V8),
|
|
739
|
+
707px, instead of 800px**, and its warning is a `dia-too-wide` diagnostic
|
|
740
|
+
with the lesson file rather than an untagged `console.warn`.
|
|
741
|
+
- **The manifest schema is now v30 (additive).** `lessons[].headings[].text`
|
|
742
|
+
is the text a reader sees — a formula as it reads, a `[[key]]` term as its
|
|
743
|
+
label — and `math: true` marks a heading with inline math. Slugs are
|
|
744
|
+
unchanged. Each choice option in `assessmentContent` carries
|
|
745
|
+
`labelSegments`, its label split into text and math like
|
|
746
|
+
`promptSegments`.
|
|
747
|
+
- **The anchor of a heading with math reads as the heading does.**
|
|
748
|
+
`## The range $\explain{motion.range}{R}$ in a heading` was anchored
|
|
749
|
+
`#the-range-explainmotionranger-in-a-heading`, in the address bar, a copied
|
|
750
|
+
link, a `[[sec-…]]` reference and both exports; it is now
|
|
751
|
+
`#the-range-r-in-a-heading`. A Greek letter slugs as LaTeX names it, so a
|
|
752
|
+
heading whose math holds no markup keeps its anchor
|
|
753
|
+
(`$e^{\lambda\cos(u)}$` is still `…elambdacosu`); one with `\explain`,
|
|
754
|
+
`\frac` or the like gets a new one. No heading in the courses on the
|
|
755
|
+
maintainer's machine changes.
|
|
756
|
+
- **Two notation formulas may name each other, local or shared.** A cycle
|
|
757
|
+
through `notation.local` formulas failed with `reference-cycle`, while the
|
|
758
|
+
same cycle through shared formulas passed. Formulas no longer count toward
|
|
759
|
+
a cycle for either kind: `confidence-level` (γ = 1 − α) and
|
|
760
|
+
`significance-level` (α = 1 − γ) are both right, and so are three entries
|
|
761
|
+
that each show the one model equation they appear in (data-science-I and
|
|
762
|
+
time-series do both). A cycle through meanings and bodies still fails.
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
### Fixed
|
|
766
|
+
|
|
767
|
+
- **A nest of `\left … \right` brackets grows outward in the LaTeX book and
|
|
768
|
+
PDF, as it does on the website.** The KaTeX patch behind rule N17 sets
|
|
769
|
+
`\delimitershortfall` to `-1pt`, but `explico.cls` kept TeX's 5pt, so the
|
|
770
|
+
exports drew nested pairs at one size. The class now sets it too; rebuild
|
|
771
|
+
the PDF to pick it up.
|
|
772
|
+
|
|
773
|
+
- **A formula's notation marker links to its entry in the LaTeX book.** A
|
|
774
|
+
`\explain{key}{tex}` in a part or course PDF now links to the key's entry in
|
|
775
|
+
the book's notation appendix, when the book has one; a chapter's own PDF,
|
|
776
|
+
which has no appendix, still prints the TeX. An entry's defining formula in
|
|
777
|
+
the appendix links the other entries it names, not its own symbol. Where
|
|
778
|
+
markers nest, as the resolver writes `\dot{x}`, only the outermost with an
|
|
779
|
+
entry links, since a link inside a link breaks the PDF's tagging. A marker
|
|
780
|
+
in a heading, caption or title, or inside a link, prints its TeX without a
|
|
781
|
+
link, since a link there breaks the build; a diagram's labels print theirs
|
|
782
|
+
too. The class defines `\ExplicoNotation` (`explico.cls`).
|
|
783
|
+
|
|
784
|
+
- **A card wider than the article column stays clear of the side panels.**
|
|
785
|
+
A figure card is up to `80ch` wide, which is wider than the article
|
|
786
|
+
column at 1200–1280 px with both panels open. Such a card was centred in
|
|
787
|
+
the whole window, and the navigation painted over its left part. Cards
|
|
788
|
+
are now placed between the navigation and the rail, the room a dragged
|
|
789
|
+
card already kept to, and a card wider than that room is narrowed to it
|
|
790
|
+
(`components/card-placement.ts`, `cardBand`).
|
|
791
|
+
- **The splash hero prints its light image.** Print is always light, but a
|
|
792
|
+
reader in dark mode printed the hero's dark image, whose pale strokes
|
|
793
|
+
vanish on white paper (`styles/global.css`).
|
|
794
|
+
- **A declared operator's card binds only that operator.** The glyph
|
|
795
|
+
resolver fingerprinted every `\operatorname{…}` and `\mathop{…}` by its
|
|
796
|
+
node type alone, so they all looked alike (`reference/math-glyphs.mjs`,
|
|
797
|
+
`signatureParts`). A page's one operator card wrapped every other declared
|
|
798
|
+
operator on the page: `\operatorname{Cov}` opened the
|
|
799
|
+
`\operatorname{Var}` card, with no diagnostic. Two operator cards on one
|
|
800
|
+
page failed the build with `ambiguous-canonical-notation`. A declared
|
|
801
|
+
operator is now fingerprinted by its letters with spacing dropped, the
|
|
802
|
+
name rule N8 already uses, so `\operatorname{arg\,max}` and
|
|
803
|
+
`\operatorname{argmax}` are still one operator. `\mathop{\mathrm{Var}}`
|
|
804
|
+
and `\operatorname{Var}` stay distinct. A course that put a name on
|
|
805
|
+
`rules.N8.allow` only because its card was refused can give the card back
|
|
806
|
+
and drop the name.
|
|
807
|
+
- **The engine's two hooks into Starlight's mobile menu follow the 0.42
|
|
808
|
+
markup**, where the old selectors would match nothing: the menu button
|
|
809
|
+
rises above the raised header as `.sl-menu-button` (`global.css`), and
|
|
810
|
+
open cards hide while the menu is open through
|
|
811
|
+
`body:has(#starlight__sidebar:popover-open)` (`HoverPanel.astro`).
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
- **Copy LaTeX no longer glues a command to the next letter.**
|
|
815
|
+
`stripNotationMarkers` (`reference/math-glyphs.mjs`) joined the two sides
|
|
816
|
+
of a removed `\explain{…}{…}` or `\slot{…}{…}` marker with nothing
|
|
817
|
+
between them, so `\times\explain{k}{m}` copied as `\timesm`,
|
|
818
|
+
`\left\lVert\explain{k}{X}` as `\left\lVertX` and
|
|
819
|
+
`\explain{a}{\lambda}\explain{b}{u}` as `\lambdau`: undefined commands to
|
|
820
|
+
any TeX that pasted them. A space now separates a control word from a
|
|
821
|
+
letter on either edge of a removed marker. Every copy button (an
|
|
822
|
+
equation's, a notation card's, a lab's) and the `data-latex` of inline
|
|
823
|
+
math take the fix.
|
|
824
|
+
- **The Print button no longer waits forever for a lazy image** the reader
|
|
825
|
+
never scrolled to: it switches such images to load now and opens the
|
|
826
|
+
print dialog after at most five seconds of waiting for images.
|
|
827
|
+
- **`content check` points a render error at its line in the file.** It
|
|
828
|
+
rendered a lesson's body with the frontmatter removed and its `import`
|
|
829
|
+
lines deleted, so an error was reported that many lines too early
|
|
830
|
+
(line 4 for an error on line 16, which `astro build` reports as 16).
|
|
831
|
+
The frontmatter is now blanked with spaces, as Astro's MDX plugin does,
|
|
832
|
+
and an `import` line is emptied, not removed (`compiler/cli.ts`,
|
|
833
|
+
`lessonSource`).
|
|
834
|
+
- **`validate:content` and `content check` reject what `astro build`'s
|
|
835
|
+
collection schemas reject.** The manifest walk read content with its own
|
|
836
|
+
checks and never applied the schemas in `content-config.ts`, so a notation
|
|
837
|
+
`meaning` with a `$`, a source `type` of `web` or `studyMinutes: [10, 5]`
|
|
838
|
+
passed both and then failed the build with `InvalidContentEntryDataError`.
|
|
839
|
+
The schemas now live in `explico/compiler/content-schemas`, which
|
|
840
|
+
`content-config.ts` and the manifest both use, and every record that does
|
|
841
|
+
not match is a `content-schema` error at the field's line (invariant
|
|
842
|
+
`content-schema`). In the other direction, a shared notation entry may now
|
|
843
|
+
leave out `aiAssisted` and `alignment`, as the schema already allowed: the
|
|
844
|
+
walk threw "aiAssisted must be a boolean" where the build used the
|
|
845
|
+
defaults. The plain-prose message for a notation `meaning` also says how
|
|
846
|
+
to write an amount of money.
|
|
847
|
+
- **An equation or a float in a list item, a quote or a `:::note` aside
|
|
848
|
+
is numbered the same way by the manifest and the page.** The manifest
|
|
849
|
+
counted every `$$…$$` in a lesson's text, and every `<Table>`, `<Figure>`
|
|
850
|
+
and `<Diagram>`, while the page numbered only those at the top level and
|
|
851
|
+
in a `<Memo>`, `<ShortNote>` or `<Fold>`. One unlabelled equation in a
|
|
852
|
+
list item, a `>` quote or an aside, or an inline `$$x$$` in a sentence,
|
|
853
|
+
made the next labelled equation fail the build with "Inconsistent equation
|
|
854
|
+
numbering … recompile the manifest", which never helped. Now both count
|
|
855
|
+
the lesson's flow, list items and quotes included, and neither counts an
|
|
856
|
+
aside, which is illustrative like `<Aside>` (a `<Table>` or `<Figure>` in
|
|
857
|
+
one fails the build, naming the aside). A display equation is a `$$`
|
|
858
|
+
block whose fences sit on lines of their own, as remark-math reads it;
|
|
859
|
+
`$$x$$` inside a sentence is inline math (`reference/equations.mjs`,
|
|
860
|
+
`reference/keyed-jsx-floats.mjs`). `content check` now parses `:::`
|
|
861
|
+
directives as the build does, through the new `remark-directive`
|
|
862
|
+
dependency.
|
|
863
|
+
- **The PDF numbers citations as the page does.** The page lists a source
|
|
864
|
+
once per locator it is cited with (`[@s]`, `[@s; ch. 3]` and
|
|
865
|
+
`[@s; eq. (4.21)]` are three entries, [1], [2] and [4]), but the LaTeX
|
|
866
|
+
export gave every entry of a source the same `\bibitem` key: LuaLaTeX
|
|
867
|
+
reported it multiply defined, and every `\cite` of it printed the last
|
|
868
|
+
entry's number, so the PDF read [4] where the page read [1]. A source
|
|
869
|
+
cited with several locators now gets one key per entry (`s/cite-4`), a
|
|
870
|
+
source cited once keeps its id, and `\cite` no longer repeats the
|
|
871
|
+
locator, which the entry already gives (`exports/latex/serialize.ts`).
|
|
872
|
+
- **A heading can no longer take an anchor the page already uses.**
|
|
873
|
+
`## References` on a page that cites a source gave the page two
|
|
874
|
+
`id="references"` elements (the author's heading and the generated
|
|
875
|
+
References section), and `## Tab totals` beside `<Table id="totals">` two
|
|
876
|
+
`#tab-totals`: every link went to the first, "On this page" listed
|
|
877
|
+
References twice, and the LaTeX export defined the label twice. Such a
|
|
878
|
+
heading now fails `validate:content` as `heading-anchor-collision`
|
|
879
|
+
(keyed-floats invariant), naming what holds the anchor: a keyed equation,
|
|
880
|
+
table, figure, diagram, example set or knowledge check, a `<Memo>` or
|
|
881
|
+
`<ShortNote>`, or the generated References section
|
|
882
|
+
(`reference/sections-validate.ts`, `validateHeadingAnchors`).
|
|
883
|
+
- **A heading with math reads as it renders everywhere it is named.**
|
|
884
|
+
Astro lists a heading by all the text in it, and KaTeX writes a formula
|
|
885
|
+
three times (MathML, its LaTeX annotation, its glyphs), so
|
|
886
|
+
`## The range $\explain{motion.range}{R}$` showed as "The range
|
|
887
|
+
R\explain{motion.range}{R}R" in "On this page", the heading link's
|
|
888
|
+
screen-reader label, the "Link copied" bubble and the copied link. Each
|
|
889
|
+
now reads "The range R": "On this page" takes the manifest's text for a
|
|
890
|
+
heading with math (`LayoutPageSidebar.astro`), the link's label skips the
|
|
891
|
+
annotation and the glyph copy (`rehype-heading-anchors.mjs`), and the
|
|
892
|
+
copied link and a card's "Opened at" read the heading through
|
|
893
|
+
`readableText`. The manifest's `lessons[].headings[].text` is the text a
|
|
894
|
+
reader sees, a `[[key]]` term as its label, and is what an unnumbered
|
|
895
|
+
`[[sec-…]]` quotes; a heading's anchor is unchanged. Rule S1 measures the
|
|
896
|
+
same text: `\explain{…}{…}` no longer counts against the limit.
|
|
897
|
+
- **The site search indexes a formula once, as it reads.** Pagefind indexed
|
|
898
|
+
KaTeX's MathML and its LaTeX annotation beside the glyphs, so a search for
|
|
899
|
+
`dfrac` or `explain` matched every page with a formula and the excerpts
|
|
900
|
+
read "…35.3 m\explain{motion.range}{R} = \dfrac{…". KaTeX's MathML copy is
|
|
901
|
+
now `data-pagefind-ignore`, in lesson math (`rehypeFailKatexErrors`, the
|
|
902
|
+
pass after KaTeX), in notation cards and diagrams (`renderNotationMath`)
|
|
903
|
+
and in lab math (`renderLabMath`).
|
|
904
|
+
- **A knowledge check's options render their math.** An option label went
|
|
905
|
+
to the page as plain text, so `"$30^{\circ}$"` showed its dollars and
|
|
906
|
+
LaTeX, and nothing warned. A label's math is now resolved and typeset like
|
|
907
|
+
the prompt's: rule N4 checks it, `AssessmentRunner` renders it, and the
|
|
908
|
+
LaTeX and Markdown answer keys typeset it (`assessmentContent` options
|
|
909
|
+
carry `labelSegments`). Rule N9 still does not apply to a label, so
|
|
910
|
+
"30 degrees" stays valid.
|
|
911
|
+
- **A reference or a citation in a knowledge check's text fails
|
|
912
|
+
`validate:content`.** A check renders its prompt, explanation and options
|
|
913
|
+
as text and math, so `[[projectiles/projectile-range#eq-range]]` or
|
|
914
|
+
`[@source]` there reached students exactly as written, with no
|
|
915
|
+
diagnostic. Each is now an `invalid-assessment` error naming the item and
|
|
916
|
+
the field. The error for a numeric answer's tolerance also says what is
|
|
917
|
+
wrong: it must be greater than 0, and an exact whole-number answer takes
|
|
918
|
+
one below one half.
|
|
919
|
+
- **A diagram's labels fit their boxes at any browser font size.** The
|
|
920
|
+
boxes are measured at build time for 13.6px text, but a label was
|
|
921
|
+
`0.85rem`, so a reader with a larger default font size (Chrome's "Large",
|
|
922
|
+
20px) got labels that outgrew their boxes and were cut off, in the
|
|
923
|
+
playground's own diagrams too. A label is now set in px at the size its
|
|
924
|
+
box was measured for (`Diagram.astro`); browser zoom still enlarges it.
|
|
925
|
+
Scaling the whole drawing with the font size was ruled out: WebKit on iOS
|
|
926
|
+
scales an SVG's geometry but not the HTML in its `foreignObject`.
|
|
927
|
+
- **A part with nothing in it yet no longer fails the build.** A part
|
|
928
|
+
listed in `course.settings.json` before its directory existed took an
|
|
929
|
+
ordinal in `parts[]` and a sidebar group, while lessons were numbered as
|
|
930
|
+
if it were absent; every page built, then the LaTeX export failed with
|
|
931
|
+
"LaTeX numbers part/… differently from the website". Such a part is now
|
|
932
|
+
left out of the sidebar and of every part number until it has a chapter
|
|
933
|
+
or an overview page, with a `part-empty` warning; a part with only an
|
|
934
|
+
overview page counts in both.
|
|
935
|
+
- **A lesson in a directory no part lists fails `validate:content`** as
|
|
936
|
+
`lesson-outside-parts`, naming the `parts` entry to add. It used to pass
|
|
937
|
+
and then fail the build with a message about `remarkNotation` wiring.
|
|
938
|
+
- **A lesson's `draft: true` fails `validate:content`** as
|
|
939
|
+
`unsupported-key`, with the advice to keep the lesson outside
|
|
940
|
+
`content/docs/`: Starlight dropped the page from the production build
|
|
941
|
+
while the sidebar still named it, so the build crashed with "The slug …
|
|
942
|
+
specified in the Starlight sidebar config does not exist". A chapter's
|
|
943
|
+
`sidebar.order`, which does nothing, warns as `ignored-key`.
|
|
944
|
+
- **The marker of an open memo the reader cannot see goes to it.** A
|
|
945
|
+
memo's marker toggles the memo, so on an open memo off screen (one with
|
|
946
|
+
`defaultOpen`, under `disclosure.memos.defaultOpen: true`, or one the
|
|
947
|
+
reader left open) a click closed it out of sight: no scroll, no URL
|
|
948
|
+
change, as if nothing happened. The marker now scrolls to such a memo and
|
|
949
|
+
sets `#memo-…`; it folds a memo only while some of it is on screen
|
|
950
|
+
(`Memo.astro`).
|
|
951
|
+
- **A number alias into a short note opens it.** A deep link such as
|
|
952
|
+
`#eq-2.2.3` to an equation inside a closed `<ShortNote>` was rewritten to
|
|
953
|
+
the equation's named anchor after the short note had already looked at
|
|
954
|
+
the address, so the note stayed closed and the target had no size; the
|
|
955
|
+
named anchor itself worked. The short note now looks again once every
|
|
956
|
+
script has run (`ShortNote.astro`).
|
|
957
|
+
- **The build warns when a PDF leaves characters blank.** The LaTeX
|
|
958
|
+
export's fonts have no Greek, CJK or emoji glyphs, and LuaLaTeX only logs
|
|
959
|
+
a `Missing character` line and leaves a blank, so a chapter with
|
|
960
|
+
"Ελληνικά" or "中文" in its prose shipped a PDF reading "Ε𝜆𝜆" and "��"
|
|
961
|
+
with no warning. Each chapter whose PDF misses characters is now named in
|
|
962
|
+
a build warning with the characters (`exports/latex/compile.ts`,
|
|
963
|
+
`missingCharacters`).
|
|
964
|
+
- **Pandoc's `[@a; @b]` cites both sources.** The second source was read
|
|
965
|
+
as the first one's locator, so the page showed one `[1]` and its entry
|
|
966
|
+
read "Ling et al., … @openstax-college-physics-2e.", with no diagnostic.
|
|
967
|
+
A `;`-separated part that is only `@id` now starts another citation with
|
|
968
|
+
its own marker and entry; any other part is still the locator, so
|
|
969
|
+
`[@a; §1.2; eq. 3]` reads as before. The page, the manifest's citations
|
|
970
|
+
and the lesson's derived sources share one parser
|
|
971
|
+
(`citation-format.mjs`, `bracketCitations`).
|
|
972
|
+
- **A diagram edge from a node to itself fails the build** with a message
|
|
973
|
+
saying how to draw the repetition instead. The layout drew it as a stray
|
|
974
|
+
line out of the node.
|
|
975
|
+
- **A diagram formula that cannot be bound says why.** The error quoted
|
|
976
|
+
the same two guesses for every failure; it now gives the resolver's own
|
|
977
|
+
message (an unknown glyph, a shared base, a parse error). A diagram
|
|
978
|
+
written straight into MDX gets no notation scope, so none of its symbols
|
|
979
|
+
can resolve; the error now says so and names `labMathScope`.
|
|
980
|
+
- **An equation in a reference card sits flush in it.** The card's
|
|
981
|
+
`margin-block: 0` for a displayed equation was inside `@layer
|
|
982
|
+
starlight.components`, and `katex.css` is unlayered, so KaTeX's `1em`
|
|
983
|
+
margins won and left air above and below every `[[eq-…]]` preview. An
|
|
984
|
+
engine test now fails on any layered rule aimed at a KaTeX class.
|
|
985
|
+
- **The LaTeX and Markdown exports punctuate a short caption as the page
|
|
986
|
+
does.** Each added its own period unless the short caption ended in one,
|
|
987
|
+
so `short="Is it zero?"` printed "Is it zero?." in the PDF's caption,
|
|
988
|
+
the Markdown caption line and both alt texts. They now use the page's
|
|
989
|
+
`captionTitle`, which keeps a closing `!`, `?`, `…`, `:` or `;`.
|
|
990
|
+
- **LaTeX's numbering and reference habits fail with the explico form.**
|
|
991
|
+
The gate parses every span as inline math, so `\begin{align}`,
|
|
992
|
+
`\begin{equation}` or `\tag{A}` in a `$$…$$` block was reported as "can
|
|
993
|
+
be used only in display mode". The error now says the block already is
|
|
994
|
+
the display, numbered from its `\label{eq:key}`, and names the inner
|
|
995
|
+
environment to use (`aligned`, `gathered`, `alignedat`) or says to drop
|
|
996
|
+
the wrapper or the `\tag`. An unprefixed `\label{…}` names
|
|
997
|
+
`\label{eq:key}`, and `\eqref{eq:first}` or `\ref{…}` in math names
|
|
998
|
+
`[[eq-first]]`. In prose, where MDX failed on its braces with "Could not
|
|
999
|
+
parse expression with acorn", `validate:content` now reports it first
|
|
1000
|
+
(`eq-latex-ref`).
|
|
1001
|
+
- **The N8, N10 and N14 messages name the setting to use.** Each told an
|
|
1002
|
+
author to allowlist a term in `operators.allow`, `romanLabels.allow` or
|
|
1003
|
+
`abbreviations.allow` "in course.config.ts", keys that raise
|
|
1004
|
+
`config-deprecated-key`. They now name `rules.N8.allow`,
|
|
1005
|
+
`rules.N10.allow` and `rules.N14.allow` in the course config
|
|
1006
|
+
(`course.config.ts`, or the `course.settings.json` it reads), as the
|
|
1007
|
+
README and the doc comments do.
|
|
1008
|
+
- **A course rule reads what a reader sees: a link's text, not its
|
|
1009
|
+
address, and a caption.** A `forbid` pattern matched inside
|
|
1010
|
+
`[a page](https://example.org/basically/)` and skipped
|
|
1011
|
+
`<Table caption="This caption says basically.">`. Link destinations and
|
|
1012
|
+
`[ref]: https://…` definitions are now blanked from the prose surface
|
|
1013
|
+
(so N9 and N14 no longer read an address either), and the text of a
|
|
1014
|
+
`caption`, `short`, `title` or `label` prop is matched as a paragraph of
|
|
1015
|
+
its own under the `paragraph` and `prose` scopes.
|
|
1016
|
+
- **`content check <lesson>` fails on a fault in a shared notation entry
|
|
1017
|
+
the lesson shows**, as `validate:content` does. A formula of a shared
|
|
1018
|
+
entry naming an unknown key is reported against the entry's own file, so
|
|
1019
|
+
the per-lesson check left it out and printed `ok` for every page that
|
|
1020
|
+
showed the card.
|
|
1021
|
+
- **Money that remark-math would read as math fails `validate:content`**
|
|
1022
|
+
(`currency-dollar`). remark-math pairs any two `$` on a line, so
|
|
1023
|
+
`pay $5 ~ $6` showed "pay 5 6" with every gate passing (the gate's own
|
|
1024
|
+
span scan follows Pandoc and skipped the pair), and "between $5 and $6"
|
|
1025
|
+
failed the build on the letters of "and". A pair whose content starts with
|
|
1026
|
+
a digit and ends in a space or runs into a digit is now an error that says
|
|
1027
|
+
to write `\$5 to \$6`. None of the courses on the maintainer's machine
|
|
1028
|
+
has one.
|
|
1029
|
+
- **A table one row over `truncateAfter` shows whole.** Truncating it hid
|
|
1030
|
+
that one row behind a "… 1 more row …" line just as tall, and the reader
|
|
1031
|
+
had to click to see it. A table now starts truncated only when that hides
|
|
1032
|
+
two rows or more (`table-truncation.ts`).
|
|
1033
|
+
- **A pinned card whose section the reader collapses waits out of sight.**
|
|
1034
|
+
It stayed where it stood, over the text that moved up into its section's
|
|
1035
|
+
place, and scrolled with the page as if still attached. It now hides,
|
|
1036
|
+
keeping its size, while its trigger is folded away, and comes back beside
|
|
1037
|
+
the trigger when the section or fold opens. A closed `<details>` keeps
|
|
1038
|
+
its content's last boxes in current browsers (`content-visibility:
|
|
1039
|
+
hidden`), so the card manager asks `checkVisibility()`, not
|
|
1040
|
+
`getClientRects()`, whether the trigger is folded.
|
|
1041
|
+
- **N9 quotes a hand-typed sub/superscript whole.** The pattern took three
|
|
1042
|
+
characters, so `2^10` was reported as "2^1" and `e^{i t}` as "e^{". It
|
|
1043
|
+
now takes the whole runs on both sides, or a braced group.
|
|
1044
|
+
- **A folded section counts the numbered floats and equations inside a
|
|
1045
|
+
short note.** Everything in a `<ShortNote>` counted as part of the note,
|
|
1046
|
+
and the note itself was never counted, so a section whose table or display
|
|
1047
|
+
equation sat in one said only "Hidden here: 1 paragraph". A numbered float
|
|
1048
|
+
or equation in a short note now counts, and a float with a short caption
|
|
1049
|
+
is named, as in a `<Fold>`; the note's prose still belongs to its
|
|
1050
|
+
paragraph.
|
|
1051
|
+
- **Three notation errors say what to write.** A glyph two page entries
|
|
1052
|
+
share ("structurally identical LaTeX") now cites rule N4 and says to write
|
|
1053
|
+
one of them differently or keep one off the page, and that `\explain`
|
|
1054
|
+
does not lift the clash (it never did). An invalid key says what it most
|
|
1055
|
+
likely meant: `[[motion.range|reach]]` that a reference takes no link
|
|
1056
|
+
text (write `[[motion.range]]`), `[[dia-My_Diagram]]` that a diagram's
|
|
1057
|
+
id is lower-case kebab-case, anything else the key grammar.
|
|
1058
|
+
- **An unclosed `[[` fails `validate:content`** (`malformed-reference`, at
|
|
1059
|
+
its line). Only the render caught it, and `content check` printed Astro's
|
|
1060
|
+
whole error object (its syntax tree, `cause`, `place`) above its own
|
|
1061
|
+
line; `renderLesson` now drops that log and carries the error's line and
|
|
1062
|
+
column into its diagnostic.
|
|
1063
|
+
- **"Opened at" quotes a section the course shows unnumbered**, as a
|
|
1064
|
+
reference to it prints: `Opened at “What this chapter uses”`, not the
|
|
1065
|
+
bare title (`sectionPlace`).
|
|
1066
|
+
- **A caption prop written as an expression warns**
|
|
1067
|
+
(`fig-unread-prop`, `tab-…`, `dia-…`, `ex-…`). `<Figure short={"…"}>`
|
|
1068
|
+
rendered its short caption, but the manifest reads only a quoted prop, so
|
|
1069
|
+
the float's `[[…]]` card, a copied link, a folded section's line and the
|
|
1070
|
+
"Figures and tables" page named it without one, silently.
|
|
1071
|
+
- **A float id the manifest rejects is named as such at render.**
|
|
1072
|
+
`<Diagram id="My_Diagram">` failed `validate:content` with
|
|
1073
|
+
`dia-invalid-key`, and then the render (and `content check`) said "Stale
|
|
1074
|
+
Explico manifest … Recompile the manifest before rendering", which no
|
|
1075
|
+
recompile fixes. It now says the id is not a valid key and to fix it.
|
|
1076
|
+
- **A section reference to a part's page says why it cannot resolve.**
|
|
1077
|
+
`[[motion#sec-…]]` failed with "names lesson motion, which does not
|
|
1078
|
+
exist", though the page exists. It now says the page is not a chapter, a
|
|
1079
|
+
section reference reaches a chapter's top-level headings only (rule S10),
|
|
1080
|
+
and how to link the heading with a Markdown link instead.
|
|
1081
|
+
- **`remark-citation.mjs` is a text file again.** It used a literal NUL
|
|
1082
|
+
character as a key separator, so git showed every change to it as
|
|
1083
|
+
`Bin … bytes` and grep skipped it. It now writes `\u0000`, and a test fails
|
|
1084
|
+
on a NUL byte in any source, doc or content file.
|
|
1085
|
+
- **A PDF table's caption no longer sits on the table.** With
|
|
1086
|
+
`\DocumentMetadata`, which every export's `main.tex` has, the kernel's
|
|
1087
|
+
tagging code sets each caption itself, so none of the class's
|
|
1088
|
+
`\captionsetup` applied: a table's caption, set above it, kept the
|
|
1089
|
+
kernel's space above and none below, and its top rule ran about 1pt under
|
|
1090
|
+
the caption's descenders. A table's caption now gets the same space on both
|
|
1091
|
+
sides (8pt), and every caption the class's form: small type, and a quad
|
|
1092
|
+
after "Table 2.1.1" instead of a colon, as on the web page.
|
|
1093
|
+
- **Prose in another script reaches the PDF.** Under LuaLaTeX, a Greek
|
|
1094
|
+
word, Cyrillic, Chinese, Japanese, Korean and emoji come from fallback
|
|
1095
|
+
fonts, the first the build machine has (CMU Serif from TeX Live's
|
|
1096
|
+
`cm-unicode`, now in `texlive-packages.txt` as optional, then Noto Serif or
|
|
1097
|
+
DejaVu Serif; Noto CJK or Fandol; Noto Color Emoji), loaded only for a
|
|
1098
|
+
document that needs them (the class option `scripts`). A Greek word was set
|
|
1099
|
+
in math italic, letter by letter, and an accented letter, Chinese and emoji
|
|
1100
|
+
were blank. A Greek letter on its own stays a math symbol, as in a caption's
|
|
1101
|
+
"polar coordinates ρ and φ".
|
|
1102
|
+
- **pdfLaTeX no longer fails the whole build on a character it cannot set.**
|
|
1103
|
+
`EXPLICO_LATEX_ENGINE=pdflatex` stopped at "Unicode character έ not set up
|
|
1104
|
+
for use with LaTeX" after every page had rendered. The character now stays
|
|
1105
|
+
blank and the build warns, as under LuaLaTeX without a fallback font.
|
|
1106
|
+
- **A LaTeX compile no longer reruns until it gives up.** latexmk counted
|
|
1107
|
+
luaotfload's shared font caches as inputs; the build's parallel compiles
|
|
1108
|
+
rewrite them, so a compile could see its inputs change on every run and fail
|
|
1109
|
+
with "'lualatex' needed too many passes". The build and the shipped
|
|
1110
|
+
`latexmkrc` ignore them, and a failure latexmk reports itself now shows
|
|
1111
|
+
latexmk's words instead of the log's last lines.
|
|
1112
|
+
- **Braces in prose fail `validate:content`, at their line** (`mdx-expression`,
|
|
1113
|
+
invariant `prop-text`). MDX reads `{a}` as JavaScript; both checks passed
|
|
1114
|
+
it, and the build failed with "a is not defined" in a compiled chunk, with
|
|
1115
|
+
no file or line. The message says to write `\{a\}`, or `$\{a\}$` for a set.
|
|
1116
|
+
None of the courses on the maintainer's machine has one.
|
|
1117
|
+
- **An equation wider than the column shows that it goes on.** On a phone a
|
|
1118
|
+
wide display equation scrolls sideways inside its box with no scrollbar,
|
|
1119
|
+
and it simply stopped mid-formula beside its number. The edge it is cut
|
|
1120
|
+
at now fades (`data-overflow` on `.katex-display`, set while it overflows
|
|
1121
|
+
and kept current as it scrolls); focus and print show it whole.
|
|
1122
|
+
- **A part page's stats read apart in search and to a screen reader.** They
|
|
1123
|
+
were spans in a row, separated only by space on screen, so the search
|
|
1124
|
+
index read "Part 1 of 23 chapters8 numbered equations". They are a list
|
|
1125
|
+
now (`PartOverview.astro`), and search reads "Part 1 of 2. 3 chapters."
|
|
1126
|
+
- **A power or a mark no longer breaks a whole form** (rule N23).
|
|
1127
|
+
KaTeX parses `v_0^{2}` as one node with the power, so it never matched the
|
|
1128
|
+
entry `v_0`: only the letter was highlighted, and where the letter had an
|
|
1129
|
+
entry of its own the card was wrong (`\sigma_k^2` opened the population
|
|
1130
|
+
standard deviation). The whole form is matched and wrapped now, the power
|
|
1131
|
+
outside it; a mark (`v_0'`) stays rule N22's. A whole form inside another
|
|
1132
|
+
whole form's subscript keeps its own card too: `T_{\mathrm{opt}}` in
|
|
1133
|
+
`B_{T_{\mathrm{opt}}}^{\mathrm{dirty}}` is one target, not a highlighted `T`.
|
|
1134
|
+
Authors' `\explain{key}{v_0}^{2}` workarounds still work.
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
## [0.12.0] - 2026-09-28
|
|
1138
|
+
|
|
1139
|
+
### Breaking
|
|
1140
|
+
|
|
1141
|
+
- **Every symbol a figure shows opens its notation card, and the build
|
|
1142
|
+
checks it** (rule V3, rule N4). Two checks fail a lab that draws math with
|
|
1143
|
+
KaTeX itself, whose symbols have no card:
|
|
1144
|
+
- **`lab-katex-direct`** (error, rule V3; `reference/lab-katex-validate.ts`,
|
|
1145
|
+
in `diagnostics.figures`): `pnpm validate:content` follows each lesson's
|
|
1146
|
+
relative imports to the course's components and fails a file that
|
|
1147
|
+
imports `katex` (not a type-only import, not the stylesheet), naming the
|
|
1148
|
+
chain of imports that reaches it. V3 now has a check, so it counts as
|
|
1149
|
+
partly enforced.
|
|
1150
|
+
- **`astro build` fails a figure's unbound symbol**: at `astro:build:done`,
|
|
1151
|
+
every letter KaTeX drew inside a `figure.keyed-figure` (its tools
|
|
1152
|
+
included) must sit in a `[data-notation-key]`; upright text
|
|
1153
|
+
(`\text{}`, `\mathrm{}`, a named operator such as `\sin`) is exempt
|
|
1154
|
+
(`reference/figure-symbols.ts`, `assertFigureSymbolsBound`).
|
|
1155
|
+
- **`setFigureState` takes no symbol typed as text.** A run is a string or
|
|
1156
|
+
`{ math }`; the italic (`{ text, italic: true }`), plain `{ text }` and
|
|
1157
|
+
subscript (`{ sub }`) runs are gone, and one passed anyway throws, naming
|
|
1158
|
+
the fix. `FigureStateRun` is `string | { math: RenderedLabMath }`, so
|
|
1159
|
+
`astro check` fails an old run.
|
|
1160
|
+
- **A page that is not a chapter numbers nothing, and `validate:content` says
|
|
1161
|
+
so** (rule S10, locked). On the landing page, a part's overview page, or
|
|
1162
|
+
any other page outside a part directory, `pnpm validate:content`
|
|
1163
|
+
(`reference/gate-non-chapter-pages.ts`) fails `<Table>`, `<Figure>`,
|
|
1164
|
+
`<Diagram>`, `<CompactExamples>`, `<AssessmentSet>`, a lab (a component
|
|
1165
|
+
imported from a `labs/` module, or any `client:*` island) and
|
|
1166
|
+
`\label{eq:…}` (`non-chapter-float`); `notation.local` and
|
|
1167
|
+
`notation.suspend` (`non-chapter-local-notation`); and `$…$` or `[[…]]` in
|
|
1168
|
+
`hero.title`, `hero.tagline` or a `<PartOverview chain>` step, which print
|
|
1169
|
+
literally (`non-chapter-plain-text`). A `<Diagram>` rendered there
|
|
1170
|
+
unnumbered before, and `<Table>` and `<Figure>` threw at render;
|
|
1171
|
+
`remarkNotation` now fails the same blocks and labels at render, naming
|
|
1172
|
+
S10. Link the chapter's float instead: `[[<chapter>#tab-<key>]]` shows it
|
|
1173
|
+
in its card.
|
|
1174
|
+
- **Math on a page that is not a chapter binds like a chapter's** (rule N4,
|
|
1175
|
+
rule S10). Every symbol needs a `[[key]]` or an `\explain` on the page, or
|
|
1176
|
+
the build fails; plain `$v$` on a part page used to render with no card
|
|
1177
|
+
and no check. The text and math gates (rule N4, rule N8, rule N9,
|
|
1178
|
+
rule N10, rule N12, rule N14, rule N22, and a course's `X` rules) and
|
|
1179
|
+
per-place waivers now scan these pages too.
|
|
1180
|
+
|
|
1181
|
+
### Added
|
|
1182
|
+
|
|
1183
|
+
- **`renderLabMath(template, scope, { display: false })`** renders inline lab
|
|
1184
|
+
math — a `.katex` with no `.katex-display` — for a formula that sits in a
|
|
1185
|
+
line: a legend entry, an axis title, a control label. It never scrolls.
|
|
1186
|
+
`RenderLabMathOptions` is exported; the default stays a display equation.
|
|
1187
|
+
- **A `{ math }` run for the caption's live clause.** `setFigureState`
|
|
1188
|
+
writes a `RenderedLabMath` from `renderLabMath(…, { display: false })` as
|
|
1189
|
+
`span.float-caption__math`, so "Shown for v₀ = 20 m/s" names the lesson's
|
|
1190
|
+
own `v₀`, which opens its card.
|
|
1191
|
+
- **`unboundFigureSymbols(html)`** (`explico/reference/figure-symbols`) lists
|
|
1192
|
+
the figures in an HTML string, and the symbols in each, that KaTeX drew
|
|
1193
|
+
outside a notation binding. A course's browser test runs it on a hydrated
|
|
1194
|
+
figure's `outerHTML`, which also holds what an island draws only in the
|
|
1195
|
+
browser; the playground's `labs.spec.ts` does.
|
|
1196
|
+
- **A link to a chapter shows the chapter's full title as its tooltip.** A
|
|
1197
|
+
Markdown link or a JSX `<a href>` the author wrote to another chapter —
|
|
1198
|
+
root-relative, relative, or under the course's `base`, with or without a
|
|
1199
|
+
`#` anchor — gets the chapter's `title` as its `title` attribute
|
|
1200
|
+
(`remarkNotation`, from the manifest's lessons). A link with a title of its
|
|
1201
|
+
own, a same-page anchor, and a `[[…]]` reference, which opens a card of its
|
|
1202
|
+
own, are left alone.
|
|
1203
|
+
- **Cards on a page that is not a chapter** (rule S10). A `[[key]]` term,
|
|
1204
|
+
bound math, a citation, an abbreviation and a `[[chapter#tab-key]]`
|
|
1205
|
+
reference open their cards on the landing page and on a part's overview
|
|
1206
|
+
page: `LessonFooter` mounts the notation, citation, abbreviation and
|
|
1207
|
+
float-reference layers there, from the page's own notation bundle (shared
|
|
1208
|
+
entries only). The manifest schema is now v25: `pages` lists every such
|
|
1209
|
+
page with its `id` (`index`, `motion.index`), `slug`, `file` and a
|
|
1210
|
+
`notation` bundle of the lesson shape, and `notation.bundles` and
|
|
1211
|
+
`notation.backlinks` carry those pages' ids too.
|
|
1212
|
+
|
|
1213
|
+
### Changed
|
|
1214
|
+
|
|
1215
|
+
- **The operator baseline drops `\limsup` / `\liminf` and the
|
|
1216
|
+
category-theory `\injlim` / `\projlim` / `\varlimsup` / `\varliminf` /
|
|
1217
|
+
`\varinjlim` / `\varprojlim`.** Only `\lim` stays in `BASE_OPERATORS`
|
|
1218
|
+
(`reference/base-operators.mjs`): the other eight are not "everyone knows
|
|
1219
|
+
this" the way a plain limit, `\max`, or `\min` is, so rule N8's
|
|
1220
|
+
`operator-explained` warning now asks a course that uses one for a
|
|
1221
|
+
notation entry, like any other domain operator. A course that relies on
|
|
1222
|
+
the old baseline can restore it with `rules.N8.allow: ['limsup',
|
|
1223
|
+
'liminf', 'injlim', 'projlim', 'varlimsup', 'varliminf', 'varinjlim',
|
|
1224
|
+
'varprojlim']` in its settings.
|
|
1225
|
+
- **A lab's math wrapper never scrolls.** `.lab-math` loses its
|
|
1226
|
+
`overflow-x: auto`, `overflow-y: hidden` and `padding-block`: a display
|
|
1227
|
+
template's `.katex-display` scrolls sideways when it is wider than its
|
|
1228
|
+
box, like a lesson equation, and carries the padding. `.lab-math` keeps
|
|
1229
|
+
its `margin-block` only when it holds display math.
|
|
1230
|
+
- **A float's caption line is at least as tall as its buttons**
|
|
1231
|
+
(`min-block-size: 1.5rem` while a `.float-tool` shows, reset in print), so
|
|
1232
|
+
the row never hangs below the line — past a figure's body, or into a
|
|
1233
|
+
table's header — even when a course hides the caption's text.
|
|
1234
|
+
- **The local-notation mismatch names what it compared.**
|
|
1235
|
+
`assertLocalNotationParity` says "notation mismatch", names the page's
|
|
1236
|
+
frontmatter `notation.local` and the manifest's bundle for the page, and
|
|
1237
|
+
gives both causes left: a stale manifest, or an entry `validate:content`
|
|
1238
|
+
rejected.
|
|
1239
|
+
- **`notationDefinitionsForRenderedPage(manifest, pageId, dependencies)`**
|
|
1240
|
+
takes a lesson's id or a non-chapter page's (`manifest.pages[].id`), and
|
|
1241
|
+
its errors say "on page" instead of "in lesson". The `<Table>` and
|
|
1242
|
+
`<Figure>` missing-number errors name rule S10.
|
|
1243
|
+
|
|
1244
|
+
### Fixed
|
|
1245
|
+
|
|
1246
|
+
- **An abbreviation glossary entry can be scrolled to.** Its anchor
|
|
1247
|
+
(`#abbr-…`) sat on a `display: contents` wrapper, which has no box, so a
|
|
1248
|
+
direct URL, a full navigation and a same-page click all left the reader
|
|
1249
|
+
where they were. The `id` is on the entry's `<dt>`, with the
|
|
1250
|
+
`scroll-margin-block-start: 5rem` the other anchor targets carry.
|
|
1251
|
+
- **On a narrow screen, the header no longer covers Starlight's menu
|
|
1252
|
+
button**, so the navigation opens again on a phone: the button sits one
|
|
1253
|
+
level above the raised header (`starlight-menu-button > button`).
|
|
1254
|
+
- **Links on a part overview page and in `<CourseContents>` use the course
|
|
1255
|
+
accent** (`--sl-color-text-accent`) instead of the browser's default link
|
|
1256
|
+
colour, which `.not-content` let through.
|
|
1257
|
+
- **Printing no longer breaks a knowledge check that hydrates while the page
|
|
1258
|
+
is prepared for print** (React error #418). A collapsed-content note never
|
|
1259
|
+
goes inside an Astro island: a closed disclosure inside one gets its note
|
|
1260
|
+
after the outermost island, once per target URL, so the folded questions
|
|
1261
|
+
of one check share one note after the check.
|
|
1262
|
+
- **A `notation.local` entry that a page uses only by shape** — an operator
|
|
1263
|
+
entry `{}'` for `w'`, as rule N22 suggests — **no longer fails the build
|
|
1264
|
+
as a stale manifest.** A page's own local entries seed its notation bundle
|
|
1265
|
+
(`buildNotationRegistry`), so none is `unused-definition` any longer; the
|
|
1266
|
+
`weak-local` advice still names one the page barely uses.
|
|
1267
|
+
- **A `lint-ignore.yml` `<detail>` can name a hyphenated notation key.**
|
|
1268
|
+
`parseLintIgnore`'s line grammar excluded `-` from the detail segment, so
|
|
1269
|
+
`- notation-units:arg-min — …` (or any acknowledgement keyed to a
|
|
1270
|
+
kebab-case notation key, the shape every key in a course that follows the
|
|
1271
|
+
authoring docs' own naming convention takes) never matched the line
|
|
1272
|
+
pattern and `validate:content` threw "expected `- <code>[:<detail>] —
|
|
1273
|
+
<reason>`" instead of loading the file. Only whitespace and the em-dash
|
|
1274
|
+
separator are excluded from `<detail>` now; a bare `-`, `--`, or ` - ` was
|
|
1275
|
+
never valid *inside* a detail on its own (the separator needs the em dash,
|
|
1276
|
+
or the ASCII forms flanked the way the grammar already required), so this
|
|
1277
|
+
only admits what the docstring already promised: "a notation key".
|
|
1278
|
+
- **A table inside a worked example no longer reports rule S3's
|
|
1279
|
+
`raw-table-markdown`** (or `raw-table-html`): such a table is
|
|
1280
|
+
illustrative, like an equation there. The scan counts a table only where a
|
|
1281
|
+
`<Table>` would number it, at the lesson's top level or in a `<Memo>`,
|
|
1282
|
+
`<ShortNote>` or `<Fold>` (`scanRawFloats`, `collectRawFloats`), as
|
|
1283
|
+
`structure-rules.md#s3` always said.
|
|
1284
|
+
- **A `<Table>` or `<Figure>` nested in a worked example fails with the real
|
|
1285
|
+
reason.** `remarkNotation` names the component it sits in and the edit to
|
|
1286
|
+
make, at its line; the components' own guards name the nesting before the
|
|
1287
|
+
Astro configuration.
|
|
1288
|
+
- **A figure never draws a vertical scrollbar.** `.keyed-figure__body` kept
|
|
1289
|
+
`overflow-x: auto`, which computes `overflow-y` to `auto` as well, so a
|
|
1290
|
+
fractional height at a browser zoom scrolled by a pixel; it now clips
|
|
1291
|
+
vertically (`overflow-y: hidden`).
|
|
1292
|
+
- **A display equation that just fits no longer scrolls by 2 px.** KaTeX's
|
|
1293
|
+
stacked scripts hang a 2 px spacer outside their box; `.katex-display` (in
|
|
1294
|
+
lesson content and in `.lab-math`) reserves it with `padding-inline: 2px`
|
|
1295
|
+
on both sides, which keeps a centred equation centred.
|
|
1296
|
+
- **A `[[key]]` or an `\explain` on a part overview page no longer fails
|
|
1297
|
+
`astro build` after `validate:content` passed.** The page had no notation
|
|
1298
|
+
entries, so the payload invariant found a trigger with no card. Rule S2's
|
|
1299
|
+
"its math and `[[key]]` references render" now holds.
|
|
1300
|
+
- **An indented `[[key]]` inside a component of an `.mdx` page reaches the
|
|
1301
|
+
page's bundle.** The reference extractor masked a line indented by four
|
|
1302
|
+
spaces as an indented code block, which MDX does not have, so text
|
|
1303
|
+
indented inside `<Card>` or `<Memo>` rendered a trigger its bundle lacked,
|
|
1304
|
+
and the build failed. A `.md` file keeps CommonMark's indented code.
|
|
1305
|
+
|
|
17
1306
|
## [0.11.1] - 2026-09-28
|
|
18
1307
|
|
|
19
1308
|
### Fixed
|
|
@@ -2143,7 +3432,9 @@ under **Breaking** below; a PATCH never breaks.
|
|
|
2143
3432
|
system with its completeness gate, the curriculum-graph validator, the
|
|
2144
3433
|
Astro/Starlight UI, the LMS / session / analytics seams, and the `content` CLI.
|
|
2145
3434
|
|
|
2146
|
-
[Unreleased]: https://github.com/danieltuzes/explico/compare/v0.
|
|
3435
|
+
[Unreleased]: https://github.com/danieltuzes/explico/compare/v0.13.0...HEAD
|
|
3436
|
+
[0.13.0]: https://github.com/danieltuzes/explico/compare/v0.12.0...v0.13.0
|
|
3437
|
+
[0.12.0]: https://github.com/danieltuzes/explico/compare/v0.11.1...v0.12.0
|
|
2147
3438
|
[0.11.1]: https://github.com/danieltuzes/explico/compare/v0.11.0...v0.11.1
|
|
2148
3439
|
[0.11.0]: https://github.com/danieltuzes/explico/compare/v0.10.0...v0.11.0
|
|
2149
3440
|
[0.10.0]: https://github.com/danieltuzes/explico/compare/v0.9.0...v0.10.0
|