Open app
Contents API reference

These docs follow the latest development version of vDesign.

API reference

Every function and type @getv.design/embed exports, generated from the declarations the package publishes. How to use them is on Embedding. The package is at 0.x: an API may still change in a minor version.

Entries

Four JavaScript entries, each an ES module, and two stylesheets. The editor and the exact-fonts code are separate files that load only when a page asks for them, so importing an entry costs only what it needs.

@getv.design/embed

const version: string;

The package’s version, as published: 0.1.0, say.

function mount(
  el: HTMLElement,
  source: Source,
  options: MountOptions,
): Promise<ViewHandle | EditHandle | PlayHandle>;

Show a document in el, to view, present or edit.

Types: every type below.

@getv.design/embed/static

function parse(text: string): ParseResult;

Read .vd text. Never throws: what is wrong comes back as problems.

function renderSvg(source: Source, options?: RenderSvgOptions): Promise<string>;

Draw a document, or one of its pages, as a standalone SVG.

function designOf(text: string): string | undefined;

The .vd text in text: itself for a .vd, the design it carries for a .vd.svg, undefined for an SVG that carries none. For copying a design out of an SVG as text.

function outline(text: string): Outline;

A document’s title and pages, each with the line its frame is written on: what an editor needs for an outline, breadcrumbs, and keeping a preview on the page the cursor is in. Never throws.

The line is found by reading the text for the page’s top-level frame line, never by evaluating anything, so it is as cheap as parsing.

function createRenderer(options?: RendererOptions): Promise<Renderer>;

A renderer that draws synchronously once it exists. Exact fonts are fetched here, all of them, because which ones a later document needs is not known yet and the render cannot wait to find out.

function approximateRenderer(): Renderer;

The renderer with no font files, made synchronously: what the Markdown adapters use when a host does not hand them one, because a markdown-it plugin is installed in a synchronous call.

Also version, as above.

Types: Outline, OutlinePage, ParseResult, Problem, Renderer, RendererOptions, RendererRenderOptions, RenderSvgOptions, Source, VdDocument.

@getv.design/embed/view

function view(el: HTMLElement, source: Source, options?: ViewOptions): Promise<ViewHandle>;

Show a document in el. Rejects, leaving el untouched, if the source cannot be read.

Also version, as above.

Types: every type below.

@getv.design/embed/edit

function edit(el: HTMLElement, source: Source, options?: EditOptions): Promise<EditHandle>;

Edit a document in el. Rejects, leaving el untouched, if the source cannot be read.

Also version, as above.

Types: every type below.

@getv.design/embed/markdown

function createFenceIds(prefix?: unknown): () => string;

Ids for one page of HTML: each fence on it gets its own prefix.

function isVdFence(info: string | undefined | null): boolean;

The language a fence must name. vdesign is accepted too, for hosts that know vd as something else.

function parseInfo(info: string): FenceOptions;

The attributes after the language: key=value, key="quoted value", or a bare key for a flag. Unknown keys are ignored, so adding one later breaks no fence written today.

function renderFence(
  body: string,
  info: string | FenceOptions,
  options?: FenceRenderOptions,
): string;

A fence to HTML. info is the whole info string (vd page=1) or options already parsed. Never throws: a fence that cannot be drawn comes back as its code block, with what was wrong.

Also createRenderer, as above.

Types: FenceOptions, FenceRenderOptions, Problem, Renderer.

@getv.design/embed/markdown-it

function vdesignMarkdownIt(md: MarkdownItLike, options?: MarkdownItOptions): void;

md.use(vdesignMarkdownIt, options).

Also createRenderer, as above.

Types: FenceOptions, FenceRenderOptions, MarkdownItOptions, Problem, Renderer.

@getv.design/embed/rehype

function rehypeVdesign(options?: RehypeOptions): void;

.use(rehypeVdesign, options).

Types: FenceOptions, FenceRenderOptions, Problem, RehypeOptions, Renderer.

@getv.design/embed/marked

function vdesignMarked(options?: FenceRenderOptions): {
  renderer: { code(this: unknown, token: CodeToken | string, info?: string): string | false };
};

A marked extension. Returning false hands the block back to marked’s own renderer.

Also createRenderer, as above.

Types: FenceOptions, FenceRenderOptions, Problem, Renderer.

