API WebAssembly
The nova-wasm module allows you to compile NovaType documents directly in the browser via WebAssembly.
Installation
Via npm
npm install @novatype/wasm
Via CDN
<script type="module">
import { NovaCompiler } from 'https://unpkg.com/@novatype/wasm';
</script>
Basic Usage
import { NovaCompiler } from '@novatype/wasm';
// Initialize the compiler
const compiler = await NovaCompiler.init();
// Typst source code
const source = `
#set document(title: "My Document")
#set page(paper: "a4")
= Introduction
Hello from the browser!
`;
// Compile to SVG
const result = compiler.compile(source);
if (result.success) {
// result.svg_pages contains an array of SVGs (one per page)
document.getElementById('preview').innerHTML = result.svg_pages[0];
} else {
console.error('Errors:', result.errors);
}
API Reference
NovaCompiler
NovaCompiler.init(options?)
Initializes a new compiler instance.
const compiler = await NovaCompiler.init({
// Options
fonts: ['./fonts/custom.ttf'], // Additional fonts
root: './documents/' // Virtual root directory
});
compiler.compile(source, options?)
Compiles a document and returns the result.
| Parameter | Type | Description |
|---|---|---|
source |
string | Typst source code |
options.format |
string | 'svg' or 'pdf' (default: 'svg') |
options.page |
number | Page to render (default: all) |
Result
interface CompileResult {
success: boolean;
content: string; // Content without frontmatter
metadata?: object; // Extracted metadata
svg_pages: string[]; // Array of SVGs (one per page)
errors: string[]; // Compilation errors
}
compiler.validate(source)
Validates a document's metadata.
const validation = await compiler.validate(source);
if (validation.valid) {
console.log('Valid metadata:', validation.metadata);
} else {
console.error('Errors:', validation.errors);
}
compiler.addFile(path, content)
Adds a file to the virtual file system.
// Add a BibTeX file
compiler.addFile('references.bib', `
@book{knuth1984,
author = {Knuth, Donald E.},
title = {The TeXbook},
year = {1984}
}
`);
// Add an image (base64 encoded)
compiler.addFile('image.png', imageBase64, { encoding: 'base64' });
Complete Example
<!DOCTYPE html>
<html>
<head>
<title>NovaType Editor</title>
<style>
.container { display: flex; height: 100vh; }
.editor { flex: 1; }
.preview { flex: 1; background: #f5f5f5; overflow: auto; }
textarea { width: 100%; height: 100%; font-family: monospace; }
</style>
</head>
<body>
<div class="container">
<div class="editor">
<textarea id="source">= Hello World
Welcome to NovaType!
$ e^(i pi) + 1 = 0 $</textarea>
</div>
<div class="preview" id="preview"></div>
</div>
<script type="module">
import { NovaCompiler } from '@novatype/wasm';
const compiler = await NovaCompiler.init();
const sourceEl = document.getElementById('source');
const previewEl = document.getElementById('preview');
let timeout;
function compile() {
const result = compiler.compile(sourceEl.value);
if (result.success) {
previewEl.innerHTML = result.svg_pages.join('');
} else {
previewEl.innerHTML = `<pre style="color:red">${result.errors.join('\n')}</pre>`;
}
}
sourceEl.addEventListener('input', () => {
clearTimeout(timeout);
timeout = setTimeout(compile, 300);
});
compile();
</script>
</body>
</html>
Export PDF
async function downloadPDF() {
const result = await compiler.compile(source, { format: 'pdf' });
if (result.success) {
const blob = new Blob([result.pdf], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
URL.revokeObjectURL(url);
}
}
Error Handling
try {
const result = await compiler.compile(source);
if (!result.success) {
for (const error of result.errors) {
console.error(`Line ${error.line}: ${error.message}`);
// Display in the interface
highlightError(error.line, error.column);
}
}
// Handle warnings
for (const warning of result.warnings || []) {
console.warn(`Warning: ${warning.message}`);
}
} catch (e) {
console.error('Fatal error:', e);
}
React Integration
import { useState, useEffect, useCallback } from 'react';
import { NovaCompiler } from '@novatype/wasm';
function useNovaCompiler() {
const [compiler, setCompiler] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
NovaCompiler.init().then(c => {
setCompiler(c);
setLoading(false);
});
}, []);
const compile = useCallback(async (source) => {
if (!compiler) return null;
return compiler.compile(source);
}, [compiler]);
return { compile, loading };
}
function NovaEditor() {
const { compile, loading } = useNovaCompiler();
const [source, setSource] = useState('= Hello\n\nWorld!');
const [preview, setPreview] = useState('');
useEffect(() => {
const timer = setTimeout(async () => {
const result = await compile(source);
if (result?.success) {
setPreview(result.svg);
}
}, 300);
return () => clearTimeout(timer);
}, [source, compile]);
if (loading) return <div>Loading...</div>;
return (
<div className="editor">
<textarea
value={source}
onChange={e => setSource(e.target.value)}
/>
<div dangerouslySetInnerHTML={{ __html: preview }} />
</div>
);
}
Performance
The WASM module is approximately 37 MB (embedded fonts included). Use a 200-300ms debounce to avoid excessive recompilations while typing.