reconcile-paper-sync
Back to list

millionco/reconcile-paper-sync

Reconcile Paper Sync

GitHub

Verify and repair a Paper-to-code implementation against its paper-sync canonical render, including fonts, exact tokens, and screenshot diffing.

11 installsSystemsFrontendCraft0 demos

Real-world examples not captured yet

This skill shows a gallery of live HTML demos (CDN libraries welcome — GSAP, Three.js, etc.) rendered inline via srcdoc.

Skill markdown
# Reconcile a Built App with paper-sync

You make a running app match the Paper design it was built from, using the project's `paper-sync` output as the canonical reference render.

This is the verification-and-repair phase that follows `paper-to-code-components`. The conversion produces maintainable code; this skill confirms the result still looks like the design and closes the gaps where it drifted.

## When this applies

- A Paper-derived app (e.g. a Next.js site) renders close to the design but "slightly off."
- A `paper-sync` project exists (a `.paper-sync/<fileId>/` directory and usually a dev server such as `localhost:6006`).
- You want to verify a fresh Paper-to-code implementation before calling it done.

If there is no paper-sync project, fall back to the Paper screenshot as the oracle and apply the same method.

## RED/GREEN Intent

This skill prevents these reconciliation failures:

- Declaring parity from reading code instead of comparing rendered pixels
- Leaving the app on `system-ui`/Geist/Georgia fallbacks while the design uses real licensed fonts
- Collapsing the design's several typefaces into one font token
- "Fixing" a difference that is actually newer design work in paper-sync by inventing data to match it
- Dropping small decorations (code-chip backgrounds, hairlines, dashed outlines, badges) during conversion and never noticing

GREEN outcome: the running app, screenshotted at the frame's width, matches the paper-sync render on typeface, type scale, color, spacing, and per-element decoration — and any remaining differences are explicitly attributed to newer design iterations, not conversion bugs.

## 1. Find the paper-sync canonical

paper-sync mirrors the Paper file into the repo. For each Paper file it keeps:

1. `.paper-sync/<fileId>/.canonical/*.tsx` — the **verbatim** Paper export per frame, the source of truth for exact values. Frame files are named `page-1--frame-<id>-0.tsx` and carry a header comment with the Paper URL (`.../<FILE>/1-0/<FRAME>`).
2. `.paper-sync/<fileId>/paper.css` — `@font-face` declarations and the design's CSS.
3. `.paper-sync/<fileId>/public/paper-assets/fonts/*.otf` — the real font files.
4. A dev server with a preview route: `?preview#<FRAME>` renders a single frame alone (the frame id is the uppercase hash, e.g. `N66-0`).

Map the frame you are reconciling to its canonical file by matching visible text (`grep -l "We introduce React Bench" .canonical/*.tsx`). The on-disk `.canonical` can lag the running server; trust the live `?preview#<frame>` render for what the user sees, and the canonical `.tsx` for exact numeric values.

## 2. Fonts first — the biggest lever

Substituted fonts are the most common cause of "slightly off." Do this before chasing spacing.

1. List the families the canonical frame uses: `grep -ohE "font-\['[^']+'" <frame>.tsx | sort | uniq -c | sort -rn`. Expect several distinct families by role (body, serif display, UI/label, numeric/mono, code).
2. For each family, confirm the app self-hosts the real font via `@font-face` and maps it to its own token. If it instead falls back to Geist/Georgia/system, that is the bug.
3. Port any missing fonts from `public/paper-assets/fonts/*.otf` into the app (e.g. `public/fonts/`), add `@font-face` per weight/style, and point each token at the real family with the system stack only as fallback. Keep distinct typefaces as distinct tokens — do not collapse them.

See `paper-to-code-components` §8 for the porting rules.

## 3. Extract exact values from the canonical

The `.canonical/*.tsx` holds the real numbers. For any element that looks off, read its canonical class list and match:

1. Type: `text-[15px]/6` is 15px / line-height 24px; replicate size AND line-height, not just size.
2. Color: `color(display-p3 ...)` and hex — keep the exact gamut/value.
3. Decoration: backgrounds, borders, dashed outlines, underlines, radii, small markers.

Do not read sizes or colors off a screenshot when the canonical source is available.

## 4. Screenshot-diff the running app against the frame

1. Render both at the same width. A headless browser screenshot works without installing Playwright: drive a cached Chromium, e.g. `chrome-headless-shell --hide-scrollbars --force-device-scale-factor=2 --virtual-time-budget=6000 --window-size=<w>,<h> --screenshot=out.png <url>`. Allow time for `@font-face` to load before the shot.
2. Capture the app (`localhost:3000`) and the frame (`localhost:6006/?preview#<FRAME>`), then compare side by side.
3. Reconcile element stacking order (e.g. nav above vs below a header band), content width and text measure (same paragraph → same line count?), typeface, type scale, color, spacing, and every decoration. A flow/responsive layout will not be pixel-identical to absolute Paper coordinates — judge structural, typographic, and decorative fidelity, not coordinate equality.

## 5. Separate conversion drift from version drift

A difference has two possible causes; treat them differently:

-

…

More from millionco