01 — Why I built it

Figma kept lying to me. So I moved the source of truth into code.

Every Pinnlo screen I drew in Figma looked good on the canvas and fell apart in the browser. Spacing drifted, states were missing, hover behaviours were implicit. I stopped trusting Figma as the source of truth and built a design system in HTML instead — every component rendered, interactive, and ready to copy into the real product.

24

Components across buttons, cards, inputs, surfaces, and nav — each with states.

6

Categories: colour, type, space, motion, components, patterns.

1

Source of truth. The HTML is the spec, the prototype, and the export — all at once.

Live components + source

Buttons

3 variants · ripple hover
buttons.csscss
.btn {
  position: relative;
  min-width: 97px;
  min-height: 44px;
  padding: 0 16px;
  border-radius: 6px;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 12px;
  font-weight: 500;
  overflow: hidden;
}

.btn .ripple-grid {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 1fr);
  pointer-events: none;
}

@keyframes cellRipple {
  0%  { background: rgba(251,146,60,0.5); }
  40% { background: rgba(244,114,182,0.4); }
  70% { background: rgba(147,197,253,0.3); }
  100%{ background: transparent; }
}

Three variants with a 10×5 ripple grid that radiates Orange → Pink → Blue from the cursor on hover.

Strategy Card

190×254 · ripple grid

Strategy Name

An app for strategy…

Created by: Maria, Dec 9

Last Updated: Dec 11, 4:25pm

strategy-card.csscss
.strategy-card {
  width: 190px;
  height: 254px;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.08);
  border: 1px solid rgba(0,0,0,0.08);
  overflow: hidden;
  position: relative;
}

.content-inner {
  position: absolute;
  inset: 8px;
  background: rgba(255,255,255,0.85);
  border-radius: 8px;
}

.grid-bg {
  background-image:
    linear-gradient(rgba(0,0,0,0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,0,0,0.03) 1px, transparent 1px);
  background-size: 16px 16px;
}

The primary card — grid background behind a frosted inset, with the signature ripple hover animating through the cells.

3D Box Loader

8 boxes · isometric · pure CSS
loading.csscss
.loader-3d {
  width: 200px;
  height: 320px;
  transform-style: preserve-3d;
}

.loader-box div {
  width: 48px;
  height: 48px;
  transform: rotateY(-47deg) rotateX(-15deg)
             rotateZ(15deg) scale(0);
}

.box0 div, .box3 div, .box6 div { background: var(--orange); }
.box1 div, .box4 div, .box7 div { background: var(--pink); }
.box2 div, .box5 div            { background: var(--blue); }

Eight boxes fly in from offscreen, stack in isometric perspective, then drop through a lit ground plane. 3s cycle, zero JavaScript.

02 — How I worked

From Figma to code, step by step.

  1. 01
    Audited the UI surface

    Screenshotted every Pinnlo screen. Counted buttons, cards, inputs. Most were subtly different — that was the problem to solve.

  2. 02
    Explored in Figma first

    Set colour, type, and spacing tokens as variables. Built component variants. Stress-tested states, density, dark mode.

  3. 03
    Translated each component into HTML

    Took the Figma spec and rebuilt it in raw HTML + CSS. No framework. Tokens became CSS custom properties.

  4. 04
    Interactive states in the browser, not Figma

    Hover, focus, active, disabled, loading — written once in CSS and reused. Figma can't show these honestly; code can.

  5. 05
    Ported components into React

    Each HTML prototype became a React component in Pinnlo. Same tokens, same names, same behaviour.

  6. 06
    Kept the HTML library as the reference

    When something drifts in production, I open the HTML library and copy it again. It's the canonical version.

03 — Design × engineering

HTML is a better Figma than Figma.

Figma is a drawing tool pretending to be a spec. Browsers are a spec pretending to be nothing. When the design system lives in HTML, there's no translation layer and no drift: the prototype is the spec, the spec is the demo, and the demo is what ships. Tokens defined once in CSS custom properties propagate through every surface — light mode, dark mode, Pinnlo brand, client brand — without any rebuild.

04 — What I learned

Building a design system taught me to design less.

Most of the job wasn't designing components — it was deleting them. Every near-duplicate button, card, or input was a decision I'd failed to make earlier. Pruning the system forced me to commit to one answer per problem.

Tokens are the most important thing in a design system, and they're invisible. Naming them well — --surface-muted, not--grey-200 — is what lets the system outlive the brand it was built for.

The best proof a system works is how fast you forget it's there. By month three, I was shipping Pinnlo features without thinking about components at all — which is exactly the point.