npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

slidev-theme-lilas

v0.1.12

Published

A standalone Slidev theme with reusable presets and optional Obsidian integration.

Readme

slidev-theme-lilas

NPM version

A standalone Slidev theme with reusable visual presets and optional obsidian-slidev integration.

Ordinary Slidev Markdown can use the theme directly. When a deck is generated by obsidian-slidev, the theme additionally renders its Obsidian-specific semantic markup.

Install

Install the package:

pnpm add slidev-theme-lilas

Then add the following frontmatter to your slides.md:

Learn more about how to use a theme.

Obsidian Integration

obsidian-slidev can emit the following frontend-native structures, and this theme styles them directly:

| Source idea | Generated target | | --- | --- | | Obsidian callouts | .obsidian-slidev-callout blocks | | Vault images, videos, and audio | .obsidian-slidev-media figures | | YouTube links | Slidev's built-in <Youtube> component | | Video embeds | Slidev's built-in <SlidevVideo> component | | Obsidian note links | .obsidian-slidev-link anchors | | Missing references | .obsidian-slidev-warning blocks |

The theme does not parse Obsidian Markdown by itself. Keep conversion logic in obsidian-slidev; keep rendering and presentation in this theme.

Shared protocol compatibility

Lilas declares consumer support for the independently versioned shared contracts:

Both declarations use the conservative half-open range [1.0.0, 1.1.0). The declaration lives at package.json#/obsidianSlidev/support. Package name, package version, and publication digest are not runtime compatibility inputs.

Generated decks carry obsidian-slidev-protocol, and may explicitly select obsidian-slidev-profile. During setup, Lilas parses those fields and its own support declaration, evaluates the exact coordinates, and updates the generated .obsidian-slidev-compatibility notice. In an embedded Obsidian preview it also echoes the opaque obsidianSlidevToken in an obsidian-slidev/protocol-support parent message. A compatible result hides the notice, missing support remains visibly unverified, and an explicit mismatch stays visible as a best-effort warning without stopping setup. The message is runtime advice only; it is never formal conformance evidence.

In a source repository checkout, the verified publication snapshot is under vendor/obsidian-slidev-protocol/1.0.0/, with source revision, publication digest, and deterministic archive digest recorded in protocol.lock.json. These conformance artifacts are repository evidence and are not shipped in the runtime npm package. Do not edit those files by hand. To adopt a new exact publication from an explicit obsidian-slidev checkout:

node /path/to/obsidian-slidev/scripts/export-protocol-publication.mjs \
  --protocol-root /path/to/obsidian-slidev/protocol \
  --publication X.Y.Z \
  --expected-publication-sha256 <publication-sha256> \
  --output "$PWD/vendor/obsidian-slidev-protocol/X.Y.Z" \
  --archive "$PWD/vendor/obsidian-slidev-protocol/X.Y.Z.tar"

node /path/to/obsidian-slidev/scripts/verify-protocol-consumer-lock.mjs \
  --protocol-root /path/to/obsidian-slidev/protocol \
  --publication X.Y.Z \
  --theme-root "$PWD" \
  --expected-source-repository https://github.com/xunz3/obsidian-slidev.git

Record the exporter’s hashes and full source revision in protocol.lock.json, update the package ranges only after the canonical core/Profile fixtures pass, then run node --test tests/quality/protocol-conformance.spec.mjs and pnpm run quality. Export into an absent version path; a published version is immutable and must not be overwritten.

default, ucas, and ict, their light/dark visuals, branding, tokens, and layout styling remain Lilas-only implementation features. They are deliberately absent from Profile facts and never influence protocol compatibility.

Semantic Boundary

The theme keeps generic presentation structure separate from integration-specific markup:

| Scope | Names | | --- | --- | | Theme frame and layouts | SlideFrame, .slide-frame, .slide-layout-* | | Theme configuration | themeConfig.presentation, presentationPreset, presentationDensity | | Theme design tokens | --presentation-* | | Markup emitted by obsidian-slidev | .obsidian-slidev-* |

Only the last group is intentionally Obsidian-specific.

Theme Config API

The stable public configuration surface is themeConfig.presentation.

title: My Deck
subtitle: Optional deck subtitle
footer: Custom center footer
authors:
  - name: xunz
    institution: UCAS
    email: [email protected]
  - name: jane
    institution: UCAS
    email: [email protected]
