Files
Voiced/docs/templates/07-crimson-grid.md
T
xavierk c95514ee8d Add Ledger and Band template families with decor primitives
Crimson Grid, Tangerine Ledger, Slate Band and Teal Swoosh are rebuilt from
the Canva PDFs with grid and band tables that survive page breaks,
full-bleed fixed bands, pennant tabs, gradient corner swooshes with
keep-outs, Carbon icon circles, and the user's logo in the measured slot
(knockout or white chip on the dark Slate band). Adds static Poppins
500-700 and Inter fonts. Thumbnails regenerated for all eight templates;
the item-count sweeps run in their own test file.
2026-10-04 08:34:18 +05:30

18 KiB

Template 7: Crimson Grid (crimson-grid)

Source: templates/Modern Neutral Invoice Template/7.pdf. All coordinates are in points from the top-left of the Canva page (595.5 x 842.25). Measured from the PDF content streams during design analysis.

Style

Bold corporate boxed grid. A huge black Poppins INVOICE sits top-left, with the logo and a 2-line name top-right. Below: a 1.5pt crimson rule, a table fully ruled in 0.75pt black with a crimson header row, a ruled totals box, and a full-bleed crimson footer band carrying a cream contact line.

Fonts

One family: Poppins, static weights 400/600/700. Metrics per 1000 units: ascent 1050, descent -350, cap ~700.

  • Poppins Bold 700: title 'INVOICE' 43.8pt #000000, tracking +0.37pt (~0.0085em). Total-row label and value 12pt.
  • Poppins SemiBold 600: brand lockup 'STUDIO'/'SHODWE' 15.44pt uppercase, baselines 80.75 and 95.22 (pitch 14.47, i.e. lineHeight 0.94). Section headings 12pt uppercase (vendor name, 'BILL TO', 'NOTES / TERMS:', 'PAYMENT METHOD', 'PREPARED BY'). Table header labels 11pt #FFFFFF.
  • Poppins Regular 400: body 12pt (meta, party lines, notes, bank lines, prepared-by). Table cells and totals 11pt. Footer contact line 12.44pt #EFEDDF, tracking +0.8pt (~0.064em).
  • Line pitch: 12pt body lines 16.5pt (lineHeight 1.375). Meta lines 18.68pt. Heading baseline to first body baseline: 23.98 (party and payment blocks), 20.8 (notes).
  • Any other measured tracking (~0.1pt) is rounding in Canva's per-glyph placement. Use letterSpacing 0.
  • The embedded subsets have no U+20B9 (₹). Check that the full Poppins TTFs include it before bundling.

Colours

Exact fill operators:

  • #A00000 (rg 0.6275 0 0), crimson: header rule, table header row fill, footer band.
  • #000000: title, all body text, table and totals grid lines.
  • #FFFFFF: page background, table header labels, separators between header cells.
  • #EFEDDF (0.9373 0.9294 0.8745), cream: footer contact text.
  • #ED1C24 (0.9294 0.1098 0.1412): placeholder flame logo only. Drop it; the vendor logo replaces it. No transparency: every ExtGState has ca/CA 1. The ca=0 rectangles are invisible accessibility tag boxes.

Layout

A4 595.5x842.25pt, y measured from the page top. Side margins 59.55 (= 10% of width) and 58.8. Content x 59.55-536.70 (477.15 wide).

Region Geometry (pt)
Title INVOICE x 59.55, baseline 100.58 (cap top ~69.7), text box ~186 wide
Logo mark x 420.0-452.4, y 53.0-98.7 (32x46)
Brand name x 466.1 (13.7 right of logo), baselines 80.75/95.22, right edge <= 536.7
Header rule y 128.85, x 59.55-536.70, 1.5pt #A00000
Meta x 59.55, baselines 173.58 'Invoice Number: #...' and 192.26 'Invoice Date: ...'
Party row 2 columns: vendor at x 59.55, BILL TO at x 304.31 (51.3% split). Heading baseline 231.07; lines 255.05/271.55/288.06/304.56
Items table y 335.84-497.90 (40.5 header + 3 rows of 40.52)
Notes (left) heading baseline 523.33, body 544.12/560.62, wraps at ~182 wide
Totals box (right) x 353.59-536.70, y 509.21-632.26
Payment (left, x 59.55) and Prepared by (right, x 322.44, misaligned with 304.31; normalise) heading baselines 686.95; lines 711.72/728.23/744.74
Footer band full bleed, y 779.26-842.25 (63 tall), text centred, baseline 815.88
Vertical gaps: rule to meta cap top ~36. Last meta baseline to party heading cap top ~30. Last party baseline to table 31.3. Table to totals box 11.3. Totals bottom to payment cap top ~46. Last payment baseline to band 34.5. In the title/brand row the bottoms roughly align (title baseline 100.6, logo bottom 98.7), so use alignItems flex-end.

