Skip to content

Commit dee0bf7

Browse files
committed
feat(examples): add EngineShowcase flagship + replace README hero image (Phase B + C)
Wires up Phases B and C of the pre-v1.6.6 presentation polish plan. Phase B - new flagship example: examples/src/main/java/com/demcha/examples/flagships/EngineShowcase.java (~330 LOC) renders a single-page cinematic brand promo - not a CV, not a business document - that shows the visual register the engine can hit when an author cares about presentation as much as data. Navy + electric-orange palette, A4 portrait. Composition: top marquee band (brand + version), thin orange rule, 516x280 rounded clip frame holding pre-rendered hero artwork (semantic-graph -> polished-PDFs visual metaphor) via ShapeContainerNode + ClipPolicy.CLIP_PATH, magazine-headline lockup ("Documents as code. / Cinematic by default."), three KPI cards (Templates v2 / 1,033 tests / v1.6.6 Maven Central) via softPanel + stroked card rings, three-column capability grid (Semantic DSL / Deterministic Layout / Cinematic Themes) with accentLeft rules, footer brand stripe. Hero image (examples/src/main/resources/engine-hero.png, 1.8 MB) loaded over the classpath so the example needs no filesystem assumptions. Added to examples gallery README under "Start here" tier. Phase C - persistent rasteriser + hero image swap: examples/src/main/java/com/demcha/examples/support/PdfPageRasterizer.java (60 LOC) is a tiny PDFBox-based CLI that converts one page of a PDF to PNG at a chosen DPI. Lets the repo regenerate hero/social-card images without depending on Ghostscript, ImageMagick, or pdftoppm - none of which are reliably available on Windows Git Bash. assets/readme/repository_showcase_render.png replaced with EngineShowcase page 1 (2.1 MB, 1653x2338 px at 200 DPI). Iteration story: first attempt was a meta-narrative CV via the MintEditorial preset, but visual review (read PNG inline, three sidebar labels wrapped mid-letter) flagged it as the wrong register for the hero asset - a hero CV competes with the actual CV gallery rather than complementing it. Pivoted to a cinematic engine-capability promo using a pre-rendered brand artwork, which lands as the engine's brand register rather than another template render. Doc + version guards green (CanonicalSurfaceGuardTest + DocumentationExamplesTest + DocumentationCoverageTest + VersionConsistencyGuardTest = 30/0/0). CHANGELOG entry rewritten under v1.6.6 Planned ### Documentation subsection.
1 parent 7cfa21b commit dee0bf7

6 files changed

Lines changed: 431 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,31 @@ to ship the same artefact.
202202

203203
### Documentation
204204

