Skip to content

feat(templates): add the Orange Ops two-column CV preset - #632

Merged
DemchaAV merged 1 commit into
feature/template-promotionfrom
feat/orange-ops-cv-preset
Aug 31, 2026
Merged

DemchaAV merged 1 commit into
feature/template-promotionfrom
feat/orange-ops-cv-preset

Conversation

@DemchaAV

Copy link
Copy Markdown
Owner

Why

orange-ops-cv is the last of the finished AI Flow bundles still living outside the
library. It is a two-column operations CV — a dark role bar with accent slashes, a
contact strip on hairlines, achievement discs, and a metric strip with full-height
rules between the numbers — and none of that is reachable from any built-in preset
today.

It also asks something none of the promoted presets have asked before: its display
face is Oswald, which graph-compose-fonts does not carry. The preset therefore
names the family and leaves registering it to whoever composes the document.

What

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

The font is the caller's. OrangeOps.DISPLAY_FONT is the name to register
against, and the class documentation carries the call. In this repo the callers are
the gate and the example, and each supplies the two faces from its own module's
resources (qa/src/test/resources/fonts/oswald/,
examples/src/main/resources/fonts/oswald/, with the SIL OFL text beside them). No
published artifact gains a font.

Eight berths, four to a column, reached by title rather than by Slot. A berth
nobody fills takes its heading, its accent rule and its join hairline with it — the
rule belongs to the pair of blocks, so dropping one block must not leave a line over
the gap.

Two shapes are what the design shows rather than what a row could hold. The role
bar is a layer stack because the plate's box and the slash group's box overlap
horizontally. An achievement is a layer stack because a table cell anchors its disc to
the foot of the pair instead of the top. And a badge is one leaf, not two: the disc is
re-emitted around the glyph inside a widened viewBox, because a shape container placed
in a table cell reserves its box and composes none of its children.

A heading's parenthetical is split off at the title's first bracket and set smaller
beside it, which is how KEY KPI SNAPSHOT (Recent 12 Months) reaches the page.

As on the presets before it, a link is drawn as its own label with the address behind
it. That is the one deliberate departure from the ported sheet, measured at
7 241 of 2 173 720 pixels.

One note on the baseline

The bundle's published preview was rendered on 2.2.1-SNAPSHOT. Frozen on that engine
it reproduces the preview to 0 pixels; on 2.2.3-SNAPSHOT it differs by 50 858,
and diffing the text layers shows why — the preview reads Warehouse Opera ons,
marcus.benne @email.com and Counterbalance Forkli Truck Instructor, the Latin GSUB
ligatures the engine has since stopped emitting. The current engine draws the words
correctly, so the parity baseline is the bundle rendered on the engine this branch
targets, not the stale preview.

Tests

  • Pixel parity against the bundle: 0 / 2 173 720 differing pixels, 116 layout nodes
    against the bundle's 116, rendering the bundle's own data on 2.2.3-SNAPSHOT.
  • OrangeOpsSmokeTest — 19 cases: the packaged marks, the unknown-mark data error, an
    entry with no mark, the uppercased name and role bar, the parenthetical heading, a
    trunk prefix left undialled (+44 (0)20 7946 0832tel:+442079460832), the globe
    on a link that is not a network, metrics whose captions differ in length, the link
    targets on every kind of title, a dropped berth taking its join rule with it, a
    document with nothing but an identity, and the run onto a second page.
  • OrangeOpsLayoutSnapshotTest — exact geometry, 116 nodes, one page.
  • OrangeOpsVisualParityTest — 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-orange-ops-v2; assets/readme/examples/cv-orange-ops-v2.pdf
    is regenerated from the committed code.

A one-page operations CV in three bands over a split body: a two-tone
name above a dark role bar whose right edge and three accent slashes
lean by one ratio, a contact strip on hairlines, then a narrow column of
dotted skills, achievement discs, a degree and certifications beside a
wide column of profile, dated roles, a four-metric strip and the closing
lines.

Ships as cv.presets.OrangeOps on the existing CvDocument model, so the
port needed no model change. It is the first preset whose display family
the engine does not carry: Oswald is not in graph-compose-fonts, so the
preset names it through OrangeOps.DISPLAY_FONT and the caller registers
it, with the gate and the example each supplying the two faces from
their own module's resources.

Eight berths reach their sections by title, four to a column, and a
berth nobody fills takes its heading, its accent rule and its join
hairline with it. A main-column heading's parenthetical is split off at
the title's first bracket and set smaller beside it.

Guarded by a 19-case smoke test, an exact layout snapshot and a
pixel-parity gate.
}
double[] box = new double[4];
for (int i = 0; i < 4; i++) {
box[i] = Double.parseDouble(parts[i]);
@DemchaAV
DemchaAV merged commit f3a34ad into feature/template-promotion Aug 31, 2026
12 checks passed
@DemchaAV
DemchaAV deleted the feat/orange-ops-cv-preset branch August 31, 2026 19:21
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.

2 participants