themeConfig:
  presentation:
    preset: default
    accent: "#345f8f"
    density: normal
    chrome: auto
    header: false
    footerAuthors: true
    pageNumber: true

Supported keys:

| Key | Values | Default | Purpose | | --- | --- | --- | --- | | preset | default, ucas, ict | default | Selects the visual system without changing generated markup | | accent | Any CSS color | theme default | Overrides the primary accent color | | density | compact, normal, relaxed | normal | Adjusts slide padding, spacing, and body scale | | chrome | auto, on, off | auto | Controls footer metadata chrome | | header | true, false | false | Shows the optional per-slide title/subtitle header | | footerAuthors | true, false | true | Shows or hides author names in the left footer | | pageNumber | true, false | true | Shows or hides the right footer page number |

Per-slide overrides:

| Frontmatter key | Values | Purpose | | --- | --- | --- | | presentationPreset | default, ucas, ict | Override the preset for one slide | | presentationDensity | compact, normal, relaxed | Override density for one slide | | presentationChrome | auto, on, off | Override slide chrome behavior | | chrome | auto, on, off | Alias for presentationChrome | | presentationHeader | true, false | Force the optional header on or off for one slide | | header | true, false | Alias for presentationHeader | | footerAuthors | true, false | Override left footer author visibility for one slide | | pageNumber | true, false | Override right footer page-number visibility for one slide | | footer | Text | Override the centered footer content for one slide | | accent | Any valid CSS color | Override the presentation accent for one slide |

themeConfig is Slidev's standard theme/addon configuration object. This theme keeps its own options under themeConfig.presentation so they do not collide with Slidev core fields or other addons. density selects the spacing scale: compact uses tighter padding and lists for information-dense slides, normal is the default, and relaxed gives content more breathing room.

Values resolve independently using first valid precedence. When a layer exists for an option, the order is an explicit layout prop, the canonical per-slide key, its documented alias, the deck-level themeConfig.presentation value, and finally the default. Invalid or empty values are skipped instead of suppressing a valid lower-priority value. accent uses the narrower order of valid slide accent, valid deck themeConfig.presentation.accent, then the active preset/mode token.

Textual booleans are accepted for YAML and generator compatibility. Boolean options accept native booleans plus the strings true, false, on, and off after trimming; other spellings such as yes, no, 1, or uppercase variants are invalid. chrome also maps native or textual true to on and false to off.

Deck metadata such as title, subtitle, footer, and authors stays at the Slidev frontmatter root because it describes content, not theme behavior. The cover layout renders explicit subtitle metadata under the title; it does not infer a subtitle from the first paragraph. authors can be a list of strings or objects with name, institution, and email; the cover layout renders each author's full details side by side under the title, and the footer uses only author names on the left when themeConfig.presentation.footerAuthors is enabled. The centered footer uses per-slide footer first, then top-level footer, then top-level title.

Title rendering follows a fixed rule:

| Location | Visible title source | Metadata role | | --- | --- | --- | | cover layout | Root or cover-slide title / subtitle metadata | The first Markdown # is hidden when metadata title exists, preventing duplicate cover titles | | intro layout | Markdown # content | Intro titles use the same large display scale as section dividers while retaining normal chrome behavior | | Normal content layouts | Markdown content such as # Slide Title | Per-slide title / subtitle is metadata for navigation, TOC extraction, and the optional header | | Optional header | Per-slide title / subtitle metadata only | It never falls back to the deck title, so global deck metadata is not repeated on every slide | | Footer center | Per-slide footer, then root footer, then root title | Footer content is deck chrome, not the slide's visible content title |

Theme chrome means the non-content frame around each slide. By default it is footer-only: author names are used on the left footer, deck metadata is used in the centered footer, and themeConfig.presentation.pageNumber only controls the right footer page number. The header is intentionally opt-in because per-slide title and subtitle usually duplicate the visible Markdown heading.

Institutional lockups are reserved for cover and section-divider slides. Ordinary content slides leave the top-right corner unbranded in both the UCAS and ICT presets, including when the optional header is enabled.

Pre-1.0 migration

This package has not reached 1.0, so it keeps one canonical route for each concept instead of carrying unused aliases:

  • use layout: end instead of layout: thanks;
  • use author instead of cite for quote-layout attribution;
  • use Figure's typed fit="contain|cover" instead of the undocumented duplicate backgroundSize prop. The image-left and image-right layouts still use backgroundSize;
  • move any centered-footer value from the undocumented root info field to root or per-slide footer, or use the root title fallback.

