| name | editorial-app-craft |
| description | Build a considered, cozy, editorial single-file web app (Firebase backend optional).
Use when the user asks for a personal/family/couple/journaling/cozy app: "build a family board",
"shared list app for me and my partner", "create a household app", "single-file Firebase app",
"warm cream sage design", "Playfair editorial UI", "apply Field Notes aesthetic", "cozy productivity",
"small considered web app". NOT for marketing landing pages, dashboards, or generic SaaS.
Bundles a tuned design token system (sage + cream + terracotta + honey), Playfair Display + Source Sans 3
typography, multi-layer paper shadows, Apple-style easing, and a set of considered detail patterns:
daily rotating ornament + palette + quote, time-of-day greeting, editorial cards with byline metadata,
Field Notes detail modal with italic serif numerals, day-varying empty states, toast personality variants,
page-load orchestration, streak milestone ornaments, iOS-aware voice input, mobile touch targets.
|
| version | 1.0.0 |
| category | build |
| platforms | ["CLAUDE_CODE"] |
editorial-app-craft
You build a single-file HTML web app with a cozy editorial aesthetic — sage + cream + terracotta,
Playfair Display + Source Sans 3, with a curated set of "considered detail" patterns layered in.
Optional Firebase backend (Auth + Firestore + Hosting + custom domain).
This is for personal / family / cozy / journaling / shared-with-loved-ones apps. It is NOT
for marketing pages, dashboards, or generic SaaS. The aesthetic is "Field Notes meets a quiet
weekend morning at home."
============================================================
=== PRE-FLIGHT ===
Before starting, verify:
If any check fails:
- Aesthetic mismatch (marketing landing page, dashboard, etc.) → say so and decline. This skill
has strong opinions; using it on the wrong target produces strange output.
- Firebase CLI not installed →
brew install firebase-cli or skip the deploy phase entirely
and produce a static single-file app instead.
- DNS unclear → produce the app and stop before custom-domain wiring; tell user to come back
once they know.
============================================================
=== PHASE 1: UNDERSTAND THE APP ===
Ask (in ONE message, then proceed):
- What is the app for, in one sentence?
- Who's it for? (just you, you + partner, family of N, etc.)
- What are the 2–4 main "things" the app needs to hold? (tasks, lists, notes, photos, journal entries...)
- Does it need to sync across devices / multiple users? (yes → Firebase; no → localStorage only)
If the user already gave enough signal in their prompt, skip the questions and proceed.
VALIDATION: You can describe the app in one paragraph and name its core data model.
FALLBACK: If still unclear, propose a small default and let the user redirect.
============================================================
=== PHASE 2: SCAFFOLD ===
Create the project at ~/git/<app-name>/:
~/git/<app-name>/
├── index.html # single-file app
├── icon.svg # favicon SVG (small fleuron in brand gradient)
├── apple-touch-icon.png # 180×180 PNG (render via Playwright screenshot of icon.svg)
├── firebase.json # if Firebase
├── firestore.rules # if Firestore
└── .firebaserc # if Firebase
The index.html skeleton has these sections in this order:
<head> with theme-color meta, favicon link, apple-touch-icon link, Google Fonts (Playfair
Display + Source Sans 3), inline <style>.
- The full design tokens block from
assets/design-tokens.css.
- The component patterns block from
assets/patterns.css.
<body> with: welcome-modal, family-setup-modal (if multi-user), app shell, content modals.
<script type="module"> with Firebase imports (if needed), state, render, the detail-patterns
functions from assets/detail-patterns.js.
VALIDATION: index.html opens directly in a browser without a server and renders the empty welcome
modal with daily ornament + time-of-day greeting.
FALLBACK: If something blocks rendering, fix it before adding features.
============================================================
=== PHASE 3: APPLY DETAIL PATTERNS ===
Layer these in. Each is described in assets/detail-patterns.js:
| Pattern | Where it goes |
|---|
| Daily rotating ornament | Brand mark (top-left) + welcome-modal mark. Call applyDailyOrnament() on boot + setInterval(60_000). |
| Time-of-day greeting | Italic Playfair line above the welcome-modal headline. |
| Daily quote | Below the sign-in button or somewhere persistent the user sees on each visit (footer ribbon, settings panel). |
| Editorial cards | Title in Playfair italic, metadata as inline byline with · separators, no pill backgrounds. Sage rail on hover, terracotta rail on "meaningful". |
| Field Notes detail modal | Italic serif numerals 01/02/03 for sub-items, hairline dividers, memo-line input. |
| Day-varying empty states | Pull a line from EMPTY_STATES[zoneKey] by dayIndex(). |
| Toast personality variants | Use celebrationLine({...}) instead of generic "+1 pt for X". |
| Page-load orchestration | Add .first-paint class to the board on first render, strip after 900ms. |
| Streak milestones | If the app has any streak/count, use streakOrnament(n) and isStreakMilestone(n). |
| iOS-aware voice | Use setupVoiceInput({...}) — auto-hides the mic on iOS WebKit. |
| Mobile touch targets | Wrap icon-button styles in @media (hover: none) { min-width: 40px; min-height: 40px; }. |
For each pattern: write it, then verify it renders + works.
VALIDATION: Open the running app at 1400px AND 390px. Check that the editorial details actually
show. Touch targets must be ≥40px on mobile.
FALLBACK: If a pattern doesn't fit the app's data model (e.g., no "meaningful" concept), skip
it rather than forcing it.
============================================================
=== PHASE 4: FIREBASE WIRING (optional) ===
If the user wants sync, follow assets/firebase-deploy.md:
firebase projects:create + register a Web app + grab SDK config
- Enable Firestore + Identity Toolkit APIs (refresh CLI token if needed)
- Create Firestore database
- User enables Google sign-in via Console (one click — unavoidable)
- Write
firebase.json, firestore.rules, .firebaserc
firebase deploy --only hosting,firestore:rules
VALIDATION: Live URL works, sign-in flow completes, a test write to Firestore succeeds.
FALLBACK: If any step blocks, write a static localStorage-only version first and ship that.
Firebase can be added later without disturbing the UI.
============================================================
=== PHASE 5: CUSTOM DOMAIN (optional) ===
Only proceed if user confirmed DNS provider in pre-flight.
- Call
customDomains API to register the subdomain
- Read
requiredDnsUpdates.desired — extract CNAME + TXT records
- If user authorized AWS access: write Route 53 records via
aws route53 CLI
- Otherwise: print the exact records and instruct user to paste at their registrar
- Poll cert status until
HOST_ACTIVE + CERT_ACTIVE
- Add the new hostname to Auth's
authorizedDomains list
VALIDATION: https://<custom.domain> loads with a green padlock.
FALLBACK: If cert provisioning takes >40 min, hand off to the user with a watch command and
the current status; don't block.
============================================================
=== SELF-REVIEW ===
Score the output (1–5):
- Complete: All requested core features built and live?
- Detail-rich: Did you layer in at least 6 of the 11 detail patterns from Phase 3?
- Brand-faithful: Sage + cream + terracotta palette intact? Playfair + Source Sans? Multi-layer
shadows? No purple gradients / emoji icons / pill-cluster cards?
- Mobile-honest: Verified at 360px or 390px? Touch targets ≥40px? Mic hidden on iOS?
- Cozy, not clinical: Empty states warm, copy human, italic Playfair used where it earns?
If any score < 4:
- Identify the specific gap and fix it.
- If unfixable in this run, note it explicitly as a known limitation in the final message.
============================================================
=== LEARNINGS CAPTURE ===
After completing, append one entry to ~/.claude/skills/editorial-app-craft/LEARNINGS.md:
## <YYYY-MM-DD> — <app name + key decisions>
- **What worked:** <pattern that landed especially well, or a setup step that was smooth>
- **What was awkward:** <step that needed retries — Firebase auth provider, iOS Safari quirk, DNS, etc.>
- **Suggested patch:** <one concrete improvement — e.g., "default to Route 53 path detection",
"add explicit step for custom-domain authorizedDomains", "include a ">
[Smooth / Minor friction / Major friction]
Anti-patterns this skill refuses
- Purple gradients of any kind
- Pill clusters on cards (use editorial byline with dot separators instead)
- "B" letter on the brand mark (use the daily fleuron)
- Em-dashes in user-facing copy (commas / colons / sentence breaks instead)
- Emoji as decorative icons (only as content-bearing characters: ❤ for meaningful, 🔥/✦/🏆 for streak tiers)
- Cards with left-color-border + flat shadow (the 2020–2024 Material/Tailwind look)
- Inter/Roboto/system fonts as display (always Playfair Display for headings)
- "Add family members and kids" → say "Add family members". The app doesn't draw an adult/child line.