System Map

Generator System Map

This file is the shortest path to understanding the generator as a whole.

Source Of Truth

  • Hugo templates and partials under layouts/ are the render authority.
  • Markdown content files in site repos are the authoring authority for page text and structured fenced blocks.
  • Browser editors in cdn/custom/ are editing interfaces, not render-authority.
  • The local markdown bridge remains the localhost and future-local-app path.
  • Hosted website editing should use the workspace provider backed by generator-api.
  • For websites, the draft host under *.drafts.quantalumin.com is the primary editor surface. Nextcloud/qloud is the shell and discovery layer, not the main website editor UI.

Main Runtime Layers

Render pipeline

  • Page shells: layouts/_default/
  • Shared partials: layouts/partials/
  • List/summary cards: layouts/partials/views/summary.html
  • Shop/storefront section templates:
  • Page chrome contract/render shell:
    • layouts/partials/page/chrome-contract.html
    • layouts/partials/page/chrome-render.html
  • Header contract:
    • layouts/partials/page/header-contract.html
  • Site archetype contract:
  • Hugo blog workspace contract:
  • Render hooks / preprocessors:
    • layouts/_default/_markup/
    • layouts/partials/preprocess.html
  • Newsletter subscription surface:
    • layouts/partials/footer.html
    • layouts/partials/form/newsletter-inner.html
    • layouts/partials/helpers/newsletter-listmonk-config.html

Site/page chrome behavior such as sticky headers is now resolved through the shared header contract. Preferred config lives in params.header.* and page front matter header.*. Older params.chrome.stickyHeader, chrome.stickyHeader, top-level stickyHeader, and the legacy header fixed class are still accepted as compatibility inputs, but they now flow into the same header contract instead of staying separate chrome logic.

List-page summary cards also follow the Hugo render pipeline rather than flattening rendered output. views/summary.html now routes summary sources through a first-paragraph helper, so cards only use the first real paragraph and skip headings, quotes, figures, and similar leading blocks while still preserving inline render output such as passthrough math/KaTeX inside that paragraph. That helper must return a safe HTML fragment rather than escaped tag text because the summary card injects it directly into the rendered card body. List cards can now also read richer page front matter directly, including summary_title, summary_eyebrow, summary_link_label, and icon, so list pages can stay author-light while child pages own their own summary-card copy, iconography, and CTA text.

Editorial TODO surfaces also stay draft-only across both supported authoring forms. The fenced todo codeblock and the [!TODO] blockquote/callout path now both suppress output unless site.BuildDrafts is enabled, so author notes do not leak into published pages.

The rendered header shell reads that semantic model in layouts/partials/header.html and passes it down to logo and nav/breadcrumbs, which now prefer params.header.* first and only fall back to legacy HeaderNav.* fields when the semantic fields are not yet present. Header-bound runtime code should also treat the header as a replaceable SPA surface rather than a static singleton. Shared navigation currently depends on ql:header-swapped from cdn/prefetch/prefetch.js so late header sync passes can re-bind burger toggles and other direct header DOM behavior after the header node itself is replaced. The mobile header runtime in cdn/custom/brochure-nav.js also keeps a body-level MutationObserver on direct header swaps, so it can recover when a later SPA header refresh lands after the usual route events. That same runtime now owns the shared build-revision handshake as well: layouts/partials/head.html publishes meta[name="ql-build-version"] plus ql-build.json, while cdn/prefetch/prefetch.js uses that revision to invalidate stale SPA HTML and force one full reload onto a newer deployment when the browser is still running an older head/runtime. The brochure/mobile header path is owned jointly by cdn/custom/brochure-nav.js and cdn/custom/brochure-responsive.css: at phone widths the shared contract is burger toggle on the left, centered logo in the top row, collapsed menu panel below. The toggle now renders in the shared header HTML so first paint already matches the mobile shell; the runtime only wires aria-controls, open/closed state, CTA relocation, and the mobile altmenu merge. Do not fork that behavior in site-local header CSS. The shared image pipeline in layouts/partials/media/resource-image.html also treats .section-banner figures as banner-class assets explicitly, so large split-homepage images keep the responsive WebP path even when the surrounding section layout tokens do not reach the figure itself. Page-level CTA rows in layouts/partials/main.html should not depend on the template auto-title being visible: CV/download actions need to remain available even when a page owns its title via a markdown H1 instead of the template header block.

Sections are now moving in the same direction. Hugo still emits legacy layout classes for compatibility, but rendered section roots and #editorData now also carry a smaller semantic axis contract:

  • flow
  • media_side
  • size
  • content_align
  • surface
  • layout_family

Those section axes currently appear as data-ql-flow, data-ql-media-side, data-ql-size, data-ql-content-align, data-ql-section-surface, and data-ql-layout-family on each rendered section root.

