Skip to content

feat(templates): add the Midnight Navy plate CV preset - #634

Merged
DemchaAV merged 2 commits into
feature/template-promotionfrom
feat/midnight-navy-cv-preset
Aug 31, 2026
Merged

DemchaAV merged 2 commits into
feature/template-promotionfrom
feat/midnight-navy-cv-preset

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Why

midnight-navy-cv is the first of a second batch of finished AI Flow bundles. It is a
navy-plate sidebar CV — an outlined monogram, metered skills, dotted language ratings,
an experience rail and achievement discs — and none of that combination is reachable
from a built-in preset today.

What

cv.presets.MidnightNavy on the existing CvDocument model; the port needed no model
change. Split as the family is: MidnightNavy routes, MidnightNavyStyles holds the
tokens, and Aside / Main / Widgets / Icons draw.

The plate is page chrome, not a fill. The navy reaches the top, left and bottom
paper edges and a section's fill stops at its own box, so the plate is a page
background sized by the same ratio the body row splits on — the two cannot drift apart.

Every horizontal pair goes through one wrapper. A row nested directly in a row cell
is refused and both columns are cells, so a skill and its meter, a language and its
dots, a title and its dates, a disc and its line, and the certification columns are
each a row wrapped in a single layer of a stack.

Three marks are relationships rather than lengths. The experience rail is the entry
section's left accent, so its height derives from the entry and the gap between entries
is padding inside the border — which is what makes consecutive rails meet instead of
breaking between roles. A certification divider is its column's own accent. A skill
meter is three layers sharing the track's axis; seating one at the stack's top instead
draws a meter as three unaligned pieces.

The monogram and the role line come from the identity — two initials and the name's
own words — so a document fills neither in twice.

Seven berths reach their sections by title. The contact heading is the preset's own,
because a document has no section that carries it.

Two deliberate departures from the ported sheet, both measured. A link is drawn as
its own label with the address behind it, as on the presets before it. And every rail
marker is centred on its rail: an accent is drawn centred on the edge it belongs to, so
the section's left edge already is the rail's axis, and the ported sheet's extra
half-thickness correction put each marker a rail width to the right of the line it sits
on. Measured on the render, the marker centre was at x=449.5 against a rail centre at
x=448.0 at 150 dpi — 0.72 pt, visible at reading size. Centred, the residual is half
a raster pixel at any resolution (0.24 pt at 150 dpi, 0.06 pt at 600), which is
antialiasing rather than geometry. Together the two departures come to 2 498 of
2 173 720 pixels
, of which the centring is 200.

One page, strictly

The body is a single row and a row is atomic, so this sheet does not paginate: a
longer CV is refused with an AtomicNodeTooLargeException naming the node rather than
being cut. That is the honest failure for a design whose two columns have to reach the
same foot — splitting the row would leave the plate on one page and half the aside on
the next. The first draft of this PR claimed it flowed; the smoke test disproved it,
and both the Javadoc and the test now pin the real behaviour.

Tests

  • Pixel parity against the bundle: 0 / 2 173 720 differing pixels, 240 layout nodes
    against the bundle's 240. The bundle also freezes to 0 against its own published
    preview on both its pinned engine (2.2.2) and 2.2.3-SNAPSHOT, so there is no engine
    drift to account for here.
  • MidnightNavySmokeTest — 15 cases: the packaged marks, the unknown-mark data error,
    the monogram taken from the name, the uppercased name and tracked role, a language
    rating rounded to the nearest of five dots, a skill with no level, a trunk prefix left
    undialled, the link targets on every kind of title, a dropped berth, a document with
    nothing but an identity, and the refusal past one page.
  • MidnightNavyLayoutSnapshotTest — exact geometry, 240 nodes, one page.
  • MidnightNavyVisualParityTest — pixel baseline; recorded without disturbing any other
    baseline in the suite.
  • Full reactor gate green:
    ./mvnw -B -ntp clean verify -pl :graph-compose-core,:graph-compose-render-pdf,:graph-compose-render-docx,:graph-compose-render-pptx,:graph-compose-templates,:graph-compose-testing,:graph-compose-qa,:graph-compose-coverage -am
  • The showcase gains cv-midnight-navy-v2; assets/readme/examples/cv-midnight-navy-v2.pdf
    is regenerated from the committed code.

A one-page CV on a full-height navy plate: an outlined monogram over a
two-weight name and a tracked role line, then contact, education, metered
skills and dotted languages down the plate, beside a paper column with
the summary, roles on a rail, achievement discs and divided certification
columns.

Ships as cv.presets.MidnightNavy on the existing CvDocument model, so the
port needed no model change. The plate is a page background rather than a
section fill — it reaches three paper edges — sized by the same ratio the
body row splits on. The monogram and the role line are built from the
identity, so a document fills neither in twice.

One page strictly: the body is a single row and a row is atomic, so a
longer CV is refused with the node that could not fit rather than being
cut. Splitting the row would leave the plate on one page and half the
aside on the next.

Guarded by a 15-case smoke test, an exact layout snapshot and a
pixel-parity gate.
An accent is drawn centred on the edge it belongs to, so an entry
section's left edge already is the rail's axis: a marker reaches it by
walking back across the gutter and half its own width, and nothing else.
Correcting by half the rail's thickness on top of that pushed every
marker a rail width to the right of the line it sits on — 0.72 pt,
measured on the render as a marker centre at x=449.5 against a rail
centre at x=448.0 at 150 dpi.

Centred, the residual is half a raster pixel at any resolution (0.24 pt
at 150 dpi, 0.06 pt at 600), which is antialiasing rather than geometry.

The change costs 200 of 2 173 720 pixels against the ported sheet, and
both baselines are re-recorded with it.
@DemchaAV
DemchaAV merged commit ccb83b1 into feature/template-promotion Aug 31, 2026
12 checks passed
@DemchaAV
DemchaAV deleted the feat/midnight-navy-cv-preset branch August 31, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant