back to portfolio

jawnpaper

A drop-in CSS design system that makes any web page look like marker on cream paper. Tokens, components, and utilities for the hand-drawn aesthetic — with one wobbly SVG filter doing the heavy lifting.

sibling kit swisskit is the same drop-in idea in the Swiss, or International Typographic, style — ink on a grid. Namespaced sk-, so it and jawnpaper (np-) run on the same page.
install Add two lines to your <head> and one class to <body>:
<link rel="stylesheet" href="jawnpaper.css">
<script src="jawnpaper.js" defer></script>
<body class="notebook">

No npm, no build step. Or grab it from the CDN / npm i jawnpaper. See it in the wild →

try it on

Drag, click, and pick. Live changes apply to the whole page. Copy the :root block when you find a theme you like.

contrast — paper vs ink

themes

Nine ready-made themes. Click to apply. Sticks to ?theme=… in the URL so you can share a vibe.

why "jawn"paper?

"Jawn" is Philly slang — a stand-in for any noun: a thing, a place, a person. It's the most flexible word in American English. That's the bet here too: one wobbly filter, a dozen color tokens, and a small kit of components that can be any thing.

This started as the border-shape playground — one CSS rule that wobbles an SVG border. Then it became "what if a whole page was that?" The lack of design is the design. The hand-lettered fonts, the marker-on-cream feel, the slightly tilted notes — it should look like someone sketched it during a meeting.

tokens type cards notes buttons tabs accordion modal alerts tags + stamps badges + kbd annotations code tables breadcrumbs + pagination forms progress bubbles checklist timeline layout flourishes web components install / cdn / npm

tokens

Everything is wired through CSS custom properties on :root. Override any of them in your own stylesheet to retheme.

palette

--np-yellow
#ffe87a
--np-red
#e85a4f
--np-blue
#5b9bd5
--np-green
#6ec275
--np-purple
#a780e8
--np-orange
#ff924f
--np-pink
#f48fb1
--np-teal
#4ec9b0

paper + ink

--np-paper
#fdfaf2
--np-paper-deep
#f6efd8
--np-paper-deeper
#ede4c5
--np-ink
#1a1a1a

typography

Three font families, all hand-lettered. Headings use Caveat, body uses Patrick Hand, the stamp class uses Patrick Hand SC for that all-caps marker feel.

heading 1 / Caveat

heading 2 / Caveat

heading 3 / Caveat

heading 4 / Caveat

A lede paragraph uses .np-lede for a slightly oversized intro line that signals "start reading here."

Body copy is Patrick Hand. Inline code sits on a yellow highlighter swatch. Underlined phrases use a CSS gradient. Colored text via utilities.

cards

The basic container. Wobbly ink border drawn by a ::before pseudo-element so it doesn't affect the contents.

plain card

Use .np-card on any block element.

<div class="np-card">
  ...
</div>

deep paper

Same card with a deeper paper background via .np-bg-deep.

highlighter card

Yellow background reads as a sticky note.

Wrap a grid in .np-tilt-children to give every Nth card a subtle pinned-note rotation. Tilts are auto-disabled below 720px and for prefers-reduced-motion.

notes / callouts

Highlighted callouts for asides, warnings, and tips. The default is yellow; modifier classes change the wash color.

Default note. Yellow highlighter wash. Good for "heads up" or "note to self."
Red note. Use for warnings or destructive actions.
Blue note. Use for general info or links to docs.
Green note. Use for confirmations or success messages.
Purple note. Use for trivia or "fun fact" asides.
Paper note. Subtle deep-paper background for low-emphasis callouts.

buttons + toolbars

Use <a class="np-button"> for links and <button class="np-button"> for actions. 44px minimum tap height built in.

Use .np-toolbar on a wrapping element for an evenly-spaced flex group:

tabs

Paper folder tabs that switch panels. Native ARIA — keyboard arrows work.

Tab one panel. Use role="tab", aria-controls, and a role="tabpanel" for each.

accordion

Native <details>/<summary> dressed up. Free a11y, no JS needed for open/close.

