Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion COPY.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ These exact strings. Do not paraphrase them per page.
| 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 |
| Nav: CLI | CLI | guidance only: the header nav and the mobile menu item that link `/cli` |
| Nav: developers | Developers | guidance only: the header menu trigger, and the group label in the mobile menu. The menu holds the five cards below |
| Nav: CLI | CLI Β· Search, run, install, and keep Skills current. Β· Install the CLI | guidance only: the first card in the Developers menu: name, line, action. Links `/cli`. The mobile menu shows the name only. The line is the CLI line and the action is the CLI install label, so change those first |
| Nav: MCP server | MCP server Β· For ChatGPT, Claude, and any app that speaks MCP. Β· Add the MCP server | guidance only: a Developers menu card. Links `/developers?setup=mcp`. The line is the MCP setup card on `/developers`, and the action is its section heading |
| Nav: SDK | SDK Β· For your own code, with the TypeScript SDK or plain HTTP. Β· Call the skilld API | guidance only: a Developers menu card. Links `/developers?setup=api`. The line is the API setup card on `/developers`, and the action is its section heading |
| Nav: make | Make a skill Β· Guides and three authoring Skills to write and review your own. Β· Get the steps | guidance only: a Developers menu card. Links `/make-skill`. The line is the Step 05 description |
| Nav: Skillgen | Skillgen Β· Keeps your package skill current with a draft pull request after each release. Β· Set up Skillgen | guidance only: the last Developers menu card. Links `/skillgen` |
| Nav: setup guides | All setup guides | guidance only: the link under the Developers menu cards. Links `/developers` |
| Skillgen lead | Keep your package skill current. After each release tag, Skillgen opens a draft pull request that updates the Skill in your repository. You review it and decide what merges. | guidance only: the `/skillgen` line under the H1. Its first two sentences are the page's meta description |
| Skillgen opt-in | Skillgen opens a draft pull request after each release tag. It runs only on the repositories you turn on here. | guidance only: the intro of the Skillgen view on `/me?view=skillgen`. The `/skillgen` step 02 says the same in its own words: Skillgen never runs on a repository you did not turn on |
| CLI H1 | The skilld CLI | guidance only: the `/cli` H1 and its OG title |
| CLI line | Search, run, install, and keep Skills current. | guidance only: the `/cli` line under the H1. It is the CLI's own `--help` line, so change it in the CLI first |
| CLI intro | Give your Agent Skills that real maintainers write. A run reads the current source every time, and one command updates the Skills you install. Install the skilld Skill once, and your Agent searches and loads Skills on its own. | guidance only: the `/cli` intro under the line |
Expand Down
3 changes: 2 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 textures in "Brand System" are the only decoration, and each has one job
- 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. The cards in the header's Developers menu are the one exception: each carries one atmosphere layer
- Compact components: tight padding, defined shapes, minimal radius
- Whitespace is intentional structure, not generous filler