@getv.design/embed/auto

function hydrate(root?: ParentNode, options?: HydrateOptions): Promise<ViewHandle[]>;

Every figure.vd-figure[data-vd-mode="view"] under root that is not live yet. Resolves once each has opened or stayed a drawing; never rejects. Safe to call again after the page changes: figures already live are skipped.

Types: HydrateOptions, ViewHandle, ViewOptions.

@getv.design/embed/view.css, @getv.design/embed/edit.css

The styles the view and the editor otherwise insert as a <style> element. Link them under the ids vd-viewer-styles and vd-editor-styles when your content security policy refuses inline styles; see Embedding.

@getv.design/embed/fonts/*

The Inter faces the exact-fonts layout reads, one .woff2 per weight and style, and their licence, OFL.txt. Serve this folder yourself and set fontBase to keep font requests on your own origin.

Types

VdDocument

A parsed document. Opaque: pass it back to any function that takes a Source.

Opaque: it has no members you can read.

Source

What a document can be given as: .vd text, a URL to fetch, a file, or a parsed document.

type Source = string | URL | Blob | VdDocument;

Problem

Something wrong with a document. Reading never throws; it reports these instead.

  • line?: number

    The 1-based line in the .vd text, when the problem belongs to one.

  • code: string

    Stable and machine-readable; branch on this, not on message.

  • message: string

  • severity: 'error' | 'warning'

ParseResult

  • document: VdDocument
  • problems: Problem[]

RenderSvgOptions

  • page?: string | number

    One page to draw: its id, or its 0-based index among the pages. Omitted, the whole document is drawn.

  • fonts?: 'exact' | 'approximate'

    How text is measured. 'approximate' (the default) needs no font files and runs anywhere; line breaks can differ slightly from the app’s. 'exact' lays text out from the font files the app’s exports use, so lines break where theirs do: in Node they are read from the package’s own fonts/ folder, in a browser fetched from fontBase. If a face cannot be had, the drawing is approximate and onProblems hears a fonts-unavailable warning; it does not reject.

  • fontBase?: string | URL

    The folder 'exact' reads the faces from (Inter-Regular.woff2 and so on): a URL, or a path resolved against the page. Default: in Node, the package’s own fonts/; in a browser, the package’s fonts/ on jsDelivr.

  • onProblems?: (problems: Problem[]) => void

    Called once, before the SVG is returned, with what is wrong: the document’s own problems and, under 'exact', any face that would not load. Empty when nothing is.

  • idPrefix?: string

    Put in front of every id the SVG defines for itself (clips, shadows, gradients) and of every reference to one. Two SVGs inline in one page otherwise share those names, and the second one’s shapes clip to the first one’s rectangles. The /markdown entries give each fence its own.

OutlinePage

A page in outline(): what view() calls a page, and where it starts in the text.

  • id: string

  • name?: string

  • line?: number

    The 1-based line of the page’s frame line in the text given, which for a .vd.svg counts the SVG’s own lines. Undefined only if the frame could not be found, which a document parse accepted does not do.

Outline

  • title?: string

  • pages: OutlinePage[]

    In play order: top-level frames that are not hidden.

  • problems: Problem[]

RendererOptions

  • fonts?: 'exact' | 'approximate'

    'approximate' (the default) needs no font files. 'exact' fetches every bundled face once, before createRenderer resolves, so each later render can lay text out from them without waiting. That is all 18 faces, about 2.6 MB: meant for a build step or an editor’s preview, not a web page.

  • fontBase?: string | URL

    As for renderSvg.

RendererRenderOptions

  • page?: string | number
  • idPrefix?: string
  • onProblems?: (problems: Problem[]) => void

Renderer

Renders synchronously, for a caller that cannot wait: a markdown-it rule returns a string. Under fonts: 'exact' a document that needs a face that did not load draws approximately and onProblems hears fonts-unavailable.

  • renderSvg(source: string | VdDocument, options?: RendererRenderOptions): string

    .vd or .vd.svg text, or a parsed document, to an SVG string. Throws a RangeError for a missing page.

  • readonly fonts: 'exact' | 'approximate'

    What createRenderer was asked for, and what it got: 'approximate' if the faces would not load.

ViewOptions

  • fit?: 'page' | 'content' | 'none'

    What the camera shows. 'page' (the default) fits the current page to the element; 'content' fits everything; 'none' leaves the camera at 100%. Applied on mount, by fit(), when the element is resized, and, for 'page', by goTo(); under the other two, goTo() centres the page at the current zoom.

  • page?: number | string

    The page to start on: its id, or its 0-based index among the pages. A page is a top-level frame that is not hidden, counted as renderSvg and the app’s exports count them.

  • interactive?: boolean

    Ctrl or ⌘ with the wheel (or a trackpad pinch) zooms; middle-drag or Space-drag pans. A plain wheel is left to the page, so the reader’s scroll is never caught by the view. false turns all of it off. Default true.

  • fonts?: 'exact' | 'browser'

    How text is measured. 'browser' uses the page’s own fonts. 'exact', the default, lays text out from the font files the app and its exports use, so lines break where theirs do: the view draws at once with the page’s fonts, fetches only the faces the document uses, then lays the text out again once, when they arrive. If a face cannot be fetched the view stays on the page’s fonts, problems gains a fonts-unavailable warning, and the fonts event says 'browser'.

  • fontBase?: string | URL

    The folder 'exact' fetches faces from (Inter-Regular.woff2 and so on): a URL, or a path resolved against the page. Default: the package’s fonts/ on jsDelivr, which means the reader’s browser asks jsDelivr for them. To keep that request on your own origin, serve the package’s fonts/ folder yourself and point this at it.

  • surface?: string

    The colour behind the pages.

  • onLink?: (href: string) => void

    A click on an https: or mailto: link in the document. Without it the link opens in a new tab. A #page link goes to that page either way.

PageInfo

  • id: string
  • name?: string

ViewEvents

ready and problems describe the document on screen, so a listener added late is told the current state at once. One added in the same tick as a load() can therefore hear ready and problems twice: once from that replay and once when the load lands.

  • ready: () => void

    A document is drawn: the first, and each one load() brings. A listener added after that is called once straight away.

  • problems: (problems: Problem[]) => void

    What is wrong with the document on screen, empty when nothing is; again after every load(). A listener added later is called with the current list straight away.

  • page: (page: PageInfo) => void

    The current page changed. Not replayed.

  • fonts: (fonts: 'exact' | 'browser') => void

    What text is measured with, once that is settled: 'exact' when the font files are in use, 'browser' under fonts: 'browser' or when they could not be fetched. Fires when that is settled, and again if a later load() needs a face that cannot be fetched; a listener added later is told the current answer at once.

PlayOptions

  • page?: number | string

    The page to start on. Default: the one the view is showing.

PlayHandle

  • goTo(page: number | string): void

  • destroy(): void

    Stop presenting. Escape does the same.

ViewHandle

  • load(source: Source): Promise<void>

    Show another document, or a new version of this one, in place: what is unchanged is not redrawn. The page on screen and the camera stay while that page is still there. Rejects, leaving the view as it was, if the source cannot be read. When loads overlap, the last one called wins: an earlier one that finishes later resolves without drawing.

  • pages(): PageInfo[]

  • goTo(page: number | string): void

    Throws a RangeError for a page that is not there.

  • fit(): void

    Apply the fit option again, for an element resized without the browser noticing.

  • play(options?: PlayOptions): Promise<PlayHandle>

    Present over the view, one page at a time; Escape comes back.

  • edit(options?: EditOptions): Promise<EditHandle>

    Edit what is on screen, in place: the editor replaces the view in the same element, where the person was looking, and this handle is destroyed. The editor’s code loads only now. options override the view’s own. Rejects, leaving the view as it was (a presentation and a load() in flight included), if the editor cannot open, and rejects a second call made while one is opening. A load() that lands while the editor opens is dropped once it has: the editor shows the document from when edit() was called.

  • on<E extends keyof ViewEvents>(event: E, callback: ViewEvents[E]): () => void

    Throws a TypeError for an event that is not one of these.

  • destroy(): void

    Take the view away, leaving the element empty, and release its image URLs.

EditOptions

As for a view, with these differences: a link is followed on ⌘-click (Ctrl elsewhere), since a plain click selects; fit frames the document once, and again on a resize only until the person moves the camera.

extends ViewOptions

  • toolbar?: boolean

    The floating toolbar and the context menu. Default true.

ChangeEvent

  • text(): string

    The whole .vd file after the change, as getText(); composed only when called.

EditHandle

  • getText(): string

    The whole .vd file: the design and its images.

  • getDocument(): VdDocument

    The document as it stands, to pass to renderSvg, view() or load().

  • on(event: 'change', callback: (event: ChangeEvent) => void): () => void

    One change per undo step: a whole drag is one, on pointerup, and so are an undo and a redo. Throws a TypeError for any other event.

  • undo(): void

  • redo(): void

  • view(): Promise<ViewHandle>

    Back to a view of the document as edited, in the same element, keeping the camera; this handle is destroyed. Rejects, leaving the editor, if the view cannot open, and rejects a second call made while one is opening. The canvas takes no input meanwhile; a change that still lands (an undo()) is shown by the view.

  • destroy(): void

    Take the editor away, leaving the element empty. Safe to call twice.

MountMode

type MountMode = 'view' | 'edit' | 'play';

MountOptions

type MountOptions = { mode: MountMode } & EditOptions;

FenceOptions

What a fence’s info string asks for: ```vd page=pricing mode=view source.

  • page?: string | number

    One page, by id or 0-based index (a number written as digits). Default: the whole document.

  • src?: string

    A file to draw instead of the body, resolved by resolveSrc.

  • height?: number

    The live view’s height in CSS pixels. Default: the drawing’s own aspect ratio.

  • mode?: 'static' | 'view'

    'view' hydrates into a live view; 'static' stays an SVG. Default: the adapter’s mode.

  • source?: boolean

    Also show the .vd text, folded, under the drawing.

  • alt?: string

    The drawing’s accessible name. Default: the document’s title.

FenceRenderOptions

  • renderer?: Renderer

    Default: a renderer with no font files (approximateRenderer()). createRenderer makes an exact one.

  • resolveSrc?: (src: string) => string | undefined

    Read a fence’s src=. Without it, or when it returns undefined, the fence shows a problem.

  • mode?: 'static' | 'view'

    For fences that do not say. Default 'static'.

  • output?: 'inline' | 'img'

    'inline' (the default) puts the SVG in the page: its text can be selected and searched. 'img' wraps it in <img src="data:…">: isolated from the page’s CSS, and what a mail client or a CMS that strips <svg> accepts.

  • inlineStyles?: boolean

    false for a page whose content security policy refuses style="". A drawing that needs one (a blend mode) is then wrapped as an <img>, which the policy does not reach into. Default true.

  • limits?: { bytes?: number; nodes?: number }

    The most text and nodes one fence may hold. Past either it stays a code block.

  • idPrefix?: () => string

    A fresh prefix for each drawing’s ids. Default: vd1-, vd2-, … per call of createFenceIds.

  • attributes?: readonly (readonly [string, string])[]

    Extra attributes for the <figure>, as the host’s own code block would have carried them: VS Code’s preview marks blocks class="code-line" data-line="12" to keep its scroll in step with the editor.

MarkdownItOptions

extends Omit<FenceRenderOptions, 'resolveSrc'>

  • resolveSrc?: (src: string, env: unknown) => string | undefined

    Read a fence’s src=. env is what the host passed to md.render(text, env).

RehypeOptions

extends Omit<FenceRenderOptions, 'resolveSrc' | 'renderer'>

  • fonts?: RendererOptions['fonts']

    Default 'exact'. Ignored when renderer is given.

  • fontBase?: RendererOptions['fontBase']

  • renderer?: Renderer

  • resolveSrc?: (src: string, path: string | undefined) => string | undefined

    Read a fence’s src=. path is the Markdown file’s own path when the pipeline knows it. Default, in Node: the file, relative to the Markdown.

  • include?: (path: string | undefined) => boolean

    Which Markdown files to draw fences in, by path. Default: all of them. For a site whose reference pages quote DSL to teach it, where the reader came for the code, not the picture.

HydrateOptions

  • fonts?: ViewOptions['fonts']

    Passed to each view. Default 'exact', from fontBase.

  • fontBase?: ViewOptions['fontBase']

  • surface?: ViewOptions['surface']

  • onLink?: ViewOptions['onLink']