Onykia Docs

Quickstart

Installation

npm install @mudomi/onykia-engine

For an editor with syntax highlighting, autocomplete and diagnostics, also install the CodeMirror or Monaco bindings (see CodeMirror):

npm install @mudomi/onykia-codemirror
#or
npm install @mudomi/onykia-monaco

Prerequisites

The engine runs the Typst compiler in a Web Worker. That worker pulls in two companion assets - onykia_worker.js and onykia_engine.wasm (~30 MB) - and it uses SharedArrayBuffer for its thread pool. So your app has to satisfy two requirements:

  1. The worker and wasm must be served from a URL the browser can reach. createWasmFactory() finds them for you (see below).
  2. The page must be cross-origin isolated, or SharedArrayBuffer is unavailable and the compiler throws on boot.

symbolic request and response diagram

(c) Mariko Kosaka @ Google 1

Cross-origin isolation

Every response from your app must carry these two headers. Without them SharedArrayBuffer is undefined and createWasmFactory() throws a cross-origin-isolated error.

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

See Vite for the config, including a SvelteKit/Nuxt caveat.

Usage

A minimal, end-to-end setup:

import { Core, createWasmFactory, renderToCanvas, type PageInfo } from '@mudomi/onykia-engine';
 
const PATH = '/main.typ';
const previewEl = document.getElementById('preview')!;
 
const core = new Core({
  wasm: createWasmFactory(),
});
 
// `pages` fires on every layout change; render it to canvas.
let pages: PageInfo[] = [];
core.onPages(({ pages: next }) => {
  pages = next;
  if (pages.length > 0) void renderToCanvas(core, { container: previewEl, pages, fit: 'width' });
});
 
await core.create(PATH, 'text/x-typst', '= Hello, Onykia\n\nIt compiles!');
await core.setTarget('svg');
await core.setMain(PATH); // triggers the first compile

After setMain, any create/edit/move/delete to the main file or a dependency re-compiles and re-fires onPages automatically - you never trigger a recompile yourself. setTarget only picks what export() produces; the canvas path works under any target, so 'svg' is the lightweight choice for a preview-only setup.

Where do the asset URLs come from? createWasmFactory() defaults to new URL('./wasm/onykia_worker.js', import.meta.url) (and the same for the wasm), resolved against the engine's own module. Any import.meta.url-aware bundler turns that into a real, fingerprinted URL and ships the assets for you.

Some bundlers (notably Vite production builds) inline the worker and break it. When that happens, self-host the assets and pass explicit URLs - see Vite.

createWasmFactory({
  wasmUrl: '/onykia/onykia_engine.wasm',
  workerUrl: '/onykia/onykia_worker.js',
});

The matching files live in node_modules/@mudomi/onykia-engine/dist/wasm/.

To make it editable, push changes with core.edit(path, edits). The CodeMirror bindings wire that up for you.

Exporting

core.export() returns a downloadable artifact, independent of what you preview:

const { data, mime } = await core.export({ format: 'pdf' });

pdf and html export the whole document; svg and png take a zero-based page index. See Rendering for the full matrix.

Next steps

  • Vite - config and the cross-origin isolation headers.
  • Rendering - canvas, SVG, PNG, PDF and HTML strategies.
  • CodeMirror - full editor integration.
  • Fonts - register fonts and load them lazily.
  • Packages - resolve @preview and private packages.

Footnotes

  1. This image, from this web.dev article, was created and shared by Google and used according to terms described in the Creative Commons 4.0 Attribution License.

On this page