| name | habitio-marketing |
| description | Generate marketing screenshots, GIF, and video for habit.io and create/update the making-first-habit landing page. Use this skill whenever the user says "retake screenshots", "update screenshots", "generate marketing materials", "update landing page", "making-first-habit page", "social media assets", "app preview", or whenever a new feature was shipped and screenshots need refreshing. Also trigger when the user says a version was bumped and asks "what needs updating" — screenshots are always part of the answer. |
habitio-marketing
Generate all marketing assets for habit.io: Playwright screenshots, device-framed PNGs, animated GIF, MP4/WebM video, and the making-first-habit/ landing page.
Prerequisites
Before starting, verify:
- Local server running at
http://localhost:5000 (run npx serve . -p 5000 in the repo root)
ffmpeg in PATH (for video + GIF)
playwright installed (yarn install && npx playwright install chromium)
If the server isn't running, tell the user: "Start the local server first: npx serve . -p 5000"
Phase 1 — Feature Audit
The screenshot script (scripts/take-screenshots.js) can drift behind the app as features ship. Before running it, check if it's current.
Check git log for UI-touching commits since the screenshots were last taken:
git log --oneline --since="$(git log --format="%as" -- docs/screenshot-tracker.png | head -1)" -- app.js styles.css i18n.js index.html
Also check the known features list in AGENTS.md (Architecture section) and compare against the FRAMES array and screenshot steps in scripts/take-screenshots.js.
Features that must have screenshot coverage (add to script if missing):
- Onboarding modal
- Tracker (today's habits, phase emojis 🌱🔨⚡✨, morning group)
- Add-habit modal (suggestion list + custom input)
- Journal: first step (grateful) —
screenshot-journal.png
- Journal: summary/complete state —
screenshot-journal-summary.png
- Journal: mood slider (if visible mid-flow) — part of journal flow
- Stats page (full page — streaks, heatmap, mood trend, 30-day bars)
- Settings: base settings —
screenshot-settings.png
- Settings: reminders toggle on/off (if reminders feature exists in app)
- AI Coach panel (if visible in stats or journal view)
If screenshot-journal-summary.png is listed in generate-gif.js FRAMES but not generated by take-screenshots.js, that's a gap — add it.
How to identify features in the app:
grep -n "nav-tab\|data-view\|renderView\|activeTab" app.js | head -30
grep -n "renderReminder\|renderCoach\|renderMood\|renderDiary\|renderStats" app.js
Phase 2 — Update take-screenshots.js (if gaps found)
When adding a new screenshot step, match the existing pattern exactly:
console.log(" screenshot-feature-name.png");
await loadWithState(mobile, );
await mobile.waitForTimeout(600);
await mobile.screenshot({ path: path.join(DOCS_DIR, "screenshot-feature-name.png") });
Key rules for new steps:
- Use
SEED_STATE as the base unless the feature needs specific state (e.g., reminders need aiCoach fields, reminder prefs)
- Always
waitForTimeout(400–800) after navigation — the app renders synchronously but animations need settling
fullPage: true only for scrollable pages (stats, settings)
- Add the new filename to
FRAMES array in generate-gif.js if it belongs in the user journey
For the journal-summary step (completing all 4 diary fields), the state should have no diary entry for today so the journal flow renders — then programmatically click through all steps:
await mobile.locator(".nav-tab").nth(1).click();
await mobile.waitForTimeout(400);
await mobile.locator('[data-action="journal-next"], .journal-next, button:has-text("Next")').click();
await mobile.waitForTimeout(600);
await mobile.screenshot({ path: path.join(DOCS_DIR, "screenshot-journal-summary.png") });
After editing the script, run a quick sanity check:
node -e "require('./scripts/take-screenshots.js')" 2>&1 | head -5
Phase 3 — Capture Screenshots
node scripts/take-screenshots.js
Expect output listing each file as it's generated. If any step fails, read the error — common causes:
- Selector not found (app changed, update the selector in the script)
- Server not responding (restart
npx serve . -p 5000)
waitForSelector timeout (increase timeout or add a waitForTimeout before it)
Phase 4 — Device Frame (Rounded Corners + Shadow)
Run the bundled framing script:
node .claude/skills/habitio-marketing/scripts/frame-screenshots.js
This wraps each mobile screenshot in a device frame (border-radius + drop shadow) and saves to docs/marketing/framed/. Framed outputs are used in the landing page and social media materials.
Phase 5 — GIF + Video
node scripts/generate-gif.js
bash .claude/skills/habitio-marketing/scripts/generate-video.sh
Videos go to docs/marketing/. GIF stays in docs/ (used by README).
Phase 6 — Landing Page
Create or update making-first-habit/index.html.
Read the content spec: .claude/skills/habitio-marketing/references/landing-page-spec.md
Page location: making-first-habit/index.html → served at habitio.rafal-sladek.com/making-first-habit/
Visual assets to embed (use relative paths ../docs/...):
- Hero:
../docs/marketing/user-journey.mp4 (autoplay muted loop) with ../docs/user-journey.gif as fallback
- Feature screenshots: framed versions from
../docs/marketing/framed/
Design constraints (match the main app):
- Dark theme:
#12121f background, #c0c0e8 primary text, #7878a0 muted text
- Accent:
#7c6fff (purple)
- Font: same Google Fonts call as
index.html (Inter)
- Mobile-first, max-width 640px content column, centered
Structural requirements:
- No build step — pure HTML/CSS/JS, no imports, no bundler
- Must work with GitHub Pages (no server-side rendering)
- Include
<link rel="canonical"> pointing to https://habitio.rafal-sladek.com/making-first-habit/
- Add to
sitemap.xml if not already present
Content sections — see references/landing-page-spec.md for full copy, science citations, and section structure.
Phase 7 — Verify and Checklist
After all assets are generated:
Visual check (open in browser):
open http://localhost:5000/making-first-habit/
open docs/marketing/framed/screenshot-tracker.png
Notes on the Data Model for Screenshots
SEED_STATE in take-screenshots.js uses profile.name = "Alex" — keep this relatable
- All dates use UTC (
utcDaysAgo(n)) — never use new Date().toLocaleDateString()
- Phase emojis depend on check count: 🌱 <10, 🔨 10-35, ⚡ 35-66, ✨ 66+
- The
morning: true habit always renders at the top — keep "Morning Workout" as first habit
mood field in diary is "1"–"5" string (not integer)
- Reminder state lives in
state.reminderEnabled / state.reminderTime (check exact field names in app.js)
When to Re-run (Partial vs Full)
| Changed | Run |
|---|
| Only one screen changed | Re-run take-screenshots.js → frame-screenshots.js → generate-gif.js + video |
| New feature added | Full Phase 1–7 |
| Landing page copy only | Phase 6 only |
| GIF looks wrong | Just generate-gif.js |