first pass at the newspaper builder
Test / test (push) Has been cancelled

This commit is contained in:
2026-09-14 11:57:22 +10:00
commit bec1eaac87
497 changed files with 178953 additions and 0 deletions
@@ -0,0 +1,197 @@
# Requirements — Wedding Newspaper Generator
## Intent Analysis
The user is building a wedding-newspaper generator: a tool to take authored
content — the stories, schedules, messages, and inside jokes of a wedding — and
render them as a genuine-feeling newspaper. The deep goal is not just "generate
HTML" but to produce a keepsake that reads, on real paper, like a newspaper
published the day of the wedding: classic broadsheet look, a proper masthead,
crosswords and comics, and a front-page cartoon that ties the occasion together.
The product must be fully local: the generator runs on the couple's laptop,
content is private, and nothing is published beyond the machine. The output is
a self-contained HTML page opened directly (`file://`) and printed to A4 from
the browser's own print dialog. Because a printed multi-page newspaper is the
central deliverable, layout fidelity on paper — clean automatic page breaks,
content flowing across sheets — is a first-class, non-negotiable requirement.
## Functional Requirements
### FR1 — Multi-page newspaper output (MUST)
The generator SHALL produce a newspaper that flows across multiple A4 sheets
with automatic page breaks when content exceeds one page; it MUST NOT be
limited to a single page.
- FR1.1 — When the total content exceeds one A4 sheet, the output MUST
continue onto subsequent sheets with a clean break between pages.
- FR1.2 — Page breaks MUST occur at section or article boundaries where
possible (never splitting a single article's body awkwardly mid-paragraph
unless unavoidable).
- FR1.3 — Each printed page MUST be self-consistent: page numbers, running
headers/footers, and masthead continuation render correctly across sheets.
### FR2 — Classic newspaper masthead (MUST)
- FR2.1 — The front page SHALL render a title (masthead) banner.
- FR2.2 — The masthead SHALL include a date line, an issue number, and a
"Volume X" line.
- FR2.3 — The masthead SHALL be styled in the classic broadsheet manner
(large serif title, rule lines above and below).
### FR3 — Article types (MUST)
The layout SHALL support all of the following content types, mapped from
markdown into newspaper sections:
- FR3.1 — Lead / front-page story (a large featured article on page one).
- FR3.2 — Interior news articles with headings and bylines.
- FR3.3 — Pull quotes, sidebars, and fact boxes (standalone callout styling,
not just body paragraphs).
- FR3.4 — A "schedule" or "events" block (e.g. ceremony / reception
timetable), rendered as a clearly formatted table.
- FR3.5 — A lighter section (messages / letters / well-wishes / memory
corner) distinct in visual weight from hard news.
### FR4 — Crosswords and comics ("the funnies") (MUST)
- FR4.1 — The generator SHALL build crossword puzzles **from content the user
provides** (grid + across/down clues derived from user-supplied words/theme
words and clues), not from a fixed built-in set.
- FR4.2 — The generator SHALL support comic-strip blocks (one or more panels
with art + dialogue), including beyond a single cartoon.
- FR4.3 — Crossword and comic blocks MUST remain printable and legible on A4.
- FR4.4 — The "fun" section is first-class: it may include other word puzzles
(e.g. word search / "find-a-word") and other comics (e.g. Dilbert, Garfield,
or a tasteful equivalent) so long as they are funny and print cleanly.
### FR5 — Front-page cartoon tied to the occasion (MUST)
- FR5.1 — The front page SHALL render an xkcd-style or genuine single-panel
cartoon that relates to the wedding / the couple / the day.
- FR5.2 — The cartoon SHALL be generated with awareness of context: the
couple, the occasion and the day's details inform its subject, so it feels
like it belongs rather than a generic cartoon.
- FR5.3 — The cartoon SHALL be rendered entirely on-machine (see NFR3
Local-only and NFR4 Zero-network); the final printed page never depends on a
remote resource.
- FR5.4 — A genuine xkcd cartoon MAY be sourced from the real xkcd site
(searched for one related to the occasion) as a generation-time input; if
one is fetched, it SHALL be embedded locally so the delivered page remains
self-contained and print-capable offline.
### FR6 — Photos and images (MUST)
- FR6.1 — Articles SHALL support embedded photos/images placed per article.
- FR6.2 — The layout SHALL auto-balance images into the column structure so
they flow naturally with text.
- FR6.3 — Images SHALL support optional captions and byline/credit lines.
### FR7 — Content ingestion (MUST)
- FR7.1 — Content is authored as Markdown (and/or plain text) files and
read by the generator.
- FR7.2 — The generator SHALL produce a single self-contained `newspaper.html` —
the printed artifact — from the ingested content.
- FR7.3 — The generated page SHALL provide a live-load path (native file
picker / drag-and-drop) so alternate content can be swapped in and rendered
without regenerating (matches affirmed practice: user-granted reads only).
- FR7.4 — Photos are optional inputs: when photos are supplied, the layout
SHALL embed them (per FR6); when none are supplied, the layout SHALL generate
cleanly without photographs (never fabricate placeholder images).
- FR7.5 — Newspaper metadata (masthead title, couple names, date, issue
number, volume) is dynamic and SHALL be supplied at generation time rather
than hard-coded, so a new issue can be produced without editing the code.
### FR8 — Optional AI draft support (SHOULD)
- FR8.1 — The generator MAY call a local AI to draft newspaper copy (lead
story, filler articles, pull quotes) before the final render.
- FR8.2 — AI-drafted copy MUST be authored into content exactly as if
hand-written, then flow through the same layout pipeline.
- FR8.3 — The AI route MUST be local Ollama only; the granted model is
`deepseek-v4-flash:cloud`. No content SHALL be sent to an external/cloud
service.
- FR8.4 — AI generation SHALL run the whole first-pass newspaper, then STOP
for per-article human review: the user SHALL be able to approve, request
edits, or replace any single article's copy before the final render. This
review is per-article; approved articles stay unchanged while others are
revised and re-rendered.
## Non-Functional Requirements
- NFR1 (Printability) — The page MUST print cleanly to A4 from the browser's
own print dialog, with no clipping and correct margins. (MUST)
- NFR2 (Layout integrity) — Print CSS MUST keep every section, article,
image, and puzzle inside the sheet with no overflow, orphaned columns, or
broken page breaks. (MUST)
- NFR3 (Local-only) — Everything must run purely from the local filesystem;
the page MUST never be served or deployed beyond localhost. (MUST)
- NFR4 (Zero network) — The page SHALL make zero network requests (no CDN
fonts, no remote `<script>`/`<style>`/assets), so it is fully functional
offline from `file://`. Fonts, images, and any asset ship with the page.
(MUST)
- NFR5 (Content read policy) — Content SHALL be read only through
user-granted means (native file picker / drag-and-drop); the page SHALL NOT
rely on `fetch()` of sibling local files (opaque-origin CORS blocks it in
stock browsers). (MUST)
- NFR6 (Pure, dependency-free render) — The output SHALL be pure HTML5 + CSS
+ vanilla JS with no build step and no external dependencies. (MUST)
- NFR7 (Fidelity to markdown) — The markdown→HTML transform SHALL preserve
content exactly (no mangled quotes, em-dashes, escaping, or dropped
sections). (MUST)
- NFR8 (Classic aesthetic) — The visual theme SHALL be classic broadsheet:
black ink on white/cream, serif headlines and body, and column rules.
(SHOULD, from Q5=a)
- NFR9 (AI isolation) — Any AI generation SHALL be an optional, opt-in step
that never runs when not requested, and SHALL keep all content local
(Ollama). (MUST)
## Constraints
- C1 — The project runs on the wedding couple's local machine, never published.
- C2 — Node.js is available but the Python (3.14) + `uv` runtime is the
affirmed primary path; the generator is a Python static generator.
- C3 — Output must be a self-contained static HTML file; no server process is
required or desired at print time.
- C4 — Only local Ollama is permitted for AI; no external/cloud LLM API.
- C5 — A4 is the fixed print format.
## Assumptions
- A1 — The couple prefers print realism (classic broadsheet) over modern web
styling for the printed keepsake.
- A2 — "Fluid" pagination (flow onto as many A4 pages as needed) is preferred
over forcing a fixed page count (Q7=a).
- A3 — Photos will be supplied as local image files referenced from content;
the generator embeds them (self-contained output).
- A4 — The xkcd-style cartoon is generated by the local AI with contextual
awareness of the couple and day, then rendered as an SVG/embedded image.
- A5 — Crosswords are authored as structured puzzle data (grid + clues)
provided in content, then laid out by the generator.
- A6 — A default visual identity (title, accent) can be supplied by the user
but is not required for the generator to produce a valid first output.
## Out of Scope
- OS1 — Deploying or hosting the newspaper anywhere (web, static host,
printer service).
- OS2 — Sending any content or generation to an external/cloud AI service.
- OS3 — Dynamic server-side rendering or a persistent runtime service.
- OS4 — A full WYSIWYG editor UI (content stays in markdown/text files).
- OS5 — Non-A4 print formats (US Letter, tabloid) in this iteration.
## Open Questions
- OQ1 (RESOLVED) — Crosswords and other "fun" puzzles are **built from user-provided
content**; the fun section may include other comics that are funny, and the
xkcd-style cartoon should be a genuine xkcd searched on the real site when
possible.
- OQ2 (RESOLVED) — Photos are handled when supplied; if none are supplied,
no photos are generated or fabricated.
- OQ3 (RESOLVED) — Newspaper masthead metadata (title, names, date, issue,
volume) is dynamic and brought in at generation time.
- OQ4 (RESOLVED) — AI generation runs the whole first-pass newspaper, then
provides a per-article human review mechanism (approve / request edits /
replace any single article) before the final render.