Shared media/button render hooks also preserve backward compatibility for authored content:

  • local .html media defaults to inline rendering through layouts/partials/figure/html.html, while explicit iframe embeds still use the iframe path
  • local .glb and .gltf media resolve through layouts/partials/figure/model.html and the lazy Three.js runtime in cdn/custom/modelViewer.js, so sites can author 3D models with the normal markdown image contract such as ![](hall.glb){.fig .fit}; the runtime applies a neutral fallback material only to implicit bare-white meshes so materialless exports do not render as flat white by default, and page modelViewer front matter can add a floor-plan backdrop (floorPlanSrc, floorColor, floorPlanOpacity), an optional modelColor tint, and progressive rooms navigation that renders before the Three.js runtime is ready
  • the buttons fenced block accepts both standard markdown links and legacy angle-bracket shorthand such as [Label](</path .button .primary>)

Workspace-backed assets can be exposed to the render hooks through Hugo assets when the workspace app writes a mount overlay for the build. The app remains responsible for access control: a Hugo command run scans authored Markdown image destinations and may only mount source workspaces that the current user can read. Once mounted, the generator resolves strict workspace markdown image destinations through layouts/partials/media/utils/find.html using Hugo resources.Match.

Authors can use either same-owner or fully qualified workspace references:

![Josephson island](qulab:josephson-island-geometry.png)
![Ray sheet bridge](henry/qulab:qulab/caustics/animations/blender/ray_sheet_bridge.png)
![Explicit glob](henry/qulab:**/figs/fold-cusp-caustics.svg)

Resolution is intentionally strict:

  • qulab:foo.png mounts readable workspace qulab under the same owner as the target workspace, then searches workspaces/qulab/**/foo.png.
  • henry/qulab:foo.png mounts readable workspace henry/qulab, then searches workspaces/henry/qulab/**/foo.png.
  • henry/qulab:some/path/foo.png tries exact workspaces/henry/qulab/some/path/foo.png, then workspaces/henry/qulab/**/some/path/foo.png.
  • henry/qulab:**/figs/foo.svg is an explicit glob under workspaces/henry/qulab/.
  • zero matches fail the Hugo build
  • multiple matches fail the Hugo build and list the matching asset names
  • missing or unreadable source workspaces fail in the workspace app before Hugo starts

This keeps workspace figure reuse author-friendly without silently publishing broken or ambiguous figures. Plain static URLs do not participate in strict asset validation.

The shared newsletter form is also site-configured rather than site-forked. Newsletter copy and list IDs live in params.subscribe.*, while ListMonk transport settings now live in params.subscribe.listmonk.*. That lets different client websites point at different ListMonk nodes without modifying shared partials.

The first site-wide archetype contract now lives alongside that config layer. Sites should declare params.site.archetype once in config, then let shared generator templates and editor runtime consume that semantic label through the resolved site archetype contract. Current canonical archetypes are:

  • brochure
  • venue
  • storefront
  • service-commerce
  • research
  • generic

Those archetypes are intentionally smaller than a full theme system. In practice, the shared authored pattern for sites such as Rawson Hall and TutorLumin is a place-network stack built from world, card_grid, steps, calendar, booking, and platform shortcodes rather than site-local layout forks.

Editor pipeline

  • Edit-mode shell and inspector: cdn/custom/toggleMarkdown.js
  • Nowtype source: cdn/editor/src/
  • Runtime editor bundle: cdn/editor/nowtype.min.js
  • Local file bridge: scripts/local-markdown-bridge.mjs

In replace-main presentation, the editor toolbar belongs to the editor shell flow. Keep it mounted inside the replace-main panel rather than portaling it to document.body; that allows the toolbar to sit above the page surface and push the editing surface down instead of drawing over the page/header chrome.

The replace-main image-preview path also upgrades local SVG figure previews from <img> to inline SVG markup inside cdn/custom/toggleMarkdown.js. Those editor-side inline SVG instances must namespace their internal IDs per preview mount; otherwise duplicated gradients, clip-paths, markers, or <use> targets can collide at document scope and lose paint data in edit mode even though Hugo normal-mode rendering remains correct.

The shared inspector now has a first semantic chrome edit path:

  • when no live section is selected, the Layout tab exposes a Header card
  • that card edits site config params.header.* or page front matter header.*
  • the local bridge exposes:
    • /ops/header/read
    • /ops/header/set
    • /ops/header/unset

The shared inspector also now reads the new section axis contract first for selected live sections. Its current canonical write split is:

  • section-frame semantics write to the section body’s leading { ... } attr block
  • content width and block layout presets write to the section body’s trailing --- { ... } attr block

