pages/drafts/, folder rules for ClaudeYou are inside the Studio (the playground for marketing drafts).
The rules here are deliberately looser than production. Read this
file alongside the repo-root website/CLAUDE.md.
The system explicitly wants drafts to invent. Production pages stay coherent; drafts are the R&D lab. Lean into creative remixing here.
Before scaffolding a new draft:
Read the existing production pages for inspiration:
src/pages/home-v1.astro (PlanetHero, FeatureBlock with
alternating image+text, ComparisonTable, FinalCta with phone
mockup, the Gnosis Card 3D section with floating coins + esteira
belt, TrustStrip)src/pages/index.astro (the campaign page with FeatureCard
grid, AccordionItem deep-dives, TierLadder)src/pages/leaderboard.astro (tier-coloured row washes)Identify which patterns fit the briefing and which don’t. Then:
Inventing is encouraged, not tolerated. A draft that uses 4 off-the-shelf components in a sensible way is fine; a draft that invents a fresh visual treatment which feels brand-aligned is better. That’s how the design system grows. Surface the new pattern at the end so the designer can decide whether to harvest it into a shared component.
Atoms locked, compositions free. The mental model: brand atoms (fonts, palette, type scale, button geometry, gradient recipes) are the basic ingredients. Use them — always. Drafts never invent a new ingredient. Compositions (layouts, motion, interactions, scroll effects, novel visual treatments, never- built-before interactive graphics) are the recipes. Cook anything you want, as long as you only use brand ingredients.
line-height: var(--display-line-height) (1.33) — apply the
.display utility class to lock all four spec values at once.
Don’t introduce a new typeface even if a competitor’s pattern
feels like it wants one.var(--purple-N) —
never hardcode hex.weight=duotone by
default). Never introduce a different icon library, never
hand-draw a one-off when Phosphor has the glyph. Full standard
in _brand/visual-identity/iconography/iconography.md._brand/visual-identity/colors/gradients.json
(V1-V4, fresh-dawn, sunset, the smooth purple ladder). Use
var(--purple-N) tokens for stops or color-mix(in srgb, var(--token) X%, transparent) for translucent washes — never
rgba(63, 42, 205, 0.08)-style hardcoded values.
The split: WHAT the page contains has wide creative latitude
(compose freely). HOW it expresses itself at the atomic level
(typography, colour, spacing primitives) does not.
The test: does the result still feel like world-class
Gnosis design? Would the existing pages and this new draft
sit comfortably side-by-side? If the answer requires you to
ship a new colour or font to make it work, the answer is no.
Re-translate the idea through the existing palette.npm run check:brand-usage will catch hardcoded brand-palette
hex, Boldonse rules without locked line-height, and gradients
that bypass tokens — anywhere in the codebase, drafts included.
The harvest loop applies to tokens too. A one-off value in
a draft that proves useful across multiple campaigns gets
harvested into tokens.css as new canonical token. That’s how
the palette grows: bottom-up from real campaign needs, not
top-down speculation. Surface harvest candidates explicitly.
Aim for world-class. The bar isn’t “on-brand and acceptable.” It’s the calibre of Linear, Stripe, Apple, Vercel, Phantom, Arc. Drafts in Studio should aspire to that standard. World-class design routinely breaks rules to make a point. The rules just come back stronger after the experiment. Default to permissive in drafts; default to strict in production.
The system invariants are NOT permissive. A.4’s wide latitude covers colours, effects, layouts, custom spacing. It does NOT cover the things that make the brand recognizable across pages:
.display)| Topic | Production rule (default) | Studio rule (this folder) |
|---|---|---|
| Layout wrapper | CampaignLayout / BaseLayout directly | DraftPage preferred (auto-draft={true} + metadata banner) |
| New components | Forbidden, surface to designer | Permitted inline within the draft file |
| Hardcoded URLs | Banned, use @lib/links | Tolerated, but still prefer registry when convenient |
| Hardcoded hex / px | Banned, use tokens | Tolerated for one-off campaign visuals; prefer tokens |
npm run check | Must pass | Must pass (drafts are still linted; the lints just exclude some drift checks for drafts (see scripts)) |
| Indexable by Google | Yes | No, noindex enforced by <DraftPage> |
| Linked from Nav / Footer / sitemap | Yes | No, drafts live at /drafts/<slug> only |
Copy _starter-template.astro as your scaffold.
cp src/pages/drafts/_starter-template.astro src/pages/drafts/<slug>.astro
The starter is the canonical pattern. Edit the copy + structure from there.
Use <DraftPage> as the layout wrapper with metadata:
<DraftPage
title="Campaign name"
briefingUrl="https://notion.so/..."
owner="Maya"
status="sketch"
>
{/* page content */}
</DraftPage>
Pull copy from src/copy/drafts/<lang>/<slug>.md if structured
YAML makes sense. For very short drafts, inline copy in the
.astro file is fine.
Use existing canonical components when they fit:
<PlanetHero>, <FeatureBlock>, <FeatureCard>,
<AccordionItem>, <TierLadder>, <Button>, <Disclaimer>,
<SocialProof>, etc. List in _docs/COMPONENTS.md.
Invent inline if no canonical component fits. Custom CSS
inside the .astro file is fine. Do NOT add new files to
src/components/ from a draft session. That’s a designer
decision (see “Component promotion” below).
Add files to src/components/. New shared components are a
designer-gated decision. If a pattern looks reusable, surface
it: “This split-testimonial layout could be a shared component
if it’ll be reused. Want me to keep it inline in this draft, or
flag it for the designer to formalize?” Wait for the answer.
Edit the link registry without explicit ask. If a campaign
needs a new URL, add it to src/lib/links.ts only if the user
confirms it’s a stable URL the project owns. Otherwise, hardcode
in the draft and surface: “This URL is hardcoded for now. Should
I add it to the registry so future pages can reuse it?”
Promote to production unilaterally. Even if the user says
“this is great, ship it”. Confirm explicitly:
“To promote <slug> to production I’ll move it from
pages/drafts/ to pages/, drop the draft flag, and move the
copy file. The promotion PR will need designer review. Proceed?”
Then follow _docs/DRAFT-WORKFLOW.md.
Add tracking, analytics, or third-party scripts. Drafts run
inside the same noindex shell. No GA, no pixels, no chat
widgets. If a draft needs analytics, that’s a discussion with
the designer + the privacy/consent system, not a unilateral add.
When a draft needs new assets, follow these conventions. Don’t invent new directories; use the existing structure.
| Type | Location | Why |
|---|---|---|
| Illustrations (PNG, SVG) | src/assets/illustrations/ | Astro will optimise (resize, WebP/AVIF, srcset) at build time |
| Photos | src/assets/photos/ | Same, Astro optimises |
| Icons | src/assets/icons/ | Same, Astro optimises |
| Logos / brand marks | src/assets/ (top-level) | Same |
| Static assets that don’t need processing | public/ | Served as-is, no Astro optimisation. Use for OG images that need exact dimensions, video files, robots.txt, etc. |
Always import images via @assets/<path> and pass them to
Astro’s <Image> or to a component prop, not hardcoded <img src>.
That’s how you get automatic optimisation.
q3-earning-season.png, not Q3 Earning Season.PNGcard-illustration-earn.png, not image1.pngtier-casual.png,
tier-power.png, tier-top.pngnpm run check
asset-size warning fires above 2 MB. Astro will still optimise
bigger files, but it slows the build._docs/MEDIA.md) for transparent video against dark
backgrounds.src/copy/drafts/<lang>/<slug>.md with YAML frontmatter. The page
imports the frontmatter and renders fields..astro
file. No need to YAML-ify a 5-word headline.<style> block in the
.astro file (Astro auto-scopes it).tokens.css
(--space-*, colours, radii, motion) before reaching for raw px.global.css from a draft
session. Surface for designer review (see “Component promotion”
below).dist/
(gitignored), never src/.When marketing asks you to “add this image”, confirm the source
file exists locally, drop it into the right src/assets/ folder
with a sensible slug-cased name, import it in the draft, and tell
the user where you put it (so they know for next time).
When the same pattern appears in two or more drafts, it’s a candidate for promotion to a shared component. The signal usually looks like: marketing asks “make me one of those split-testimonial things again” and you find yourself copy-pasting from another draft.
When that happens:
src/components/<Name>.astro._docs/COMPONENTS.md, replace inline copies
in both drafts.This is how the design system grows organically. New patterns are born in drafts, harvested by the designer when reuse proves their value.
The promotion process lives in _docs/DRAFT-WORKFLOW.md. Quick
summary:
pages/drafts/<slug>.astro → pages/<slug>.astro.<DraftPage> with the appropriate production layout
(<CampaignLayout> or <BaseLayout>), drop draft props.copy/drafts/<lang>/<slug>.md → copy/<lang>/<slug>.md.npm run check. Production-strict lints now apply.Run npm run check (drafts pass loosened lints, but copy / brand
checks still apply).
Summarize what you built in plain language so the user can share with their team.
ALWAYS finish your final reply with a “Where to see it” block. Non-technical users don’t automatically know about localhost, dev servers, or preview URLs. Include this every time you create or modify a draft, even if you’ve explained before in this session. Format:
Where to see it:
• Locally (right now): http://localhost:4321/drafts/<slug>
If that page doesn't load, open a terminal in this folder
and run `npm run dev`, then refresh.
• Shareable preview (after you push):
1. Say "open a PR" and I'll create one.
2. Wait ~60 seconds for Vercel to finish building.
3. The preview URL will appear as a comment on the PR.
Click through to share with the team.
Localhost = fastest path to seeing it. PR-preview = shareable path. Both in that order. Adapt the slug for the actual draft.