dot-skills Design-to-React Conversion Best Practices
The reverse-engineering pipeline that converts Sketch files into pixel-perfect React + CSS, with regression-safe iteration as the load-bearing constraint. The skill is organized around the cascade effect of design-to-code conversion: a wrong call in stage N corrupts every output from stage N+1 onward, so categories are ordered by how much downstream they own.
The user's primary requirement — "each improvement doesn't cause regressions" — is enforceable only if the iteration loop, the layer tree, and the layout solver are correct before you start polishing styles. Read the rules in priority order.
When to Apply
- Building a converter that ingests a
.sketchfile (or equivalent design source) and emits React + CSS - Iterating on an existing converter where each improvement risks breaking other components
- Diagnosing why a converted component "almost matches" the design but visual-regression fails
- Designing the snapshot-gate / baseline strategy for a design-to-code pipeline
- Choosing between flexbox vs grid vs absolute positioning when the source is freeform geometry
- Translating Sketch-specific primitives (
MSImmutableFlexGroupLayout,attributedString,curvePoint,MSImmutableStyleCorners) into idiomatic CSS
Rule Categories by Priority
The ordering is the cascade — fix earlier stages first; later-stage fixes are wasted if the upstream tree is wrong.
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Reverse-Engineering Iteration Strategy | CRITICAL | iter- |
| 2 | Tree Reconstruction & Symbol Resolution | CRITICAL | tree- |
| 3 | Layout Algorithms (Flex/Freeform Inference) | CRITICAL | layout- |
| 4 | Coordinate & Geometry Math | HIGH | geom- |
| 5 | Visual Regression & Diff Algorithms | HIGH | diff- |
| 6 | Style Translation (Color, Gradient, Shadow, Border) | MEDIUM-HIGH | style- |
| 7 | Typography Math | MEDIUM | type- |
| 8 | Path & Shape Rendering | MEDIUM | path- |
Quick Reference
1. Reverse-Engineering Iteration Strategy (CRITICAL)
iter-bisect-from-root— Convert top-down, bisect bottom-up to localize regressions in O(log n)iter-baseline-snapshot-gate— Every change must pass committed baselines before mergeiter-convert-symbols-before-instances— Topologically sort symbols → instances; never inline duplicatesiter-freeze-design-tokens-first— Extract sharedSwatches/layerStyles to CSS variables BEFORE any componentiter-one-family-per-pr— Scope conversions to one component family per iterationiter-keep-known-good-branch— Maintain a baseline branch as a three-way regression triage anchor
2. Tree Reconstruction & Symbol Resolution (CRITICAL)
tree-resolve-overrides-before-emit— ApplyoverrideValuesagainst master into named propstree-hash-subtrees-for-componentization— Structural hashing finds repetition designers missedtree-collapse-passthrough-groups— Drop no-style single-child groups; preserve world coordstree-hoist-shared-style-via-subtree-equivalence— Subtree equivalence + modifier classes, not per-property deduptree-clipping-mask-is-stacking-context—hasClippingMaskrequiresisolation: isolate+ clip-pathtree-foreign-symbols-become-library-imports— Foreign symbols are package imports, not duplicates
3. Layout Algorithms (CRITICAL)
layout-flex-group-enum-mapping— MapMSImmutableFlexGroupLayoutenums 1:1 to CSS flex propertieslayout-infer-flex-from-axis-projection-overlap— 1D separating-axis test for freeform → flex row/columnlayout-detect-grid-via-2d-coordinate-clustering— Cluster edge coordinates with ε to detect CSS Gridlayout-promote-freeform-when-equal-gaps— Equal gaps within tolerance →display: flex; gap: Npxlayout-reverse-engineer-padding-not-margin— Insets become parent padding; rebase childrenlayout-preserve-wrapping-enabled—wrappingEnabledis the only way the source signals responsive intentlayout-ignore-layout-is-absolute-escape—flexItem.ignoreLayout: true→position: absoluteoverposition: relativeparent
4. Coordinate & Geometry Math (HIGH)
geom-compose-parent-transforms-before-emit— Compose 2D affine matrices, don't concatenate raw x/ygeom-round-only-at-leaves— Carry floats through; round once at the CSS boundarygeom-rotation-is-css-transform— Frame is unrotated AABB; emittransform: rotate()geom-shape-group-bounds-via-union— Bounds = axis-aligned union of children, rebase to origingeom-clipping-bounds-intersect-not-union— Nested clips intersect; never union or replace
5. Visual Regression & Diff Algorithms (HIGH)
diff-use-ssim-for-aa-content— SSIM for antialiased content; raw pixel diff false-positives on every retestdiff-region-budgeted-tolerances— Per-region SSIM floors (text 0.99, gradient 0.95, image 1.0)diff-antialias-aware-pixelmatch-threshold— PixelmatchincludeAA: falsefor icon defect detectiondiff-perceptual-hash-for-wrong-component-detection— Hamming distance buckets route triage automaticallydiff-subtree-bisection-to-localize-regression— Disable subtrees in binary search to find the offending nodediff-baseline-per-component-not-per-page— Storybook per-story snapshots; scope = blast radius
6. Style Translation (MEDIUM-HIGH)
style-srgb-float-to-hex-via-gamma-correct-path— Sketch sRGB floats are already gamma-encoded; direct conversion onlystyle-preserve-display-p3—colorSpace: 1→ emitcolor(display-p3 …)with sRGB fallbackstyle-gradient-angle-via-atan2—atan2(dx, -dy)reframes Sketch vector to CSS gradient anglestyle-stack-multi-shadow-in-paint-order— Reverse shadow array — Sketch paints last-first, CSS first-laststyle-reconcile-border-position— Border position 0/1/2 → frame expansion oroutlinefor outsidestyle-per-corner-radii-shorthand— Per-corner radii map toTL TR BR BLclockwise (not Sketch's row order)
7. Typography Math (MEDIUM)
type-split-attributed-string-runs-only-when-differ— Coalesce identical adjacent attribute runs; single-run case needs no inner spantype-pt-lineheight-to-unitless—lineHeight / fontSize→ CSS unitless that scales with the fonttype-kerning-pt-to-em-letter-spacing—kerning / fontSize→ em-relativeletter-spacingtype-build-font-fallback-ladder— Sketch family → web stack; SF Pro needs-apple-system, BlinkMacSystemFont, …type-paragraph-spacing-between-not-after— Usegapon the parent, notmargin-bottomwith:last-child
8. Path & Shape Rendering (MEDIUM)
path-curve-point-to-svg-cubic-bezier—M+ per-segmentCfromcurveFrom/curveTopath-rectangle-with-fixed-radius-is-css— Detect axis-aligned rounded rects early; emit<div>not<svg>path-apple-smooth-corners-via-superellipse— Apple smooth corners are superellipses (n≈5), not circular arcspath-flatten-boolean-ops-at-parse-time— Resolve union/subtract via paper.js in Node; ship one flat pathpath-honor-winding-rule—windingRule0/1 → SVGfill-rulenonzero/evenodd; explicit, not default
How to Use
- Read
references/_sections.mdfor category definitions and the cascade rationale - Start with the iteration strategy (
iter-*) — without the regression gate, every other rule is just techniques - Then tree (
tree-*) and layout (layout-*) — these are the load-bearing structural decisions - Then geometry (
geom-*) and diff (diff-*) — these are the precision and validation layers - Style, type, and path are the polish layer — high fidelity but mostly local impact
For a brand-new converter, follow the rules in priority order. For an existing converter, identify which stage owns the regression you're seeing (use [[diff-subtree-bisection-to-localize-regression]] + [[diff-perceptual-hash-for-wrong-component-detection]] to triage) and fix at the highest stage that owns it.
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions, impact levels, cascade rationale |
| assets/templates/_template.md | Template for adding new rules to this skill |
| metadata.json | Version, discipline, references |
| AGENTS.md | Auto-built TOC (regenerate via scripts/build-agents-md.js) |