April 10, 2026 · 12 min read · Design Systems

The Tattoo Flash Design System I Built for My Dev Brand

I got tired of every developer site looking like a Stripe clone. So I built a design system inspired by tattoo flash sheets, notebook doodles, and the chaos of a well-loved sketchbook. Here's how doodles.css works, why it exists, and how you can steal it.

1. Why Every Dev Site Looks the Same

Go look at ten indie dev portfolios right now. I'll wait. You'll find: a dark background (probably #0a0a0a), an Inter or Geist font stack, perfectly rounded cards with subtle borders, a gradient purple-to-blue hero, and maybe a grid of bento boxes if they're feeling adventurous.

It's all beautiful. And it all looks like it was generated from the same Figma template. Which, often, it was.

I'm not here to trash the SaaS aesthetic. It works. It converts. It communicates "I am professional and I ship software." But when I started building dashbuilds.dev, I wanted something that communicated something different: "I am a person who made this by hand, and I had fun doing it."

That's how I landed on tattoo flash.


2. The Aesthetic — Tattoo Flash Meets Dark IDE

Tattoo flash sheets are those pre-drawn designs you see on the walls of a tattoo parlor. Bold outlines, limited color palettes, small imperfections that make them feel alive. They're art, but they're also functional — each design exists to be picked up and used.

That felt right for a dev brand. My site is a collection of tools, templates, and ideas. Each one should feel like a little design on the wall: grab it, use it, make it yours.

The other half of the equation is the dark IDE. I spend most of my life staring at a code editor with a dark theme. That deep near-black background, monospace fonts, syntax highlighting in purple and teal. Combining those two worlds — the sketchbook and the terminal — gave me something that felt genuinely mine.

If your design system doesn't make you smile when you open your own site, you built the wrong one.


3. The Design Tokens

Color Palette

Everything starts with #08070e — a purple-black that's warmer than pure black and easier on the eyes at 2 AM. The accent is #a78bfa, a muted lavender that reads as "purple" without screaming. Supporting cast:

#08070e
#0f0e18
#161525
#a78bfa
#f0abfc
#67e8f9
#fbbf24
#34d399
#f87171

Typography

Four fonts, each with a job:

DM Serif Display — headings that feel like book titles
Inter — clean body text that gets out of the way
Fira Code — code blocks and technical details
Caveat — handwritten margin notes and annotations

The interplay between DM Serif Display (elegant, editorial) and Caveat (messy, human) is what gives the system its personality. One says "I know what I'm doing." The other says "I drew this during a meeting."


4. The Sketchy Card System

This is where the personality really shows. Here's a standard SaaS card next to a sketchy card, rendered live:

Generic SaaS Card

API Dashboard

Monitor your API usage, track rate limits, and manage keys in real time.

Sketchy Card

API Dashboard

Monitor your API usage, track rate limits, and manage keys in real time.

The differences are small but they compound: dashed borders instead of solid, a slight rotation (rotate(-.4deg)), the serif heading font, and a subtle background shift. The card looks hand-drawn without being cartoonish.

In the full system, nth-child rules give each card a slightly different tilt:

.card:nth-child(2n) { transform: rotate(.3deg); }
.card:nth-child(3n) { transform: rotate(-.4deg); }
.card:nth-child(5n) { transform: rotate(.6deg); }
.card:nth-child(7n) { transform: rotate(-.2deg); }

No two cards sit at the same angle. It's subtle enough that you don't consciously notice it, but it makes the whole page feel less rigid.

Washi Tape + Margin Notes

Some cards get the full treatment: a washi tape strip across the top and a handwritten margin note:

pinned

Brain Kit

The toolkit I use to organize my second brain — Notion templates, automation scripts, and the thinking frameworks behind every build.

this one's my favorite →

The washi tape is just a semi-transparent rectangle with rgba(167,139,250,.18) background, rotated 2 degrees. The margin note uses Caveat and sits in position: absolute off the right edge. Resize your browser — on mobile, the note disappears gracefully.


5. The Doodle Library

Six hand-drawn SVG doodles float around the edges of every page. They're the heart of the brand — small enough to be ambient, distinctive enough to be memorable. Here they are at full size:

Skull
animation: dFloat 6s
Heart + Arrow
animation: dWobble 5s
Lightning Bolt
animation: dFloat 7s
Eye
animation: dPulse 4s
Ghost
animation: dFloat 8s
Code Brackets
animation: dFloat 6s

Each doodle is pure SVG — no images, no external files, about 200 bytes each. They use fill="rgba(...,.05)" for that faint wash of color behind the strokes, which mimics the way marker ink bleeds slightly on paper. The strokes themselves use stroke-linecap="round" because tattoo flash lines taper at the ends.

Every doodle gets its own animation. The skull floats. The heart wobbles. The eye pulses. They're positioned with position: fixed and pointer-events: none so they drift in the margins without interfering with content.


6. Generating Icons with AI

The doodles are hand-coded SVGs, but the product icons across the site (20 total) were generated with Gemini's image model and post-processed with Python. Here's the pipeline.

The Prompt

Finding the right prompt took about 40 iterations. Too vague and you get clip art. Too specific and the AI freezes up. This is what I landed on:

Gemini Prompt

"Hand-drawn tattoo flash style icon. Bold PURPLE and MAGENTA marker outlines with visible diagonal hatching fill strokes in purple/violet. Subtle neon purple glow around edges. A few tiny sparkle dots and rough energy lines. Sophisticated but raw, not childish not corporate. ALL lines and fill in purple/magenta/violet tones (NOT black). White background, square icon, no text."

Why Each Constraint Matters

"NOT black" — without this, every icon comes out with black outlines that clash on dark bg

"diagonal hatching" — gives the fill a hand-drawn quality instead of flat color

"not childish not corporate" — narrows the style window to exactly where I want it

"no text" — AI loves adding random text to icons

The Post-Processing

Raw Gemini output comes on a white background with inconsistent sizing. I wrote a Pillow script that handles the cleanup:

# Smart white background removal
# Lightness > 220 AND color spread < 30 = transparent
# This catches off-whites and near-whites without
# eating into the purple artwork
from PIL import Image
import numpy as np

img = Image.open(path).convert("RGBA")
data = np.array(img)
r, g, b, a = data[:,:,0], data[:,:,1], data[:,:,2], data[:,:,3]
lightness = np.maximum(np.maximum(r, g), b)
spread = (np.maximum(np.maximum(r,g),b).astype(int)
        - np.minimum(np.minimum(r,g),b).astype(int))
mask = (lightness > 220) & (spread < 30)
data[mask] = [0, 0, 0, 0]

The lightness > 220 AND spread < 30 threshold is the key insight. Pure white is easy to remove, but Gemini outputs have gray speckles, slightly blue whites, shadow gradients. Checking both lightness (is it bright?) and spread (is it colorless?) catches all the near-whites without accidentally nuking the light purple tones in the actual artwork.

Final output: 128-200px transparent PNGs for the site, plus 512x512 white-background JPEGs (auto-cropped and squared) for Stripe product images. 20 icons total — 9 product icons, 4 feature icons, 6 build category icons, and the site logo.


7. The Little Details

The big pieces get the attention, but the small things are what make the system feel cohesive.

Noise Grain SVG fractalNoise at 2.5% opacity, fixed over the entire viewport. Makes flat CSS colors feel like textured paper. One line of CSS on body::before.
Color Splashes Radial gradients placed like ink splotches — purple, magenta, teal, amber. They sit behind content with filter: blur(80px) and low opacity. The page breathes.
Custom Cursor A small purple circle replaces the default arrow. It's the .cursor-sketch class — just a 12px radial-gradient cursor PNG. Tiny touch, but it sells the hand-drawn feel.
Notebook Lines The .ruled class adds faint horizontal rules via repeating-linear-gradient. Looks like lined notebook paper. Used on blog posts and long-form content.

Highlighter Markers

Four colors, each with a gradient that mimics a real highlighter — heavier on the left edge, fading at the ends:

Yellow for key facts and callouts
Magenta for things that matter emotionally
Teal for technical details and specs
Purple for brand-voice moments

The trick is the linear-gradient(104deg, ...) with opacity ramps at both ends. A flat background color looks like a selection highlight. The gradient looks like someone dragged a marker across the text.

Color Splashes in Action

^ those are just blurred divs. that's it. that's the whole trick.

Squiggly Underlines

Links and emphasis text use a hand-drawn squiggly underline instead of a straight text-decoration. It's an inline SVG path encoded in the background-image — a sine-wave-ish line that repeats horizontally. Cost: zero HTTP requests, about 180 bytes.


8. The Doodle Pack — Free Download

Everything described in this post is free to use. Below are all six SVG doodles at copy-paste size, plus the animation CSS. Grab what you need.

Doodle Pack

6 SVG doodles + animations + the full doodles.css file

Download doodles.css

All 6 SVGs — Copy and Paste

Each SVG below is self-contained. Copy the code, drop it into your HTML, done. They're designed to work on dark backgrounds (#08070e to #1a1a2e range).

Skull
copy SVG above
Heart + Arrow
copy SVG above
Lightning Bolt
copy SVG above
Eye
copy SVG above
Ghost
copy SVG above
Code Brackets
copy SVG above

Animation CSS

Drop this into your stylesheet to animate the doodles:

@keyframes dFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-10px) rotate(3deg); }
}