Items table

4 columns, fully ruled. Grid-line centres at x 59.93 | 308.96 | 406.84 | 447.86 | 536.33, giving widths 249.0 / 97.9 / 41.0 / 88.5 (52.3% / 20.5% / 8.6% / 18.6%).

  • Header row: 40.5 tall, fill #A00000. Poppins SemiBold 11 #FFFFFF. 'Item & Description' left-aligned; 'Unit Price', 'Qty', 'Amount' right-aligned. 0.75pt #FFFFFF separators between header cells. Canva artefact: cells 1 and 3 have black top/bottom edges while cells 2 and 4 have white ones. Normalise to a black 0.75 outer box with white inner verticals.
  • Body rows: 40.52 tall, white, 0.75pt #000000 on every cell edge (outer box, verticals, row lines). Poppins Regular 11 #000. Description left-aligned; unit price, qty and amount right-aligned. Horizontal padding 9.4 on both sides.
  • Vertical: baseline is 23.64 below the row top. In react-pdf (natural line 15.4 at 11pt) that is paddingTop 12.1 and paddingBottom 13.0, or minHeight 40.5 with alignItems center.
  • No zebra striping. Keep numbers right-aligned. The Qty column is only 41 wide (~4 digits), so put the unit with the rate (e.g. '/hr').
  • Recommendation: make each money column at least 95-100pt for en-IN amounts (see overflow_risks).

Totals and payment

  • Totals box, right side: x 353.59-536.70 (183.1 wide = 38.4% of content). 2 columns: label 93.45 | value 88.9. The value-column edge at 447.41 lines up with the table's Qty|Amount line at 447.86. Rows: 'Sub-Total' 40.52, 'Tax (6%)' 40.52, 'Total' 42.02. Full 0.75pt black grid. Labels Regular 11 left-aligned (padding 9.4), values right-aligned. Total row is Poppins Bold 12 in both cells.
  • Notes/Terms sit left of the totals box, top-aligned with it (heading baseline 523.33; box top 509.21).
  • PAYMENT METHOD: SemiBold 12 heading, then Regular 12 lines 'Bank:', 'Account Name:', 'Account Number:'.
  • PREPARED BY: heading, then a name line and a 'title, company' line. No signature graphic.
  • Footer band: one centred line 'email | website | phone'.
  • Missing from the template: amount in words, signature, thank-you line, due date, page number.

Decoration and images

No raster XObjects. Everything is vector shapes plus live text.

  • Logo: flame made of 3 bezier subpaths, #ED1C24, 32x46. Replace with a vendor logo Image.
  • Header rule: 1.5pt #A00000 line.
  • Table header: 4 #A00000 rectangles (one per cell). Grid strokes 0.75pt.
  • Footer band: #A00000 rectangle drawn with bleed (x -30..626, y 779.3..872). Implement as a View, absolute, left 0, right 0, bottom 0, height 63.
  • 3 invisible (ca=0) rectangles tagged 'Image' over the logo, rule and band are accessibility tags. Ignore them. Everything can be built with View backgroundColor and borders. Svg is only needed for an optional vector logo.