does jawnpaper have a build step?

No. Drop in three files (CSS, JS, optional SVG) and add class="notebook" to <body>. That's it.

can I use it without the wobble?

Sure. Set --np-wobble-scale: 0 in your own CSS and the borders go straight. Or use the slider in the playground above.

does it ship JavaScript?

The base jawnpaper.js only injects the SVG filter. The extended behaviors (theme switcher, playground, tabs, etc.) are all opt-in via class names or data attributes. Loading the script doesn't change anything until you opt in.

Native <dialog> styled as a sticky-note overlay. Add data-jp-open="dialog-id" to a button.

a sticky-note overlay

Backdrop dim, slight settle-in animation. Press esc or click the × to close.

alerts

Page-level callouts in four flavors. Use .np-alert with a modifier and an icon span.

Heads up. The wobble filter relies on SVG filter; modern browsers only.
Saved. Your theme tokens have been written to localStorage.
Slow path. The @import for Google Fonts is render-blocking — see the README for faster options.

tags + stamps

Tags are small inline labels: draft urgent info done fyi

Stamps are bigger, rotated, and meant to grab attention: experimental draft approved final

badges + kbd

Solid-fill badges for status pills: new urgent info live beta

Sketched keycaps for keyboard hints: press ctrl+k to focus search, or +/ to open the cheat sheet. Use .np-kbd.

annotations

Circle a phrase: like this. Or in a different color: blue oval, green oval, purple oval.

Underline a phrase with a marker swipe: default yellow, red, blue, green.

code

Inline code uses a yellow swatch automatically when inside .notebook, or with the .np-code class anywhere.

For multi-line code, wrap a <pre> in .np-codebox:

function wobble(element) {
  element.style.filter = 'url(#np-wobble)';
  return element;
}

const card = document.querySelector('.card');
wobble(card);

tables

componentclasswhat it does
card.np-cardBordered paper container.
note.np-noteHighlighter callout. Add --red / --blue / etc. for color.
button.np-buttonPill button with 44px min height. Add --primary or --danger.
tag.np-tagSmall inline label. Same color modifiers.
stamp.np-stampRotated red label. Eye-catching.
circled.np-circledWobbly oval annotation around a phrase.

Breadcrumbs (use a <nav>+<ol> with .np-breadcrumbs):

Pagination (use a <nav>+<ul> with .np-pagination):

forms

progress

A wobbly outline filled with marker scribbles. Set aria-valuenow for screen readers and the inline width on the fill.

draft progress
editing
final review

speech bubble + quote

a wobbly tail-down speech bubble. Use .np-bubble.
The most important step a man can take is the next one. Dalinar Kholin, Oathbringer

checklist

For things outside a form. Click an item to toggle it. Adds a marker strikethrough on done items.

timeline

Vertical anchored list. Use <ol class="np-timeline"> with .np-event children.

  1. may 2, 2026

    jawnpaper 0.2

    Tabs, accordion, modal, alert, breadcrumbs, pagination, progress, timeline, checklist, badge, kbd. Theme presets, live playground, four example pages, and a CDN/npm story.

  2. may 1, 2026 (later that night)

    jawnpaper 0.1

    Cards, notes, buttons, tags, stamps, circled, code, tables, forms, bubbles. The wobble filter, generalized into a system.

  3. may 1, 2026

    border-shape playground

    A single page experimenting with SVG-filtered borders. The seed that became this whole thing — about six hours before the system around it.

layout helpers

classwhat it does
.np-containerCentered max-width 960px container with fluid padding.
.np-gridAuto-fit responsive grid. Each cell is at least 310px or 100% of the parent.
.np-stackVertical stack with consistent spacing between children.
.np-stack--lg / --smBigger or smaller stack gap.
.np-tilt-childrenAuto-rotate every 3rd child a fraction of a degree (pinned-note effect).
.np-wobble-borderApply a wobbly ink border to any element.
.np-tilt-left / --right / -2 / -3One-off tilt utilities.

flourishes

Opt-in extras. Click a button to flip the flourish on for this page, or scrub through the inline samples below.