205+
- **New flagship example: `EngineShowcase`** + **regenerated
206+
`assets/readme/repository_showcase_render.png` hero image** ahead of
207+
the Maven Central debut. A presentation audit before v1.6.6 flagged
208+
that the existing hero PDF was a dated single-page render and the
209+
GitHub Pages showcase had 20 broken asset paths (CV v2 migration
210+
added `-v2` suffixes that `docs/index.html` never picked up). Fixed
211+
in three commits: (a) `docs/index.html` path repair so every CV /
212+
cover-letter preview resolves; (b) new flagship
213+
`examples/.../flagships/EngineShowcase.java` renders a single-page
214+
cinematic brand promo — a navy + electric-orange composition with a
215+
rounded clip-frame hero (semantic-graph → polished-PDFs visual
216+
metaphor), a magazine-headline lockup ("Documents as code. /
217+
Cinematic by default."), three KPI cards (Templates v2 · 1,033
218+
tests · v1.6.6 Maven Central), a three-column capability grid
219+
(Semantic DSL · Deterministic Layout · Cinematic Themes), and a
220+
footer brand stripe — exercising `ShapeContainerNode` +
221+
`ClipPolicy.CLIP_PATH` for the hero frame, classpath-loaded image
222+
embedding (`examples/src/main/resources/engine-hero.png`),
223+
`softPanel(...)` + `accentLeft(...)` decorators on V2 sections, and
224+
mixed serif/sans typography; (c) page 1 rasterised to
225+
`assets/readme/repository_showcase_render.png` via the new persistent
226+
helper `com.demcha.examples.support.PdfPageRasterizer` (PDFBox-based,
227+
no external Ghostscript / ImageMagick dependency). The hero now
228+
reads as the engine's brand register rather than a Lorem-ipsum
229+
template render.
205230
- **`docs/architecture/package-map.md` updated** alongside H2. A new
206231
intro paragraph documents the stability-marker convention (Stable
207232
default; engine packages are package-level `@Internal`; individual
1.62 MB
Loading

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ are with the canonical DSL, then jump to its detailed section below.
5353
| [Invoice — cinematic V2](#invoice-cinematic-v2) | `InvoiceTemplateV2 + BusinessTheme.modern()` — the recommended invoice path | [PDF](../assets/readme/examples/invoice-cinematic.pdf) · [Source](src/main/java/com/demcha/examples/templates/invoice/InvoiceCinematicFileExample.java) |
5454
| [Cover Letter](#cover-letter) | One-page `BusinessTheme.modern()` cover letter with section presets | [PDF](../assets/readme/examples/cover-letter.pdf) · [Source](src/main/java/com/demcha/examples/templates/coverletter/CoverLetterFileExample.java) |
5555
| [Module-first Profile](#module-first-profile) | Authoring directly against `DocumentSession.module(...).paragraph(...)` — DSL-direct, no template | [PDF](../assets/readme/examples/module-first-profile.pdf) · [Source](src/main/java/com/demcha/examples/flagships/ModuleFirstFileExample.java) |
56+
| **Engine Showcase** | Single-page cinematic brand promo — semantic-graph → polished-PDFs visual metaphor with rounded clip frame, magazine headline lockup, KPI cards, capability columns; source of the README hero image | [Source](src/main/java/com/demcha/examples/flagships/EngineShowcase.java) |
5657

5758
### 🧱 Core DSL
5859

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
package com.demcha.examples.flagships;
2+
3+
import com.demcha.compose.GraphCompose;
4+
import com.demcha.compose.document.api.DocumentPageSize;
5+
import com.demcha.compose.document.api.DocumentSession;
6+
import com.demcha.compose.document.image.DocumentImageData;
7+
import com.demcha.compose.document.image.DocumentImageFitMode;
8+
import com.demcha.compose.document.node.TextAlign;
9+
import com.demcha.compose.document.style.ClipPolicy;
10+
import com.demcha.compose.document.style.DocumentColor;
11+
import com.demcha.compose.document.style.DocumentInsets;
12+
import com.demcha.compose.document.style.DocumentStroke;
13+
import com.demcha.compose.document.style.DocumentTextStyle;
14+
import com.demcha.compose.font.FontName;
15+
import com.demcha.examples.support.ExampleOutputPaths;
16+
17+
import java.io.InputStream;
18+
import java.nio.file.Path;
19+
import java.util.Objects;
20+
21+
/**
22+
* Single-page cinematic engine showcase used as the
23+
* {@code assets/readme/repository_showcase_render.png} source. NOT a
24+
* business document, NOT a CV — a brand promo page that demonstrates
25+
* the visual register the engine can hit when an author cares about
26+
* presentation as much as data:
27+
*
28+
* <ul>
29+
* <li><b>Top navy band</b> — full-width branded marquee (canonical
30+
* {@code pageBackgrounds} band fill).</li>
31+
* <li><b>Cinematic hero image</b> — pre-rendered brand artwork
32+
* (semantic graph → polished PDFs visual metaphor) mounted in a
33+
* rounded clip frame ({@code ShapeContainerNode} +
34+
* {@code ClipPolicy.CLIP_PATH}).</li>
35+
* <li><b>Magazine-headline typography</b> — three-line bold lockup
36+
* set in the canonical serif heading style.</li>
37+
* <li><b>Three KPI cards</b> — soft-panel sections with accent rules
38+
* (V2 templates count · test count · Maven Central debut).</li>
39+
* <li><b>Three-column capability grid</b> — labelled rich-text
40+
* paragraphs showcasing inline style mixing.</li>
41+
* <li><b>Footer brand stripe</b> — accent rule + brand links.</li>
42+
* </ul>
43+
*
44+
* <p>The hero image lives in {@code examples/src/main/resources/engine-hero.png}
45+
* and is loaded over the classpath so the example runs without any
46+
* filesystem path assumptions.</p>
47+
*
48+
* <p>Output:
49+
* {@code examples/target/generated-pdfs/flagships/engine-showcase.pdf}
50+
* — page 1 is rasterised by {@link com.demcha.examples.support.PdfPageRasterizer}
51+
* into {@code assets/readme/repository_showcase_render.png}.</p>
52+
*
53+
* @author Artem Demchyshyn
54+
* @since 1.6.6
55+
*/
56+
public final class EngineShowcase {
57+
58+
// ── Theme palette — cinematic navy + electric accent ─────────
59+
private static final DocumentColor PAPER = DocumentColor.rgb(248, 247, 242);
60+
private static final DocumentColor NAVY = DocumentColor.rgb(18, 26, 56);
61+
private static final DocumentColor NAVY_DARK = DocumentColor.rgb(10, 14, 36);
62+
private static final DocumentColor ACCENT = DocumentColor.rgb(255, 138, 36);
63+
private static final DocumentColor ACCENT_SOFT = DocumentColor.rgb(255, 198, 138);
64+
private static final DocumentColor INK = DocumentColor.rgb(20, 24, 38);
65+
private static final DocumentColor MUTED = DocumentColor.rgb(110, 116, 132);
66+
private static final DocumentColor RULE = DocumentColor.rgb(220, 218, 210);
67+
private static final DocumentColor CARD_RING = DocumentColor.rgb(232, 226, 212);
68+
69+
private EngineShowcase() {
70+
}
71+
72+
public static Path generate() throws Exception {
73+
Path output = ExampleOutputPaths.prepare("flagships", "engine-showcase.pdf");
74+
DocumentImageData hero = loadHeroImage();
75+
76+
try (DocumentSession document = GraphCompose.document(output)
77+
.pageSize(DocumentPageSize.A4)
78+
.pageBackground(PAPER)
79+
.margin(36, 38, 32, 38)
80+
.create()) {
81+
82+
document.pageFlow()
83+
.name("EngineShowcase")
84+
.spacing(14)
85+
86+
// ── Marquee band: brand + version ──────────────
87+
.addRow("Marquee", row -> row
88+
.spacing(0)
89+
.weights(1, 1)
90+
.addSection("MarqueeLeft", section -> section
91+
.addParagraph(p -> p
92+
.text("GRAPHCOMPOSE")
93+
.textStyle(bandLeft())
94+
.margin(DocumentInsets.zero())))
95+
.addSection("MarqueeRight", section -> section
96+
.addParagraph(p -> p
97+
.text("v1.6 · MAVEN CENTRAL")
98+
.textStyle(bandRight())
99+
.align(TextAlign.RIGHT)
100+
.margin(DocumentInsets.zero()))))
101+
102+
// ── Thin orange rule ──────────────────────────
103+
.addShape(s -> s.size(516, 1.2).fillColor(ACCENT)
104+
.margin(DocumentInsets.zero()))
105+
106+
// ── Hero frame with cinematic engine image ────
107+
.addContainer(frame -> frame
108+
.name("HeroFrame")
109+
.roundedRect(516, 280, 14)
110+
.fillColor(NAVY_DARK)
111+
.stroke(DocumentStroke.of(ACCENT, 0.8))
112+
.clipPolicy(ClipPolicy.CLIP_PATH)
113+
.center(new com.demcha.compose.document.dsl.ImageBuilder()
114+
.name("HeroImage")
115+
.source(hero)
116+
.size(512, 276)
117+
.fitMode(DocumentImageFitMode.COVER)
118+
.build()))
119+
120+
// ── Magazine-headline lockup ──────────────────
121+
.addSection("Lockup", section -> section
122+
.padding(new DocumentInsets(8, 4, 0, 4))
123+
.spacing(2)
124+
.addParagraph(p -> p
125+
.text("Documents as code.")
126+
.textStyle(headline())
127+
.margin(DocumentInsets.zero()))
128+
.addParagraph(p -> p
129+
.text("Cinematic by default.")
130+
.textStyle(headlineAccent())
131+
.margin(DocumentInsets.zero()))
132+
.addParagraph(p -> p
133+
.text("Describe what your document says. The engine resolves layout, pagination, themes, and PDFBox rendering deterministically.")
134+
.textStyle(tagline())
135+
.lineSpacing(1.35)
136+
.margin(new DocumentInsets(6, 0, 0, 0))))
137+
138+
// ── Three KPI cards ───────────────────────────
139+
.addRow("KpiRow", row -> row
140+
.spacing(12)
141+
.weights(1, 1, 1)
142+
.addSection("KpiTemplates", section -> kpiCard(section,
143+
"16", "Templates v2",
144+
"Layered CV + cover-letter presets, mintEditorial accent rules, theme-token customisation."))
145+
.addSection("KpiTests", section -> kpiCard(section,
146+
"1,033", "Tests · 0 failures",
147+
"Snapshot baselines, japicmp binary-compat gate, parallel-session stress harness."))
148+
.addSection("KpiCentral", section -> kpiCard(section,
149+
"v1.6.6", "Maven Central",
150+
"Signed artefacts via GPG, sources + javadoc jars, auto-mirrored on javadoc.io.")))
151+
152+
// ── Capability columns ────────────────────────
153+
.addRow("Capabilities", row -> row
154+
.spacing(14)
155+
.weights(1, 1, 1)
156+
.addSection("CapDsl", section -> capabilityColumn(section,
157+
"SEMANTIC DSL",
158+
"Modules, sections, paragraphs, lists, tables, rows — author intent, not coordinates."))
159+
.addSection("CapDeterm", section -> capabilityColumn(section,
160+
"DETERMINISTIC LAYOUT",
161+
"Reviewable layout snapshots, stable pagination, regression-tested at every release."))
162+
.addSection("CapTheme", section -> capabilityColumn(section,
163+
"CINEMATIC THEMES",
164+
"BusinessTheme · CvTheme · component-level tokens; v2 layered preset architecture.")))
165+
166+
// ── Footer brand stripe ───────────────────────
167+
.addShape(s -> s.size(516, 0.6).fillColor(RULE)
168+
.margin(new DocumentInsets(8, 0, 0, 0)))
169+
.addRow("Footer", row -> row
170+
.spacing(0)
171+
.weights(2, 1)
172+
.addSection("FooterLeft", section -> section
173+
.addParagraph(p -> p
174+
.text("graphcompose.dev · github.com/DemchaAV/GraphCompose")
175+
.textStyle(footer())
176+
.margin(DocumentInsets.zero())))
177+
.addSection("FooterRight", section -> section
178+
.addParagraph(p -> p
179+
.text("Java · PDFBox · MIT")
180+
.textStyle(footer())
181+
.align(TextAlign.RIGHT)
182+
.margin(DocumentInsets.zero()))))
183+
184+
.build();
185+
186+
document.buildPdf();
187+
}
188+
return output;
189+
}
190+
191+
private static DocumentImageData loadHeroImage() throws Exception {
192+
try (InputStream is = Objects.requireNonNull(
193+
EngineShowcase.class.getResourceAsStream("/engine-hero.png"),
194+
"engine-hero.png missing from examples/src/main/resources/")) {
195+
return DocumentImageData.fromBytes(is.readAllBytes());
196+
}
197+
}
198+
199+
// ── Helpers ──────────────────────────────────────────────────
200+
201+
private static void kpiCard(com.demcha.compose.document.dsl.SectionBuilder section,
202+
String value, String label, String detail) {
203+
section
204+
.softPanel(DocumentColor.WHITE, 8, 12)
205+
.stroke(DocumentStroke.of(CARD_RING, 0.5))
206+
.spacing(2)
207+
.addParagraph(p -> p
208+
.text(value)
209+
.textStyle(kpiValue())
210+
.margin(DocumentInsets.zero()))
211+
.addParagraph(p -> p
212+
.text(label)
213+
.textStyle(kpiLabel())
214+
.margin(new DocumentInsets(0, 0, 0, 0)))
215+
.addParagraph(p -> p
216+
.text(detail)
217+
.textStyle(kpiDetail())
218+
.lineSpacing(1.25)
219+
.margin(new DocumentInsets(4, 0, 0, 0)));
220+
}
221+
222+
private static void capabilityColumn(com.demcha.compose.document.dsl.SectionBuilder section,
223+
String label, String prose) {
224+
section
225+
.accentLeft(ACCENT, 2.5f)
226+
.padding(new DocumentInsets(2, 10, 2, 0))
227+
.spacing(3)
228+
.addParagraph(p -> p
229+
.text(label)
230+
.textStyle(capLabel())
231+
.margin(DocumentInsets.zero()))
232+
.addParagraph(p -> p
233+
.text(prose)
234+
.textStyle(capProse())
235+
.lineSpacing(1.3)
236+
.margin(new DocumentInsets(2, 0, 0, 0)));
237+
}
238+
239+
// ── Text styles ──────────────────────────────────────────────
240+
241+
private static DocumentTextStyle bandLeft() {
242+
return DocumentTextStyle.builder()
243+
.fontName(FontName.HELVETICA_BOLD)
244+
.size(10)
245+
.color(NAVY)
246+
.build();
247+
}
248+
249+
private static DocumentTextStyle bandRight() {
250+
return DocumentTextStyle.builder()
251+
.fontName(FontName.HELVETICA)
252+
.size(9)
253+
.color(MUTED)
254+
.build();
255+
}
256+
257+
private static DocumentTextStyle headline() {
258+
return DocumentTextStyle.builder()
259+
.fontName(FontName.TIMES_BOLD)
260+
.size(38)
261+
.color(INK)
262+
.build();
263+
}
264+
265+
private static DocumentTextStyle headlineAccent() {
266+
return DocumentTextStyle.builder()
267+
.fontName(FontName.TIMES_BOLD_ITALIC)
268+
.size(38)
269+
.color(ACCENT)
270+
.build();
271+
}
272+
273+
private static DocumentTextStyle tagline() {
274+
return DocumentTextStyle.builder()
275+
.fontName(FontName.HELVETICA)
276+
.size(11)
277+
.color(INK)
278+
.build();
279+
}
280+
281+
private static DocumentTextStyle kpiValue() {
282+
return DocumentTextStyle.builder()
283+
.fontName(FontName.TIMES_BOLD)
284+
.size(26)
285+
.color(NAVY)
286+
.build();
287+
}
288+
289+
private static DocumentTextStyle kpiLabel() {
290+
return DocumentTextStyle.builder()
291+
.fontName(FontName.HELVETICA_BOLD)
292+
.size(9)
293+
.color(ACCENT)
294+
.build();
295+
}
296+
297+
private static DocumentTextStyle kpiDetail() {
298+
return DocumentTextStyle.builder()
299+
.fontName(FontName.HELVETICA)
300+
.size(8)
301+
.color(MUTED)
302+
.build();
303+
}
304+
305+
private static DocumentTextStyle capLabel() {
306+
return DocumentTextStyle.builder()
307+
.fontName(FontName.HELVETICA_BOLD)
308+
.size(9)
309+
.color(NAVY)
310+
.build();
311+
}
312+
313+
private static DocumentTextStyle capProse() {
314+
return DocumentTextStyle.builder()
315+
.fontName(FontName.HELVETICA)
316+
.size(9)
317+
.color(INK)
318+
.build();
319+
}
320+
321+
private static DocumentTextStyle footer() {
322+
return DocumentTextStyle.builder()
323+
.fontName(FontName.HELVETICA)
324+
.size(8)
325+
.color(MUTED)
326+
.build();
327+
}
328+
329+
public static void main(String[] args) throws Exception {
330+
System.out.println("Generated: " + generate());
331+
}
332+
}

0 commit comments

Comments
 (0)