Skip to content

press v2.0.0

Choose a tag to compare

@clintecker clintecker released this 22 Jul 03:38
· 262 commits to main since this release

The composable press. A new design major: trim, binding, cover material, and
print vendor are configurable; typography and web design are profile-driven;
chapters may open with a drop cap; and books extend the press by declaration.
A @v1 book is unaffected and keeps rendering byte-for-byte; a book opts into
v2 by repinning (press migrate), and until it selects a non-house profile,
even a @v2 build is unchanged.

Fixed

  • The cover wrap is now print-safe (#189). The wrap embedded the raw
    assets/cover.jpg and imprint logo, so a transparent logo (a soft mask) or
    an over-resolution source reached the cover and tripped a print-on-demand
    preflight (Lulu, KDP), even though the interior had been cleared. The
    generator now embeds flattened, resolution-capped copies via
    print_safe.prepare_cover: the logo is composited onto the exact field
    colour it lies on (so it stays invisible against the field, with no soft
    mask), and both cover art and logo are capped from the wrap geometry, since
    the logo prints small on the cover (a 1000px logo at 1.1in is 909 PPI, over
    the limit) where the same file clears the interior's roomier placement.
    verify_coverwrap now refuses a wrap that carries transparency or an image
    over 600 PPI, so a regression cannot ship a cover a printer would reject.
    Verified end to end on a real 46-page 6×9 wrap: the logo drops from 1024²
    RGBA at 909 PPI to an opaque 649² at 590 PPI, with zero soft masks.

Added (v2)

  • Semantic chapter-opening drop caps (#192). A design may open each
    chapter with a dropped or raised initial, and the manuscript stays ordinary
    prose: no \lettrine, no CSS floats, no font commands. The decision is made
    at the document-tree layer by a pandoc Lua filter that finds the first
    eligible paragraph after each chapter heading (skipping an epigraph or other
    non-prose opener) and splits its opening word into a Unicode grapheme
    initial (a base letter with its combining marks, never a stranded accent),
    the leading punctuation kept with it, and the remainder of the first word.
    For the PDF it emits a single centralized \PressDropCap macro (built on
    lettrine, with a needspace guard so a chapter opening is never stranded
    at the foot of a page); for HTML and EPUB it emits semantic
    chapter-opening/drop-cap spans a floated stylesheet renders, with a
    clearfix so a short opening paragraph never overlaps the initial. Enabled
    through the profile (design default) or a book's own chapter-opening
    override (style, lines, small-caps-remainder); off by default, so a
    book that does not opt in renders byte-for-byte unchanged (proven by the
    house visual baseline showing zero drift with the filter installed). The
    literary-novella gallery example opts in to show it. Guaranteed by
    INV-dropcap-opening, proven at the grapheme level in test_dropcaps and
    at the emission level by running the filter through pandoc.
  • A gallery of very different example books (#190), proving nothing is
    hardcoded. Five complete books under examples/ — a naturalist field guide,
    a poetry chapbook, an academic monograph, a literary novella, and a seasonal
    cookbook — each produced by the same pipeline with only its own config
    differing: two trims (house 6×9 and novella 5×8), five aesthetics, footnotes,
    a subject index, a custom web stylesheet, four kinds of front matter, three
    kinds of appended matter, and a per-book jargon allowance. Every example is
    proven a valid press book on each test run (the config passes the typed
    model, the design surfaces genuinely vary, and each passes press check),
    and the docs site gains a gallery page cross-linked from the parts-of-a-book
    and configuration guides.
  • Registrations automation: ONIX 3.0, PCN prep, and ISBN conversions
    (#191). press onix generates the ONIX 3.0 metadata record distributors
    ingest (dist/<slug>.onix.xml) from config: a product per sellable edition
    (the print ISBN as a physical product whose form follows the binding, the
    EPUB ISBN as an EA product), the ISBN as ProductIDType 15, title,
    contributors, publisher, and a year-only publishing date — degrading
    honestly where the press holds nothing (no <Price>, because a book
    repository holds no price by design). press pcn assembles the Library of
    Congress PrePub Book Link field values (dist/<slug>-pcn.txt) for the LCCN
    application, flagging any gap the form needs. New registrations helpers
    round out the arithmetic: ISBN-10↔13 conversion and the ISBN-10 / ISSN
    mod-11 check digits. There is no API that issues an identifier or accepts a
    feed without human onboarding; the automation is the generate/validate/
    format side, and the manual gates are documented honestly.
  • Typography and web design are now profile-driven (#172): a design
    profile carries not just trim and margins but the structural type treatment
    (paragraph indent, leading) and the web reading measure (max width, base
    size, line height). The house profile projects exactly the v1 values, so a
    house book renders byte-for-byte unchanged — proven against the committed
    visual baseline with zero drift — while novella-5x8 becomes a genuinely
    different qualified design (its own type treatment and measure, not just a
    resized house). The split is deliberate: the profile seals the structural
    typography that defines a design, and the aesthetic keeps owning identity
    (font family, palette), overriding the profile. Each profile has a stable
    digest over its design-affecting data, so a sealed value cannot change
    without the key that scopes its visual baseline moving; a new
    INV-profile-geometry proves every profile renders at its declared trim.
  • The v1→v2 migration and rollback contract (#174): press migrate
    moves a book to the next press major by repinning it — the press major in
    requirements.txt and the CI workflow — and nothing else. The
    manuscript, config, and accepted art come out byte-for-byte identical; a
    dry run (press migrate plan) reports every change and design consequence
    before any mutation; apply writes an exact backup first; rollback
    restores the pre-migration bytes exactly. Because the house profile
    reproduces the sealed v1 geometry, a v1 book that repins to v2 and keeps
    the house profile renders unchanged — the design moves only when the
    author selects a non-house profile. Custom overrides the profile does not
    govern (tex/title-page.tex, assets/web/*.css, config/aesthetic.yaml)
    are named by the plan, never silently carried. Guaranteed by
    INV-migration-safe and INV-migration-preview, proven by
    check_migration's scaffolded-book round-trip, and documented in
    docs/MIGRATION.md.
  • The extension contract (#171): the decision record and executable gate
    for what a book or third party may add to the press. Everything extensible —
    a design profile, provider spec, artifact, skill, or workflow — is a named
    data file selected by id, never an imported plugin, so behavior cannot come
    from import or entry-point order. An extension carries a manifest declaring
    the names it claims, the contract major it targets, the invariants it takes
    on and their proofs, and its capabilities; press's conformance gate
    refuses a manifest that collides with a core name, targets an unsupported
    contract major, is malformed, names an unknown dependency, claims a sealed
    capability, or leaves an invariant unproven — before anything is built. The
    mandatory verification, path containment, artifact graph, config validation,
    and release gate stay sealed. Modelled by INV-extension-conformance and
    INV-extension-seal, proven by check_extension_conformance over a
    reference and five hostile fixtures, and documented in
    docs/EXTENSION-CONTRACT.md.

Changed (v2 — breaking, configurable print formats)

  • Trim, binding, cover material, and print vendor are now configurable, a v2
    (design-major) change: a book pins @v2 to opt in, and a @v1 book stays
    a 6×9 paperback, byte-for-byte. Design is modelled as versioned print
    profiles
    (print.profile) carrying trim and interior geometry; the house
    6×9 profile reproduces the v1 output exactly. print.binding
    (perfect-bound, saddle-stitch, coil, casewrap, dust-jacket), print.material
    (paperback, casewrap, linen), and print.provider select the rest. Trim is
    derived from the profile, not hand-entered; the INV-config-trim invariant
    is rewritten around it.
  • Provider manufacturing specs for Lulu, KDP, and IngramSpark (from
    sourced, attributed research): the spine caliper, cover bleed, safety, and
    hardcover wrap geometry are vendor-specific and no longer hardcoded. The
    spine model branches on binding (a paperback formula vs a hardcover lookup
    or caliper), and the cover generator composes per-binding geometry that
    matches IngramSpark's published casewrap and jacket formulas. Unsupported
    combinations (a dust jacket at KDP, an uncut trim, a page count out of
    range) are refused before rendering.
  • A user guide,
    trim & binding,
    and the internal design record docs/PRINT-PROFILES-PLAN.md.