An offline invoice generator that prints to PDF: one HTML file, no server

An offline invoice generator that prints to PDF: one HTML file, no server

AEFRI engineering note · 2026-11-03

This article was written with AI assistance (an AI coding agent) and reviewed against the project's own test suite. Disclosed per DEV's guidelines; see the #ABotWroteThis tag.

The shape of the problem

Invoicing is the one piece of admin that every freelancer and small studio does, and it is the one piece that is most often outsourced to a SaaS with a monthly fee, an account, a login, and a "your data lives on our servers" clause. We wanted the opposite: a single HTML file you open in a browser, fill in, preview on a paper-sized canvas, and print to PDF. No server, no account, no data leaving the machine.

The Invoice Writer is that file. It ships as one of the products in our storefront (https://aefristore.web.app) and is also part of the Everything Bundle. This post is the engineering notes.

What "offline" actually means here

or a USB stick and it works.

but nothing is ever transmitted.

a fixed paper size, margins, and a print-only layout, so the output looks like a real invoice, not a screenshot of a web page.

The layout trick: a live paper canvas

The preview is not a separate "print view". It is the same document, rendered on screen at a scaled-down paper size, so what you see is what prints. Two details made this work:

  1. A fixed-size container (A4 proportions) with transform: scale(...) so it

fits the viewport without changing the print geometry.

  1. Print styles that reset the transform and margins, so the browser's print

engine sees the raw paper dimensions.

The result is that editing a line item updates the total, the tax, and the print preview in the same frame. No "preview" button, no second window.

Numbering and totals

re-opening the file continues the sequence instead of restarting at 001.

subtotals, and a configurable tax rate are derived, never stored. Storing derived values is how rounding bugs and stale totals happen.

in whatever currency the client pays in.

What we deliberately left out

CRM, and a CRM is a different product with a different support burden.

storefront keeps its own hash-chained ledger; the invoice tool does not, because mixing "draft an invoice" with "be a system of record" is how small tools become fragile.

is the feature, not a limitation.

The companion: a contract kit

The same storefront ships a Freelance Contract & Invoice Kit (6 fillable documents) for the part that comes before the invoice: scope, terms, and sign-off. The two are designed to be used together but neither depends on the other.

Where it lives

The Invoice Writer is also the thing we use to bill our own small freelance work, which is the only honest test of a tool like this: if we would not use it ourselves, it does not ship.