Mapping to Voiced fields

  • Logo slot: vendor logo (Image maxHeight 46, maxWidth ~110, objectFit contain). If the logo is a wordmark (e.g. public/brand/arun-p-logo.png), hide the text lockup.
  • Brand lockup: vendorName (SemiBold 15.4 uppercase, wraps, right-aligned).
  • 'INVOICE': show 'TAX INVOICE' when taxType != none, else 'INVOICE'.
  • Meta lines: 'Invoice No: {number}', 'Invoice Date: {date}', NEW 'Due Date: {dueDate}' (3rd line, same 18.68 pitch), optional 'PO No: {poNumber}'.
  • Left party block (heading = vendor name): vendorAddress (multi-line), vendorPhone, vendorEmail, NEW 'PAN: {vendorPan}', NEW 'GSTIN: {vendorGstin}'.
  • BILL TO: clientName, clientAddress, 'GSTIN: {clientGstin}' (optional), NEW 'Place of Supply: {state} ({code})'.
  • Table: Item & Description = description. Unit Price = rate with unit (e.g. '₹1,500.00 / hr'); em dash for fixed-mode lines. Qty = quantity (1 for fixed mode). Amount = line amount.
  • HSN/SAC (no slot): grey 9pt sub-line under the description, or an optional 5th column (~55pt) taken from the description width.
  • Totals box: Sub-Total, Discount (if > 0), then CGST (r/2 %) and SGST (r/2 %) or IGST (r %), then Total (bold). This makes 4-6 rows.
  • Amount in words (no slot): full-width line under the notes/totals row, SemiBold 11 'Amount in words:' followed by Regular 11 text. Indian-system strings run 60-110 chars, so 1-2 lines.
  • Notes/Terms: notes, with a default 'Payment due within {paymentTermsDays} days'.
  • PAYMENT METHOD: bank fields Bank, Account Name, Account No, IFSC, Branch, UPI (planned). Up to 6 lines.
  • PREPARED BY: rename to 'AUTHORISED SIGNATORY'. Show the signature Image (maxHeight ~36) and vendorName, or Regular 9 fine print 'Computer-generated invoice; no signature required.'
  • Footer band: 'vendorEmail | vendorPhone', optionally ' | GSTIN ...'. Voiced has no website field. A page number 'n / N' can sit at the band's right end.

Overflow risks

  • Header (same class as the reported INVOICE overlap bug): the brand area is only 420-536.7 (116pt). A long vendorName wraps to 3+ lines and pushes into the rule at 128.85. 'TAX INVOICE' at 43.8pt is ~285pt wide (59.6 to ~345), leaving ~75pt before the logo. Use a flex row, never absolute positioning: title flexShrink 0; brand View flex 1, maxWidth ~40%, alignItems flex-end; rule below in normal flow.
  • Party blocks: the template ends at baseline 304.56 (4 lines) and the table starts at 335.84. A Voiced vendor block (address 2-3 lines, phone, email, PAN, GSTIN = 6-8 lines) adds 33-66pt, so the table must flow, not sit at a fixed y.
  • BILL TO column is 232pt (~36 chars per line at 12pt). Long addresses wrap, which is fine in flow.
  • Items: with 40.5pt rows only ~6 fit before the totals on page 1. The 249pt description column holds ~40 chars per line at 11pt, so long text grows the row. More than 8 rows go to page 2, which needs the header row repeated.
  • Money: the Amount column's inner width is 69.7pt, and '₹10,00,000.00' at 11pt Poppins is ~72pt, so it overflows from 10 lakh up. Unit Price (79pt inner) is fine up to ~99 lakh. Widen Amount to ~100pt (taking from description) or set numbers at 10pt.
  • Totals box: with Discount, CGST and SGST it has 5-6 rows x 40.5 = 200-245pt, which reaches the PAYMENT block (686.95) and the band (779) on A4. Use compact rows (~26pt) and flow.
  • Payment block: 6 bank lines x 16.5 = 99pt from 711.7 ends at ~810, past the band top at 779. Let it flow to page 2 or tighten it. Page paddingBottom must be >= 63 + 16.
  • Footer line: about 60 chars fit in 477pt at 12.44pt with 0.8 tracking. Email + phone + GSTIN can exceed that: use fontSize 10, or maxLines 1 with ellipsis, or 2 lines (the 63pt band fits 2).