Ordinary Slidev Markdown, root deck metadata, themeConfig.presentation, documented per-slide overrides, canonical public components/layouts, and .obsidian-slidev-* semantic markup remain supported. The theme does not convert Obsidian syntax. Legacy chrome and header per-slide configuration aliases remain accepted because they are active documented inputs; presentationChrome and presentationHeader are preferred in new decks.

The corrected visuals are intentional: images now honor explicit contain/cover geometry, generated and component-authored figures share stable states, links use one text-bounded underline, callout families keep their semantic markers, Badge markers are opt-in, completed tasks are quieter than unfinished tasks, highlights are flat prose washes, Steps and Timeline have distinct sequence cues, and minimal closings are centered.

Public content components

These eight components auto-register for ordinary Slidev Markdown. They need no addon or conversion step, forward normal class and style attributes to their root, and introduce no focusable control except a valid authored email link.

| Component | Props | Default / slot contract | | --- | --- | --- | | Callout | type, title | Neutral type; a type-specific title or Callout; default slot accepts Markdown/Vue | | Figure | src, alt, caption, fit | Missing-source state; resolved alt described below; no caption; fit="contain" | | Authors | variant (cards or cover) | Reads root authors, then root author; cards is the normal presentation | | Steps | none | Default slot should contain one ordered Markdown list | | Timeline | none | Default slot should contain one ordered Markdown list; native <time> is optional | | Tag | none | Default slot is visible category text | | Badge | tone, marker | tone="neutral"; marker="false"; default slot is visible status text | | Kbd | keys string array, accessibleSeparator | Without keys, the default slot is one key; non-empty keys wins; separator defaults to plus |

Callout

Callout accepts all 19 canonical Obsidian types: note, info, todo, abstract, summary, tip, success, check, warning, caution, attention, danger, error, failure, question, help, faq, quote, and cite. Matching is case-insensitive after trimming. Empty or unsupported values use the neutral treatment and default title Callout; an authored non-empty title always wins.

<Callout type="warning" title="Reproducibility">

