Skip to content

One design, two authoring paths

The Northstar invoice and Common Ground report now have two source versions: editable HTML templates and reusable Python components. They share the same data, CSS, fonts and artwork. All four PDF pages match pixel for pixel in the same-runtime checks described below.

Download both source versions Northstar component PDF Common Ground component PDF

Component alpha 2.6.0a4

These examples use fullbleed.ui.experimental from the explicitly pinned 2.6.0a4 prerelease. The API may change before stabilization. The original 2.4.0 showcase downloads remain available; this comparison renders both authoring paths on 2.6.0a4.

Keep the design, choose the source

Document HTML/CSS output Component output Pages
Northstar Studio HTML-authored PDF Component-authored PDF 1
Common Ground HTML-authored PDF Component-authored PDF 3

Northstar invoice with a condensed headline, serif studio identity and forest-green total panel.

Northstar Studio

InvoiceField groups a label and several lines. InvoiceItems maps records to typed table columns. AmountDue owns the total panel and exposes its label and amount as named styling parts. The full document composes these pieces and calculates totals with Decimal.

Read the component source

The recipient block can be written either way:

from fullbleed.ui.experimental import Strong
from invoice_components import InvoiceField

recipient = InvoiceField(
    "Prepared for",
    Strong("Maple & Finch"),
    "Attn. Avery Morgan",
    "Portland, Oregon",
)
<div>
  <h2 class="kicker">Prepared for</h2>
  <p><strong>Maple &amp; Finch</strong><br>
     Attn. Avery Morgan<br>Portland, Oregon</p>
</div>

The component supplies the tags, line breaks, text escaping and internal styling targets. Call it again with different values to create another field.

Common Ground cover with oversized green type, a warm orange sun and a vector neighborhood landscape.

Common Ground

ReportPage provides the masthead and folio. The cover, reach and resources pages compose metrics, a participation chart and an allocation table. The illustration uses the original local SVG asset; chart heights and allocation shares come from the data.

Read the component source

Reach page · Resources page

Where the styling lives

These are custom document designs built with the component primitives; they do not need Bootstrap's default appearance. Both source versions use common.css and their existing invoice.css or report.css.

class_name="kicker" emits the literal class kicker. It has an appearance because design_document() loads the shared .kicker CSS rule into Document(styles=...). The class name itself does not register a style or find a stylesheet automatically.

Styling choice What it controls here
class_name="metric-caption" Selects an existing rule in the shared CSS
style=style(margin_top=pt(12)) Applies a value to that node's root
.with_parts(value=style(...)) Changes the internal value advertised by Metric
Page(size="A4", margin=mm(0)) Owns the component document's paper geometry

For example, customize a metric without knowing its internal tags:

from fullbleed.ui.experimental import pt, style
from report_components import Metric

reach = Metric(1240, "households took part", "across four neighborhoods")
accented = reach.with_parts(
    value=style(color="#b74624", font_size=pt(44)),
)

The examples also customize DataTable's header and cell parts to match the existing ruled tables. A small selector rule supplies the original numeric columns' white-space: nowrap behavior.

Run and compare

Extract the download, then run from its root in a fresh Python environment:

python -m pip install -r requirements.txt
python examples/design_showcase/compare_authoring.py --out output

Open output/html/invoice/invoice.pdf and output/components/invoice/invoice.pdf, then the equivalent report files. output/comparison.json records the comparison. Use --only invoice or --only report to check one document.

To render directly, run this from examples/design_showcase/:

from pathlib import Path
from fullbleed.ui.experimental import Renderer
from invoice_components import northstar_invoice
from render import DATA, FONTS

invoice = northstar_invoice(DATA["invoice"])
renderer = Renderer(font_files=[str(path) for path in FONTS])
Path("invoice.pdf").write_bytes(invoice.render_pdf(renderer))
Path("invoice.html").write_text(invoice.to_html(include_styles=True), encoding="utf-8")
Path("invoice.unstyled.html").write_text(invoice.to_html(include_styles=False), encoding="utf-8")

Styled HTML embeds CSS. Unstyled HTML retains the authored classes and content while omitting styles. Both exports are static. For browser use, make the named fonts available through your application's font setup; PDF font registration does not install fonts in a browser.

These are fixed A4 compositions with one and three page budgets. Review the layout after substantial content growth. The quarterly chart keeps the original 980-household scale unless you explicitly change it.

What the matching-output check proves

  • Both paths pass the CLI's overflow, missing-glyph and font-substitution gates, expected page counts, required-text checks and deterministic render/verify replay.
  • All four native page PNGs are byte-identical at 120 DPI.
  • All four saved PDF pages have identical pixels in PDFium at 144 DPI and the same extracted text.
  • Northstar's two PDF files are byte-identical. Common Ground's component SVG introduces additional graphics-state scopes, so its PDF bytes differ while its rendered page appearance matches.
  • Direct component rendering and embedded-style HTML produce the same component PDF bytes. Unstyled exports omit CSS and preserve authored classes.

Native comparison · Independent-reader comparison · Source and download hashes

These checks cover these two designs on the pinned runtime. They do not imply that arbitrary HTML, CSS or browser layout has complete parity.