ontoref-outreach/scripts/decks/decks.ncl

106 lines
5.9 KiB
Text
Raw Normal View History

decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
# Which Slidev deck projects onto which site pages.
#
2026-07-17 01:00:32 +01:00
# ONE SOURCE PER PAGE, with the deck's `source` as the default.
#
# The first shape of this file said "one source, N pages" — true only for a deck that is not
# translated. A bilingual deck is TWO sources, and without a per-page source the only way to have
# an English page is to serve Spanish slides under an English URL. A page that lies about its
# language is worse than a page that does not exist.
#
# So: `pages[].source` overrides the deck's. Omit a page and that language simply has no page.
decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
{
decks = [
{
source = "ontology_slides.md", # relative to outreach/presentation/
id = "ontoref-ontologia-reflexion",
pages = [
{ lang = "es", slug = "ontoref-ontologia-reflexion" },
2026-07-17 01:00:32 +01:00
# The English page has its OWN source. The deck is Spanish (the "46/57 mix" I first
# reported was a false signal — my classifier counted `runtime`, `Nickel`, `commit` as
# English; the prose is clean Spanish). ontology_slides_en.md is a controlled translation
# that keeps the product name, the coined terms and the glossary lexicon, and uses the
# REAL English field names for the code (nodes/invariant/description/…) — which the
# Spanish deck localizes and so, on that one point, the English deck is more faithful.
{ lang = "en", slug = "ontoref-ontology-and-reflection",
source = "ontology_slides_en.md" },
],
},
{
# An intro to ontoref for an INFRA audience: "does AI manage your infra — do you know what's
# happening?". Authored in Spanish (ai-infra_es.md), translated to English (ai-infra.md) as a
# faithful counterpart — same content, glossary lexicon and real English field names in the
# code. Two sources → one build/capture/asset-dir each.
source = "ai-infra_es.md",
id = "ai-infra",
pages = [
{ lang = "es", slug = "la-ia-gestiona-tu-infra" },
{ lang = "en", slug = "does-ai-manage-your-infra", source = "ai-infra.md" },
],
},
{
source = "rustikon_es.md",
id = "rustikon",
pages = [
{ lang = "es", slug = "por-que-necesite-rust" },
{ lang = "en", slug = "why-i-needed-rust", source = "rustikon.md" },
decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
],
},
],
# Classes the site is entitled to carry INTO the deck. Everything else of the site's
# is reverted at the boundary. `gloss-`: the glossary decorates deck text — the whole
# point of the projection. `deck-`: the projection's own chrome (card, switcher, zoom).
boundary_allow = ["[class*=\"gloss-\"]", "[class*=\"deck-\"]"],
2026-07-17 01:00:32 +01:00
# The URL category segment, per language. The route is /recursos/{category}/{slug}; the KIND
# localizes (recursos↔resources) but {category} is filled literally from the content, so an ES
# deck under category "decks" gives /recursos/decks/… — Spanish path, English word. Localizing
# the category (es = "presentaciones") keeps the whole ES URL Spanish. Runtime route, no rebuild;
# registers on server restart.
category = { es = "presentaciones", en = "decks" },
decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
# Slidev's native slide geometry. The WIDTH is the scaling base; the height is only a
# floor — 12 of 16 slides in this deck hold more than 552px, so the card grows to its
# measured content instead of cutting it.
slide = { width = 980, height = 552 },
# The chrome is the SITE's UI, so it speaks the page's language. One capture, N pages:
# the deck body is shared, the wrapper around it is not.
i18n = {
es = {
read = "Leer todo", slider = "Diapositivas", index = "Índice",
index_head = "Índice", slides = "diapositivas",
prev = "Anterior", next = "Siguiente",
zoom = "Ampliar diapositiva", slide = "Diapositiva",
2026-07-17 01:00:32 +01:00
aria = "Presentación de %n diapositivas. Con el foco puesto, las flechas o la barra espaciadora navegan.",
help = "Cómo usar",
help_title = "Cómo usar esta presentación",
help_items = [
"Diapositivas / Leer todo — pasa las slides una a una, o vélas todas apiladas (ahí funciona buscar con <kbd>Ctrl</kbd>+<kbd>F</kbd>, seleccionar y copiar el texto).",
"Índice — muestra u oculta el índice lateral; al pulsar una entrada saltas a esa slide.",
"Términos del glosario — algunas palabras llevan un realce ámbar: pasa el ratón por encima (o púlsalas en móvil) para ver una definición breve.",
"Teclado — con la presentación seleccionada: <kbd>→</kbd> o <kbd>Espacio</kbd> avanzan, <kbd>←</kbd> o <kbd>Shift</kbd>+<kbd>Espacio</kbd> retroceden.",
"Ampliar — el botón <kbd>⤢</kbd> abre la slide a pantalla completa; <kbd>Esc</kbd> la cierra.",
"Copiar código — pasa el ratón por un bloque de código y pulsa el botón de arriba a la derecha para copiarlo.",
],
decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
},
en = {
read = "Read all", slider = "Slides", index = "Index",
index_head = "Index", slides = "slides",
prev = "Previous", next = "Next",
zoom = "Enlarge slide", slide = "Slide",
aria = "Deck of %n slides. With focus on it, arrows or the space bar navigate.",
2026-07-17 01:00:32 +01:00
help = "How to use",
help_title = "How to use this deck",
help_items = [
"Slides / Read all — step through one at a time, or see them all stacked (there <kbd>Ctrl</kbd>+<kbd>F</kbd>, select and copy the text all work).",
"Index — shows or hides the side index; clicking an entry jumps to that slide.",
"Glossary terms — some words carry a faint amber highlight: hover them (or tap on mobile) for a short definition.",
"Keyboard — with the deck focused: <kbd>→</kbd> or <kbd>Space</kbd> advance, <kbd>←</kbd> or <kbd>Shift</kbd>+<kbd>Space</kbd> go back.",
"Enlarge — the <kbd>⤢</kbd> button opens the slide full-screen; <kbd>Esc</kbd> closes it.",
"Copy code — hover a code block and press the button at its top-right to copy it.",
],
decks: the slides stop being pixels — Slidev's own render, captured and re-homed The published deck was a hand-written carousel of exported PNGs: the words of every slide were an IMAGE of words. Nothing indexed them, no glossary tooltip could reach them, no screen reader read them, and the page drifted from the source the moment a slide changed. The deck is NOT re-parsed. Slidev's markdown is not standard markdown, and its meaning does not live in the markdown anyway — it lives in a compiled bundle of UnoCSS utilities, theme rules and <style scoped> blocks. Re-implementing that is re-implementing a renderer, in any language. So Slidev renders (its own /print route, the one `slidev export` drives) and we capture what it produced: the DOM, and the CSS the browser actually applied. Measured on the served page: 0 → 2152 indexable words, 16/16 slides reachable, 0 third-party origins added, 0 broken references. Twelve traps, none of which raised an error: · The CSS must be asked of the BROWSER (17 stylesheets; index.html links 2). · Collapsing :root/html/body imports the SPA's viewport cage — it clipped the deck at 900px and swallowed 14 of 16 slides, silently. · UnoCSS's preflight, scoped, kills the glossary underline it was supposed to enable. · :not() inherits its argument's specificity — the boundary guard grew with every exemption until it reverted the slide scaling. :not(:where(…)) contributes zero. · scale(calc(100cqw / 980)) is invalid CSS and is dropped in silence; on a phone the box was 328px while the content stayed 980px and two thirds of every slide was cut. · The site's markdown renderer destroys an inline <script>: curly quotes, injected <p>, &amp;&amp;. CSS and JS go to external files — correctness, not optimisation. · The 980x552 frame CUT 12 of 16 slides (Slidev cuts them too; nobody had seen it, because the slides were PNGs of themselves). · transform: translateY(0) — an IDENTITY transform — makes <main> the containing block for position:fixed, and the zoom modal landed at top = -221px. Two views over one DOM (slider default, stacked reads with Ctrl+F), an index derived from each slide's own H1, a sticky rail, zoom, and Slidev's own copy buttons revived — they shipped in the captured DOM at 0x0, unclickable by any human. Twelve gates (A–L), and IN THE CHAIN: `just decks` in sync-full, `decks-check` in `check` (on disk), `decks-served` in `check-live` (the page). A generator outside the chain is a generator that does not run.
2026-07-14 19:41:51 +01:00
},
},
}