Keep the **raw observations** and link to the [protocol](https://example.com).

</Callout>

The component emits the same core .obsidian-slidev-callout structure and preset treatment as generated callout markup. Type wording and the invariant family shape accompany color, so meaning is not color-only: positive uses a diamond, caution a triangle, danger a square, question a ring, and quotation a bar. Presets may tune spacing and surface treatment, but do not flatten those markers, change the family title tone, or alter authored title casing.

Figure

<Figure
  src="/results.png"
  alt="Accuracy increases across three evaluation rounds"
  caption="Figure 1. Evaluation accuracy by round."
/>

alt is tri-state:

| Authored state | Result | | --- | --- | | Non-empty alt | Uses that text alternative | | Explicit alt="" | Treats the image as decorative; never substitutes the caption | | Omitted alt, non-empty caption | Uses the caption as the alternative | | Omitted alt and caption | Uses Figure |

An empty src or failed request removes the broken image and retains meaningful fallback text. The bounded media viewport reserves space before decode. Empty captions add no figcaption; fit accepts contain or cover. When a transient request fails, a template ref may call the exposed retry() method to remount the same source without changing its URL.

contain is the default and preserves the complete source inside the bounded region; cover fills that region and may crop opposite edges when aspect ratios differ. Direct image figures generated by obsidian-slidev use the same default fit, region size, caption treatment, and pending/ready/failed vocabulary without being reparented. A failed meaningful generated image replaces the broken asset with an equally sized named fallback; an explicit decorative alt="" remains unnamed and never invents fallback text.

Native video figures reserve the same stable viewport height before metadata loads. The video fills the available width and uses object-fit: contain, so unusual source ratios remain fully visible without moving surrounding content. YouTube embeds retain their explicit 16:9 viewport.

Links

Ordinary Markdown links, generated .obsidian-slidev-link anchors, author email actions, and closing contacts use one underline bounded to rendered text. There is no persistent full-container border or second underline. Keyboard focus adds a visible outline without changing layout, and block links remain block-level only when the author requests that layout.

Authors

Declare authors in root frontmatter, then place <Authors /> on any slide:

authors:
  - Ada Lovelace
  - name: Grace Hopper
    institution: US Navy
    email: [email protected]
<Authors />

Strings become names. Objects accept name, institution, and email; empty fields and empty records disappear, while collection order and intentional duplicate records remain. Within one card, exact-after-trim duplicate values render once. If a name is absent, email becomes the primary label before institution, without being repeated as detail. Root authors wins, with legacy root author used only when the plural value has no valid entry. An address matching ^[^\s@]+@[^\s@]+$ becomes exactly one visible-focus mailto: link. Other non-empty email text remains visible but non-actionable.

Steps and Timeline

Both components preserve the authored <ol> and source order. Steps adds numbered sequence cues; Timeline adds chronological markers and may contain author-controlled <time datetime="…"> elements.

<Steps>

1. **Collect** observations.
2. **Normalize** measurements.
3. **Report** uncertainty.

</Steps>

<Timeline>

1. <time datetime="2026-07">July 2026</time> — Dataset frozen.
2. **Today** — Results released.

</Timeline>

Steps node labels follow authored ordered-list numbering, including start and item value. Timeline suppresses visual ordinals, uses unnumbered chronological nodes, and aligns authored <time> and leading <strong> labels in equivalent containers. Both use one center-to-center rail between adjacent nodes. Zero or one item creates no orphan connector, and non-list slot content remains readable without sequence decoration.

Tag, Badge, and Kbd

<Tag>Method</Tag>
<Badge tone="positive" marker>Complete</Badge>
<Badge tone="caution">Needs review</Badge>

Press <Kbd>Esc</Kbd>, or open commands with
<Kbd :keys="['Ctrl', 'Shift', 'P']" />.

Tag is an outlined category cue; Badge is a filled status cue. Badge tone accepts neutral, info, positive, caution, danger, question, or quotation after case-insensitive trimming; invalid values resolve to neutral. marker accepts a native boolean or the lowercase textual booleans true, false, on, and off after trimming, and defaults off so authored icons never gain an unintended duplicate dot. Invalid text also resolves off. When enabled, the marker uses the same non-color semantic shape as the tone. Tag and Badge remain visible text, non-focusable, and distinct without relying on hue. Kbd ignores non-string and empty runtime keys entries, gracefully falls back when keys is not an array, and renders a readable, non-focusable key sequence. Separators are visible as + and exposed to assistive technology as the word “plus”. Set accessibleSeparator (for example, " 加 ") to localize that spoken separator. It is never a button.

Tasks and highlights

Normal Markdown task lists keep their checked state but become presentation-only: checkbox inputs are disabled, removed from tab order, and cannot toggle on click or key press. Nested and wrapped labels stay aligned, and checked items use a visible check plus text treatment rather than color alone. The same normalizer accepts generated .obsidian-slidev-task-list / .task-list-item markup, including nodes added after initial render.

Use native <mark> for standalone highlights:

- [x] Reproduce the result
- [ ] Archive the environment

Compare the <mark>validated cohort</mark> with a [linked cohort](https://example.com)
and `inline code`.

Generated .obsidian-slidev-highlight markup receives the same prose treatment. The theme does not parse ==highlight==, and highlight selectors are reset inside pre and code, so literal syntax and code samples remain code.

Completed tasks use a visible check and muted regular-weight text; unfinished tasks retain the stronger primary emphasis. Prose highlights use a flat warm wash with no border, radius, inset edge, or keycap shadow, and the wash follows wrapped line fragments.

Containment and authoring fallback

Components wrap at the canonical 980 × 552 viewport. Inline labels/keycaps cannot create slide-level horizontal overflow; sequences and author cards stay contained; media reserves bounded space; and the shared frame provides last-resort scrolling for unusually long callouts or figures. For long image-and-text narratives or code, prefer compact density, shorten the content, or split the slide rather than shrinking text below a readable size.

Structural chrome, section brand spacing, and bilingual headings

Each rendered frame resolves one local --presentation-chrome-accent. Header and footer dividers, table-header rules, ordinary list markers, sequence rails, and the ICT footer cap consume that same secondary role; semantic callout carriers remain independently stronger. Ordinary content slides render no institutional mark and therefore reserve no dead brand strip. Cover branding occupies dedicated cover structure. UCAS and ICT section dividers reserve inline-end space for their lockup, use a smaller lockup at the compact viewport, and omit that top-right lockup when an explicitly enabled header owns the row. Their decorative watermark stays behind content at the same strength in light and dark mode.

The theme intentionally normalizes rendered bilingual heading text in the DOM. In h1h4 and frame title/subtitle text, canonical English · 中文 spacing becomes English · 中文: only the breaking space immediately before U+00B7 is replaced with U+00A0. This keeps the separator with the preceding phrase while the following phrase can still wrap. The normalizer also observes later heading-text updates, is idempotent, and does not rewrite source Markdown. Because the rendered text node is changed, copying that heading from the presentation preserves the non-breaking space. Other punctuation, spaces, nested emphasis/links, casing, and generated body text are left unchanged.

Slide-level accent

Set a deck default under themeConfig.presentation.accent, or override one slide with frontmatter:

---
accent: "oklch(62% 0.18 28)"
---

Values must be non-empty CSS colors accepted by the shared color validator. Resolution is first valid slide accent, then valid deck accent, then the active preset/mode token. Empty or invalid local values fall through; they never clear a valid deck value. A local value is bound only to that rendered slide's --presentation-accent and --slidev-theme-primary, so navigation, overview, presenter, and export views cannot leak one slide's color into another.

The resolved accent affects links, focus treatment, general callouts, chrome, tables, code, highlights, and sequence/status decoration. It does not recolor official UCAS/ICT artwork or locked brand tokens, semantic warning/danger/success/question colors, or author-supplied image pixels.

CSS Variables

Advanced users can override theme tokens from custom CSS or a Slidev style entry.

| Variable | Purpose | | --- | --- | | --slidev-theme-primary | Slidev-compatible primary color | | --presentation-accent | Theme accent used for links, chrome, callouts, and highlights | | --presentation-chrome-accent | Frame-local secondary color shared by structural chrome consumers | | --presentation-bg | Slide background base color | | --presentation-bg-elevated | Elevated surface color | | --presentation-bg-muted | Muted code/table background color | | --presentation-frame-bg | Optional frame-level background overlay | | --presentation-text | Main text color | | --presentation-text-muted | Secondary text, captions, and chrome text | | --presentation-border | Borders for tables, chrome, callouts, and inline code | | --presentation-border-strong | Strong table and default divider borders | | --presentation-shadow | Shared elevation shadow | | --presentation-scrollbar-thumb | Scrollbar thumb color for overflowing slide content | | --presentation-scrollbar-track | Scrollbar track color for overflowing slide content | | --presentation-font-sans | Shared sans-serif family stack | | --presentation-font-serif | Shared serif family stack | | --presentation-font-body | Body-copy family selected by the active preset | | --presentation-font-display | Heading and display family selected by the active preset | | --presentation-font-quote | Quote layout italic font stack | | --presentation-font-label | Chrome, metadata, and numeric-label family | | --presentation-font-mono | Code font stack | | --presentation-reading-width | Width of paragraphs, lists, blockquotes, and sequence components (defaults to the full content area) | | --presentation-block-width | Maximum width for tables, code blocks, callouts, and warnings | | --presentation-slide-padding | Frame padding | | --presentation-two-cols-gap | Gap between columns in the two-cols layout | | --presentation-content-gap | Vertical rhythm between common markdown blocks | | --presentation-body-size | Base body font size | | --presentation-body-line-height | Base body line height | | --presentation-heading-scale | Multiplier for heading size | | --presentation-heading-weight | Heading font weight | | --presentation-heading-letter-spacing | Heading tracking | | --presentation-heading-line-height | Heading line height | | --presentation-list-spacing | Vertical space between list items | | --presentation-table-size | Table text size | | --presentation-chrome-size | Header and footer text size | | --presentation-caption-size | Figure caption and secondary label size | | --presentation-footnote-size | Footnote text size | | --presentation-table-header-bg | Table header background | | --presentation-table-row-alt-bg | Alternating table row background | | --presentation-code-bg | Code block background | | --presentation-code-border | Code block border | | --presentation-inline-code-bg | Inline code background | | --presentation-inline-code-border | Inline code glass border | | --presentation-inline-code-shadow | Inline code glass shadow | | --presentation-blockquote-bg | Blockquote background | | --presentation-blockquote-border | Blockquote left border | | --presentation-blockquote-font-style | Blockquote font style | | --presentation-callout-bg | Default generated callout background | | --presentation-callout-border | Default generated callout border color | | --presentation-callout-radius | Generated callout border radius | | --presentation-callout-shadow | Generated callout shadow | | --presentation-warning-bg | Generated warning background | | --presentation-warning-border | Generated warning border color | | --presentation-warning-text | Generated warning text color | | --presentation-caption-font-style | Generated media caption font style | | --presentation-caption-letter-spacing | Generated media caption tracking | | --presentation-media-max-height | Maximum height for media assets outside a stable viewport | | --presentation-media-viewport-height | Stable Figure, generated-image, and native-video region height | | --presentation-media-viewport-bg | Media letterbox background; transparent by default | | --presentation-media-fit | Resolved contain or cover fit inside the media region | | --presentation-media-radius | Generated image/video corner radius | | --presentation-media-shadow | Generated image/video shadow | | --presentation-quote-size | Quote layout text size | | --presentation-quote-line-height | Quote layout line height |

Tables, code blocks, callouts, and warnings use the quieter block measure by default. Add class="presentation-full-width" to one of those top-level blocks when a wide table or code sample genuinely needs the full content area.

Presets

Use themeConfig.presentation.preset to switch visual systems without changing the generated markup.

| Preset | Use case | | --- | --- | | default | Paper talks, methods reports, reading groups, and thesis defenses | | ucas | UCAS-branded courses, seminars, project reviews, and research talks | | ict | ICT-branded systems, architecture, AI, and computing research talks |

When no preset is specified, default is selected. It is a paper-inspired but projection-aware system derived from the quiet editorial language of xunz.ink: warm paper and graphite surfaces, muted sage accents, serif display type, a centered title page, booktabs-like tables, flat code, hairline fieldset callouts, and restrained section dividers. The namesake lilas violet appears only as a quiet brand signature on ceremonial pages — the cover rules, the section kicker and hairline, and the statement rule — while content slides stay on the functional sage accent; override --presentation-lilas to retune it.

ucas is an academic editorial direction based on the official UCAS blue and bundled bilingual identity assets. A narrow cobalt spine anchors the cover; ordinary slides use a quiet blue-white paper canvas, serif hierarchy, booktabs-like rules with a blue top rule, and margin-note callouts without a floating institutional mark. Section and statement pages step into a flat institutional-blue field with white serif type; section dividers add the white wordmark and emblem watermark, while statements keep the field content-first. Institutional identity stays visible without turning scientific content into a branded card system.

ict is a precise systems-and-engineering direction based on the bundled bilingual lockup and orbital emblem. Its unbranded cool-paper content canvas combines sans-serif display type, compact mono labels and table headers, square list markers, open technical rules, flat tables and code, and bracket-like callouts. Section and statement pages shift to a flat deep-navy field with white type and a two-tone cyan rule; section dividers add the inverted bilingual lockup and orbital watermark. The result remains visibly technical without relying on heavy fills, rounded panels, or full-slide gradients.

For ucas and ict, themeConfig.presentation.accent changes content accents such as links, callouts, and chrome while the official identity colors used by logos and signature layouts remain locked.

Typography

All presets share the same three bilingual families, but map them to different roles so their personalities stay distinct without causing large text reflow:

| Preset | Display | Body | Quote | Labels / code | | --- | --- | --- | --- | --- | | default | Source Serif 4 / Noto Serif SC | Source Sans 3 / Noto Sans SC | Source Serif 4 / Noto Serif SC | Source Sans 3 / JetBrains Mono | | ucas | Source Serif 4 / Noto Serif SC | Source Sans 3 / Noto Sans SC | Source Serif 4 / Noto Serif SC | Source Sans 3 / JetBrains Mono | | ict | Source Sans 3 / Noto Sans SC | Source Sans 3 / Noto Sans SC | Source Serif 4 / Noto Serif SC | JetBrains Mono |

Slidev loads Source Sans 3, Source Serif 4, and JetBrains Mono through its configured web-font pipeline and exposes the same families through UnoCSS utilities such as font-sans, font-serif, and font-mono. The theme requests real roman and italic faces at weights 400, 500, 600, and 700; its CSS uses only those weights. Noto Sans SC and Noto Serif SC are declared as local fonts, so the theme never adds a second render-blocking Google Fonts import for them. When those local CJK fonts are unavailable, the documented system sans/serif fallbacks apply. Decks marked with a Chinese lang keep CJK headings, captions, and quotations upright with neutral tracking.

For offline venues, install the two Noto SC families locally and configure Slidev to preload or self-host the three web families, or override the --presentation-font-* variables with fonts installed on the presentation machine.

Layouts

This theme provides the following layouts:

| Layout | Purpose | | --- | --- | | default | Main content slides with optional footer chrome | | cover | Opening slide, chrome hidden by default | | intro | Introductory slide with normal chrome behavior and large display-title treatment | | section | Section divider, chrome hidden by default | | toc | Table of contents generated from section slides | | center | Centered single-message slide | | two-cols | Two-column content layout using ::right:: | | statement | Large centered claim or takeaway | | quote | Pull quote with optional author and source frontmatter | | figure | Centered media-first slide | | references | Smaller reference/bibliography slide | | end | Closing message with optional contact, authors, and logo | | image-left | Narrative plus a visually left-hand figure | | image-right | Narrative plus a visually right-hand figure | | code | Title plus a full-width, contained code region |

Section layout: section

Section dividers stay on the ordinary slide canvas so they read as a quiet beat rather than a hard break. Every preset uses the same auto-numbered kicker and title rhythm: default renders it as an editorial accent, ucas as a restrained academic folio, and ict as a compact technical label.

| Input | Default | Behavior | | --- | --- | --- | | kicker | Auto-numbered Section NN | Counts section slides in deck order, matching toc numbering; a custom string replaces the label and false hides it |

---
layout: section
kicker: 第一章
---

# Method / 方法

Closing layout: end

---
layout: end
---

# Thank you

Questions and discussion

| Input | Default | Behavior | | --- | --- | --- | | Default slot | Authored closing message | Primary content and first in DOM order | | contact | Omitted | Valid email becomes a visible-focus mailto: link; other text stays non-interactive | | showAuthors | false | When true, reuses the root author collection | | logo | Omitted | Adds the closing logo region | | logoAlt | Presentation logo when omitted | Explicit "" is decorative; non-empty text is meaningful | | chrome | auto | Hides closing chrome; explicit on still works |

Omitted regions consume no grid space. A message-only closing resolves the minimal state and centers the message on both axes. Adding contact, authors, or logo resolves the rich state, while source order remains message, contact, authors, logo. The dedicated closing-logo region uses contain fit without a Figure tray border, tinted background, or shadow. Missing/failed logos retain meaningful fallback text and do not shift the message, contact, or authors.

For most talks, keep the closing concise with only a message; this uses the centered minimal state shown above. Add contact or a meaningful project/institution logo only when it helps the audience take a next step. Use <Authors /> on a dedicated team or ownership slide when full author details matter. Enable showAuthors only when the closing itself needs to repeat the root author collection.

Image-and-text layouts: image-left and image-right

---
layout: image-left
image: /experiment.png
imageAlt: Diagram of the three-stage experiment
caption: Figure 2. Collection, analysis, and validation.
backgroundSize: contain
---

# Experimental design

The narrative remains first in document reading order.

Both orientations keep narrative then figure in the DOM; CSS alone places the image on the left or right.

| Input | Default | Behavior | | --- | --- | --- | | Default slot | Authored narrative | Heading and prose region | | image | Omitted | Existing Slidev key; omission collapses the figure region | | class | Omitted | Existing built-in-compatible class input | | backgroundSize | contain | Any safe, non-empty CSS background-size; cover and contain use native image fit | | imageAlt | Caption, then Figure | Same tri-state rules as Figure; explicit "" is decorative | | caption | Omitted | Empty values create no figcaption |

Both regions contain wrapping and overflow, while the media shell prevents image decode/failure from moving the narrative. contain is the default across Figure and image-text layouts; cover remains available when intentional edge cropping is preferred. Both values render through the accessible image element. Other valid values such as 80%, auto 72%, or 120px auto render as a centered, non-repeating viewport background while the same source remains present as the accessible image and retains its pending/ready/failed state. Empty, unsafe, or excessively long values fall back to cover instead of being injected into an inline style.

Code layout

---
layout: code
title: Solver implementation
---

# Solver implementation

```ts
export const solve = (input: Input) => normalize(input)
```

The default slot is the authored content. Its first visible h1 remains the title region; frontmatter title remains navigation/TOC/optional-header metadata and is not duplicated. Without a visible heading, code receives the available title space. The primary Slidev code wrapper uses full content width, scrolls long lines horizontally, contains excess lines vertically, and preserves Slidev highlighting, annotations, line numbers, and copy controls without adding a renderer or dependency.

Maintained preset fixtures

The three maintained preset decks are complete, coherent research-talk examples:

  • fixtures/default-preset.md — academic calibration example using the default preset
  • fixtures/ucas-preset.md — geometric-learning example using the UCAS preset
  • fixtures/ict-preset.md — intelligent-systems example using the ICT preset

Each deck follows a practical sequence—research question, method, evidence and reproducibility, conclusion, references, takeaway, and closing—while demonstrating Callout, Figure, Authors, Steps, Timeline, Tag, Badge, and Kbd; native task lists and prose highlights; slide-level accent override; the code, image-left, and image-right layouts; and a metadata-driven end closing slide. The examples use only ordinary Slidev authoring and the theme's bundled /theme/public/obsidian-card.svg asset.

Build them independently with:

pnpm run build:default
pnpm run build:ucas
pnpm run build:ict

Protocol Fixture

The repository includes fixtures/obsidian-protocol.md, a dedicated deck for validating the generated markup contract with obsidian-slidev.

It covers:

  • Obsidian callout classes
  • Generated image, video, audio, and YouTube media figures
  • Obsidian links and warning blocks
  • Long lists, tables, inline code, code blocks, and footnotes
  • Default preset behavior plus UCAS and ICT overrides on the same generated protocol
  • Preset contrast slides with identical content structure
  • Section-driven deck structure with TOC
  • Preset-specific statement, quote, figure, references, and center layouts

Run it with:

pnpm run dev:fixture
pnpm run build:fixture

Quality gates

Install dependencies from the frozen lockfile before running release checks:

pnpm install --frozen-lockfile

Focused diagnostics:

node tests/quality/configuration.spec.mjs
node --test tests/quality/protocol-conformance.spec.mjs
node scripts/check-presentation-css.mjs
node --test tests/quality/preset-isolation.spec.mjs
node --test tests/quality/accessibility.spec.mjs
node --test tests/quality/visual.spec.mjs
pnpm run assets:check

pnpm run assets:optimize is the deterministic source-maintenance command for the six UCAS SVGs. It removes only the reviewed non-rendering metadata and refuses unknown source hashes. Run pnpm run assets:check afterward to verify exact size budgets, structure, alpha, browser RGBA output, explicit image dimensions, and idempotence. Normal asset checks do not rewrite assets or approved baselines.

The aggregate release command is:

pnpm run quality

It verifies the pinned publication before applying fixture overlays, builds the maintained and generated contract decks (including the canonical core and Profile adapters), then runs configuration, architecture, preset isolation, accessibility, interaction, visual, asset, and post-visibility layout-stability gates. A phase summary is retained under .artifacts/quality/. There is no aggregate build-time, output-growth, bundle-size, or navigation-latency acceptance threshold. The previous raw output/navigation sampling baselines and their update command were removed because they did not gate product correctness and were disproportionately large. Per-process timeouts detect a hung tool rather than enforce a performance budget. The blocking size rule is limited to shipped theme assets checked by pnpm run assets:check. The gate exits 0 on success, 1 for product or contract failures, and 2 for harness errors or unapproved skips.

Approved visual baselines are immutable during normal checks. Update them only for an intentional reviewed visual change:

pnpm run quality:update-visual-baselines -- --reviewer "Reviewer name" --rationale "Approved visual change"
git diff -- tests/quality/baselines/visual
pnpm run quality

Review the resulting PNG, manifest, and provenance diff. Never update a baseline merely to hide an unexplained failure.

Development

The latest cross-preset visual review is recorded in qa/fix-theme-visuals/visual-review.md.

  • pnpm install
  • pnpm run dev to start theme preview of example.md
  • pnpm run dev:fixture to start the protocol fixture preview
  • pnpm run build:default / pnpm run screenshot:default for the Default research showcase
  • pnpm run build:ucas to build the UCAS preset showcase
  • pnpm run screenshot:ucas to render the UCAS showcase as PNG slides
  • pnpm run build:ict to build the ICT preset showcase
  • pnpm run screenshot:ict to render the ICT showcase as PNG slides
  • pnpm run build to verify the example can be built
  • pnpm run build:fixture to verify the plugin/theme protocol fixture can be built