Expand Down Expand Up @@ -460,3 +460,4 @@ These are editorial sets, not necessarily database collections yet. If a set has
- **Trending shares the /skills shell**: `/skills/trending` uses the full-width layout from `/skills`. Its heading replaces `CompactPageHeader` and lines up with the results column. A sticky 14rem sidebar holds the range links, then the weekly CTA and the skilld install. Nothing sits right of the board, so the board takes every column the sidebar leaves. Rows switch on their own width, and the post carousel shows two cards where it has room. On narrow screens the ranges are a compact row above the board, and the CTA stays after the fifth row. Harlan asked for this on 2026-10-06. It supersedes the 2026-10-01 call that dropped the 9/3 sidebar for taking a quarter of the board's width: that sidebar sat right of a 64rem board, and this one sits left of a board that runs the full page width.
- **Trending rows scan in one pass**: the rank is a plain mono number, and the first three are a step darker. Each metadata line runs source, stars, then the signal that ranked the row, and an empty slot renders nothing. Descriptions stop at two lines, the run chip is as wide as its command, and the post carousel shows whole cards only. The sidebar invitation drops the email preview and the card. Its button is the rail's one solid rose element, so the install chip beside it inks its dot. Harlan asked for this polish on 2026-10-06.
- **A six-step lifecycle band replaces the four tiles**: under the hero, one band maps the whole product in its real order: find, run, install or fork, keep current, make, build on. The site and the CLI share one line. Each step is one link: a mono `01` marker and step name, then one sans line that opens with its pitch line where COPY.md has one. A line of stone dots joins the steps. Run, the default, carries the band's one rose dot, so no step lights rose on hover. Six columns from 1024px; below that a vertical list with the dots down the left. Keep the band no taller than the tiles it replaced: the hero and the band must fit a 1440Γ—900 viewport. Harlan approved it on 2026-10-06.
- **A Developers menu groups the build surfaces**: the desktop header keeps Trending Skills and Find Skills as links, and folds CLI, MCP server, SDK, Make a skill and Skillgen into one Developers menu, as nuxtseo.com does. The trigger is a button, so a keyboard opens the panel without leaving the page; the panel's last link reaches `/developers`. Each item is a card with a lucide icon tile and one `.editorial-atmosphere` layer. The three ways to connect share the top row, and the two authoring cards share the row below. CLI takes rose because it is the recommended path; the others take ember or stone. The mobile menu lists the same five items as a plain group. Harlan asked for this on 2026-10-06.
11 changes: 11 additions & 0 deletions GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Shared terms match the skilld CLI glossary (`skilld-dev/skilld/GLOSSARY.md`). Th
| skilld token | `cli_tokens`, `layers/identity` | Author 1β€”N token | "skilld token" |
| provenance | Skill detail, cards | Skill 1β€”1 author and source link | "written by", "source" |
| behavior | `skilld-protocol/behaviors`, Skill page | Skill 1β€”N behavior | "Skill behaviors" |
| Skillgen | `workers/skill-harness`, `/skillgen` | Repository 1β€”N draft pull request | "Skillgen" |
| task search | search box, `layers/registry` | sentence 1β€”N Skill | "Find skills for this task" |

Collisions
Expand Down Expand Up @@ -241,6 +242,16 @@ Existing route paths, table names, and protocol fields keep their identifiers.

**Casing:** lowercase in prose and UI.

### Skillgen

**Is:** the `skilld-skillgen` GitHub App. After each release tag, it opens a draft pull request that updates a package skill. The maintainer reviews it and decides what merges.

**Use for:** the App and its per-repository switch. A maintainer turns Skillgen on for each repository on their account page, and it runs nowhere else. It supports npm packages only.

**Never:** bot (in UI copy), skill generator, auto-update.

**Casing:** `Skillgen` in prose and UI. `skilld-skillgen` only where GitHub shows the App's name.

### guide skill

**Is:** a curation tag for a Skill not tied to a package. Distributed as a git Skill, tagged for filtering in browse views.
Expand Down
88 changes: 31 additions & 57 deletions app/app.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
import { onClickOutside, onKeyDown } from '@vueuse/core'
import HeaderNavigation from '~/components/_HeaderNavigation.vue'
import { developerMenuItems } from '~/utils/developer-menu'
import { isEditableElement } from '~/utils/input'

