page 2 break is an EXPLICIT Document::addPage() between two * writeHtml() calls (the same pattern as handbook.php), not CSS * `page-break-before`. This is a deliberate engine-limitation workaround, * verified empirically (2026-07-13 minimal repro): NextPDF's multi-column * engine is a single-page-per-container, stream-based algorithm * (NextPDF\Html\MultiCol\MultiColLayoutEngine — "cross-page fragmentation ... * is delegated to the page-break controller and is out of scope for this * engine"). Letting the auto page break (Document::setAutoPageBreak()) land * INSIDE the findings `column-count` block mid-render splits it across the * page boundary and corrupts the column redistribution (all items collapse * into a single narrow column with the tail silently dropped) — CSS * `break-inside: avoid` on the container does NOT prevent this, because the * container's total height is only known after it finishes rendering, one * pass, so the page-break controller cannot pre-empt a break before it opens. * The explicit addPage() guarantees the multicol block always starts fresh * on a page with a full body height available, which every item here fits * inside easily. The continuation header (slim band, footer "2 / 2") is * still exercised genuinely — it renders from the page-number-keyed header * callback (SampleTemplate::installHeader()), not from anything specific to * how the page break was triggered. * * @see NextPDF\Samples\SampleTemplate * @see NextPDF\Core\Concerns\HasTextOutput::writeHtml() * @see NextPDF\Html\MultiCol\MultiColLayoutEngine */ require __DIR__ . '/../lib/bootstrap.php'; use NextPDF\Samples\Edition; use NextPDF\Samples\SampleSpec; use NextPDF\Samples\SampleTemplate; $spec = new SampleSpec( id: 'report', title: 'Analytics Report', description: 'A structured quarterly report with an executive summary, KPI stat cards, a throughput table, and multi-column findings that exercise the continuation header.', capability: 'HTML/CSS layout, multi-column', edition: Edition::Core, standards: ['ISO 32000-2'], ); $template = new SampleTemplate($spec); $doc = SampleTemplate::createDocument($spec); $template->apply($doc); $doc->addPage(); $template->masthead($doc); $template->registerFaces($doc, [['Inter', 'B']]); // emphasis + KPI values $page1 = <<<'HTML'

NextPDF Engine — Q2 2026 · Prepared for the Platform Team

Executive summary

Document throughput grew across every workload class this quarter while median render latency continued to fall. The engine processed 4.2 million documents at a 99.98% success rate, and peak-hour concurrency held steady under a 3× synthetic load test. Growth was broadest in the invoice and signed-archival profiles, while the table below lists the illustrative profiles and values used by this sample.

The figures below summarize volume, latency, and conformance by document profile; the continuation page breaks the quarter down into the findings that drove these numbers and the actions the platform team is carrying into Q3.

4.2M

+18% QoQ

Documents rendered

38 ms

−14% QoQ

Median render latency

99.98%

+0.03 pts QoQ

Render success rate

Throughput by document profile

Profile Documents Median (ms) p99 (ms) Success
Invoices & statements 1,840,200389199.99%
Reports & dashboards 986,5406418299.98%
Shipping labels 742,3102153100.00%
Signed & archival (PDF/A) 631,07011229899.95%
Encrypted deliveries 198,4104510399.97%
All profiles 4,398,5305317899.98%

Figures are illustrative sample data generated for demonstration purposes only.

HTML; $page2 = <<<'HTML'

Key findings

Median latency fell 14% quarter-over-quarter after the layout-cache rollout — the largest single-quarter improvement on record.

Worker-safe rendering held steady under a 3× synthetic peak-traffic load test with zero dropped jobs.

Invoice workloads account for the largest volume in this illustrative dataset.

Archival output passed conformance checks on every sampled batch, with zero PDF/A validator failures.

p99 latency on signed & archival documents remains the highest of any profile, tracking closely with PAdES signing and timestamp overhead.

Font-embedding failures dropped to zero after the strict PDF 2.0 embedding gate shipped in Core 3.3.

Recommended actions

1Extend the layout cache to the reports profile to recover p99 headroom.
2Promote the signed-output pipeline to the default for compliance tenants.
3Add a synthetic canary for the archival profile to catch drift early.
4Investigate CMS timestamp batching to trim signed-document p99 further.

Generated by the NextPDF engine. Figures are illustrative sample data.

HTML; $css = <<<'CSS' CSS; $doc->writeHtml(SampleTemplate::sharedCss() . $css . $page1); $doc->addPage(); $doc->writeHtml(SampleTemplate::sharedCss() . $css . $page2); $output = \getenv('NEXTPDF_SAMPLE_OUTPUT') ?: __DIR__ . '/../output/report.pdf'; $doc->save($output); echo "Created: {$output}\n";