Skip to content

Repository files navigation

PDF Maker

pdf-forms.sight2030.com

A drag-and-drop PDF form designer that runs entirely in the browser. Build a document by dragging blocks onto a page, then export a real PDF with working AcroForm fields — the kind you can fill in with Acrobat, Preview, or any browser's PDF viewer.

Nothing is uploaded. There is no server, no API key and no account: the editor, the layout engine and the PDF writer all run on the client.

Running it

npm install
npm run dev

Then open http://localhost:5173. npm run build produces a static dist/ you can host anywhere (or open from a file:// URL — base is relative).

Pushing to main deploys to GitHub Pages via .github/workflows/deploy.yml. The custom domain lives in public/CNAME — Vite copies public/ to the root of dist/, so it rides along in the artifact and survives every redeploy.

How it works

Puck provides the drag-and-drop editing surface, and pdf-lib writes the PDF. In between sits a small layout engine of our own:

Path Role
src/puck/config.tsx Block catalogue — the fields shown in the sidebar
src/puck/preview.tsx How each block looks on the editing canvas
src/pdf/blocks.ts How each block is drawn into the PDF
src/pdf/context.ts Pages, cursor, fonts, page breaks, headers/footers
src/pdf/export.ts Walks the document and hands back bytes

The canvas preview is an approximation for designing against; the exporter is the source of truth. Adding a block means adding it in three places: a renderer in blocks.ts, a preview in preview.tsx, and an entry in config.tsx.

The layout engine

Content flows top-to-bottom with a cursor, exactly like a word processor. Blocks ask for vertical space and the engine starts a new page when they do not fit; paragraphs are the one block allowed to split mid-way. Columns are handled with a measure pass — every renderer honours a dry flag that advances the cursor without drawing, so a row can find its tallest column before committing to a baseline.

Units are millimetres in the sidebar and points in the PDF, converted at the boundary in src/pdf/units.ts.

Blocks

Content — heading, text, section header, divider, spacer, image, page break.

Form fields — text input (single or multi-line), date, dropdown, checkbox, checkbox group, radio group, signature. Each becomes a genuine AcroForm field.

Layout — 2- or 3-column rows with adjustable splits, and tables whose cells can optionally be fillable fields.

Document-wide settings (page size, orientation, margins, font, colours, running header and footer, field styling) live in the sidebar when nothing is selected.

Field names

Every form control carries a name, which is what appears when the filled PDF is read back programmatically. Leave Field name blank and it is derived from the label; collisions get a numeric suffix, since AcroForm names must be unique.

Saving

The document autosaves to localStorage as you work. Save template and Open… move it in and out as JSON, which is the format to use for sharing a design or keeping it in version control.

Known limits

  • Text uses the 14 standard PDF fonts, which are WinAnsi-encoded. Characters outside that range (CJK, emoji) are replaced with ? rather than failing the export. Embedding a Unicode font would need @pdf-lib/fontkit.
  • Images must be PNG or JPEG, and are stored inline in the template, so large ones can exhaust localStorage. Export the template as JSON if autosave starts failing.
  • A column taller than the remaining page will overflow rather than break; keep rows short, or put a page break before them.
  • "Flatten on export" produces a read-only PDF — the fields are painted onto the page and are no longer fillable.

About

Drag-and-drop PDF form designer that runs entirely in the browser. Exports real fillable AcroForm PDFs.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages