Skip to content
silverpoint
Documentation menu

New in 0.9

Slide decks

New in silverpoint 0.9 and reflex-silverpoint-react 0.9. SpDeck draws a Marp/Marpit Markdown presentation in silverpoint: the silverpoint theme on the library's grounds and substrates, directives that move a slide to another ground or to precision, fragments, presenter notes, and silverpoint fences that become real charts inside a slide.

Try it

A Marp deck drawn by sp_deck. Click into it, then use the arrows, Space, PageUp/PageDown or Home/End; o opens the overview, f full screen and n the notes. Each list item is a fragment, revealed a step at a time; each chart is a silverpoint fence, hydrated in place. The controls set the deck's props; a slide's own directive wins.

Ground
Mode
Palette
Size
Notes
silverpoint · slide decks

Charts drawn like silverpoint

A Marp deck, from Markdown

silverpoint 0.9

Slide 1 of 9

on_page_change: page 1 of 0 · on_fragment_change: 0 / 0

Install

In React, Vue and Angular, SpDeck is on the deck subpath of the adapter, and its engine, @silverpoint/marp (which brings @marp-team/marpit), is an optional peer: install it only for decks. Import four stylesheets, in this order (Angular lists them in the styles array of angular.json):

ts
import '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import '@silverpoint/grounds/ui.css';
import '@silverpoint/marp/deck.css';

In Reflex, sp_deck (reflex-silverpoint-react 0.9.0 or later) lists @silverpoint/marp as its own npm dependency and imports the four stylesheets, so an app installs the engine only when a page renders a deck. MARP_VERSION and DECK_STYLESHEETS say which.

In your code

shell
npm install @silverpoint/react @silverpoint/marp @silverpoint/grounds @silverpoint/fonts
tsx
// src/main.tsx: the stylesheets, in this order
import '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import '@silverpoint/grounds/ui.css';
import '@silverpoint/marp/deck.css';

// src/Talk.tsx
import { useState } from 'react';
import { SpDeck } from '@silverpoint/react/deck';
import markdown from './talk.md?raw';

export function Talk() {
  const [page, setPage] = useState(1);
  return (
    <SpDeck
      markdown={markdown}
      page={page}
      onPageChange={({ page }) => setPage(page)}
      onReady={({ total }) => console.log(total, 'slides')}
      showNotes
    />
  );
}

Writing a deck

Slides are separated by ---. The front matter sets the deck's directives; a <!-- key: value --> comment sets one from that slide on, and <!-- _key: value --> on that slide only. Any other comment is a presenter note, and each list item a fragment.

markdown
---
paginate: true
header: My talk
ground: silverpoint
substrate: cream
---

<!-- _class: lead -->

# Title slide

---

<!-- _ground: cyanotype -->

## A chart on cyanotype

```silverpoint
{"chart": "bar-chart", "props": {"title": "Visits"}, "height": 400}
```

<!-- A presenter note: any comment that is not a directive. -->

---

* fragment one
* fragment two
1) and ordered ones
DirectiveValuesDefaultEffect
groundsilverpoint · cyanotypesilverpointThe ground a slide is drawn on; its charts follow.
substratecream · green · blue · ochre (silverpoint); prussian (cyanotype)the ground's firstThe prepared paper.
modeink · precisioninkprecision switches the inking off.
classlead · invert · plate · hatched—The theme's classes (below).
paginatetrue · falsefalsePage numbers (Marpit).
header · footertext—Repeated on each slide (Marpit).
backgroundColor · backgroundImage · colorCSS—Marpit's own; ![bg right:40%](…) splits a slide.
size16:9 · 4:316:9The slide size (Marpit); also the size prop.

The silverpoint theme's classes, set with <!-- _class: lead -->:

ClassEffect
leadA title slide: the content centred, the heading larger, one rule under it.
invertLight text on the substrate darkened to the ground's ink; its contrast computed per ground.
plateAn inked plate mark, a double rule inset from the edge, behind the content.
hatchedAn inked hatched band around the slide, behind the content.
Note
Raw HTML is never rendered: it shows as text, and javascript: and non-image data: URLs are dropped. A <style scoped> block still restyles one slide, and Marpit's background images (bg, split backgrounds such as bg right:40%, sizing and filters) keep their meaning.

Charts in a slide: the silverpoint fence

A fenced block whose language is silverpoint holds one chart as JSON, the same input as the MCP render_chart tool. It is static SVG in the server's render and a live chart in the browser (unless interactive is false), and it takes its slide's ground, substrate and mode unless it names its own.