That keeps Hugo and markdown authoritative while older frontmatter.sections[*] metadata remains a compatibility/editor seam instead of the primary render source.

Style/token pipeline

  • Root + scoped tokens: assets/css/variables.css
  • Shared SCSS entry: assets/scss/main.scss
  • Widget integration contract: Widget integration
  • Widget subsystem rule: widget roots alias site tokens into local --widget-* variables, reset shared component leakage locally, and rebuild their own controls explicitly inside that namespace.
  • Shared motion/reveal layer:
    • assets/scss/libs/_animation.scss
    • cdn/custom/fadeAnimation.js
  • Chat/support bubble integration:
    • layouts/partials/page/chatwoot-contract.html
    • cdn/custom/chatwoot.js
    • Site/page config flows through params.chatwoot / chatwoot front matter and into body[data-ql-chatwoot-*]; the runtime only loads Chatwoot when both baseUrl and websiteToken are present. The shared contract prefers explicit params.chatwoot.supportSiteSlug, but can also derive the support site from the current site.BaseURL host against params.chatwoot.site.<slug>.website mappings. Use this path for optional live chat before bridging into the wider helpdesk system.
  • Navigation/discovery buttons:
    • cdn/vim/lib/help.js
    • assets/scss/components/_vim-help.scss
    • cdn/spherelist/spherelist.js
    • assets/scss/components/_spherelist.scss
    • layouts/_default/sitemap.xml
    • layouts/partials/tools/spherelist.html
    • Keep the keyboard-shortcut helper and SphereList as explicit buttons, not invisible hover affordances, so visitors can discover them without knowing internal vimkeys.
    • The keyboard helper renders its own searchable, grouped shortcut palette from the registered Vim binding metadata; do not duplicate that shortcut menu in site-local layouts.
    • Public sitemap output should exclude page-lock-tracked pages, while SphereList should hydrate from the embedded runtime site index and only surface member pages whose current lock status has already resolved to unlocked for the visitor.
  • Section/layout components:
    • assets/scss/components/_wrapper.scss
    • assets/scss/components/_banner.scss
    • assets/scss/components/_spotlight.scss
  • Homepage hero rotator:
    • layouts/partials/page/homepage-banner.html
    • layouts/partials/page/homepage-banner-config.html
    • assets/js/homepage-banner.js
    • Contract: the first home section can opt in with homepageBanner on the page or site; slides resolve from page resources or site assets/ globs and reuse layouts/partials/media/render.html for responsive WebP output. Timing is controlled by intervalMs and transitionMs; visual tuning can be driven per page/site with imageBrightness and overlayOpacity so banner imagery can be lightened or darkened without forking the shared component. Homepage-banner content width follows the shared --surface-content-max-width path, and text over mixed-luminance imagery can opt into the .ql-hero--liquid-glass card utility from assets/scss/libs/_theme-helpers.scss, which preserves the background image while giving hero copy deterministic contrast and exposes text-only shadow hooks (--ql-liquid-hero-text-shadow, --ql-liquid-hero-lead-shadow, --ql-liquid-hero-kicker-text-shadow) without changing the glass surface itself.

Reveal-enabled templates opt in declaratively with data-ql-reveal-* attributes. Current shared knobs are:

  • data-ql-reveal: enable the runtime on a container
  • data-ql-reveal-trigger: reveal mode such as load or enter
  • data-ql-reveal-target: descendant selector to animate
  • data-ql-reveal-order: reveal ordering such as sequence, reverse, or random
  • data-ql-reveal-duration: transition duration
  • data-ql-reveal-base-delay: initial delay before the first target starts
  • data-ql-reveal-stagger: per-item stagger duration

Inline markdown figures still use the shared floated figure-inline contract in assets/scss/components/_figure.scss. The first inline figure after prose still clears prior floats, but back-to-back opposite-side inline figures are allowed to share a row instead of forcing a fresh clear on each figure. That reduces dead whitespace in chapter flows while keeping headings below the float stack.

Authoring Surface

The generator currently supports four main authored input styles:

  1. Normal markdown sections and figures
  2. Structured fenced blocks like team, gallery, contact, faq, stats, testimonials, world, card_grid, steps, pricing, and facts
  3. Hugo shortcodes under layouts/shortcodes/
  4. Front matter / config token overrides, including params.site.archetype

Agent/MCP Documentation Surface

For agents editing sites through an MCP-style protocol, the intended documentation stack is:

The manifest is the canonical inventory for shortcode availability and should be preferred over ad hoc template inference in agents.

Documentation Rule

When adding or changing a shortcode:

  1. update the shortcode implementation in layouts/shortcodes/
  2. update shortcodes.manifest.json
  3. update shortcodes.md if the author-facing contract changed
  4. run scripts/check-shortcode-manifest.mjs