yzhao062/ci-mockup-figure
Create space-efficient figures for papers and proposals. HTML mockups for systems, dashboards, and timelines; TikZ or skia-canvas for abstract diagrams with arrow routing. Covers tool selection, design, capture, and LaTeX insertion. The primary goal is maximizing information per page — every figure must earn its space.
npx skills add https://github.com/yzhao062/anywhere-agents --skill ci-mockup-figure
The goal is space-efficient, information-dense figures that communicate
a system's design, a method's pipeline, or an architectural flowchart in
minimal page area. Three paths depending on figure type:
timelines, and any figure where content is rectangular with no cross-node
arrows. Build interactive HTML, capture screenshots, insert into LaTeX.
HTML build phase, but capture via headless Chrome to a PNG and embed it as a
Markdown image referencing assets/fig.png. Requires larger type, higher content density, and
one dominant focal element -- the viewer scales the image down to column width.
architecture overviews, dependency topologies, and any figure needing
arrow routing between non-adjacent nodes. Use TikZ, skia-canvas, or
Illustrator ExtendScript.
Every figure must pass the space test: does this figure communicate more per
square inch than the text it displaces? If a full-width figure takes half a
page but only says "A → B → C → D", it fails. A wrapfigure showing an
interactive prototype with search results, graph nodes, and real data labels
passes because it communicates system design, data model, and UX simultaneously.
This skill works for any document where figures need to communicate design
or methodology credibly: research papers (method overview, architecture
diagrams, pipeline flowcharts), proposals (NSF, NIH, DOE, etc.), technical
reports, or demo writeups. It is especially effective when the figure needs
to show multi-component structure, data flow, or step-by-step methodology
and reviewers evaluate whether the design is credible and well-conceived.
HTML and TikZ each have a clear strength. The deciding factor is **whether
the figure needs arrow routing between non-adjacent nodes**.
| | HTML mockup | TikZ |
|---|---|---|
| Visual polish | Modern CSS, shadows, gradients, rounded cards | Flat, academic-looking boxes |
| Iteration speed | Change CSS and refresh | Recompile LaTeX, debug positioning |
| Layout control | Flexbox/grid, responsive | Manual coordinate math |
| Color/font variety | Full CSS + web fonts | Limited, verbose color defs |
| Interactivity | View switching, capture mode | Static only |
| Arrow routing | Breaks on cross-row/non-adjacent nodes | Node anchoring solves this natively |
| Font matching | Separate from LaTeX | Perfect match with document body |
Prefer HTML for system mockups, dashboards, Gantt/timeline figures, and
any figure where the content is inherently rectangular and flows naturally
(no cross-node arrows needed).
Prefer TikZ for abstract framework diagrams, dependency topologies, and
architecture overviews where arrows must route between non-adjacent nodes
(L-shaped, curved, crossing rows). TikZ node anchoring (node.south,
node.east) handles this natively. Also prefer TikZ for small inline
diagrams that must live inside the LaTeX source or when exact font matching
is critical.
Prefer skia-canvas (Node.js) when you need the arrow-routing control of
TikZ but want faster iteration (edit .mjs, run, get PDF) and richer
visual styling than TikZ provides.
HTML mockups are strictly better than AI-generated images for system and
method figures. AI image generation is acceptable only for artistic/conceptual
overview diagrams.
| | HTML mockup | AI image generation |
|---|---|---|
| Text legibility | Pixel-perfect, real fonts | Often garbled or blurry |
| Data accuracy | Every number/label controlled | Hallucinated values |
| Iteration speed | Change CSS and refresh | Re-prompt and hope |
| Consistency | Same palette across figures | Each generation varies |
| Print quality | Vector PDF via browser print | Always raster |
| Reviewer trust | Looks like a system you could build | Looks like a concept sketch |
HTML is also better than PPTX for Gantt/timeline figures:
| | HTML | PowerPoint |
|---|---|---|
| Alignment | CSS grid, pixel-perfect | Manual drag |
| Edits | Change one label, everything reflows | Reposition every box |
| Color consistency | CSS variables, one source of truth | Manual color matching |
| Capture | Browser Print → PDF (vector) | Export PDF (often wrong margins) |
(e.g., "representation layer + discovery service + workflow engine", or
"data collection → feature extraction → model training → evaluation")
pipeline with real labels, not just boxes and arrows
use Python (matplotlib, seaborn, plotly) or LaTeX (pgfplots, tikz) instead.
This skill is for system/method diagrams, not data visualization.
dependency topologies, architecture overviews with curved arrows between
non-adjacent nodes, box-and-arrow conceptual figures. HTML/CSS fails at
arrow routing: JS-positioned SVG arrows drift and misalign, CSS
pseudo-element arrows work only for simple adjacent connections, and card
grid layouts read as a product dashboard, not a research diagram. Use the
Abstract Figure Toolchain section below.
When the figure is NOT a UI mockup, dashboard, or timeline (i.e., it needs
arrows between nodes, dependency edges, or architectural flow), HTML/CSS is
the wrong tool. The core problem: arrow routing is the bottleneck, not
box/text rendering. Any tool with node-anchor-based arrow endpoints works;
any tool relying on CSS layout for arrow positioning will struggle.
| Problem | Why |
|---|---|
| Curved arrows between components | Requires absolute-positioned SVG overlay that fights CSS layout |
| External screenshots as hero images | Multi-panel screenshots break object-fit: cover and explode containers |
| Card grid layout | Reads as a product dashboard, not a research diagram |
| Print fidelity | Browser print rescales unpredictably for non-page layouts |
| Emoji/icons for decoration | Instantly makes the figure look unprofessional |
| Context | Tool | Why |
|---|---|---|
| LaTeX paper, arrow-heavy | TikZ | Node anchoring (node.south, node.east) handles arrow routing natively. Font/style consistency with the paper is free. Academic gold standard. |
| Programmatic iteration needed | skia-canvas (Node.js) | Same Canvas API as HTML but headless, with direct PDF/SVG vector export. Edit coordinates in .mjs, run node script.mjs, get PDF. No browser, no capture, no pdfcrop. |
| Final hand-polish needed | Illustrator ExtendScript (.jsx) | Generate programmatically, then hand-adjust. Best for figures that need to look "designed." Requires Illustrator. |
| Python-only environment | drawsvg (pip install drawsvg) | SVG-first imperative drawing. For PDF, convert the output SVG externally (e.g., Inkscape CLI or cairosvg, which needs the Cairo C library and is tricky on Windows). |
Not recommended: D2 (auto layout too unpredictable for precise academic
figures), Graphviz (limited custom styling), matplotlib (designed for data
plots, not diagrams).
A parallel capture path to the HTML workflow, for abstract figures:
npm install skia-canvas
# edit generate-figure.mjs (Canvas API: ctx.roundRect, ctx.fillText, ctx.lineTo)
node generate-figure.mjs
# outputs figure.pdf (vector), figure.svg, figure.png
# use figure.pdf directly in \includegraphics — no pdfcrop needed
Script structure pattern:
gen_overview.mjs
├── helpers: roundRect(), text(), drawArrow(), drawImage()
├── layout constants: W, H, panel positions, gap sizes
├── draw():
│ ├── header bar (title + thumbnails)
│ ├── component panels (frame + internal diagram + footer)
│ ├── inter-component arrows with labeled handoffs
│ └── bottom strip (use cases + running example)
└── export: PDF + PNG preview
Adjust coordinates, rerun, get new PDF instantly. No browser, no print quirks.
programmatically (nodes, edges, flow stages). Screenshots are not made
for your figure's aspect ratio and will break.
ribbons) where they are decorative context, not structural elements.
Vertical stacking wastes landscape width.
description, one output line.
rgba(..., 0.06-0.08)), thick top-border accentper component. No saturated card backgrounds, no shadows, no pills/chips.
"Discovery Trace") as explicit connectors, not just whitespace.
Serif (Georgia) for text-heavy insets. Never Segoe UI, Inter, or geometric
narrow variants -- those read as AI-startup product. No emoji.
Avoid the AI-startup look. Segoe UI or Inter combined with an
indigo-violet-and-amber palette reads as a product dashboard, not a research
figure. For scientific figures:
teal #00A087, salmon #F39B7F
heavy drop shadows
Before designing anything, decide the figure budget for the document. The
table below uses LaTeX environments as examples; adapt to the target format.
| Figure type | Space cost | When to use |
|---|---|---|
| wrapfigure{r}{0.55\textwidth} | ~55% column width, text wraps beside | Best default for system mockups — gives prose enough room |
| wrapfigure{r}{0.46\textwidth} 2x2 grid | ~46% column width, 4 images in compact grid | Motivation figures with matched-ratio panels |
| figure[t] full-width | Full column, ~3-4cm height for landscape | Timelines, overview diagrams, or mockups with small text |
| subfloat 1x4 row in figure[t] | Full column, ~3cm height | Cross-domain motivation (all same aspect ratio) |
Lesson learned: 0.68\textwidth is too wide for most wrapfigures. At 0.68,
the remaining text column is too narrow for comfortable reading and the prose
wraps through multiple paragraphs. Default to 0.55–0.56\textwidth for
system mockups. Use 0.68 only for simple figures with large text.
Rule of thumb for page-limited documents (e.g., 15-page proposal):
Horizontal layout is mandatory. Vertical/portrait screenshots waste 50%+
of their space on a landscape-format page. Design the mockup for wide capture
from the start.
README and documentation hero figures differ from paper figures. Markdown
viewers scale the PNG to the content column (roughly 700-900 px on GitHub),
so design for the scaled-down view:
0.55\textwidthwill be too small in a 700 px GitHub column. Increase all font sizes by at
least 1.5x relative to a paper figure.
limited column area.
diagram -- something readable in under two seconds at thumbnail size.
pdfcrop, no LaTeX environment.
Before the first render, verify all of the following:
1px solid) are fine. Decorative glows and gradientborders are not.
variants.
color.
Do not cram multiple interfaces into one figure. If a system has a
coordinator-facing view and a citizen-facing view, build both in one HTML file
but capture them as separate screenshots, each inserted at its own
relevant subtask in the LaTeX.
Add view-switching buttons (e.g., COORDINATOR / CITIZEN / BOTH) to the
toolbar so the user can toggle views and capture each at full width. Each
view mode should have its own CSS that expands sidebars, scales up fonts,
and adjusts proportions for the full-width layout.
Each major thrust or component gets its own view. Typically 3-4 views:
Each thrust needs a distinct color palette with three tones (solid, mid,
light) so bars, cards, and legends are consistent:
--t1: #0d9488; --t1-mid: #5eead4; --t1-light: #ccfbf1;
--t2: #2563eb; --t2-mid: #93c5fd; --t2-light: #dbeafe;
Use the light tone for activity bars with a solid-tone border, the solid tone
for milestone/completion bars, and the mid tone sparingly for hover states.
Legend swatches must match the actual bar appearance — if bars are light
with colored borders, show that in the legend, not a solid fill.
Use real, public-domain scientific imagery as low-opacity backgrounds to
add geographic or domain credibility without overwhelming the schematic:
Embed as CSS background with opacity: 0.15–0.20 and filter: saturate(0.6).
Add a small attribution credit (e.g., "Imagery: NASA/USGS Landsat 9, Jan 14
2025") in the corner. Download locally to figure-src/assets/ for offline
reliability.
Use Lucide (ISC license) or similar SVG icon library. Define icons as an SVG
sprite block at the top of the HTML so they are referenced once and used
everywhere via <svg><use href="#icon-name"/></svg>. Inline SVG icons in
panel headers add polish with zero external dependencies.
should be separate files, not crammed into one)
with explicit fallback stacks (e.g., Georgia, system-ui, Consolas)
CAPTURE button): hides toolbar and any titles thatduplicate the LaTeX caption, tightens spacing, scales up fonts for legibility
@media print): hides chrome, preserves background colors,forces landscape orientation, allows text wrapping in bars
not absolute pixels, so nodes survive container resize during print
Raw mockups that look like "developer prototypes" undermine credibility. These
details make the difference:
(linear-gradient on surfaces)
metrics and audit trails, proper weight differentiation
Vary the layout between thrusts for visual interest:
px values break during print — use %wrapfigure in LaTeX needs text below it to wrap — place before a longparagraph, never at section end
at low opacity instead of giving them a full column
wrapfigure immediately beforea wraptable or another wrapfigure — LaTeX emits collision warnings and
forces floats out of position. Separate them with at least one full paragraph
of unwrapped text, or convert one to a figure[t]/table[t]
white-space: nowrap truncates text in print — bar labels and tags mustallow wrapping. Always test the print preview (Ctrl+P) before capturing.
Remove nowrap, add line-height: 1.2, and increase row height to
accommodate wrapped text.
provides the title. Duplicating it in the screenshot wastes vertical space.
For work plan timeline figures, use a standalone HTML file with CSS grid.
repeat(16, 1fr)` for a 4-year / 16-quarter layout
grid-column: N / M to span consecutive phases as single continuous blocks.
If Thrust 2 depends on Thrust 1 outputs, start Thrust 2's bar in Q2 or Q3.
so reviewers can cross-reference to the thrust text.
quarters, bordered-light bars for activity phases.
across all thrusts (M1: Component demos, M2: End-to-end pipeline, etc.).
solid for milestone, diamond for marker, dark pill for integration).
Ctrl+P → Destination: Save as PDF → Layout: Landscape→ Margins: None → Save.
figure[t] full-width (timelines need the detail).Use the implement-review skill to send the staged figure to Codex for review.
Key review points (apply to both HTML and abstract paths):
plausible for the target domain?
0.55\textwidth?vs HV-owning), does the caption explicitly label which branch is shown?
Figure~\ref{}callout in the prose. Figures without cross-references feel decorative.
Additional review points for the abstract path:
floating or misaligned endpoints.
not a product UI.
Iterate based on feedback. Typical: 2-3 rounds.
CAPTURE to hide toolbar and titlesCtrl+P → Save as PDF (landscape, no margins) for vector output, ortake a screenshot for PNG
figure/thrustN.pdf (or .png)Prefer PDF — text and SVG elements stay vector (sharp at any zoom). Only
the embedded satellite imagery stays raster. Drop the file extension in
\includegraphics so LaTeX auto-selects the best available format:
\includegraphics[width=0.55\textwidth]{figure/thrust4-coord}
height: 100% inside a flex item overflows. An inline SVG withheight: 100% inside display: flex expands beyond its parent and overlays
adjacent content. Use deterministic fixed heights: give each SVG an explicit
height in px, a viewBox whose aspect ratio matches that box, and
overflow: hidden as a backstop. Avoid flex: 1 + height: 100% SVG for
figure panels.
--window-size pairs with --force-device-scale-factor. The--window-size=W,H flag sets logical pixels. At --force-device-scale-factor=2
the output PNG is 2W x 2H physical pixels. Set W,H to the CSS viewport
dimensions, not the intended output resolution.
pdfcropBrowser-exported PDFs have full-page white margins that waste space in LaTeX.
Use pdfcrop (bundled with TeX Live) to trim to the content bounding box.
pdfcrop figure/timeline.pdf figure/timeline-trimmed.pdf
pdfcrop --margins 4 figure/thrust1.pdf figure/thrust1-trimmed.pdf
Always keep the original and write to a separate -trimmed file. This
preserves the full-page source for re-trimming with different margins later.
Use the trimmed file in \includegraphics.
pdfcrop uses Ghostscript for bounding box detection, which is reliablefor both vector and raster content.
--margins N to add N bp on all sides (2-4is typical for proposal figures).
similar — these methods frequently misdetect content bounds on
browser-exported PDFs.
Default to wrapfigure at 0.55–0.56\textwidth:
\begin{wrapfigure}{r}{0.56\textwidth}
\vspace{-1.2em}
\centering
\includegraphics[width=0.55\textwidth]{figure/thrust1}
\caption{\textbf{Thrust 1 title.} Brief description of what the
screenshot shows, referencing left and right panels. If the system
has multiple modes, state which mode is shown (e.g., ``zero-vehicle
branch; the HV-owning branch provides departure/route guidance'').}
\label{fig:thrust1}
\vspace{-1.4em}
\end{wrapfigure}
Place the wrapfigure before a paragraph with 10+ lines of text below it.
Never place at the end of a section.
For timelines, use full-width figure[t]:
\begin{figure}[t]
\centering
\includegraphics[width=\textwidth]{figure/timeline}
\caption{\textbf{Four-year work plan and integration timeline.}
Colored bars show per-thrust activities by quarter; diamonds mark
milestones; bottom row shows integration checkpoints (M1--M4).}
\label{fig:timeline}
\vspace{-1em}
\end{figure}
For a cross-domain motivation figure (e.g., "spatio-temporal data spans
multiple national-priority domains"):
Earth Observatory)
\subfloat with height= for equal-height tiling@misc bib entries using institutional authorsA sibling capture path for repository README and documentation hero figures.
The HTML build phase is identical to Phases 1-3; only capture and insertion
differ.
Resolve the browser binary first: use whichever Chrome-family executable is on the host
(chrome, google-chrome, chromium, or msedge), or an absolute path to it; create
assets/ if it does not exist. Then run:
chrome --headless --disable-gpu --hide-scrollbars \
--force-device-scale-factor=2 \
--window-size=W,H \
--screenshot=assets/fig.png \
file:///abs/path/to/fig.html
Set W and H to the CSS viewport dimensions of the mockup (e.g.,
--window-size=1400,600 for a wide dashboard). The --force-device-scale-factor=2
flag yields a retina-density PNG: physical output is 2W x 2H pixels, so the
image stays crisp when scaled down by the Markdown viewer.
Keep the HTML source and all assets under assets/figure-src/. The captured
PNG goes to assets/fig.png.
See Capture gotchas (Phase 4) for SVG overflow and window-size pairing notes.
Reference the captured PNG from the README using Markdown image syntax with a
leading exclamation point: alt text in square brackets, then the relative path
assets/fig.png in parentheses.
No LaTeX environments. No pdfcrop. The PNG is the deliverable.
assets/figure-src/assets/thumbnail size
no indigo/violet primary)
figure-src/ with all assets in figure-src/assets/figure/ (originals kept, trimmed copies via pdfcrop).mjs for skia-canvas, .tex for TikZ, .jsx for Illustrator) in figure-src/figure/ — no browser capture neededwrapfigure (0.55–0.56) or figure[t] environments in tex filesFigure~\ref{} callouts in the prose for every figureTake yzhao062/ci-mockup-figure from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip, npm.
Without those the skill loads but fails at the first command.