6. The same code in a browser
Before this: Your document builds in Node.
The content object you have been building is runtime-agnostic. Only two things differ in a browser: where the module comes from, and what you do with the bytes.
<script type="module">
import { buildDocumentPDFBytes, downloadBlob } from 'https://esm.sh/pdfnative@1.6.0';
document.querySelector('#make').addEventListener('click', () => {
const bytes = buildDocumentPDFBytes({
title: 'Made in your browser',
blocks: [{ type: 'paragraph', text: 'Nothing was uploaded.' }],
});
downloadBlob(bytes, 'hello.pdf');
});
</script>
Node used writeFileSync; the browser uses downloadBlob. That is the whole difference. Pick one โ copying the Node snippet into a browser gives you an opaque error about node:fs.
Nothing leaves the page
Generation happens in the tab. There is no API call, no key, and no upload โ which is why every playground on this site works with no account. If you are handling documents that must not travel, this is the property that matters.
For heavy documents, move generation to a Web Worker so the interface stays responsive. The scale playground does exactly that.
Tip: Alt + โ / โ moves between steps.