US Letter adaptation

  • US Letter 612x792 is 16.5pt wider and 50.25pt shorter. Keep side margin M (default 59.55 = 10% of A4 width, or the user's setting). Content width = 612 - 2M (492.9 at the default). Column percentages from items_table scale with it. Keep the totals box at 183pt (or 38.4%), right-aligned.
  • Footer band stays fixed at 63pt at the bottom (top at 729 on Letter). To recover ~50pt: rule-to-meta gap 36 -> 26; meta-to-party gap 30 -> 22; table rows 40.5 -> 32 (header 34); totals rows 40.5 -> 30; totals-to-payment gap 46 -> 28.
  • Configurable margins: top margin = logo top (53 by default); title baseline = top + 47.6. The band ignores side margins (full bleed) but its text uses M. Page paddingBottom = 63 + bottom gap (16-24).
  • Canva's 595.5x842.25 page differs from react-pdf A4 (595.28x841.89) by under 0.05%; ignore it.

react-pdf notes

  • Font.register Poppins 400/600/700 from bundled .ttf files. react-pdf takes TTF/WOFF only, not WOFF2 or variable fonts.
  • <Page size={'A4'|'LETTER'} style={{fontFamily:'Poppins', paddingTop:53, paddingBottom:83, paddingHorizontal:M}}>.
  • Footer band: <View fixed style={{position:'absolute', left:0, right:0, bottom:0, height:63, backgroundColor:'#A00000', justifyContent:'center', paddingHorizontal:M}}> containing <Text style={{color:'#EFEDDF', fontSize:11, letterSpacing:0.8, textAlign:'center'}}>. Absolute offsets are relative to the page edge; the existing InvoiceDocument footer already relies on this. This is the template's only absolute element.
  • Header: View row, justifyContent space-between, alignItems flex-end. Title Text (fontSize 43.8, fontWeight 700, flexShrink 0) plus a brand View (row, alignItems center, flexShrink 1, maxWidth '40%') holding Image and Text.
  • Rule: View with borderBottomWidth 1.5, borderBottomColor '#A00000', marginTop ~28.
  • Party and payment rows: View row with two Views at width '51%' and '49%' (or flex 1 each with gap 16).
  • Table: outer View {borderLeftWidth:.75, borderTopWidth:.75, borderColor:'#000'}. Header row <View fixed style={{flexDirection:'row', backgroundColor:'#A00000'}}>. In @react-pdf/layout 5.2 splitNodes copies a fixed child into the table's continuation fragment (checked in source), so the header repeats on following pages; confirm in a render. Body rows <View wrap={false} style={{flexDirection:'row', borderBottomWidth:.75}}>; cells padding 12/9.4 with borderRightWidth .75 (white in the header).
  • Bottom row: left View flex 1 (notes, amount in words); right totals View width 183, wrap={false}, same cell borders.
  • Payment/Prepared-by row: wrap={false} plus minPresenceAhead so it never orphans.
  • Baselines: react-pdf's renderLine draws the baseline at line top + ascent, with no half-leading. So Text top = Canva baseline - 1.05 x size for Poppins.
  • Emails and GSTINs: Font.registerHyphenationCallback(w => [w]) stops '-' being inserted. Tokens wider than the column still need a character-split fallback.

Similarity to other templates

  • Near-duplicate: 11.pdf ('Rimberio'). Same structure and placeholder copy: Invoice Number/Date, vendor and BILL TO columns, 4-column ruled grid with a coloured header row, NOTES/TERMS beside a ruled totals box, PAYMENT METHOD and PREPARED BY. Differences: orange accent, Inter body with a Poppins Bold title, mirrored header (name left, INVOICE right), filled Total row, corner shapes instead of the rule and footer band. Build 7 and 11 as one ruled-grid component with theme props (accent, fontFamily, headerMirror, totalRowFill, decoration set).
  • Weaker resemblance: 2.pdf (ruled grid with a yellow header and a ruled total cell).
  • None of 7/8/9 resembles the in-app InvoiceDocument.tsx (IBM Plex, hairline rules, title-left/meta-right). The closest in the set is 3.pdf. Not similar to format.pdf (identical to 4.pdf).

Implementation notes

Built as src/pdf/templates/ledger/ (one family component, Layout.tsx, shared with Tangerine Ledger; tokens in crimson.tsx, planning in plan.ts) on the decor primitives in src/pdf/decor/. Measured against 7.pdf with npm run templates:compare (/tmp/invoice-c4/compare-crimson-grid.png, left Canva, right ours).

Matches the design (measured, A4): title baseline 100.6 pt at x 59.5, 43.8 pt Poppins Bold; the 1.5 pt #A00000 rule at y 128.85; meta baselines 173.6 / 192.3; party heading to first line 23.9 pt; BILL TO at x 304.3; table text at x 69.7, header row 42 pt (Canva 40.5 plus the 0.75 pt rules) and 40.5 pt single-line rows; header fill #A00000 with white inner verticals and a black outer box; the 63 pt full-bleed band; all colours exact.

Intentional deviations, and why:

  • Margins. Top 53 and sides 59.55 as designed. The bottom margin floor is 26 pt plus a 53 pt footer reserve, so the flow is at least 79 pt (band 63 + 16) above the page bottom on every margin preset and on Letter. The footer text is placed by chrome.bottom (14 pt above the edge), inside the band whatever the preset.
  • Header. Title and brand block are one row without alignItems: flex-end (lint bans it): the brand block is placed from the measured slot offsets. 'TAX INVOICE' (about 281 pt) shrinks to at most 60 % of its size before the brand block (at most 40 % of the width) is squeezed. A wordmark logo replaces the whole flame + name lockup; a mark logo sits left of the vendor name in 15.44 pt caps (13.7 pt gap); without a logo only the name shows.
  • Meta adds 'Due Date:' and 'PO No:' lines (same 18.7 pt pitch); 'Invoice Number:' keeps the design's wording.
  • Parties. The vendor block's heading is the vendor name in caps, followed by address, phone, e-mail, PAN and the GSTIN (slot). Canva's PREPARED BY (x 322.4, misaligned) is normalised to the BILL TO column (x 304.3) and renamed AUTHORISED SIGNATORY.
  • Table. The grid is drawn as per-cell borders (TableRows grid), not lines over the text, so it survives page breaks: the header repeats with its rules and every row owns its bottom rule. An HSN/SAC column (at least 56 pt) appears on tax invoices. Unit Price shows '₹1,200.00/hr' on one line when it fits, else the amount over 'per hour' at 8.5 pt; the money columns are at least 100 / 45 / 100 pt and grow to their widest amount. Rows grow with wrapped descriptions (padY 12.55).
  • Totals box is widened (about 210 pt: label at least 96, value at least 100) with 28 pt rows instead of 40.5, so Sub-Total, Discount, Taxable value, CGST/SGST (or UTGST, IGST via Slot.TaxRows) and Total fit. The Total row is bold 12 pt without a fill, as designed.
  • Notes / Terms sit left of the totals box when they are at most 110 pt tall; longer notes flow below the table (a long note must never make the unbreakable totals block unplaceable). Amount in words and the reverse-charge line run full width under the box.
  • Closing. Bank lines are 10.5 / 14.5 pt (not 12 / 16.5) so six lines fit; the signature is the user's image or the computer-generated line with the signatory name.
  • Footer band. The contact line is 'email | phone' (no website field exists; the GSTIN is printed through its slot only) at 11 pt with 0.05 em tracking instead of 12.44 pt / 0.064 em, and is fitted to one line. The standard footer (supplier name, 'Generated with Voiced', Page n of N) is added inside the band in cream at 7 pt; the continuation band on pages 2+ is grey so it stays readable on white.
  • Letter. The 49.9 pt deficit comes out of the rule gap (21.5 to 12), meta (31.4 to 20), party (22.3 to 14), table (27.4 to 16), totals (11.3 to 6) and notes (12 to 8) gaps, 50.4 pt in all; type and row padding are not scaled. The band stays 63 pt at the bottom edge.
  • Grid colour. The Canva artefact (black top/bottom edges on cells 1 and 3 only) is normalised to a black outer box with white inner verticals in the header, as the doc recommends.