const title = 'skilld'
Expand Down Expand Up @@ -130,47 +132,7 @@ watch(() => route.fullPath, () => {

<div class="flex items-center justify-end gap-1.5 lg:flex-1">
<SkillSearchTrigger v-if="$route.path !== '/'" />
<!--
The braille mark makes Trending outweigh its siblings without an
emoji. Stone only: the logo dot is the header's one rose element.
It is decorative and hidden from screen readers; the label carries
the meaning. `gap-1.5` because the button's own layout does not
space sibling spans.
-->
<UButton
to="/skills/trending"
color="neutral"
variant="ghost"
size="sm"
class="hidden gap-1.5 whitespace-nowrap lg:inline-flex"
>
<TrendingMark :accent="false" />
<span>Trending Skills</span>
</UButton>
<UButton
to="/skills"
label="Find Skills"
color="neutral"
variant="ghost"
size="sm"
class="hidden lg:inline-flex"
/>
<UButton
to="/cli"
label="CLI"
color="neutral"
variant="ghost"
size="sm"
class="hidden lg:inline-flex"
/>
<UButton
to="/make-skill"
label="Make a skill"
color="neutral"
variant="ghost"
size="sm"
class="hidden lg:inline-flex"
/>
<HeaderNavigation />
<UColorModeButton
color="neutral"
variant="ghost"
Expand Down Expand Up @@ -223,22 +185,34 @@ watch(() => route.fullPath, () => {
block
class="min-h-11 justify-start"
/>
<UButton
to="/cli"
label="CLI"
color="neutral"
variant="ghost"
block
class="min-h-11 justify-start"
/>
<UButton
to="/make-skill"
label="Make a skill"
color="neutral"
variant="ghost"
block
class="min-h-11 justify-start"
/>
<USeparator class="my-1" />
<!-- Not a heading: this menu renders before the page's h1. -->
<p
id="mobile-navigation-developers"
class="section-label px-2.5 py-2"
>
Developers
</p>
<ul
aria-labelledby="mobile-navigation-developers"
class="flex flex-col gap-1"
>
<li
v-for="item in developerMenuItems"
:key="item.to"
>
<UButton
:to="item.to"
:label="item.label"
:icon="item.icon"
color="neutral"
variant="ghost"
block
class="min-h-11 justify-start"
:ui="{ leadingIcon: 'text-muted' }"
/>
</li>
</ul>
<USeparator class="my-1" />
<HeaderAccount variant="menu" />
</nav>
Expand Down
182 changes: 182 additions & 0 deletions app/components/_HeaderNavigation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<script setup lang="ts">
import { NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuRoot, NavigationMenuTrigger } from 'reka-ui'
import { developerMenuItems } from '~/utils/developer-menu'

/**
* The desktop header navigation. Developers is a button, so a keyboard opens
* the panel without leaving the page; the panel's last link reaches
* `/developers`. The mobile menu in app.vue lists the same destinations.
*/
const route = useRoute()
const openItem = ref('')

// A link inside the panel closes it itself. This covers navigation that
// starts elsewhere, such as the browser's back button.
watch(() => route.fullPath, () => {
openItem.value = ''
})
</script>

<template>
<NavigationMenuRoot
v-model="openItem"
aria-label="Main"
class="hidden lg:block"
>
<NavigationMenuList class="flex items-center gap-1.5">
<NavigationMenuItem>
<!--
The braille mark lifts Trending without an emoji. Stone only: the logo
dot is the header's one rose element. `gap-1.5` spaces sibling spans.
-->
<NavigationMenuLink as-child>
<UButton
to="/skills/trending"
color="neutral"
variant="ghost"
size="sm"
class="gap-1.5 whitespace-nowrap"
>
<TrendingMark :accent="false" />
<span>Trending Skills</span>
</UButton>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink as-child>
<UButton
to="/skills"
label="Find Skills"
color="neutral"
variant="ghost"
size="sm"
/>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem value="developers">
<!--
reka-ui sets the trigger id after mount, so SSR rendered an empty one.
The fixed id labels the panel and keeps `developers`, the item value reka-ui matches.
-->
<NavigationMenuTrigger
id="header-developers-trigger"
as-child
>
<UButton
label="Developers"
trailing-icon="i-lucide-chevron-down"
color="neutral"
variant="ghost"
size="sm"
class="group data-[state=open]:bg-elevated"
:ui="{ trailingIcon: 'size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180' }"
/>
</NavigationMenuTrigger>
<!--
The top lands 0.5rem under the header. The 1.5rem bridge spans the gap
below the trigger, so the pointer reaches the panel without closing it.
-->
<NavigationMenuContent
aria-labelledby="header-developers-trigger"
class="developers-panel absolute right-0 top-[calc(50%+var(--ui-header-height)/2+0.5rem)] w-[44rem] rounded-lg bg-default p-2 shadow-lg ring ring-default before:absolute before:inset-x-0 before:bottom-full before:h-6 before:content-['']"
>
<!-- Six columns: three connect cards fill the top row, two author cards the row below. -->
<ul class="grid grid-cols-6 gap-2">
<li
v-for="item in developerMenuItems"
:key="item.to"
class="developers-card"
:class="item.group === 'connect' ? 'col-span-2' : 'col-span-3'"
:style="{ '--stagger': item.group === 'connect' ? 0 : 1 }"
>
<NavigationMenuLink as-child>
<NuxtLink
:to="item.to"
class="group editorial-band flex h-full flex-col overflow-hidden rounded-lg border border-default p-4 transition-colors duration-200 hover:border-[var(--ui-text-muted)]"
>
<span
class="editorial-atmosphere"
:data-palette="item.palette"
data-geometry="bloom"
data-intensity="ambient"
aria-hidden="true"
/>
<span class="editorial-band__content flex h-full flex-col">
<span class="flex size-8 items-center justify-center rounded-md border border-default bg-default text-highlighted">
<UIcon :name="item.icon" class="size-4" />
</span>
<span class="mt-3 font-mono text-sm font-medium text-highlighted">{{ item.label }}</span>
<span class="mt-1 text-sm leading-snug text-muted">{{ item.description }}</span>
<span class="mt-auto inline-flex items-center gap-1.5 pt-4 font-mono text-xs text-default">
{{ item.action }}
<UIcon name="i-lucide-arrow-right" class="size-3.5 transition-transform duration-200 group-hover:translate-x-0.5" />
</span>
</span>
</NuxtLink>
</NavigationMenuLink>
</li>
</ul>
<NavigationMenuLink as-child>
<NuxtLink
to="/developers"
class="group mt-2 flex min-h-11 items-center justify-between rounded-md px-3 font-mono text-xs text-muted transition-colors duration-200 hover:bg-elevated hover:text-default"
>
All setup guides
<UIcon name="i-lucide-arrow-right" class="size-3.5 transition-transform duration-200 group-hover:translate-x-0.5" />
</NuxtLink>
</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenuRoot>
</template>

<style scoped>
/* DESIGN.md motion: 200ms, a 4px move, 60ms between rows. The panel renders
through a Teleport and carries no scope attribute, so its rules are global.
Under reduced motion the cards drop their delay too. */
:global(.developers-panel[data-state='open']) {
animation: developers-panel-in 200ms ease-out;
}

:global(.developers-panel[data-state='closed']) {
animation: developers-panel-out 150ms ease-in;
}

.developers-panel[data-state='open'] .developers-card {
animation: developers-card-in 200ms ease-out backwards;
animation-delay: calc(var(--stagger, 0) * 60ms);
}

@media (prefers-reduced-motion: reduce) {
.developers-panel[data-state='open'] .developers-card {
animation: none;
}
}

/* Ambient strength vanishes on a card this small in dark mode, so it doubles.
Keep `.dark` outside `:global()`: Vue would emit a bare `.dark` rule. */
.dark .developers-card .editorial-atmosphere {
--editorial-atmosphere-opacity: 0.56;
}

@keyframes developers-panel-in {
from {
opacity: 0;
transform: translateY(-4px);
}
}

@keyframes developers-panel-out {
to {
opacity: 0;
}
}

@keyframes developers-card-in {
from {
opacity: 0;
transform: translateY(4px);
}
}
</style>
Loading