Worked example
Five compositions that together exercise every primitive. A host sequences them; Isomer renders one composition at a time.
// A deck is a sequence of Compositions — Isomer deliberately does not model
// sequencing, because sequencing is routing and routing belongs to the host.
export const deck: Composition[] = [
{ type: 'view', title: 'Title slide', body: [titleSlide] },
{ type: 'view', title: 'Split layout', body: [splitSlide] },
// …
];
The runtime sees one composition at a time. A host renders them in order and assembles the deck.
Each composition renders on HTML, Markdown, text, Slack Block Kit, and SVG. The markdown and text surfaces are the headline claim: a composition authored once degrades to a few lines of terminal output without any work from the author.
# Title slide
## 01 · Primitives
_Reference pack_
## One composition, every surface.
The same spec renders as HTML, markdown, text, Slack, and SVG.
TITLE SLIDE
01 · Primitives
Reference pack
One composition, every surface.
The same spec renders as HTML, markdown, text, Slack, and SVG.
# Split layout
## 02 · Grammar
## Primitive pack
Vocabulary, renderers, and validation in one value.
### What a pack declares
- Primitives
- Surfaces
- Theme bound
SPLIT LAYOUT
02 · Grammar
Primitive pack
Vocabulary, renderers, and validation in one value.
What a pack declares
- Primitives
- Surfaces
- Theme bound
# Surface cards
## 03 · Surfaces
## Six render targets.
React, HTML, SVG, Slack, Markdown, and plain text.
### React
Component tree; hosts mount it.
### HTML
Self-contained envelope with stylesheet.
### SVG
The same tree and stylesheet, handed to a rasterizer.
### Slack
Block Kit blocks with fallback text.
### Markdown
GitHub-flavored, readable in terminals.
### Text
80-column output for logging and alerts.
SURFACE CARDS
03 · Surfaces
Six render targets.
React, HTML, SVG, Slack, Markdown, and plain text.
React
Component tree; hosts mount it.
HTML
Self-contained envelope with stylesheet.
SVG
The same tree and stylesheet, handed to a rasterizer.
Slack
Block Kit blocks with fallback text.
Markdown
GitHub-flavored, readable in terminals.
Text
80-column output for logging and alerts.
# Code block
## 04 · Contract
## The composition contract.
### Composition
```ts
const spec: Composition = {
type: "view",
title: "My view",
body: [node],
};
```
CODE BLOCK
04 · Contract
The composition contract.
Composition
const spec: Composition = {
type: "view",
title: "My view",
body: [node],
};
# Flow diagram
## 05 · Dispatch
## How a composition renders.
### Render pipeline
Composition -> Runtime -> Dispatcher -> Primitive -> Surface
### Host
Supplies composition, owns data and routing.
### Isomer
Owns dispatch, validation, and rendering.
FLOW DIAGRAM
05 · Dispatch
How a composition renders.
Render pipeline
Composition -> Runtime -> Dispatcher -> Primitive -> Surface
Host: Supplies composition, owns data and routing.
Isomer: Owns dispatch, validation, and rendering.
The svg surface returns { element, css, width, height } — the React tree, the pack's stylesheet with light-dark(…) already resolved to the render's scheme, and the viewport it was measured for. It does not return an image: rasterizing is a separate capability a host opts into.
@elastic/isomer-image-takumi is that capability for this repo:
import { createTakumiImageBackend } from '@elastic/isomer-image-takumi';
const takumi = createTakumiImageBackend({ fonts });
const png = await takumi.png(runtime.surfaces.svg.render(composition));
fonts is the host's, and it is not optional in practice — an unregistered family falls back to the backend's built-in face, so an unfonted render is visibly not this pack. Fonts on the image surface covers which families and weights to register; src/examples/deck/fonts.ts is the worked version, deriving the weight set from the theme.
The five .png files are written by the same test that writes the other four surfaces' artifacts, with one difference: toMatchFileSnapshot is text-only, so the PNG case hand-rolls its own comparison, and that comparison is CI-only. A local run always rewrites the artifact — a takumi or font bump would otherwise fail every PNG case on the bump alone, not on a real regression — so git diff on the five files is the review step. Under CI, a missing artifact fails instead of being written, and byte equality is asserted against the committed artifact. CI runs Ubuntu only, so this verifies same-input determinism on linux-x64; cross-platform stability (darwin-arm64 producing the same bytes) is an operating assumption at a pinned @takumi-rs/core and a fixed font set, not independently verified here — see @elastic/isomer-image-takumi's Determinism section.
The five compositions together exercise every primitive at least once:
slideTitle,slideCardGroup— the frame example and the cards slideslideSplit,slideStack,slideBulletList— the split layout slideslideCode— the code block slideslideFlow,slideTerritoryGroup— the flow diagram slide