diff --git a/AGENTS.md b/AGENTS.md index dd69aa46..95414a37 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ emails. Nuxt on Cloudflare Workers, D1, and Workers AI. ## Read first - [`VISION.md`](VISION.md) — the product filter: mission, money posture, the two loops, seven principles, anti-scope. Read before any product, scope, design, or marketing decision. When it conflicts with the code, VISION wins. -- [`DESIGN.md`](DESIGN.md) — the visual filter: tokens, the three design principles, components, motion, the noise field, and the Avoid list. Read before UI work. +- [`DESIGN.md`](DESIGN.md) — the visual filter: tokens, the three design principles, components, motion, the brand system, and the Avoid list. Read before UI work. - [`COPY.md`](COPY.md) — the verbal filter: the canonical strings, the register per context, and the banned language. Read before any user-visible string. - [`GLOSSARY.md`](GLOSSARY.md) — every product concept. Read before a user-visible string, a public API name, a doc heading, or a route segment. - [`docs/arch/README.md`](docs/arch/README.md) — the layers, the identity rule, the URL canonicals, and the server and app handler shapes. diff --git a/COPY.md b/COPY.md index c37bf902..2543378b 100644 --- a/COPY.md +++ b/COPY.md @@ -22,6 +22,22 @@ These exact strings. Do not paraphrase them per page. | Tagline | Curated agent skills by humans. | index OG image alt | | Site description | Curated agent skills by humans, written by real maintainers in their own GitHub repos | `nuxt.config.ts` site description (feeds every page's meta description) | | Elevator pitch | Skilld is a curated registry of agent skills written by real people in the GitHub repos you already depend on. One install command, every agent; watch your stack and get a digest when it changes. | guidance only: no page ships it yet (use it where two sentences fit) | +| Home H1 | Hyped agent skills, no bloat | guidance only: the homepage H1. The page draws the rose brand dot as its full stop, so never type a period | +| Home intro | Run a skill once and nothing lands on disk. Fork or install the ones you keep. Every skill comes from its maintainer's repo, and a person reads it before it's listed. | guidance only: the homepage intro under the H1 | +| Home claims line | Open-source CLI · Analytics without cookies or IPs · A skills.sh alternative | guidance only: the homepage claims line. The last item links to `/vs/skills-sh` | +| Promo label | Teach your agent skilld | guidance only: the homepage promo chip beside `npx skilld install skilld --global` | +| Tile: run | No more skill bloat: Run skills once off, fork, or install. | guidance only: a homepage tile, with the title before the colon. The run chip motif pairs with it | +| Tile: trending | Stay hyped: What devs talk about on X and Bluesky, weekly and monthly. | guidance only: a homepage tile. The braille spark motif pairs with it | +| Tile: changes | Keep updated: Watch repos and get a digest when their skills change. | guidance only: a homepage tile. The change grid motif pairs with it | +| Tile: platform | Built to be built on: CLI, API, SDK and MCP. | guidance only: a homepage tile | +| Home section: trending | Trending skills this week. | guidance only: the homepage trending section heading | +| Home section: changes | Keep up with skill changes. | guidance only: the homepage section heading for watching and the digest | +| Home section: authoring | Write a skill for your project. | guidance only: the homepage section heading for making a Skill | +| Claim: open source | open-source CLI | guidance only: the CLI. Never call skilld.dev or its site open source | +| Claim: privacy | analytics without cookies or IPs | guidance only: analytics and privacy copy. Never the bare "privacy-friendly" | +| Claim: comparison | skills.sh alternative | guidance only: always a link to `/vs/skills-sh` | + +The homepage deck has no collection section. Its old heading, "Install a collection in one command.", is retired. ### The product in four lengths @@ -131,21 +147,25 @@ near-miss is also banned. | revolutionary, game-changing, supercharge, unlock, 10x, delightful, seamless, cutting-edge, next-generation, disrupt, empower, leverage (as a verb) | the mechanism, or the number | Startup register. The reader runs CI and can tell | | AI-powered, intelligent, smart, magic, automate, autonomous, copilot (as a marketing term) | name what it does | skilld serves developers who use AI agents; it is not itself an AI product. "Agent" and "skill" stay fine as category nouns ("agent skills", "install a skill"); the ban is on "AI" modifying skilld itself | | best, fastest, most powerful, ultimate, definitive | the specific claim, with evidence | A superlative without evidence is unfalsifiable. If something genuinely is the best at one thing, say why | -| vibrant community, ecosystem (community-size claims), passionate developers, beloved by thousands | the number | "6 curators", never "a growing community". Calling skilld an ecosystem is a category claim, not a size claim; see the exception below | +| vibrant community, ecosystem (community-size claims), passionate developers, beloved by thousands | the number | "6 curators", never "a growing community". Using "ecosystem" for a package category is not a size claim; see the exception below | | named, naming, named by (in user-facing copy) | talked about, mentioned | Our internal words for the social-attribution route; they read as jargon. "3 devs talked about it", never "3 people named it". The technical sense survives in identifiers, ADRs and code comments, where the precision is the point | | people (for our audience) | dev, devs | They are developers, and "people" is a vaguer word doing a smaller job. "Developers" in full is fine where the short form reads clipped | | first person in a CTA | the content, then the destination | "We send this every Monday" spends the words on us. "Trending skills to your inbox every Monday" gives the reader both things that matter | +| privacy-friendly (bare) | analytics without cookies or IPs | A bare privacy claim cannot be checked. The mechanism can | +| open source (for the site or skilld.dev) | open-source CLI | A reader must be able to clone what the claim names, and the claim names the CLI | **Exception, the humans-versus-generated claim.** When the contrast is authorship by a human against machine generation, "human" and "person" are the right words and "dev" weakens the point. "Curated agent skills by humans" and "person-authored skills" stay as they are. The rule above is about naming our audience, not about the provenance claim. -**Exception, the homepage hero.** The 2026-09 homepage pivot made "Taste-tested agent skills -ecosystem" the landing H1 and the page title. That "ecosystem" names the category skilld -serves: skills across agents and package managers, written by their maintainers. It is not a -community-size claim, so the scoped ban above does not cover it. Package and learn pages use -the word in the same technical sense: npm, PyPI, crates, RubyGems. +**Exception, "ecosystem" as a category.** Package and learn pages use "ecosystem" in its +technical sense: npm, PyPI, crates, RubyGems. That names a category, not a community size, so +the scoped ban above does not cover it. + +**Exception, "hyped".** Harlan approved "hyped" for the homepage H1 and "Stay hyped" for the +trending tile. Both name what devs talk about on X and Bluesky, which we measure and show. Use +them only for social trending. "Hot", "popular" and "top" stay banned. ## Open questions diff --git a/DESIGN.md b/DESIGN.md index c8703885..2633144a 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -64,7 +64,7 @@ components: > Generated by `nuxt-frontend-design`. Source of truth for visual tokens. Compatible with `@google/design.md`. > -> **Front matter** holds the machine-readable tokens. **Prose below** holds the visual system: principles, components, motion, the noise field, and the Avoid list. Voice and copy rules live in [`COPY.md`](COPY.md). Token refs use `{path.to.token}`. +> **Front matter** holds the machine-readable tokens. **Prose below** holds the visual system: principles, components, motion, the brand system, and the Avoid list. Voice and copy rules live in [`COPY.md`](COPY.md). Token refs use `{path.to.token}`. ## Design Principles @@ -78,7 +78,7 @@ Practically: - One accent color used sparingly (10% of surface area, max) - UI chrome in monospace at small sizes; content in the sans-serif - Borders, not shadows, define boundaries -- No glow, no gradient, no blur, no decorative flourish in UI chrome (the brand noise field is the sole exception; see "Brand Noise Field" section) +- No glow, no gradient, no blur, no decorative flourish in UI chrome. The textures in "Brand System" are the only decoration, and each has one job - Compact components: tight padding, defined shapes, minimal radius - Whitespace is intentional structure, not generous filler @@ -122,7 +122,7 @@ Every surface has warm undertone. The accent is coral/rose. The voice is editori | Extended | none | semantic colors (success/warning/error) added when first needed | - **Neutral tinting**: every neutral is OKLCH at hue 60, chroma 0.005–0.014. Pure 0-chroma grays are banned. -- **Color budget**: 90% warm stone, 10% rose. The accent is rare so it stays meaningful. Solid rose appears on primary CTAs, active nav, and featured-content badges only. +- **Color budget**: 90% warm stone, 10% rose. The accent is rare so it stays meaningful. Solid rose appears on primary CTAs, active nav, featured-content badges, and the one rose dot of the mark, a texture or a motif. - **Primary darkening**: `--color-rose-500` is overridden to `oklch(0.555 0.225 17.32)` so white-on-primary buttons clear WCAG AA. ### Contrast & Accessibility @@ -194,7 +194,7 @@ Use `UiTooltip` (not `UTooltip`) for any tooltip that needs more than a plain st - **Container width**: `max-w-5xl` with `px-4 sm:px-6`. Wider feels institutional in the wrong way. - **Transition speed**: 200ms for every micro-interaction (hover, focus, expand/collapse). - **Animation style**: fade + `translateY(4px)` rise, 60ms stagger between siblings via `motion-v`. Total under 400ms. -- **Reduced motion**: `prefers-reduced-motion: reduce` collapses to opacity-only crossfades; the noise field freezes at ambient shimmer state. +- **Reduced motion**: `prefers-reduced-motion: reduce` collapses to opacity-only crossfades. Each brand texture draws one still frame, and the lockup dot does not blink. ## Responsive Strategy @@ -212,11 +212,14 @@ Use `UiTooltip` (not `UTooltip`) for any tooltip that needs more than a plain st > Things that break the aesthetic. Check this list before adding new patterns. -- Glow, drop-shadows on cards, backdrop-blur on surfaces (the brand noise field has a controlled additive bloom; that is the only exception). +- Glow, drop-shadows on cards, backdrop-blur on surfaces. The brand textures are flat dots and need none. - Cold accents (blue, cyan, purple) as primary or feature colors. - Pure black (`#000`) or pure 0-chroma gray anywhere. - Dense data tables on first-level views; density grows with depth. -- Emoji or playful illustrations. +- Emoji or playful illustrations. The trending flame exception is retired; the braille spark marks trending. +- A second rose element in a motif or on an OG card. One rose dot is one pick. +- Braille glyphs, canvas, or any font other than Plus Jakarta Sans and IBM Plex Mono in an OG image. Draw dots as SVG. +- The retired rose chevron, or the mark redrawn by hand. Every placement comes from `shared/brand-mark.ts`. - Gradient text effects. - Cards nested in cards. - `rounded-xl` on components. @@ -263,104 +266,97 @@ Homepage patterns become system primitives only when they help a user make the n - **Journey flow**: intent → shortlist → provenance → inspect → install or watch. Each first-level route should make its position in this sequence obvious. - **Depth rule**: first-level discovery pages can use large editorial type and atmosphere. Skill detail pages stay dense and evidence-led; do not wrap `/gh/...` pages in a marketing masthead. -## Brand Noise Field +## Brand System -The animated noise field from the CLI (`skilld/src/ui.ts`) is a core brand element, not a decorative flourish. It represents the brand's visual signature: structured noise resolving into signal, which mirrors the product thesis (curation brings order to a noisy skill landscape). +This section is the visual identity spec: the mark, the textures and the motifs. `COPY.md` owns the words that go with them. -### What the animation communicates +### Thesis -The ripple pattern expanding outward from a focal point, then settling into ambient shimmer, tells the brand story in motion: a deliberate act of selection radiating through noise until everything resolves. The fill outro (noise converging to solid) represents the moment a curator's collection crystallizes into something installable. +The dot is the atom. Stone dots are the noise: every other Skill in the registry. One rose dot is the Skill you picked. The mark, the textures and the motifs all draw from that one idea, so a visitor learns it once and reads it everywhere. -### Core visual DNA (platform-agnostic) +The rule that follows: **one rose element per motif.** A second rose dot means two picks, and the picture stops making sense. -These properties define the animation across CLI, web, and any future surface: +### Mark -| Property | Value | Why | -|----------|-------|-----| -| **Pattern** | Dot grid with varying density | Braille dots in CLI, circle grid on web; the density gradient IS the animation | -| **Ripple model** | Expanding concentric rings from a focal point | 3 rings, staggered 0.5s apart, Gaussian falloff from ring front, exponential time decay | -| **Hue seeding** | Deterministic per-context hue via djb2 hash | CLI: seeded from cwd. Web: seeded from route path. Same color every visit, different per page | -| **Color behavior** | Saturation and lightness scale with brightness | Dim dots are muted warm stone; bright dots are vivid and tinted. The field never reads as flat | -| **Brand mark** | Rose chevron (⏶) at #fb7185 | Sits at the ripple origin as the focal anchor | -| **Phases** | Ripple → ambient shimmer → fill outro → solid | Each phase has a distinct feel: energy, calm, resolution, permanence | -| **Ambient shimmer** | Low random jitter after ripples pass (~1.5s) | The field stays alive at rest, never static, never distracting | +The mark is a prompt caret with one rose dot after it. The caret is a terminal prompt, because a Skill starts as a command. The dot is the cursor, and the Skill you picked. -### Web-specific adaptations +| Part | Spec | +| --- | --- | +| Box | 100 units, `viewBox="5 0 100 100"`. The box starts at x 5 so the caret and the dot sit optically centred | +| Caret | `M58 50 L18 82 L18 68 L40.5 50 L18 32 L18 18 Z`, in ink | +| Dot | circle at (80, 50), r 10, in rose | +| 16px cut | heavier caret `M58 50 L18 82 L18 62 L33 50 L18 38 L18 18 Z`, dot r 12. Use it where the mark renders at 16px | +| Ink | stone 900 `#1c1917` on light surfaces, stone 100 `#f5f5f4` on dark ones | +| Dot colour | rose `#f43f5e` on light surfaces, `#fb7185` on dark ones | +| Tile | stone 900 rounded square behind raster icons, where the background is unknown | -The CLI uses Unicode Braille characters; the web version uses a WebGL dot grid. The math model is identical; the rendering layer changes. +**Lockup.** The ink caret, then the `skilld` wordmark in IBM Plex Mono 600, lowercase, tracked at −0.02em, then a trailing rose dot. The dot is 0.3em across, sits 0.32em after the word, and centres at half the x-height. At that size and gap it reads as a cursor. Closer and smaller, it reads as a full stop. The caret box is 1.05em tall, centred on the line, with a 0.38em gap before the word. -- **Dot grid**: 2px circles on an 8px grid, opacity and scale mapped to `brightness(x, y)` -- **Glow**: soft additive bloom on bright dots only, 4px radius max. This is the one place glow is permitted in the visual system -- **Hue seeding**: `djb2(route.path)` produces a stable hue per page. Home page gets a fixed hue (rose-adjacent) -- **Interactivity**: mouse proximity spawns a local ripple (cursor position as ring origin). Touch devices use tap position -- **Reduced motion**: `prefers-reduced-motion` shows a single static frame at ambient shimmer state, no expanding rings +**Motion.** The lockup's dot blinks once when its link is hovered: off at 25% of 900ms, back on at 75%. Nothing blinks under `prefers-reduced-motion`, and nothing else in the mark moves. -### Usage boundaries +**Source.** `shared/brand-mark.ts` holds every coordinate, the outlined wordmark, and the colours. `AppLogo`, the OG lockup and every file in `public/` draw from it. To change the mark, change that module, then run `pnpm brand:assets`. Never hand-edit a file in `public/`. -The noise field appears in exactly three contexts on the web: +| File | Use | +| --- | --- | +| `favicon.svg` | Browser tabs. The 16px cut, ink and dot switch with `prefers-color-scheme` | +| `favicon.ico` | Legacy tabs and crawlers. 16, 32 and 48px on the stone tile | +| `logo-icon.png`, `logo-icon.svg` | The weekly email header, the Discord avatar, app icons. 512px stone tile. Gmail strips SVG, so email takes the PNG | +| `logo.svg`, `logo-light.svg` | The lockup, outlined, for dark and light backgrounds. READMEs and other repositories link these names | +| `logo-mark.svg`, `logo-mark-light.svg` | The mark alone, for dark and light backgrounds | -1. **Hero background** (landing page): full-width behind content, base opacity 0.15, mouse-interactive -2. **Page transitions**: brief ripple burst during route changes, 300ms max duration, contained to viewport -3. **Loading / empty states**: small contained field (matching CLI proportions) while async data resolves +**Placement.** The lockup is the site header, the account and auth layouts, and every OG card. The mark alone goes where a square fits and a wordmark does not: favicons, avatars, app icons. The homepage H1 ends on the rose dot in place of a typed full stop. The page draws that dot, and it counts as the hero's rose element. -It does not appear in: navigation, cards, buttons, tooltips, footers, or any UI chrome. Scarcity makes it premium. +**Never:** -The noise field animation from the CLI (`skilld/src/ui.ts`) is the single kinetic brand element on the site. This section is the full identity spec: the Core visual DNA table defines it, and the sections that follow cover the visual implementation. +- Never move the dot into the `i`. The trailing dot won in the brand lab because it reads as a cursor. +- Never draw the caret in rose, or the dot in stone. The dot is the only rose part. +- Never set the wordmark as live text beside a separate icon. The lockup is one drawing, so the gaps hold. +- Never bring back the rose chevron. The caret replaced it on 2026-10-06. -### Why WebGL +### Texture System -The noise field renders thousands of dots with per-frame brightness calculations. Canvas 2D could handle it but would burn CPU on compositing and glow. WebGL moves all work to the GPU: +Three textures replace the noise field. Each has one job, and none appears outside it. -- Fragment shader computes brightness per dot (same ring + Gaussian math as CLI) -- Additive blending produces soft bloom without a separate blur pass -- Instanced rendering for the dot grid: one draw call, thousands of dots -- Main thread cost: near zero. Only passes `time` uniform each frame via `requestAnimationFrame` +| Texture | Job | What it shows | +| --- | --- | --- | +| **Braille names** | Hero, OG cards, CLI | Rows of real Skill names in braille. Far from the rose dot they thin to sparse dots. Near it they resolve into letters. Each hop of the pick sends three rings outward, half a second apart. Every cell is a real character, so the same field prints in a terminal | +| **Converge** | Dividers and loading | Scattered dots fall into one line and end on a rose dot. Many Skills in, one out. It reads as progress | +| **File minimap** | Skill pages and per-Skill OG cards | Each Skill as its own `SKILL.md`: frontmatter, headings, lists and code drawn as rows of dots. The rose dot is the cursor on the last changed line | -### Rendering spec +Rules for every texture: -| Property | Value | Notes | -|----------|-------|-------| -| **Dot size** | 2px radius circles | Matches the weight of 2px icon strokes | -| **Grid spacing** | 8px | Aligns with the 4pt spatial system (every other grid line) | -| **Base opacity** | 0.35 (hero), 0.5 (loading states) | Visible but subordinate to content | -| **Bloom** | Gaussian glow (sigma 6px) on all visible dots, intensity scales with brightness | Soft halos create overlapping luminous field | -| **Color** | HSL with hue from `djb2(route.path) % 360 / 360`, saturation 0.35 + brightness x 0.15, lightness 0.4 + brightness x 0.3 | Slightly warmer and brighter than original CLI spec for screen visibility | -| **Frame rate** | Display refresh via `requestAnimationFrame` for the 8s intro and while the cursor is over the field; 15 fps for the ambient shimmer after that | No `setInterval`; GPU-synced. The shimmer steps at 4 Hz, so 15 fps reads the same | -| **Canvas sizing** | `devicePixelRatio`-aware, resize via `ResizeObserver` | Crisp on retina, no layout thrash | +1. **Stone dots, one rose dot.** Ink at four or five alpha steps. No glow, no blur, no gradient fill. +2. **Behind content.** Measure text contrast against the surface, never against the dots. Keep a clear area behind text. +3. **Still under reduced motion.** `prefers-reduced-motion: reduce` draws one still frame, with the rings frozen mid-travel so the frame still shows a ripple. +4. **Paused when unseen.** Stop drawing when the texture is offscreen or the tab is hidden. Start after hydration, never before first paint. +5. **One per region.** No other motion runs in the same viewport region as a moving texture. +6. **Converge is the loader.** At small sizes the file minimap looks like a skeleton loader. Do not use it as one. -### Interactivity +**On OG cards.** An OG card is one still frame, drawn server side as SVG dots. The OG renderer has only Plus Jakarta Sans and IBM Plex Mono, and neither has braille glyphs, so a card never relies on a glyph or a canvas. The lockup's dot is the card's one rose element. Textures on a card draw stone only, or use the lockup's dot as their focal point. `app/utils/og-texture.ts` draws them. -- **Mouse proximity**: cursor position becomes a ring origin. One ring, no stagger, faster decay (0.8 vs 0.4) so the effect is local and brief -- **Scroll parallax**: none. The field is fixed-position behind content, does not move with scroll. Parallax would undermine the quiet principle -- **Touch**: tap spawns a single ripple at tap coordinates, same as mouse proximity but single-fire +| Card | Texture | +| --- | --- | +| Splash (`/`) | Braille names. The focal point is the lockup's dot, so the noise resolves into the wordmark | +| Skill | File minimap down the right edge, faded in from the left. Each Skill seeds its own files from its owner, repository and name | +| Make a skill | One `SKILL.md` drawn large from its frontmatter down | +| Page, Collection, Curator | None | -### Performance budget +### Motifs -- **GPU memory**: one framebuffer (bloom pass) + dot instance buffer. Under 2MB total -- **CPU per frame**: uniform update only (~0.01ms). All computation in shaders -- **Startup**: the field starts after hydration, once the main thread is idle (`onNuxtReady`). It is decoration and never competes with first paint. Shader compilation happens once -- **Fallback**: if `WebGL2` is unavailable (rare), render a static SVG dot pattern at ambient shimmer brightness. No animation, no glow. Still warm, still branded -- **Software renderer**: if WebGL runs on the CPU (SwiftShader, llvmpipe, no GPU driver), every frame is main-thread work. Draw one static frame at ambient shimmer state, at 1x, like reduced motion -- **Visibility**: pause the animation loop when the canvas is offscreen (`IntersectionObserver`) or the tab is hidden (`document.visibilityState`). Zero GPU cost when not visible +Motifs carry data. Each answers one pitch line from `COPY.md` and spends one rose element. -### Reduced motion +**Run chip.** It pairs with "No more skill bloat". Run and install sit side by side, and run is preselected. Run has a dashed border and a hollow rose dot, because nothing stays. Install has a solid border and a filled dot, because files land. A consequence line under the chip says what each choice leaves on disk. -When `prefers-reduced-motion: reduce` is active: -- No expanding rings, no ripple -- Render a single static frame at ambient shimmer state (t=3s equivalent, floor=0, density=0) -- Mouse proximity does nothing -- The field still has the per-page hue and warm color; it just doesn't move +**Braille spark.** It pairs with "Stay hyped". Seven braille bars (`⣀⣤⣶⣿`) show seven days of social mentions, with today in rose. The mention count sits beside it. The spark is made of characters, so the same line works on the site, in the weekly email, in Discord and in a terminal. It replaces the trending flame emoji. -### Integration with quiet principle +**Change grid.** It pairs with "Keep updated". A 13-week grid of days, today at the bottom right. Each change is a stone dot, and the newest change is rose. A ring around a dot shows the size of the version bump, only where a version is known. -The noise field is bounded by strict rules so it doesn't erode the quiet feel: - -1. **Contained**: only in hero, transitions, and loading states. Never in UI chrome -2. **Behind content**: always `z-index: -1` or composited behind text layers -3. **Low opacity**: text contrast ratios calculated against the surface beneath, not the dots -4. **No competing motion**: when the noise field is active, no other motion-v animations run simultaneously in the same viewport region -5. **Scarcity**: appearing in 3 contexts makes each appearance meaningful. If it were everywhere, it would be noise +### Usage Boundaries +- Textures and motifs never appear in navigation, buttons, tooltips, footers or other UI chrome. +- The `/gh` Skill detail template is frozen until the SEO gate on 2026-11-11. Do not add the file minimap to Skill pages before that gate. +- A page uses at most one texture above the fold. +- If a design needs a second rose element, split it into two surfaces. ## Homepage Editorial Direction @@ -422,7 +418,7 @@ These are editorial sets, not necessarily database collections yet. If a set has - **Crop, do not scale**: `max-block-size: 26rem` with a `mask-image` fade. A `transform: scale()` blurs the type, and the email is the one element here that has to look exactly like itself. - **The preview is `aria-hidden` and untabbable.** It carries roughly twenty real links; tabbing an inbox picture mid-homepage is a trap. The prose beside it is the accessible description. - **Rose budget**: one solid rose element, the primary CTA. Rose inside the preview is depicted content, like a photograph containing a red object, and does not count against the 10%. -- **The trending flame** (🔥) marks the email's trending section, the same documented exception to the no-emoji rule that the nav Trending button already uses. +- **The braille spark** marks the email's trending section, as it does on the site. Emoji stay banned in the email too. ## Design Decisions @@ -455,3 +451,10 @@ These are editorial sets, not necessarily database collections yet. If a set has - **Install commands are syntax-coloured, always**: `npx`, `skilld`, `add`, and the flags stay quiet; the target and the skill name carry the accent, because that is the only part that differs between two commands. The accent rose is darkened to `oklch(0.44 0.17 17.32)` in light and lightened to `oklch(0.8 0.12 17.32)` in dark, since the button rose is 3.2:1 on `bg-muted` at small mono sizes. - **Weekly CTAs point at the email, never at a sign-in**: `See this week's` opens the public preview. A button labelled "get" that opens an OAuth wall is a promise the page does not keep, and Loop 1 admits no gate (VISION principle 3). - **Trending rows lead with the Skill**: the Skill column outweighs the posts, which scroll beside it in a per-row carousel as testimony. The one acquisition CTA, an inert email preview beside `Sign in with GitHub`, sits in the page header on wide screens and after the fifth row on narrow ones. Confirmed 2026-08-21; the 9/3 sidebar gave way on 2026-10-01 because it took a quarter of the board's width. +- **The dot is the atom**: stone dots are the noise, and one rose dot is the Skill you picked. The mark, the textures and the motifs all follow it, with one rose element per motif. Confirmed in the brand lab on 2026-10-06. +- **The prompt caret replaces the rose chevron**: the mark is an ink caret plus one rose dot. In the lockup the dot trails the wordmark as a cursor. Harlan chose the trailing dot over a rose tittle on the `i`, so the dot reads as a cursor. Confirmed 2026-10-06. +- **One geometry feeds every placement**: `shared/brand-mark.ts` holds the coordinates and the outlined wordmark. `AppLogo`, the OG lockup and every file in `public/` come from it, and `pnpm brand:assets` writes the files. The old chevron lived in hand-written copies, and their rose shades and wordmark weights had drifted apart. Confirmed 2026-10-06. +- **Three textures replace the noise field**: Braille names for the hero, OG cards and the CLI; Converge for dividers and loading; File minimap for Skill pages and per-Skill OG cards. One job each, so no texture becomes wallpaper. Confirmed 2026-10-06. +- **The lockup dot is an OG card's one rose element**: the 4px rose top bar, the rose quote rails and the rose avatar ring went stone. On the Splash card, the braille field radiates from the lockup's dot, so the texture spends no second rose. Confirmed 2026-10-06. +- **The braille spark replaces the trending flame**: seven braille bars for seven days of mentions, today in rose. The emoji exception for Trending is retired. The spark keeps the sourced mention count beside it, which the flame never carried. Confirmed 2026-10-06. +- **Run and install read as different materials**: run is a dashed border with a hollow dot, because nothing stays; install is a solid border with a filled dot, because files land. Run is preselected. Confirmed 2026-10-06. diff --git a/GLOSSARY.md b/GLOSSARY.md index 72c59a26..4220c5df 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -75,6 +75,8 @@ Collisions **Is:** `skilld run`. The Agent reads the Skill for the current session and nothing lands on disk. The default command on every Skill surface. +**Marketing phrase:** "run once off", in pitch copy such as "No more skill bloat: run once off, fork, or install". It names the same path. UI labels and commands keep "run". + **Never:** try, preview, use once, ephemeral. ### install @@ -147,6 +149,8 @@ Collisions **Is:** Skills ranked by devs talking about them on X and Bluesky (ADR-0004). Never by installs. +**Marketing phrase:** "hyped", as in the homepage H1 and the "Stay hyped" tile. It names the same social signal. + **Never:** popular, hot, top, leaderboard. ### registry @@ -245,7 +249,7 @@ Existing route paths, table names, and protocol fields keep their identifiers. **Is:** installing into the Agent's home directory, so every project sees the Skill. -**Use for:** the UI label `Global`. +**Use for:** the UI label `Global`. "Teach your agent skilld" is the promo label for `npx skilld install skilld --global`, which installs the skilld Skill globally. "Teach" appears only in that label and never replaces "install". **Never:** system-wide. @@ -269,7 +273,7 @@ Existing route paths, table names, and protocol fields keep their identifiers. | --- | --- | --- | | follow | watch | One Loop 2 verb | | sync (user-facing) | import (stars), "Checked GitHub {ago}" (freshness) | Internal jargon; say what happened | -| use once, try, preview | run | One name for the transient path | +| use once, try, preview | run ("run once off" in pitch copy) | One name for the transient path | | add (CLI verb) | run or install | v2 grammar | | popular, install count | starred, stars | Installs never rank or trust | | verified safe, secure, scanned | name the exact check | An attestation cannot guarantee safety | diff --git a/VISION.md b/VISION.md index 318747c7..7ad1c741 100644 --- a/VISION.md +++ b/VISION.md @@ -143,9 +143,9 @@ Skills install as plain files in the user's repository. They work offline, survi ### 7. Quiet craft -The interface recedes; the content speaks. Warm stone, rare rose, mono chrome, borders not shadows, the noise field in exactly three contexts. The voice is editorial: confident, warm, grounded, no hype words, every claim concrete. Craft is scope, not afterthought; a feature that works but reads loud or generic is not done. Full systems live in DESIGN.md and COPY.md; this principle makes them vetoes. +The interface recedes; the content speaks. Warm stone, rare rose, mono chrome, borders not shadows, three brand textures with one job each. The voice is editorial: confident, warm, grounded, no hype words, every claim concrete. "Hyped" is the one approved exception, and it names social trending only (COPY.md). Craft is scope, not afterthought; a feature that works but reads loud or generic is not done. Full systems live in DESIGN.md and COPY.md; this principle makes them vetoes. -**How to apply:** polish PRs are first-class. New surfaces ship with empty states, motion within the 400ms budget, and copy that passes the banned-language list. The noise field never escapes its three contexts. +**How to apply:** polish PRs are first-class. New surfaces ship with empty states, motion within the 400ms budget, and copy that passes the banned-language list. A brand texture never leaves its job. **Test:** would this screen pass as a page of a well-edited technical magazine? If it reads like a startup landing page, fail. diff --git a/app/components/AppLogo.vue b/app/components/AppLogo.vue index 6d184ce2..26f038bf 100644 --- a/app/components/AppLogo.vue +++ b/app/components/AppLogo.vue @@ -1,15 +1,65 @@ + + + + diff --git a/app/components/OgBrand.vue b/app/components/OgBrand.vue index 9fd4522a..9ddd9f7b 100644 --- a/app/components/OgBrand.vue +++ b/app/components/OgBrand.vue @@ -1,23 +1,20 @@ diff --git a/app/components/OgImage/Collection.takumi.vue b/app/components/OgImage/Collection.takumi.vue index 66393929..47c9cd7c 100644 --- a/app/components/OgImage/Collection.takumi.vue +++ b/app/components/OgImage/Collection.takumi.vue @@ -35,17 +35,6 @@ const truncatedReason = computed(() => {