Generate filled PDF character sheets using MPMB templates#78
Merged
Conversation
Adds browser-native print-to-PDF export: - GET /characters/:id/print — standalone multi-column character sheet (owner + DM) - GET /campaigns/:id/print — DM-only full party export with cover page The print layout uses a two-column grid (abilities/skills left, combat/HP/weapons/items right) with a second page for traits and spells. Zero new runtime dependencies — uses the browser's built-in print dialog. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the standalone Print button row with a small printer icon in the upper-right of the character info card, next to the character name.
Loads the MPMB form-fillable template for the character's ruleset, populates name, class/level, race/background/alignment, ability scores + modifiers + saves, removes the d20warning JS overlay (which would otherwise be visible since pdf-lib doesn't execute AcroForm scripts), trims to the front page of the main sheet, and returns bytes as application/pdf. Skips form.flatten() — MPMB ships rich text fields and buttons with missing appearance streams that crash pdf-lib's flattener; the form-bearing PDF still renders correctly in Chrome, Firefox, Preview, and Evince.
Skills: all 18 skill modifiers + proficient/expert checkboxes (expertise implies proficient). Combat block: AC, Initiative, Speed, HP Max, HP Current, Proficiency Bonus, Passive Perception. Hit dice: HD1/2/3 Die / Level / Used, grouped by die size for multi-class characters. Player Name: looked up via character.user_id (user.name ?? user.email); threaded through both /characters/:id/pdf and /campaigns/:id/pdf. Two number-format helpers: fmt() for the big ability-mod boxes (signed), unsignedFmt() for fields where MPMB has a '+' pre-rendered in the sheet layout (save mods, skill mods, initiative, prof bonus) — supplying a sign there yields '++2' on render. Set /NeedAppearances=true on the AcroForm so PDF viewers and print engines regenerate appearance streams from /V on render. Without this, in-browser viewers auto-render values fine on screen but their print pipelines fall back to the stored /AP — which is stale because we save with updateFieldAppearances:false — and identity/dropdown fields come up blank in print preview.
7 tasks
Per spellcasting class on page 1 (MPMB caps at 2):
- Spell save DC {1,2} ← computed DC value
- Spell DC {1,2} Mod ← title-cased spellcasting ability
For slot tracking we use MPMB's 'Limited Feature' rows on page 1, since the
actual spell-slot checkbox grid widgets in srd52.pdf's AcroForm have orphan
/P references — they belong to the dedicated spell-sheet PDFs, not the main
sheet. The Limited Feature block has 8 visible rows on page 1, each with
Name / Max / Recovery / Used columns — a natural fit for any tracked
resource.
One row per spell level the character has slots for (recovery: Long Rest),
plus one row for warlock pact magic per pact-slot level (recovery: Short
Rest). Non-casters skip the block entirely.
Each attack-resolution cantrip (resolution.kind === 'attack' — Fire Bolt, Eldritch Blast, Toll the Dead with attack subtype, etc.) prepared on a spellcasting class becomes an entry in one of MPMB's 5 Attack rows on page 1, with name, ability mod, range, to-hit, damage dice, damage type, and brief description filled in. Implementation notes: - The visible 'Attack Name' is the Weapon Selection dropdown, not the underlying Weapon text field — they're stacked at the same coordinates. Cantrip names that aren't in MPMB's 93-option predefined list get added via dropdown.addOptions. - Damage scaling: cantrips with damageScaling.mode === 'characterLevel' get their dice resolved at the character's current total level (highest threshold ≤ level). - The 'Mod' dropdown uses the caster's ability abbreviation (Int/Wis/Cha); MPMB has no generic 'Spell' option in this template version. - Without MPMB-JS, selecting a weapon/cantrip in the dropdown doesn't auto- fill the other columns, so we fill them all manually.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the HTML print export (#77, by @lionel-lints) with a server-side PDF generation approach using MPMB's D&D Character Record Sheet as a form-fillable template.
GET /characters/:id/pdf— fills the MPMB main sheet (page 1) with the character's dataGET /campaigns/:id/pdf(DM-only) — concatenates per-character pages into one combined party PDFWhat gets filled in
user.name ?? user.email), Class & Levels, Background, Race/Species, AlignmentSelects the 2014 (
srd51.pdf) or 2024 (srd52.pdf) MPMB template based on the character'srulesetfield.MPMB templates and licensing
The 2014 and 2024 MPMB templates plus per-class spell sheets live at
assets/mpmb/with their ownLICENSE.mdclarifying that those files are GPLv3 (MPMB's license) while the rest of the repo remains FSL-1.1-MIT. Files were obtained via flapkan.com's pay-what-you-want and are redistributed under GPLv3 §6.A few MPMB-specific concessions in the renderer:
form.flatten()crashes on MPMB's rich-text-field, so we save withupdateFieldAppearances: falseand set/NeedAppearances=trueon the AcroForm — PDF viewers and print engines regenerate field appearances from/V.removePage. Spell list (the dedicated MPMB spell sheets) and equipment are future work.Why PDF instead of HTML
The HTML approach in #77 hit hard layout problems in print mode (forced page breaks with whitespace, two-column grid not balancing). Generating from MPMB's official template produces output identical to what D&D players already use, with zero design effort. The HTML/CSS/JS print code created a parallel design system to maintain.
Supersedes #77
This replaces #77 entirely. Lionel's original commit is preserved as the first commit on this branch for credit — none of the HTML print code lands in the final diff (cleaned up in
chore: remove HTML print routes and components).Test plan