lofi.css v0.1

A tiny hand-drawn wireframe framework in a single CSS file. Paper-scribble look in the spirit of Excalidraw and tldraw — wobbly borders, marker highlights, squiggly underlines — for lo-fi mockups, prototypes, and docs where you want people to discuss structure and flow, not visual polish.

Grayscale only. No JavaScript. No dependencies. Bare HTML elements are styled automatically — classes are optional extras. Pixel-perfect Deliberately imperfect.

See it in action: example mockup · icon gallery

Get started

  1. Download lofi.css and place it next to your HTML file.
  2. Add the stylesheet to your <head>, and the lofi class to <body> — the handwriting fonts are embedded in the CSS, so nothing is loaded from anywhere else:
<link rel="stylesheet" href="lofi.css">

<body class="lofi"> ... </body>
  1. Write plain semantic HTML. Headings, lists, tables, quotes, code, forms, details, dialog — everything below gets the sketchy treatment with zero classes. Use the .lf-* classes for components (cards, buttons, sticky notes, annotations).
Using Claude? Install lofi-mockups.skill (bundles the CSS) or read the plain SKILL.md. The skill enforces the house rules: strictly HTML + this CSS + text, grayscale only, and no emojis.

Typography

Heading one (Caveat)

Heading two

Heading three

Body text uses Patrick Hand. Here's a sketchy link, some highlighted text, a crossed-out mistake, and a wavy underline.

Small muted caption text for annotations and hints.

Palette

paper
ink
accent
danger
ok
highlight
note
fill

Buttons

Note: sibling buttons get different wobble shapes automatically via nth-of-type.

Form elements

Cards, notes & zones

A card

Cards alternate wobble direction and shape when they're siblings.

Double-stroke card

Add .lf-double for the Excalidraw "pen went over it twice" look.

Sticky note — good for annotations, open questions, and "TODO: ask legal" moments.

Dashed zone — drop area, empty state, or "content goes here" region

Placeholders & avatars

image
chart / graph
AB CD +3

Avatars with initials

Icons

lofi.css ships 19 built-in scribble icons as an inline SVG sprite — no icon font, no external files. Paste the sprite once, then reference by id. Icons inherit text color and size with the text:

Need more than these? The full icon set has all 1745 Lucide icons redrawn in the same scribble style — searchable, click-to-copy, or download the whole sprite as lofi-icons.svg.

<svg class="lf-icon"><use href="#lf-i-search"/></svg> Search
search menu home user sliders bell calendar mail trash edit plus close check arrow star heart image chat download

In context: 3 alerts

Full-set icons use the same ids (lf-i- + Lucide name) and markup — copy the <symbol> definitions you need into your inline sprite so the mockup stays a single file.

Badges, alerts & progress

default new done blocked

Info alert — something worth knowing.
✓ Success — it worked!
✗ Error — something went wrong here.

64% — striped marker fill

Table

FeatureStatusOwner
SearchdoneAlex
Dark modein progressTeam
CSV exportblocked—

Nav & tabs


Overview
Details
Settings
Tab panel content goes here.

Annotations

The pricing lives right here ↖ move this above the fold!


↑ hand-drawn divider  ·  ↓ wavy divider


Headings h4–h6

Heading four

Heading five
Heading six (muted)

Inline text semantics

strong · b · em · i · u (wavy) · s · del · ins · mark · small

H2O (sub) · E=mc2 (sup) · HTML abbr · dfn term · q quotation · cite — a work title

Published · value: forty-two · 漢字kanji (ruby/rt) · bdo reversed

address: 123 Main Street, Springfield

Code family

Inline code, program output samp: 404 Not Found, variable x, and keys: Ctrl + Shift + P

// pre + code block
function sketch(el) {
  return el.rotate(-0.4);
}

Lists

ul (nested)

  • Hand-drawn bullet
  • Another item
    • Nested level
    • Also nested
  • Back to level one

ol

  1. First step
  2. Second step
  3. Third step

menu

  • dl

    Wireframe
    A low-fidelity sketch of a screen.
    Mockup
    A more detailed static design.

    Quotes & figures

    Good design is as little design as possible.
    — Dieter Rams
    figure + figcaption: hero image goes here

    ↑ bare <hr> is styled automatically

    All input types

    fieldset + legend
    60 ← output
     

    details, summary & dialog

    Click to expand (details/summary)

    Collapsible content with a hand-drawn disclosure marker.

    This one starts open

    Because it has the open attribute.

    dialog element

    Shown inline here with open. Use showModal() for the real thing — ::backdrop is styled too.

    Embedded content

    img (SVG data URI)

    placeholder

    iframe (srcdoc)

    canvas / video / audio

    Full table anatomy

    caption: Q3 feature status
    FeatureEffortStatus
    Search3done
    Dark mode5wip
    Total8—

    caption, colgroup/col, thead, tbody with row headers, tfoot (double rule)

    Coverage notes

    Intentionally unstyled: non-rendering elements (head, meta, script, template, slot, datalist popup, track/source, map/area), pure wrappers (div, span, main, section, article, aside, header, footer, picture), and line-break controls (br, wbr). Obsolete elements (marquee, center, …) are out of scope.

    Putting it together — mini mockup

    This week 3 open

    burndown chart

    Activity

    Recent activity feed goes here…

    Note: overdue items get pulled to the top automatically

    Icon selector — all 1745

    The complete Lucide set (v1.23.0) redrawn in scribble style. Click an icon to copy its <use> snippet, shift-click to copy the full <symbol> for inlining. Also available as a standalone page or the raw sprite lofi-icons.svg.

    1745 shown