@keyframes dPulse {
  0%, 100% { opacity: .2; transform: scale(1); }
  50% { opacity: .4; transform: scale(1.12); }
}

@keyframes dWobble {
  0%, 100% { transform: rotate(-3deg); }
  50% { transform: rotate(3deg); }
}

@keyframes dSpin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

The full doodles.css file also includes the sketchy card system, highlighter markers, washi tape, margin notes, noise grain overlay, color splashes, notebook ruled lines, and the custom cursor. It's one file, no dependencies, no build step.


9. Should You Do This?

Honest answer: it depends.

This style works when:

This style doesn't work when:

The real question isn't "is this good design?" It's "does this feel like me?" I spent years copying whatever design trend was popular. Neumorphism, glassmorphism, the Vercel look. They were all fine. None of them felt like opening my own site and thinking "yeah, this is mine."

The tattoo flash system does. Every time I see that little skull floating in the corner, I grin. That's worth more than any conversion rate optimization.

Build something that makes you want to visit your own site. The people who get it will find you.

Want the full system?

The doodles.css file is free to download and use in any project. If you want the thinking frameworks and note-taking system behind how I organize builds like this, check out Brain Kit — it's the same system I used to plan, document, and ship dashbuilds.dev.


Thanks for reading. Now go draw on your website.