Paper-to-GPUI translation reference
Use this layer to turn one selected Paper.design frame or component into maintainable native GPUI code. Paper supplies the visual contract; the target checkout supplies the architecture and API contract.
Contents
- Required inputs
- Build the evidence pack
- Separate design from architecture
- Map layout semantics
- Translate typography, paint, and material
- Translate assets and icons
- Add state and interaction
- Handle responsive designs
- Implement in fidelity passes
- Validate the native result
- Failure shields
Required inputs
Do not begin a claimed one-to-one translation without:
- Paper Desktop running;
- intended Paper file open;
- Paper MCP tools connected;
- one exact selected artboard/frame/component or node ID;
- target GPUI checkout and owning surface;
- permission boundary: code edits versus design edits;
- target viewport(s), platform(s), and appearance(s).
If the request is an open implementation inspired by a Paper system, identify the exact source components/tokens that still govern it. “Make it like the design” is not enough when multiple frames conflict.
Run:
scripts/inspect_gpui_project.sh /path/to/projectThen read the target's manifests, root view, theme, components, assets, state, actions, tests, and current GPUI dependency.
Build the evidence pack
Follow paper-mcp.md. For the exact root capture:
- File/page identity and selected node ID
- 2x screenshot
- Root bounds and hierarchy
- JSX as a structural hint
- Computed styles for major containers and representative descendants
- Text content, family, face, size, line height, wrapping, and alignment
- Tokens/variables and resolved values
- Fill, border, radius, shadow, opacity, transform, clipping, and backdrop effects
- Exportable icons/images
- Known interactions and missing states
Record:
| Node | Semantic role | Bounds | Constraint/layout | Type | Paint/effect | Asset | State |
|---|
Resolve unknowns with narrower calls. Never replace an unknown with a plausible Apple default and later call it exact.
Paper supports modern design data such as variables/tokens, constraints, backdrop filters, variable fonts, and OpenType settings. Capture them, but map only capabilities that exist in the pinned GPUI/platform path. Evidence of a design effect is not proof of a native implementation capability.
Separate design from architecture
Preserve:
- app startup and window ownership;
- domain state and persistence;
- typed actions and key contexts;
- existing component/theme systems;
- focus and overlay conventions;
- asset source;
- async and error behavior;
- platform support.
Translate Paper into five implementation layers:
- Window/chrome: content bounds, titlebar relationship, minimum size.
- Regions: navigation, toolbar, content, inspector, footer, overlays.
- Primitives: buttons, fields, rows, chips, separators, empty states.
- Tokens: semantic color, spacing, type, radius, shadow, motion, material.
- Behavior: selection, input, loading, scrolling, resize, focus, shortcuts.
Do not create a Rust struct for each Paper node. Create a component when it repeats, owns behavior/state, maps to an existing primitive, or makes fidelity iteration materially clearer.
Map layout semantics
Paper's JSX resembles web structure; GPUI should reproduce constraint intent, not the DOM.
| Paper evidence | GPUI direction |
|---|---|
| Auto-layout row/column | flex row/column |
| Flex grow or fill container | .flex_1() or pinned equivalent |
| Fixed control/icon/sidebar | exact logical px dimension |
| Min/max constraint | pinned min/max style |
| Grid | GPUI grid when supported; otherwise semantic row composition |
| Gap/padding | exact px first, tokens after matching |
| Clip content | radius/overflow clipping on actual clipping owner |
| Overlay | anchored/deferred/project overlay layer |
| Absolute child | absolute only for genuine overlap |
| Scroll region | project/list/overflow scroll pattern |
Determine whether a width is:
- authored fixed size;
- min/max constraint;
- result of parent flex;
- intrinsic text/content size;
- screenshot-only outcome.
The biggest translation error is freezing screenshot outcomes into every child. Match the design at the target viewport, then prove it at adjacent widths.
Maintain layer/paint order explicitly. Browser z-index does not map by copying
a number; use child/deferred/overlay order supported by the target.
Translate typography, paint, and material
Typography
Match in this order:
- Runtime font family and fallback
- Available face for weight/style/variable axis
- Font size
- Line height
- Wrapping width and line count
- Baseline/alignment
- Letter spacing/OpenType behavior when supported
- Truncation
If GPUI cannot express a Paper variable axis or feature, pick the nearest available face only with an explicit delta. Do not silently bundle a license-restricted font.
Paint
Capture resolved:
- fills and gradients;
- opacity at node and paint level;
- border width/color/location;
- per-corner radii;
- shadow offset, blur, spread, alpha;
- clipping/mask behavior;
- transforms;
- background/backdrop effect.
Use exact values during first pass. Consolidate repetition into semantic tokens after matching.
Material
If Paper uses backdrop blur:
- Determine whether it is window-wide or per-element.
- Select a real target capability using apple-glass.md.
- Keep text and boundary readable over worst-case content.
- Add opaque/reduced-transparency fallback.
- Record any difference from Paper's browser-style effect.
Do not convert backdrop-filter: blur(...) into a translucent fill and claim
the blur matches. A GPUI approximation can preserve hierarchy but not sampling.
Translate assets and icons
Export only actual assets:
- icons and vector illustrations as SVG when the target asset pipeline handles them;
- alpha-heavy raster art as PNG;
- photos as appropriately compressed raster;
- multiple scale variants only when the runtime needs them.
Keep:
- Paper node ID;
- export format/scale;
- logical size;
- destination path;
- runtime tint policy;
- license/source notes if relevant.
Do not export:
- text;
- standard controls;
- complete panels/screens;
- shadows or backgrounds that GPUI can render;
- multiple raster copies of a monochrome icon that should be tinted.
Inspect SVG viewBox and optical bounds. A 16×16 icon file can still look misaligned if its paths have uneven internal whitespace.
Add state and interaction
A static Paper frame usually shows one state. Define:
- default, hover, pressed, focus-visible;
- selected/checked;
- disabled;
- loading/error;
- keyboard activation;
- tooltip/help;
- overlay open/dismiss;
- scroll and resize;
- reduced-motion/material fallbacks.
Reuse existing product behavior. Ask or state assumptions when Paper has no evidence for a materially important interaction.
Implement typed actions and stable element IDs. Keep source-anchored presentations anchored to the invoking control. Restore focus on dismissal.
Do not let a visual translation turn a functioning button into a pointer-only
div.
Handle responsive designs
If Paper provides multiple artboards:
- map each to logical bounds;
- identify what changes: visibility, order, size, density, navigation pattern;
- derive the smallest set of breakpoints;
- preserve shared components/state;
- test between authored widths.
If only one artboard exists:
- match it exactly;
- preserve existing app resize behavior;
- use sensible min/max/flex constraints from evidence;
- report unverified responsive behavior;
- do not invent a separate mobile UI.
Treat long content and localization as resize inputs. A design with one short sample is not proof of fixed-size safety.
Implement in fidelity passes
Pass 1: geometry
- root content bounds;
- major region rectangles;
- layout direction;
- fixed/flexible sizing;
- gaps/padding;
- clipping and scroll.
Pass 2: typography
- fonts and faces;
- size/line height;
- wrap/truncation;
- baseline.
Pass 3: paint
- backgrounds;
- borders/radii;
- shadows/material;
- opacity.
Pass 4: assets
- exact file;
- logical/optical size;
- tint;
- cropping.
Pass 5: behavior
- states;
- pointer/keyboard/focus;
- loading/error;
- overlay/scroll/resize.
Pass 6: extraction
Only now consolidate verified repeated values into existing tokens/components. Do not introduce a parallel design system for one frame.
Validate the native result
Use visual-validation.md:
- Build and test the owning crate.
- Launch the real app.
- Put it in the same state/content/theme.
- Match logical viewport and scale.
- Capture the native content.
- Compare side-by-side, overlay, and targeted diff.
- Fix capture, bounds, layout, typography, paint, assets, then polish.
- Exercise interaction and resize.
- Record expected native/platform variance.
Completion requires a final Paper screenshot and a final native screenshot at matching logical bounds for one-to-one work.
Failure shields
- Paper tools absent: stop extraction and connect Paper Desktop MCP.
- Wrong file open: have the user open it, then call
get_basic_infoagain. - No exact selection: request a selection or node ID.
- Huge tree: split by semantic region; retain a full-root screenshot.
- Missing font: verify, bundle/register only if authorized/licensed, recapture.
- Unsupported effect: implement honest nearest capability and record delta.
- Screenshot mismatch after equal values: inspect crop, scale, font metrics, border inclusion, opacity inheritance, clipping, and window activity.
- Existing dirty code: patch only requested files/hunks.
- Paper mutation not requested: remain read-only.
For a fully worked set of GPUI patterns, see worked-patterns.md.