brandpress
Design an identity and ship the files. A brand handover is vector artwork, an icon set, a manual and print-ready pieces — not a picture of a logo and not a web page that shows one.
You will do this with code. There is no design application here, and none is
needed: skill/assets/pipeline/ is a small toolkit that draws exact geometry,
pulls real glyph outlines out of a typeface, lays out PDF pages and writes
SVG/PDF/PNG.
When this applies
Use it for: a new logo or identity, reworking an existing one, a brand manual, logo variations and lockups, an icon/favicon set, print artwork.
Do not use it for: choosing colours inside an existing product UI (that is a design-system task), or obtaining a third party's existing logo.
Non-negotiables
- Look at every render before moving on. Generate, open the PNG, judge it. Text output describing what you drew is not evidence. Most defects in this work are visual and invisible in code.
- Explore before you commit. Draw at least five different symbol directions, render them on one sheet, then argue for one. First ideas are category clichés.
- Curves, never text. Any logo file containing
<text>renders differently on a machine without that font. Convert to outlines. - Never fabricate a measurement. If a print size, licence term or brand fact is unknown, say so and mark the assumption in the deliverable.
Process
1. Brief
Get, or infer and state: the name (exact casing), what the thing does, who buys it, the one idea the mark must carry, and where it will appear smallest.
Mine the subject's own world for form. A payments company that splits money is about division; a seed company is about radiating growth. The mark should come from the noun in the name, not from the category's stock imagery.
2. Explore — at least five directions
Build each as real geometry, put them on one sheet at equal size, render, and look. Then write down why each rejected one failed. That reasoning is part of the delivery — it is what stops the client re-proposing an idea you already tested.
Read references/anti-patterns.md before you draw. It lists shapes that
reliably read as something you did not intend — the outlined hexagon with three
inner shapes at 120° that reads as a radiation symbol, the cracked shape that
reads as failure, the tall-tipped drop that reads as flame.
3. Choose and refine
Pick one and say why in one paragraph. Then tune it: proportion, corner radius, optical centring, counter sizes. Re-render after each change.
Lock the proportions numerically in the code (HEIGHT_RATIO = 1.054), so the
mark can never be redrawn slightly differently later.
4. Wordmark
Set the name in a real typeface, pull the outlines, adjust the tracking. A logotype is drawing, not typing.
Consider one deliberate customisation — most often swapping a letter for the
symbol. It only works if the typeface's letterforms can host it: a hexagon
replacing an o needs a geometric face with a near-circular bowl.
5. Build the system
Symbol, wordmark, horizontal lockup, stacked lockup, negative version, one-colour version, icon set. Clearance rule and minimum size, both measured.
6. Check
Run qa.py and read what it says:
svg_is_outlined— no font dependency left in the logohas_trimbox— the printer knows where to cutcounter_closes_at— the size where the mark stops workingcontrast_report— WCAG ratios for every foreground/background pair
Contrast failures are normal and informative. A saturated accent on a light ground usually fails body-text contrast; that is not a reason to change the colour, it is a rule to write down: this colour is for shapes, never for paragraphs.
7. Deliver
brand/
logo/ symbol, wordmark, lockups — svg + pdf + png, every version
icon/ 16 → 1024 px, plus the source vector
print/ pieces with bleed and TrimBox in the filename
manual/ the brand manual PDF
fonts/ the typefaces used, with their licence
pipeline/ the generators
README.md what is here, and how to regenerate it
Naming: brand-piece-variant.ext, lowercase, hyphens. Print files carry their
trim size and bleed: card_85x55mm_bleed3mm.pdf.
Every deliverable must be reproducible with one command. The geometry lives in one module; changing the brand means changing that module and re-running, never hand-editing an exported SVG — the moment someone edits an export, the files start disagreeing with each other.
The toolkit
In skill/assets/pipeline/. Copy it into the project you are building.
| Module | What it does |
|---|---|
geometry.py |
polygons, corner rounding, half-plane clipping, drops, colour mixing, CMYK |
fonts.py |
fetch a variable font, cut static weights |
typography.py |
glyph outlines with real kerning, exact bounds, fit-to-width |
page.py |
multi-page PDF layout in millimetres |
printing.py |
bleed, TrimBox, BleedBox, effective DPI |
export.py |
SVG + PDF + PNG from one drawing |
qa.py |
contrast, outline check, TrimBox check, reduction proof |
Dependencies: pymupdf, fonttools, uharfbuzz. Install them before
starting; do not assume the environment already restricts you.
A complete worked example — logo, icons, card with bleed, four-page manual,
self-checks — is skill/assets/example/build_example.py. Read it before
writing your own; it is the shortest description of the whole shape of the job.
Traps that cost real time
These are not hypothetical. Each one produced a wrong file that looked fine until much later.
- Group
opacityis ignored by some SVG renderers, MuPDF among them. A background mesh at 9% opacity rendered fully solid. Flatten it yourself withgeometry.mix()and emit a solid colour. Live transparency in a print file is its own source of surprises anyway. SVGPathPenemits shorthandHandV, which carry one coordinate. Parsing a path string as x,y pairs silently produces a wrong bounding box. UseBoundsPen—typography.pyalready does.- The Google Fonts CSS endpoint with a legacy User-Agent returns a corrupt
file for variable-only families. It downloads at a plausible size and fails
deep inside the renderer. Take the variable font from the
google/fontsrepository and instance it —fonts.pydoes this and validates magic bytes. set_cropbox()with the MediaBox rect raisesCropBox not in MediaBox. Do not set it; it already matches.- A variable font renders at its default weight in most renderers. Cut static instances.
- Fonts are software. Ship the licence with the package and check the terms before commercial use.
References
references/anti-patterns.md— shapes that read as something elsereferences/geometry.md— construction techniquesreferences/typography.md— outlines, kerning, letter substitutionreferences/print.md— bleed, boxes, DPI, colour for pressreferences/manual.md— what belongs in a brand manual, page by page
Language
Deliverables follow the client's language. The toolkit is English; the artwork is not. Accented characters shape correctly — verify visually, since a missing glyph renders as an empty box rather than an error.