diff --git a/README.md b/README.md index aae2c76..f287b92 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **A design skill for Claude Code, Cursor, and Codex that refuses to look AI-generated.** -[Live demo →](https://hallmark-murex.vercel.app)  ·  twenty-three themes  ·  five verbs  ·  press `T` to cycle. +[Live demo →](https://hallmark-murex.vercel.app)  ·  twenty-three themes  ·  four verbs  ·  press `T` to cycle. Powered by Together AI. @@ -43,19 +43,18 @@ If Hallmark is wired correctly, you'll see Long Document · Linen (warm-paper ro | **Refuses pixel-clone** | yes — DNA only, never pixels | n/a | n/a | n/a (full token export) | | **Tactile-rebellion alignment** | warm-paper, custom-craft, slopless canon | strong | medium | none — token-only | | **Pages by archetype** | 21 named macrostructures, picked per brief | by brief | 5 deterministic directions | n/a | -| **Verbs** | 5 (default · `audit` · `refine` · `redesign` · `study`) | 1 | 31 | 1 (CLI) | +| **Verbs** | 4 (default · `audit` · `redesign` · `study`) | 1 | 31 | 1 (CLI) | Hallmark's edge is **`study`** — every other tool ships a preset menu or a scraper. Hallmark is the only one that takes a screenshot of a design you admire, names what it sees, refuses paid-template-marketplace listings, and rebuilds your content with the extracted DNA. Three worked study examples in [`docs/study-examples.md`](docs/study-examples.md). --- -## Five verbs +## Four verbs | Verb | What it does | | --- | --- | | *(default)* | Build new UI. Asks for audience + use + tone (skippable — the skill states what it inferred). Picks a macrostructure, applies the rule-set, runs the slop test before handing back. | | `hallmark audit ` | Score existing code against the named anti-patterns + structural sameness. Punch list, no edits. | -| `hallmark refine ` | Polish in place. Smallest possible diff. Preserves structure. | | `hallmark redesign [--mood ]` | Throw out the structure, keep copy + IA + brand, rebuild with a deliberately different fingerprint. | | **`hallmark study `** | The differentiator. Extract the **DNA** from a design the user admires — macrostructure, archetypes, type-pairing role, colour anchor — and produce a diagnosis report. Optionally rebuild *the user's* content using the extracted DNA. **Refuses paid templates and competitor pages. Names font roles, never font IDs. Never copies pixels.** | @@ -107,7 +106,7 @@ Each page is its own self-contained HTML + CSS — no shared theme, no shared la ## What's distinct (the long list) -- **One skill, five verbs.** Not eighteen commands. +- **One skill, four verbs.** Not eighteen commands. - **Genres broaden the range.** Hallmark routes a brief through one of four genres before picking a theme: **editorial** (default · the canonical anti-slop voice), **modern-minimal** (Stripe / Linear / ElevenLabs school), **atmospheric** (Suno / Runway / dark-AI-tool school), **playful** (post-Linear soft school). Each genre is its own rule overlay — atmospheric allows radial blooms; modern-minimal allows pure white and pill CTAs; editorial bans both. Detection is signal-based, silent default to editorial. - **Tone is a first-class decision.** "Clean and modern" is rejected. Pick an extreme — *editorial · brutalist · soft · technical · luxury · playful · austere*. - **Macrostructures over axes.** Pick one of 21 named whole-page shapes wholesale; the macrostructure stamp lives in the CSS comment, so the next Hallmark run picks something different. diff --git a/site/_tests/_thumbs/BananaStudio-example.mp4 b/site/_tests/_thumbs/BananaStudio-example.mp4 new file mode 100644 index 0000000..e827767 Binary files /dev/null and b/site/_tests/_thumbs/BananaStudio-example.mp4 differ diff --git a/site/_tests/_thumbs/BananaStudio-loop.mp4 b/site/_tests/_thumbs/BananaStudio-loop.mp4 new file mode 100644 index 0000000..821f243 Binary files /dev/null and b/site/_tests/_thumbs/BananaStudio-loop.mp4 differ diff --git a/site/_tests/_thumbs/Podcast-example.mp4 b/site/_tests/_thumbs/Podcast-example.mp4 new file mode 100644 index 0000000..67f6807 Binary files /dev/null and b/site/_tests/_thumbs/Podcast-example.mp4 differ diff --git a/site/_tests/_thumbs/Podcast-loop.mp4 b/site/_tests/_thumbs/Podcast-loop.mp4 new file mode 100644 index 0000000..833010e Binary files /dev/null and b/site/_tests/_thumbs/Podcast-loop.mp4 differ diff --git a/site/_tests/_thumbs/SaaS-example.mp4 b/site/_tests/_thumbs/SaaS-example.mp4 new file mode 100644 index 0000000..96b517f Binary files /dev/null and b/site/_tests/_thumbs/SaaS-example.mp4 differ diff --git a/site/_tests/_thumbs/SaaS-loop.mp4 b/site/_tests/_thumbs/SaaS-loop.mp4 new file mode 100644 index 0000000..a3ce234 Binary files /dev/null and b/site/_tests/_thumbs/SaaS-loop.mp4 differ diff --git a/site/_tests/_thumbs/study-example.png b/site/_tests/_thumbs/study-example.png new file mode 100644 index 0000000..fdf0bd5 Binary files /dev/null and b/site/_tests/_thumbs/study-example.png differ diff --git a/site/css/base.css b/site/css/base.css index 0b141dc..86df59c 100644 --- a/site/css/base.css +++ b/site/css/base.css @@ -1,63 +1,5 @@ /* Hallmark — base: fonts, reset, body */ -/* — The Future (Together AI's typeface) ——————————————— */ -@font-face { - font-family: "The Future"; - font-style: normal; - font-weight: 300; - font-display: swap; - src: url("../fonts/the-future-light.woff2") format("woff2"); -} -@font-face { - font-family: "The Future"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("../fonts/the-future-regular.woff2") format("woff2"); -} -@font-face { - font-family: "The Future"; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url("../fonts/the-future-medium.woff2") format("woff2"); -} -@font-face { - font-family: "The Future"; - font-style: normal; - font-weight: 700; - font-display: swap; - src: url("../fonts/the-future-bold.woff2") format("woff2"); -} -@font-face { - font-family: "The Future Mono"; - font-style: normal; - font-weight: 300; - font-display: swap; - src: url("../fonts/the-future-mono-light.woff2") format("woff2"); -} -@font-face { - font-family: "The Future Mono"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("../fonts/the-future-mono-regular.woff2") format("woff2"); -} -@font-face { - font-family: "The Future Mono"; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url("../fonts/the-future-mono-medium.woff2") format("woff2"); -} -@font-face { - font-family: "The Future Mono"; - font-style: normal; - font-weight: 700; - font-display: swap; - src: url("../fonts/the-future-mono-bold.woff2") format("woff2"); -} - /* — Google Fonts — all theme display & alt faces ——————————— */ @import url("https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Instrument+Serif:ital@0;1&family=Cormorant+Garamond:ital,wght@0,300..700;1,300..700&family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Newsreader:ital,opsz,wght@0,6..72,200..800;1,6..72,200..800&family=DM+Serif+Display:ital@0;1&family=Anton&family=Space+Grotesk:wght@300;400;500;600;700&family=Bricolage+Grotesque:opsz,wght@12..96,200..800&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..700&family=Hanken+Grotesk:ital,wght@0,100..900;1,100..900&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,600;1,400;1,500&family=IBM+Plex+Mono:ital,wght@0,300;0,400;0,500;0,600;1,400&family=JetBrains+Mono:ital,wght@0,400;0,500;0,700;1,400&display=swap"); diff --git a/site/css/components.css b/site/css/components.css index 38f7812..c8b2505 100644 --- a/site/css/components.css +++ b/site/css/components.css @@ -748,7 +748,6 @@ font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); - font-style: italic; max-width: 40ch; } @@ -899,7 +898,6 @@ .found-panel__rule { margin: 0; font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--color-ink-2); @@ -977,7 +975,6 @@ .type-spec__body { font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--color-ink-2); @@ -1529,7 +1526,6 @@ .vs__panel--personal[data-variant="hallmark"] .vs__panel-bio { margin: var(--space-md) 0 0; font-family: var(--font-serif); - font-style: italic; font-size: 1rem; line-height: var(--lh-relaxed); color: var(--color-ink-2); @@ -1779,7 +1775,6 @@ .install-pane__next { margin: 0; font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--color-ink-2); @@ -2030,54 +2025,14 @@ body:not(.easter-open) > footer { .easter__cursor { animation: none; opacity: 1; } } -/* — Reveals ————————————————————————————————————————— */ -.reveal { - opacity: 0; - transform: translateY(10px); -} - +/* — Reveals (disabled) —————————————————————————————————— + Scroll-in animation removed by product decision — landing reads + cleaner without staggered fades. Class kept so JS + markup stay + stable; element renders in its final state with no transform/fade. */ +.reveal, .reveal.is-in { - animation: reveal var(--dur-long) var(--ease-out) forwards; - animation-delay: calc(var(--i, 0) * 60ms); -} - -@keyframes reveal { to { opacity: 1; transform: none; } } - -/* Theme-specific reveal patterns */ -[data-theme="brutal"] .reveal, -[data-theme="manifesto"] .reveal, -[data-theme="sport"] .reveal { - transform: translateX(-16px); -} - -@keyframes reveal-sweep { to { opacity: 1; transform: none; } } - -[data-theme="brutal"] .reveal.is-in, -[data-theme="manifesto"] .reveal.is-in, -[data-theme="sport"] .reveal.is-in { - animation: reveal-sweep var(--dur-long) var(--ease-out) forwards; - animation-delay: calc(var(--i, 0) * 60ms); -} - -[data-theme="atelier"] .reveal, -[data-theme="salon"] .reveal, -[data-theme="newsprint"] .reveal { - transform: none; /* no spatial reveal — fade only */ -} - -[data-theme="atelier"] .reveal.is-in, -[data-theme="salon"] .reveal.is-in, -[data-theme="newsprint"] .reveal.is-in { - animation: reveal-fade calc(var(--dur-long) * 1.4) var(--ease-out) forwards; - animation-delay: calc(var(--i, 0) * 80ms); -} - -@keyframes reveal-fade { to { opacity: 1; } } - -[data-theme="terminal"] .reveal, -[data-theme="terminal"] .reveal.is-in { - transform: none; opacity: 1; + transform: none; animation: none; } @@ -2144,7 +2099,6 @@ body:not(.easter-open) > footer { } [data-theme="studio"] .hero__photo-caption { - font-style: italic; letter-spacing: 0; text-transform: none; font-feature-settings: "ss01"; @@ -2315,7 +2269,6 @@ body:not(.easter-open) > footer { [data-theme="riso"] .tell__why, [data-theme="riso"] .foot__tagline { font-family: var(--font-serif); - font-style: italic; font-weight: 400; } @@ -2396,7 +2349,6 @@ body:not(.easter-open) > footer { .hero__lede { font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--color-ink-2); @@ -2500,6 +2452,14 @@ body:not(.easter-open) > footer { .hero--split .hero__proof a { margin-top: var(--space-sm); } +/* Editorial: the proof block reads cleaner with just the CTA. */ +[data-theme="editorial"] .hero--split .hero__proof .label, +[data-theme="editorial"] .hero--split .hero__proof .hero__proof-line { display: none; } +[data-theme="editorial"] .hero--split .hero__proof { + padding-block-start: 0; + border-block-start: 0; +} + /* H3 — Stat-Led. Giant number + qualifier. */ .hero--stat { padding-block: var(--space-2xl) var(--space-xl); @@ -2614,7 +2574,6 @@ body:not(.easter-open) > footer { margin-block: var(--space-xl) 0; font-family: var(--font-serif); font-size: var(--text-md); - font-style: italic; color: var(--color-ink-2); line-height: var(--lh-snug); } @@ -3182,7 +3141,6 @@ body:not(.easter-open) > footer { .foot__tagline { font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); color: var(--color-ink-2); max-width: 50ch; @@ -3380,7 +3338,6 @@ body:not(.easter-open) > footer { .foot__catalog, .foot__credit { font-family: var(--font-serif); - font-style: italic; font-size: 0.9375rem; line-height: var(--lh-relaxed); color: var(--color-ink-2); @@ -3940,7 +3897,10 @@ html[data-theme="halo"] body::before { opacity: 1; } -html[data-theme="halo"] .banner, +/* Lift content above the halo body::before glow. + Banner is excluded so it keeps its sticky z-index (200) — the + theme-dropdown lives inside .banner and needs that elevation + to render above the orbit + glow layers below. */ html[data-theme="halo"] main, html[data-theme="halo"] .easter, html[data-theme="halo"] aside { @@ -4091,7 +4051,8 @@ html[data-theme="halo"] aside { font-size: 0; } -.ex-card__thumb img { +.ex-card__thumb img, +.ex-card__thumb video { display: block; width: 100%; height: 100%; @@ -4101,12 +4062,16 @@ html[data-theme="halo"] aside { } @media (hover: hover) and (pointer: fine) { - .ex-card:hover .ex-card__thumb img { transform: scale(1.025); } + .ex-card:hover .ex-card__thumb img, + .ex-card:hover .ex-card__thumb video { transform: scale(1.025); } } @media (prefers-reduced-motion: reduce) { - .ex-card__thumb img { transition: none; } - .ex-card:hover .ex-card__thumb img { transform: none; } + .ex-card__thumb video { animation-play-state: paused; } + .ex-card__thumb img, + .ex-card__thumb video { transition: none; } + .ex-card:hover .ex-card__thumb img, + .ex-card:hover .ex-card__thumb video { transform: none; } } .ex-card__meta { @@ -4927,33 +4892,21 @@ html[data-theme="halo"] aside { color: var(--color-muted); } -/* ───────────── SALON — true-centred section heads + fleuron ───────────── - Salon's existing grid override (in sections.css) was fine but the - eyebrow + title weren't perfectly stacked. Tighten the gap between - them, give the title a comfortable measure, and make the fleuron - read as a divider rather than a stray glyph. */ +/* ───────────── SALON — left-aligned, italic title, fleuron divider ───────────── */ [data-theme="salon"] .section__head { gap: var(--space-sm); padding-block-end: var(--space-2xl); } -[data-theme="salon"] .section-label { - display: inline-flex; - justify-content: center; - margin-inline: auto; -} - [data-theme="salon"] .section__title { max-width: 32ch; - margin-inline: auto; font-style: italic; } [data-theme="salon"] .section__head::after { content: "❦"; display: block; - text-align: center; color: var(--color-accent); font-size: 1.1rem; margin-block-start: var(--space-lg); @@ -4962,13 +4915,6 @@ html[data-theme="halo"] aside { opacity: 0.65; } -/* Section 07 lead paragraph + outro — Salon centers all flowing prose */ -[data-theme="salon"] .examples__intro, -[data-theme="salon"] .examples__outro { - text-align: center; - margin-inline: auto; -} - /* ───────────── NEWSPRINT — justified prose blocks ───────────── Print discipline. Long-form copy gets justified + hyphenated where the column is wide enough to render evenly. Headlines stay diff --git a/site/css/sections.css b/site/css/sections.css index 345f7f7..245480f 100644 --- a/site/css/sections.css +++ b/site/css/sections.css @@ -163,7 +163,6 @@ past the max-width. The header above stays inside the gutter. */ .examples__intro { font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); @@ -210,8 +209,9 @@ padding-inline: var(--rail-edge); padding-block: var(--space-md) var(--space-lg); scroll-padding-inline: var(--rail-edge); - scrollbar-color: var(--color-rule-2) transparent; + scrollbar-width: none; } +.examples-rail::-webkit-scrollbar { display: none; } /* Reserve trailing whitespace inside the rail so the last card snaps clean to the same content edge as the first. */ @@ -220,10 +220,6 @@ flex: 0 0 var(--rail-edge); } -.examples-rail::-webkit-scrollbar { height: 6px; } -.examples-rail::-webkit-scrollbar-track { background: transparent; } -.examples-rail::-webkit-scrollbar-thumb { background: var(--color-rule-2); border-radius: 0; } - /* — 03 · Without / With (parity panels, four pairs) —————— The section holds four W/W pairs that swap based on which toggle radio is :checked. Pure CSS, no JS. @@ -497,7 +493,6 @@ .study__intro { margin: 0 0 var(--space-2xl); font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); @@ -544,7 +539,6 @@ .skills__intro { margin: 0 0 var(--space-2xl); font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); @@ -629,7 +623,7 @@ .skill-row__title { font-family: var(--font-display); - font-size: clamp(2rem, 3.4vw + 0.5rem, 3rem); + font-size: clamp(1.4rem, 1.6vw + 0.6rem, 2rem); font-weight: 500; line-height: var(--lh-tight); letter-spacing: var(--tracking-display); @@ -643,7 +637,6 @@ .skill-row__title-meta { font-family: var(--font-serif); - font-style: italic; font-weight: 400; font-size: 0.5em; letter-spacing: 0; @@ -669,15 +662,42 @@ letter-spacing: var(--tracking-tight); } +/* Skill-row lede matches the hero lede + examples intro: same role, same + typographic treatment per theme. All ledes are roman (no italic) — the + curly single-storey italic "a" was unanimously bad to read. */ .skill-row__lede { - font-family: var(--font-body); + font-family: var(--font-serif); font-size: var(--text-md); - line-height: var(--lh-relaxed); + line-height: var(--lh-normal); color: var(--color-ink-2); margin: 0; max-width: 60ch; } +[data-theme="brutal"] .skill-row__lede, +[data-theme="manifesto"] .skill-row__lede, +[data-theme="terminal"] .skill-row__lede, +[data-theme="sport"] .skill-row__lede, +[data-theme="almanac"] .skill-row__lede, +[data-theme="studio"] .skill-row__lede, +[data-theme="pastel"] .skill-row__lede, +[data-theme="quiet"] .skill-row__lede, +[data-theme="bloom"] .skill-row__lede, +[data-theme="aurora"] .skill-row__lede, +[data-theme="plume"] .skill-row__lede, +[data-theme="halo"] .skill-row__lede, +[data-theme="coral"] .skill-row__lede, +[data-theme="violet"] .skill-row__lede { + font-family: var(--font-body); + font-style: normal; +} + +/* Studio: examples intro stays sans to match hero + verb ledes. */ +[data-theme="studio"] .examples__intro { + font-family: var(--font-body); + font-style: normal; +} + .skill-row__lede strong { font-weight: 600; color: var(--color-ink); @@ -775,7 +795,6 @@ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-2); - font-style: italic; max-width: 100%; } @@ -804,7 +823,9 @@ border: var(--rule-card, 1px) solid var(--color-rule); } -.brief-output img { +.brief-output img, +.brief-output video { + display: block; width: 100%; height: 100%; object-fit: cover; @@ -1116,61 +1137,42 @@ /* · image · reveal */ /* ════════════════════════════════════════════════════════════ */ -/* ── ATELIER — centered display, generous, narrow column ────── */ +/* ── ATELIER — generous spacing, narrow measure, left-aligned ─── */ [data-theme="atelier"] .opening { grid-template-columns: 1fr; - text-align: center; - align-items: center; padding-block: var(--space-3xl) var(--space-xl); } [data-theme="atelier"] .opening__title { - margin-inline: auto; max-width: 16ch; } [data-theme="atelier"] .opening__sub { - margin-inline: auto; margin-top: var(--space-xl); } -[data-theme="atelier"] .opening__eyebrow { - justify-content: center; -} [data-theme="atelier"] .opening__aside { display: none; } [data-theme="atelier"] .section__head { grid-template-columns: 1fr; - text-align: center; border-bottom: 0; padding-bottom: var(--space-2xl); } -[data-theme="atelier"] .section-label { - justify-content: center; -} [data-theme="atelier"] .section__title { max-width: 22ch; - margin-inline: auto; } [data-theme="atelier"] .foundations { grid-template-columns: 1fr; max-width: 38rem; - margin-inline: auto; } [data-theme="atelier"] .spec { - text-align: center; border-top: 0; border-bottom: var(--rule-hair) solid var(--color-rule); padding: var(--space-2xl) 0; } [data-theme="atelier"] .spec__head { - justify-content: center; gap: var(--space-md); } -[data-theme="atelier"] .spec__rule { - margin-inline: auto; -} [data-theme="atelier"] .step { grid-template-columns: 1fr; - text-align: center; } [data-theme="atelier"] .vs { grid-template-columns: 1fr; border: 0; } [data-theme="atelier"] .vs__col:first-child { @@ -1332,17 +1334,14 @@ } [data-theme="manifesto"] .step { border-top: 3px solid var(--color-ink); } -/* ── SALON — centered narrow, fleuron divider ───────────────── */ +/* ── SALON — italic display, fleuron divider, left-aligned ───── */ [data-theme="salon"] .opening { grid-template-columns: 1fr; - text-align: center; - align-items: center; padding-block: var(--space-3xl) var(--space-xl); } [data-theme="salon"] .opening__title { font-style: italic; font-weight: 400; - margin-inline: auto; max-width: 14ch; } [data-theme="salon"] .opening__title em { @@ -1350,36 +1349,28 @@ font-family: var(--font-display); } [data-theme="salon"] .opening__sub { - margin-inline: auto; margin-top: var(--space-xl); font-family: var(--font-serif); font-style: italic; } -[data-theme="salon"] .opening__eyebrow { justify-content: center; } [data-theme="salon"] .opening__aside { display: none; } [data-theme="salon"] .section__head { grid-template-columns: 1fr; - text-align: center; border-bottom: 0; padding-bottom: var(--space-md); } [data-theme="salon"] .section__head::after { content: "❦"; display: block; - text-align: center; color: var(--color-accent); font-size: 1.2rem; margin-top: var(--space-md); font-family: var(--font-serif); } -[data-theme="salon"] .section-label { justify-content: center; } -[data-theme="salon"] .section__title { margin-inline: auto; } [data-theme="salon"] .foundations { grid-template-columns: 1fr; max-width: 36rem; - margin-inline: auto; } -[data-theme="salon"] .spec { text-align: left; } /* ── LINEN — hanging headings, two-column asymmetric, woven texture ─── */ [data-theme="linen"] .opening { grid-template-columns: 7fr 5fr; gap: var(--space-3xl); } @@ -1526,7 +1517,6 @@ html[data-theme="almanac"] body { .anti__intro { margin: 0 0 var(--space-2xl); font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); @@ -1625,7 +1615,6 @@ html[data-theme="almanac"] body { .anti-row__desc { margin: 0; font-family: var(--font-serif); - font-style: italic; font-size: 0.9375rem; line-height: var(--lh-relaxed); color: var(--color-muted); @@ -1670,7 +1659,6 @@ html[data-theme="almanac"] body { .found__intro { margin: 0 0 var(--space-2xl); font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: var(--lh-snug); color: var(--color-ink-2); @@ -1803,7 +1791,6 @@ html[data-theme="almanac"] body { margin-block-start: var(--space-xl); padding-block: var(--space-sm); font-family: var(--font-serif); - font-style: italic; font-size: var(--text-md); line-height: 1.2; color: var(--color-ink-2); diff --git a/site/css/tokens.css b/site/css/tokens.css index f515540..22bea75 100644 --- a/site/css/tokens.css +++ b/site/css/tokens.css @@ -27,10 +27,10 @@ --color-focus: #FC4C02; --font-display: "Fraunces", "Tiempos", ui-serif, Georgia, serif; - --font-body: "The Future", "Söhne", ui-sans-serif, sans-serif; + --font-body: "Geist", "Söhne", ui-sans-serif, sans-serif; --font-serif: "Fraunces", ui-serif, Georgia, serif; - --font-label: "The Future Mono", "JetBrains Mono", ui-monospace, monospace; - --font-mono: "The Future Mono", "JetBrains Mono", ui-monospace, monospace; + --font-label: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; + --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; --display-weight: 340; --display-optical: 144; @@ -127,11 +127,11 @@ --color-accent-ink: oklch(72% 0.16 220); --color-focus: oklch(72% 0.16 220); - --font-display: "The Future", "Futura", "Avenir Next", ui-sans-serif, sans-serif; - --font-body: "The Future", "Söhne", ui-sans-serif, sans-serif; + --font-display: "Geist", "Futura", "Avenir Next", ui-sans-serif, sans-serif; + --font-body: "Geist", "Söhne", ui-sans-serif, sans-serif; --font-serif: "Instrument Serif", ui-serif, Georgia, serif; - --font-label: "The Future Mono", "JetBrains Mono", ui-monospace, monospace; - --font-mono: "The Future Mono", "JetBrains Mono", ui-monospace, monospace; + --font-label: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; + --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; --display-weight: 300; --display-optical: 144; @@ -166,9 +166,9 @@ --color-accent-ink: oklch(58% 0.24 25); --color-focus: #E63946; - --font-display: "Space Grotesk", "GT America", ui-sans-serif, sans-serif; - --font-body: "Space Grotesk", "The Future", ui-sans-serif, sans-serif; - --font-serif: "Space Grotesk", ui-sans-serif, sans-serif; + --font-display: "Albert Sans", "GT America", ui-sans-serif, sans-serif; + --font-body: "Albert Sans", "Hanken Grotesk", ui-sans-serif, sans-serif; + --font-serif: "Albert Sans", ui-sans-serif, sans-serif; --font-label: "JetBrains Mono", ui-monospace, monospace; --font-mono: "JetBrains Mono", ui-monospace, monospace; @@ -216,10 +216,10 @@ --color-focus: #B6485E; --font-display: "Cormorant Garamond", "Instrument Serif", "Fraunces", ui-serif, Georgia, serif; - --font-body: "The Future", "Söhne", ui-sans-serif, sans-serif; + --font-body: "Geist", "Söhne", ui-sans-serif, sans-serif; --font-serif: "Cormorant Garamond", "Instrument Serif", ui-serif, Georgia, serif; - --font-label: "The Future Mono", ui-monospace, monospace; - --font-mono: "The Future Mono", ui-monospace, monospace; + --font-label: "Geist Mono", ui-monospace, monospace; + --font-mono: "Geist Mono", ui-monospace, monospace; --display-weight: 400; --display-style: italic; @@ -262,7 +262,7 @@ --color-focus: oklch(45% 0.13 60); --font-display: "Playfair Display", "Cormorant Garamond", "Tiempos Headline", ui-serif, Georgia, serif; - --font-body: "Hanken Grotesk", "The Future", ui-sans-serif, sans-serif; + --font-body: "Hanken Grotesk", "Geist", ui-sans-serif, sans-serif; --font-serif: "Playfair Display", "Cormorant Garamond", ui-serif, Georgia, serif; --font-label: "IBM Plex Mono", ui-monospace, monospace; --font-mono: "IBM Plex Mono", ui-monospace, monospace; @@ -312,7 +312,7 @@ --font-display: "Playfair Display", "Crimson Pro", "Newsreader", ui-serif, Georgia, serif; --font-body: "Crimson Pro", "Newsreader", ui-serif, Georgia, serif; --font-serif: "Playfair Display", "Crimson Pro", ui-serif, Georgia, serif; - --font-label: "Inter", "The Future", ui-sans-serif, sans-serif; + --font-label: "Inter", "Geist", ui-sans-serif, sans-serif; --font-mono: "IBM Plex Mono", ui-monospace, monospace; --display-weight: 700; @@ -358,7 +358,7 @@ --color-accent-ink: oklch(78% 0.190 138); --color-focus: oklch(86% 0.190 138); - --font-display: "JetBrains Mono", "IBM Plex Mono", "The Future Mono", ui-monospace, monospace; + --font-display: "JetBrains Mono", "IBM Plex Mono", "Geist Mono", ui-monospace, monospace; --font-body: "JetBrains Mono", "IBM Plex Mono", ui-monospace, monospace; --font-serif: "JetBrains Mono", ui-monospace, monospace; --font-label: "JetBrains Mono", ui-monospace, monospace; @@ -404,9 +404,9 @@ --color-accent-ink: oklch(58% 0.24 28); --color-focus: #E51A1A; - --font-display: "Anton", "Bebas Neue", "Space Grotesk", sans-serif; - --font-body: "Inter", "Public Sans", "The Future", ui-sans-serif, sans-serif; - --font-serif: "Anton", "Space Grotesk", sans-serif; + --font-display: "Anton", "Bebas Neue", "Albert Sans", sans-serif; + --font-body: "Public Sans", "Albert Sans", "Hanken Grotesk", ui-sans-serif, sans-serif; + --font-serif: "Anton", "Albert Sans", sans-serif; --font-label: "JetBrains Mono", ui-monospace, monospace; --font-mono: "JetBrains Mono", ui-monospace, monospace; @@ -454,7 +454,7 @@ --color-focus: oklch(50% 0.12 50); --font-display: "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace; - --font-body: "Plus Jakarta Sans", "Hanken Grotesk", "The Future", ui-sans-serif, sans-serif; + --font-body: "Plus Jakarta Sans", "Hanken Grotesk", "Geist", ui-sans-serif, sans-serif; --font-serif: "Cormorant Garamond", ui-serif, Georgia, serif; --font-label: "IBM Plex Mono", ui-monospace, monospace; --font-mono: "IBM Plex Mono", ui-monospace, monospace; @@ -551,7 +551,7 @@ --color-focus: oklch(38% 0.135 250); --font-display: "Hanken Grotesk", "Inter", ui-sans-serif, sans-serif; - --font-body: "Hanken Grotesk", "Inter", "The Future", ui-sans-serif, sans-serif; + --font-body: "Hanken Grotesk", "Inter", "Geist", ui-sans-serif, sans-serif; --font-serif: "Newsreader", ui-serif, Georgia, serif; --font-label: "IBM Plex Mono", ui-monospace, monospace; --font-mono: "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace; @@ -606,8 +606,8 @@ --color-accent-ink: oklch(54% 0.20 35); --color-focus: oklch(58% 0.190 35); - --font-display: "Inter Tight", "Space Grotesk", ui-sans-serif, sans-serif; - --font-body: "Plus Jakarta Sans", "Hanken Grotesk", "The Future", ui-sans-serif, sans-serif; + --font-display: "Inter Tight", "Albert Sans", ui-sans-serif, sans-serif; + --font-body: "Albert Sans", "Hanken Grotesk", ui-sans-serif, sans-serif; --font-serif: "Inter Tight", ui-sans-serif, sans-serif; --font-label: "JetBrains Mono", ui-monospace, monospace; --font-mono: "JetBrains Mono", ui-monospace, monospace; @@ -729,7 +729,7 @@ } /* ────────────────────────────────────────────────────────────── - RISO — risograph print · Space Grotesk display, off-register + RISO — risograph print · Public Sans display, off-register Inspiration: Are.na, e-flux, Frieze, indie magazine sites. Warm peach paper, riso cyan + yellow as accents, slight CMYK misregistration on display via text-shadow. @@ -750,10 +750,10 @@ --color-accent-ink: oklch(58% 0.170 220); --color-focus: oklch(58% 0.170 220); - --font-display: "Space Grotesk", "Inter Tight", system-ui, sans-serif; + --font-display: "Public Sans", "Albert Sans", ui-sans-serif, system-ui, sans-serif; --font-body: "Newsreader", "Tiempos", ui-serif, Georgia, serif; --font-serif: "Newsreader", ui-serif, Georgia, serif; - --font-label: "Space Grotesk", ui-monospace, monospace; + --font-label: "Public Sans", "Albert Sans", ui-sans-serif, sans-serif; --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; --display-weight: 800; diff --git a/site/index.html b/site/index.html index 420448d..946db42 100644 --- a/site/index.html +++ b/site/index.html @@ -16,15 +16,11 @@ - - - - - + + href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700;800&family=Anton&family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,400;1,9..144,500&family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&family=Hanken+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Inter+Tight:ital,wght@0,500;0,600;0,700;0,800;1,500;1,600;1,700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400;1,6..72,500&family=Playfair+Display:ital,wght@1,400;1,500;1,600&family=Public+Sans:wght@400;500;600;700&display=swap" /> @@ -167,40 +163,40 @@
- +
01 - Tide - Indie podcast · warm cream, mono masthead + Banana Studio + Creative studio · playful motion, vivid yellow accent Open ↗
- +
02 - Streampipe - Open-source CLI · prose-led docs, embedded terminal + Modern SaaS + Product platform · split hero, modern-minimal register Open ↗
@@ -338,7 +334,7 @@

- Hallmark has one default behaviour and four explicit verbs. Each reads a different input and returns a different shape — same opinions, different jobs. + Hallmark has one default behaviour and three explicit verbs. Each reads a different input and returns a different shape — same opinions, different jobs.

    @@ -359,7 +355,7 @@ - Static Hour — a Hallmark output for an indie-podcast brief + @@ -389,20 +385,20 @@ - Tide — Letter macrostructure on warm cream paper + A scheduling-tool landing page — used as a study reference for Hallmark's DNA extractor
    1. Invocationhallmark study <screenshot>
    2. -
    3. MacrostructureLetter
    4. -
    5. Hero archetypeH5 Letter · salutation + body + signoff
    6. -
    7. Display roleitalic editorial serif
    8. -
    9. Body rolesame family, smaller weight
    10. -
    11. Label rolesmall-caps grotesque
    12. -
    13. Paper bandlight · warm cream
    14. -
    15. Accent huewarm orange · ≤ 3% footprint
    16. -
    17. Rhythmleft-biased · letter-format intimacy
    18. +
    19. MacrostructureSplit Hero
    20. +
    21. Hero archetypeH7 Clipped · copy-left + product-mock right
    22. +
    23. Display roleheavy geometric sans
    24. +
    25. Body rolesame family · regular weight
    26. +
    27. Label rolegrotesque · sentence case
    28. +
    29. Paper bandlight · pure white
    30. +
    31. Accent huecool blue + magenta · organic gradient
    32. +
    33. Rhythmleft-copy · right product card · overlapping watercolor blobs
    34. Refusesto ID fonts · to copy pixels
@@ -465,40 +461,10 @@ - -
  • -
    - -
    -

    Refine

    -

    Layout's fine. The details aren't. Hallmark polishes in place — smallest possible diff, layout preserved, no redesign.

    -
    -
    - -
    -
    -
    - - - Same content before refinement — centered, generic - -
    Before
    -
    -
    - - - Same content after Hallmark refine — left-biased, italic display, real proof quote - -
    After refine
    -
    -
    -
    -
  • - - +
  • - +

    Redesign

    Same content. Same brand. Different bones. Hallmark throws out the structural fingerprint and rebuilds with a deliberately different one — new section rhythm, new heading placement, new component voice.

    diff --git a/site/js/main.js b/site/js/main.js index 68e7360..1f85cd7 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -4,24 +4,9 @@ const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches; -/* — Page-load reveals (one orchestrated entrance) ——————————— */ -const reveals = document.querySelectorAll(".reveal"); -if (reduced || !("IntersectionObserver" in window)) { - reveals.forEach((el) => el.classList.add("is-in")); -} else { - const io = new IntersectionObserver( - (entries) => { - for (const entry of entries) { - if (entry.isIntersecting) { - entry.target.classList.add("is-in"); - io.unobserve(entry.target); - } - } - }, - { threshold: 0.05, rootMargin: "0px 0px -2% 0px" } - ); - reveals.forEach((el) => io.observe(el)); -} +/* Reveal/scroll-in animations are disabled by design — every .reveal + element renders in its final state on load so scrolling reads clean. */ +document.querySelectorAll(".reveal").forEach((el) => el.classList.add("is-in")); /* — Theme registry ————————————————————————————————————— */ const THEMES = { @@ -56,7 +41,7 @@ const STORAGE_KEY = "hallmark-theme"; variety: switching themes literally rebuilds the page, not just recolours it. See skill/references/component-cookbook.md. */ const ARCHETYPES = { - specimen: { hero: "specimen", footer: "colophon" }, + specimen: { hero: "marquee", footer: "colophon" }, newsprint: { hero: "split", footer: "colophon" }, atelier: { hero: "quote-led", footer: "colophon" }, garden: { hero: "letter", footer: "colophon" }, diff --git a/skill/SKILL.md b/skill/SKILL.md index 8c706e4..0f1b35f 100644 --- a/skill/SKILL.md +++ b/skill/SKILL.md @@ -1,6 +1,6 @@ --- name: hallmark -description: Use this skill when the user asks to design, build, redesign, audit, refine, or study a UI, web page, landing page, dashboard, component, or interface — or when they ask to make something "feel less AI-generated." Hallmark forces intentional design decisions (typography, color, layout, motion, interaction, structure) and refuses to default to the generic AI-UI template. Trigger phrases include "design a", "build a landing page", "make a dashboard", "redesign this site", "redesign the page", "refine this UI", "audit this design", "this looks AI-generated", "fix the design", "polish this", "give this a different look", and any request that will produce HTML / CSS / JSX / Tailwind output. **Also trigger when the user attaches a screenshot of a design they admire** — that is the `hallmark study` verb (extracts design DNA, never pixel-clones). +description: Use this skill when the user asks to design, build, redesign, audit, or study a UI, web page, landing page, dashboard, component, or interface — or when they ask to make something "feel less AI-generated." Hallmark forces intentional design decisions (typography, color, layout, motion, interaction, structure) and refuses to default to the generic AI-UI template. Trigger phrases include "design a", "build a landing page", "make a dashboard", "redesign this site", "redesign the page", "audit this design", "this looks AI-generated", "fix the design", "polish this", "give this a different look", and any request that will produce HTML / CSS / JSX / Tailwind output. **Also trigger when the user attaches a screenshot of a design they admire** — that is the `hallmark study` verb (extracts design DNA, never pixel-clones). version: 1.0.0 --- @@ -18,17 +18,16 @@ The differentiator: Hallmark insists on **structural variety**, not just visual ## How to use this skill -Hallmark has one default behaviour and four explicit verbs. +Hallmark has one default behaviour and three explicit verbs. | Invocation | What it does | | --- | --- | | *(default)* | The user asked you to design or build something new. Follow the **Design flow** below. | | `hallmark audit ` | Read the target, score it against the anti-pattern list, return a ranked punch list. **Do not edit.** | -| `hallmark refine ` | Apply the ruleset to polish the target in place. Preserve layout structure. **Smallest possible diff.** No redesign. | | `hallmark redesign [--mood ]` | Take the target's content and intent, throw out the structure, and **rebuild it from scratch with a deliberately different structural fingerprint.** New section rhythm, new heading placement, new component voice. Preserve copy, brand, and information architecture; replace everything else. | | `hallmark study ` | The user pasted or attached an image of a design they admire. Extract the **DNA** — macrostructure, archetypes, type-pairing role, colour anchor — and produce a diagnosis report, then optionally rebuild the user's content using the extracted DNA. **Never copies pixels. Never claims to identify exact fonts. Refuses obvious template-marketplace or competitor-page screenshots.** Load [`references/study.md`](references/study.md) before this verb runs. | -If the user types anything that does not clearly map to `audit`, `refine`, `redesign`, or `study`, treat it as default. If the user attaches an image without a verb prefix, ask: *"Should I `study` this (extract the DNA), or should I treat it as a reference for a fresh build?"* +If the user types anything that does not clearly map to `audit`, `redesign`, or `study`, treat it as default. If the user attaches an image without a verb prefix, ask: *"Should I `study` this (extract the DNA), or should I treat it as a reference for a fresh build?"* The default Design flow always picks a theme. By default it picks one of the **23 named themes** — the *catalog* — and rotates among them per the diversification rule. There is also a quiet *custom* branch that constructs a one-off OKLCH palette + free-font pairing for the brief; the custom route fires **only when the brief carries a creative-intent signal** (the user names a brand colour, names a multi-attribute vibe the catalog can't carry, or explicitly asks for a custom theme). For vanilla briefs, the user never sees the words "catalog" or "custom" — the catalog runs silently. See Step 1 (signal detection) and Step 2.6 (dispatch); the protocol lives in [`references/custom-theme.md`](references/custom-theme.md). @@ -36,7 +35,7 @@ The default Design flow always picks a theme. By default it picks one of the **2 ## Disciplines that hold across every verb -These four disciplines are **not** verb-specific. They apply to default Design, `audit`, `refine`, `redesign`, `study`, and component-scope alike. They sit alongside the slop test, not inside one branch of it. +These four disciplines are **not** verb-specific. They apply to default Design, `audit`, `redesign`, `study`, and component-scope alike. They sit alongside the slop test, not inside one branch of it. 1. **Pre-emit self-critique.** Before handing back any output, score it 1–5 on six axes — Philosophy, Hierarchy, Execution, Specificity, Restraint, Variety. Anything **< 3** triggers a revision pass. Stamp the six scores at the top of the artifact (`/* Hallmark · pre-emit critique: P5 H4 E5 S4 R5 V5 */`). See [`references/slop-test.md`](references/slop-test.md) § Pre-emit self-critique. @@ -200,7 +199,23 @@ Hallmark works best when you know three things before writing code: 2. **Use case.** What single job does this interface do? What is the one action the user should be able to take? 3. **Tone.** Pick an extreme — *editorial, brutalist, soft, utilitarian, luxury, playful, technical, austere*. "Clean and modern" is not a tone. -**Ask once, then commit.** If any of the three is missing, ask for all missing items in **one** short message — not one at a time, not in a follow-up. Offer the user an opt-out at the end of that message: *"or say 'go ahead' and I'll infer from the brief — I'll tell you what I picked."* +**Always ask — answering is optional.** Hallmark almost always asks before it designs. Even when the brief looks complete, post one short bundled prompt covering all three fields **plus** any open questions you'd want answered (brand colour, reference site, page sections, must-have content). Make every field skippable — the user can fill in some, all, or none. + +The prompt format: + +> *"Before I start, three quick fields — answer any or skip:* +> *· **Audience** — who's this for?* +> *· **Use case** — what one action should they take?* +> *· **Tone** — pick an extreme: editorial / brutalist / soft / utilitarian / luxury / playful / technical / austere.* +> *Anything else I should know — brand colour, reference site, must-have sections? Or just say 'go ahead' and I'll infer from the brief and tell you what I picked."* + +Send the prompt **once**, in one message. Do not ladder follow-ups; if the user answers some fields and skips others, treat the skipped fields as opt-out and infer them. If the user says "go ahead", "you pick", "just build it", "don't ask", or doesn't engage after one prompt, the inference protocol below kicks in. + +**Two narrow exceptions** where the gate is silent: +- The user already named all three (audience, use, tone) explicitly in the brief. +- The skill is invoked with `audit`, `study`, or `redesign --mood` — those verbs read context from the target, not the user. + +In every other case, ask the bundled prompt. Default is to ask, not to skip. **Genre — pick before themes.** Before the theme route, settle on a genre. Hallmark ships four: **editorial** (default · the canonical anti-slop voice), **modern-minimal** (Stripe / Linear / ElevenLabs school), **atmospheric** (Suno / Runway / dark-AI-tool school), **playful** (post-Linear soft school). The genre scopes which themes can rotate, which slop-test gates apply, and which voice fixtures the LLM picks from. Detection is signal-based — silent default to editorial unless the brief fires one of these: @@ -223,7 +238,7 @@ If any of those fires, ask one short follow-up before picking: *"This brief read If none of the signals fires, **proceed with catalog silently. Do not mention the fork.** Most briefs don't need a custom theme — the catalog's 23 themes plus the rotation rule already deliver structural variety. See Step 2.6 for the dispatch. -**If the user opts out** (says "go ahead", "you pick", "skip", "just build it", "don't ask", or simply doesn't engage with the question after one prompt): +**If the user opts out or skips fields** (says "go ahead", "you pick", "skip", "just build it", "don't ask", answers some fields and leaves others blank, or simply doesn't engage with the question after one prompt): - Infer audience, use case, and tone from the brief, the domain, and any visible context (filename, framework, surrounding code is fair game *now* — only because the user delegated). - **State the inferences in one sentence at the top of your reply** — *"Going with: audience = X · use = Y · tone = Z. If any of those is wrong, tell me and I'll redirect."* @@ -350,7 +365,7 @@ The non-negotiables live in [`references/`](references/). **Be precise about wha - [`export-formats.md`](references/export-formats.md) — load at Step 6 only when the project warrants multi-format exports (i.e. has a `design.md`). Single-page builds emit `tokens.css` from the in-memory token state and don't need this file. **Verb-specific:** -- [`verbs/audit.md`](references/verbs/audit.md), [`verbs/refine.md`](references/verbs/refine.md), [`verbs/redesign.md`](references/verbs/redesign.md) — load only when that verb runs. +- [`verbs/audit.md`](references/verbs/audit.md), [`verbs/redesign.md`](references/verbs/redesign.md) — load only when that verb runs. - [`study.md`](references/study.md) — load only when `hallmark study` runs. **Human-only (do NOT auto-load):** @@ -482,12 +497,6 @@ Load [`references/verbs/audit.md`](references/verbs/audit.md) and follow it. --- -## `hallmark refine` - -Load [`references/verbs/refine.md`](references/verbs/refine.md) and follow it. - ---- - ## `hallmark redesign` Load [`references/verbs/redesign.md`](references/verbs/redesign.md) and follow it. diff --git a/skill/references/verbs/refine.md b/skill/references/verbs/refine.md deleted file mode 100644 index 51302e1..0000000 --- a/skill/references/verbs/refine.md +++ /dev/null @@ -1,12 +0,0 @@ -# `hallmark refine` - -The user has code they are happy with structurally but wants polished. Your job is to apply the ruleset with the smallest possible diff. - -- Do not move or rename elements unless necessary. -- Do not restructure the DOM. -- Do swap fonts, rewrite colour tokens to OKLCH, tighten the type scale, correct easings, add missing states, fix any flagged anti-patterns. -- At the end, list what you changed and which reference file prompted each change. - -**If the page has a Hallmark stamp** with a genre, refine within that genre's rule overlay (loaded from [`genres/.md`](../genres/)). A modern-minimal page being refined keeps its pill CTAs and large display; an atmospheric page keeps its radial blooms; an editorial page keeps its hairlines and asymmetry. - -**If the page has no stamp**, the genre is unknown. Refine to the universal ruleset only — do not impose editorial defaults on what may have been a deliberate atmospheric or modern-minimal choice. The smallest-possible-diff principle means *not* repainting the page in your default voice.