reveal on scroll

Add .np-reveal to any element. The script fades it in via IntersectionObserver. Disabled for prefers-reduced-motion.

first thought
second thought
third thought
<div class="np-card np-reveal">…</div>

breathing wobble

Re-randomizes the SVG turbulence seed every ~5s so the page never freezes into a static image. Click below, then watch any wobbly border for a beat.

<body class="notebook" data-jp-breathe>

pen cursor

An SVG ink trail follows the pointer. Click to switch on, then move around the page. Disabled for reduced-motion users.

<body class="notebook np-pen-cursor">

doodle margins

Random hand-drawn marks scattered around the page edges. Hidden on small screens. The shapes the script picks from:

<body class="notebook notebook--doodled">

paper grain

A subtle SVG noise layer for paper-fiber texture. Sample at twice the page intensity:

<body class="notebook notebook--grainy">

torn divider

An alternative to the squiggle for a rougher break:


<hr class="np-divider--torn">

in the wild

Four full pages built entirely from jawnpaper components. They're fictional — but they show what real sites would look like.

a recipe

Hot honey carbonara. Tickable ingredients, numbered steps, "tested" stamp.

a newsletter

The Bloomfield Beat issue four. Articles, callouts, reader letters.

a résumé

Ada Velour, freelance worry consultant. Tag-cloud skills, certification stamps.

an invoice

Phantom Bookbinder LLC bills the Marlow Estate. Line items, "overdue" stamp.

customizing

All visual choices are tokens on :root. To retheme, override the variables in your own stylesheet after loading jawnpaper.css:

:root {
  --np-paper: #f0e6d2;       /* swap the cream for parchment */
  --np-ink: #2c1810;         /* sepia ink */
  --np-yellow: #d4af37;      /* gold highlighter */
  --np-red: #8b0000;         /* deep crimson */
  --np-font-display: 'Kalam', cursive;
}

Or scope the override under a class for per-page themes:

.midnight {
  --np-paper: #1c1c2e;
  --np-paper-deep: #2a2a40;
  --np-ink: #f0f0f5;
  --np-yellow: #ffd166;
}

web components

Optional. Drop in jawnpaper-elements.js and write tags instead of class strings. Same look, framework-friendly.

<script src="jawnpaper-elements.js" defer></script>

<jp-card variant="yellow">
  <h3>a card</h3>
  <p>same as <code>.np-card.np-bg-yellow</code>.</p>
</jp-card>

<jp-note variant="red">a red note</jp-note>
<jp-button variant="primary">primary</jp-button>
<jp-stamp variant="green">approved</jp-stamp>

The variant attribute is observed — change it at runtime and the right modifier classes get swapped on the host element. No Shadow DOM, so jawnpaper's CSS still styles content directly.

install / cdn / npm

Three ways to grab jawnpaper, in order of laziness:

cdn

Paste two lines into your <head>. No download, no build step.

<link rel="stylesheet"
  href="https://cdn.jsdelivr.net/gh/jamditis/stash/docs/jawnpaper/jawnpaper.css">
<script defer
  src="https://cdn.jsdelivr.net/gh/jamditis/stash/docs/jawnpaper/jawnpaper.js"></script>

Pin to a commit for production by inserting @<sha> after the repo segment (e.g. stash@abc1234/docs/...). See CDN.md.

npm

For projects with a bundler (Vite, webpack, esbuild, …):

npm install jawnpaper
// in your entry file
import 'jawnpaper/jawnpaper.css';
import 'jawnpaper/jawnpaper.js';

copy + paste

Drop the three files into your project. The STARTER.html in this folder is a complete, working copy you can rename to index.html.

view STARTER.html

browser support

Modern browsers (Chrome / Edge / Safari / Firefox 2023+). The whole system depends on filter: url(#…) and color-mix(), both of which are universally baseline now. prefers-reduced-motion disables card tilts and smooth-scroll. Print stylesheet drops the wobble for clean printouts.

examples · CDN · starter · source · born from the border-shape playground