New in 0.9
Slide decks
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.
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):
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
npm install @silverpoint/react @silverpoint/marp @silverpoint/grounds @silverpoint/fonts// 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
/>
);
}npm install @silverpoint/vue @silverpoint/marp @silverpoint/grounds @silverpoint/fonts<!-- src/Talk.vue (the four stylesheets are imported in main.ts, in the same order) -->
<script setup lang="ts">
import { ref } from 'vue';
import { SpDeck } from '@silverpoint/vue/deck';
import markdown from './talk.md?raw';
const page = ref(1);
</script>
<template>
<SpDeck :markdown="markdown" v-model:page="page" show-notes @ready="({ total }) => console.log(total)" />
</template>npm install @silverpoint/angular @silverpoint/marp @silverpoint/grounds @silverpoint/fonts// angular.json → "styles": [
// "@silverpoint/fonts/fonts.css", "@silverpoint/grounds/styles.css",
// "@silverpoint/grounds/ui.css", "@silverpoint/marp/deck.css" ]
// src/app/talk.ts
import { Component, signal } from '@angular/core';
import { SpDeckComponent } from '@silverpoint/angular/deck';
import { TALK } from './talk';
@Component({
selector: 'app-talk',
imports: [SpDeckComponent],
template: `
<sp-deck
[markdown]="markdown"
[page]="page()"
(pageChange)="page.set($event.page)"
[showNotes]="true"
/>
`,
})
export class Talk {
protected readonly markdown = TALK;
protected readonly page = signal(1);
}pip install 'reflex-silverpoint-react>=0.9.1'from pathlib import Path
import reflex as rx
from reflex_silverpoint_react import sp_deck # installs @silverpoint/marp as the deck's npm dependency
TALK = Path("assets/decks/talk.md").read_text() # read when the app compiles
class Deck(rx.State):
page: int = 1
total: int = 0
@rx.event
def on_page_change(self, page: int, total: int):
self.page, self.total = page, total
@rx.event
def on_ready(self, total: int):
self.total = total
def talk() -> rx.Component:
return sp_deck(
TALK,
page=Deck.page, # controlled; or default_page=1
on_page_change=Deck.on_page_change, # (page, total)
on_ready=Deck.on_ready, # (total,)
show_notes=True,
palette="iron_gall", # a preset's name, either spelling
id="talk",
)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.
---
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| Directive | Values | Default | Effect |
|---|---|---|---|
ground | silverpoint · cyanotype | silverpoint | The ground a slide is drawn on; its charts follow. |
substrate | cream · green · blue · ochre (silverpoint); prussian (cyanotype) | the ground's first | The prepared paper. |
mode | ink · precision | ink | precision switches the inking off. |
class | lead · invert · plate · hatched | — | The theme's classes (below). |
paginate | true · false | false | Page numbers (Marpit). |
header · footer | text | — | Repeated on each slide (Marpit). |
backgroundColor · backgroundImage · color | CSS | — | Marpit's own;  splits a slide. |
size | 16:9 · 4:3 | 16:9 | The slide size (Marpit); also the size prop. |
The silverpoint theme's classes, set with <!-- _class: lead -->:
| Class | Effect |
|---|---|
lead | A title slide: the content centred, the heading larger, one rule under it. |
invert | Light text on the substrate darkened to the ground's ink; its contrast computed per ground. |
plate | An inked plate mark, a double rule inset from the edge, behind the content. |
hatched | An inked hatched band around the slide, behind the content. |
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.
```silverpoint
{"chart": "bar-chart", "props": {"title": "Visits by quarter"}, "height": 400}
```| Field | Value | Default |
|---|---|---|
chart | a catalog slug, e.g. bar-chart | required |
props | the chart's own props, camelCase (not the fence's fields) | {} |
data | the rows the chart reads | its demo dataset |
width | 160 .. 1280 canvas px | the slide's content width |
height | 90 .. 720 canvas px | 360 |
id | the chart's id | <deck>-s<slide>-c<ordinal> |
ground · substrate · mode · palette | as on any chart | the slide's |
| Diagnostic | When |
|---|---|
SP026 | A 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. |
SP027 | An unknown directive value, or a substrate of another ground: the inherited value is kept. |
SP029 | A 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).
| Prop | Reflex | Default | |
|---|---|---|---|
markdown | markdown | — | The Marp Markdown: front matter, --- between slides, silverpoint fences. Required. |
page | page | — | Controlled current page (1-based); pair it with pageChange. |
defaultPage | default_page | 1 | Uncontrolled initial page. |
ground | ground | silverpoint | The deck's ground; a ground directive overrides it per slide. |
substrate | substrate | the ground's first | The deck's substrate. |
mode | mode | ink | ink or precision; a mode directive overrides it per slide. |
palette | palette | — | A palette preset's name, for the fence charts (iron_gall or ironGall in Reflex). |
size | size | 16:9 | 16:9 or 4:3. |
theme | theme | silverpoint | The Marpit theme. |
showNotes | show_notes | false | Show the current slide's presenter notes. |
showControls | show_controls | true | Previous, next, overview, notes and full-screen controls. |
keyboard | keyboard | true | Arrows, PageUp/PageDown, Space, Home/End, o, f and n while focus is in the deck. |
swipe | swipe | true | A horizontal swipe moves the deck. |
hash | hash | false | Read and write a #<n> deep link in the URL. |
interactive | interactive | true | Hydrate the fence charts; false keeps them static SVG. |
label | label | the first heading | Accessible name of the deck region. |
id | id | a hydration-safe id | Scopes the deck's CSS and names its charts. |
| Event | React · Vue · Angular | Reflex | Payload |
|---|---|---|---|
pageChange | onPageChange · @page-change · (pageChange) | on_page_change(page, total) | { page, total } |
fragmentChange | onFragmentChange · @fragment-change · (fragmentChange) | on_fragment_change(page, step, steps) | { page, step, steps } |
ready | onReady · @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.
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 slideMarp 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.
# 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 →