markdown
```silverpoint
{"chart": "bar-chart", "props": {"title": "Visits by quarter"}, "height": 400}
```
FieldValueDefault
charta catalog slug, e.g. bar-chartrequired
propsthe chart's own props, camelCase (not the fence's fields){}
datathe rows the chart readsits demo dataset
width160 .. 1280 canvas pxthe slide's content width
height90 .. 720 canvas px360
idthe chart's id<deck>-s<slide>-c<ordinal>
ground · substrate · mode · paletteas on any chartthe slide's
DiagnosticWhen
SP026A fence that is not JSON, names an unknown chart or prop, or asks for a size out of range: an error figure in its place.
SP027An unknown directive value, or a substrate of another ground: the inherited value is kept.
SP029A deck past a limit (512 KB, 300 slides, 60 fences): it renders up to the limit.

Props and events

React and Angular use the camelCase names, Vue templates may write them in kebab-case, and Reflex in snake_case. Use the deck controlled (page with pageChange; v-model:page in Vue) or uncontrolled (defaultPage).

PropReflexDefault
markdownmarkdown—The Marp Markdown: front matter, --- between slides, silverpoint fences. Required.
pagepage—Controlled current page (1-based); pair it with pageChange.
defaultPagedefault_page1Uncontrolled initial page.
groundgroundsilverpointThe deck's ground; a ground directive overrides it per slide.
substratesubstratethe ground's firstThe deck's substrate.
modemodeinkink or precision; a mode directive overrides it per slide.
palettepalette—A palette preset's name, for the fence charts (iron_gall or ironGall in Reflex).
sizesize16:916:9 or 4:3.
themethemesilverpointThe Marpit theme.
showNotesshow_notesfalseShow the current slide's presenter notes.
showControlsshow_controlstruePrevious, next, overview, notes and full-screen controls.
keyboardkeyboardtrueArrows, PageUp/PageDown, Space, Home/End, o, f and n while focus is in the deck.
swipeswipetrueA horizontal swipe moves the deck.
hashhashfalseRead and write a #<n> deep link in the URL.
interactiveinteractivetrueHydrate the fence charts; false keeps them static SVG.
labellabelthe first headingAccessible name of the deck region.
idida hydration-safe idScopes the deck's CSS and names its charts.
EventReact · Vue · AngularReflexPayload
pageChangeonPageChange · @page-change · (pageChange)on_page_change(page, total){ page, total }
fragmentChangeonFragmentChange · @fragment-change · (fragmentChange)on_fragment_change(page, step, steps){ page, step, steps }
readyonReady · @ready · (ready)on_ready(total){ total }

Server rendering and print

The server sends the current slide, its static charts and the controls; the browser adopts that markup, adds the controller and hydrates the charts, with no mismatch. In Next.js SpDeck renders in the App Router (a component that holds the page in state needs 'use client'); Vue renders it with @vue/server-renderer and Angular with @angular/ssr. This page is a static export: its deck was rendered when the site was built.

Printing lays every slide out at its own size, every fragment shown and the controls hidden.

Without a framework, the engine is pure: the same Markdown, options and id give the same render on the server and in the browser.

ts
import { createDeckEngine } from '@silverpoint/marp';

const deck = createDeckEngine({ id: 'talk', ground: 'silverpoint' }).render(markdown);
deck.slides;      // per slide: its HTML, notes, fragment count, ground, substrate, mode, classes
deck.css;         // the theme, scoped to the deck's id
deck.diagnostics; // SP026, SP027, SP029, … with their slide

Marp CLI and VS Code

@silverpoint/marp/theme.css carries both grounds as a plain Marp theme. There, backdrops (plate, hatched) draw no ink, a fence is shown as code and there is no controller; with silverpoint's own engine, Marp CLI draws the directives, the backdrops and the fences as static SVG.

shell
# Marp CLI with the plain theme (fences shown as code, no controller)
npx @marp-team/marp-cli --theme node_modules/@silverpoint/marp/theme.css talk.md

# Marp CLI with silverpoint's engine (directives, backdrops and fences as static SVG)
npx @marp-team/marp-cli --engine @silverpoint/marp/cli talk.md

# VS Code: the Marp extension's settings.json
"markdown.marp.themes": ["./node_modules/@silverpoint/marp/theme.css"]

Decks and agents

The silverpoint MCP server checks a deck with validate_deck (its slide count and every diagnostic), renders it as a standalone HTML document with render_deck, and writes the deck's code (SpDeck, or sp_deck in Reflex) with generate_code and a deck target. The silverpoint skill carries the same guide in references/deck.md, and reflex-silverpoint-react's skill its Reflex version. Use with AI →