From 57bd46040ac9f94341244e35fff9811e0f331479 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Tue, 6 Oct 2026 21:35:40 +1100 Subject: [PATCH 01/12] feat(registry): add Skill demos to the Skill page and the homepage A visitor could not see what a Skill makes before running it. A demo is one recorded run: a fixed prompt, the Agent's output, and how it was recorded. The Skill page shows the prompt, a scrolling full-page screenshot, and a live demo in a sandboxed frame. The homepage lists Skills with demos once three exist. scripts/record-skill-demo.ts records a demo locally with Claude Code and writes it into the repository, so merging the pull request is the human approval. The output page is served under a CSP sandbox and noindex. --- COPY.md | 4 + GLOSSARY.md | 12 + app/components/HomeDemos.vue | 106 ++ app/pages/index.vue | 6 + app/utils/home-demos.ts | 12 + .../registry/app/components/SkillDetail.vue | 9 + layers/registry/app/components/_SkillDemo.vue | 178 +++ layers/registry/nuxt.config.ts | 16 +- .../server/api/skill-demos/index.get.ts | 23 + .../server/api/skills/[...slug].get.ts | 3 + layers/registry/server/data/skill-demos.json | 109 ++ .../skills/frontend-design/index.html | 1031 +++++++++++++++++ .../diagram-design/diagram.html | 222 ++++ .../skills/emil-design-eng/toast.html | 615 ++++++++++ .../make-interfaces-feel-better/pricing.html | 652 +++++++++++ .../demos/[owner]/[repo]/[name]/live.get.ts | 25 + layers/registry/server/utils/skill-demos.ts | 119 ++ package.json | 3 +- .../skills/frontend-design/desktop.jpg | Bin 0 -> 399345 bytes .../skills/frontend-design/mobile.jpg | Bin 0 -> 280120 bytes .../diagram-design/diagram-design/desktop.jpg | Bin 0 -> 52387 bytes .../skills/emil-design-eng/desktop.jpg | Bin 0 -> 40594 bytes .../skills/emil-design-eng/mobile.jpg | Bin 0 -> 32349 bytes .../make-interfaces-feel-better/desktop.jpg | Bin 0 -> 111113 bytes .../make-interfaces-feel-better/mobile.jpg | Bin 0 -> 100575 bytes scripts/record-skill-demo.ts | 246 ++++ test/a11y.spec.ts | 73 ++ test/unit/skill-demos.test.ts | 58 + 28 files changed, 3520 insertions(+), 2 deletions(-) create mode 100644 app/components/HomeDemos.vue create mode 100644 app/utils/home-demos.ts create mode 100644 layers/registry/app/components/_SkillDemo.vue create mode 100644 layers/registry/server/api/skill-demos/index.get.ts create mode 100644 layers/registry/server/data/skill-demos.json create mode 100644 layers/registry/server/demos/anthropics/skills/frontend-design/index.html create mode 100644 layers/registry/server/demos/cathrynlavery/diagram-design/diagram-design/diagram.html create mode 100644 layers/registry/server/demos/emilkowalski/skills/emil-design-eng/toast.html create mode 100644 layers/registry/server/demos/jakubkrehel/make-interfaces-feel-better/make-interfaces-feel-better/pricing.html create mode 100644 layers/registry/server/routes/demos/[owner]/[repo]/[name]/live.get.ts create mode 100644 layers/registry/server/utils/skill-demos.ts create mode 100644 public/demos/anthropics/skills/frontend-design/desktop.jpg create mode 100644 public/demos/anthropics/skills/frontend-design/mobile.jpg create mode 100644 public/demos/cathrynlavery/diagram-design/diagram-design/desktop.jpg create mode 100644 public/demos/emilkowalski/skills/emil-design-eng/desktop.jpg create mode 100644 public/demos/emilkowalski/skills/emil-design-eng/mobile.jpg create mode 100644 public/demos/jakubkrehel/make-interfaces-feel-better/make-interfaces-feel-better/desktop.jpg create mode 100644 public/demos/jakubkrehel/make-interfaces-feel-better/make-interfaces-feel-better/mobile.jpg create mode 100644 scripts/record-skill-demo.ts create mode 100644 test/unit/skill-demos.test.ts diff --git a/COPY.md b/COPY.md index a95a028e..e40a0438 100644 --- a/COPY.md +++ b/COPY.md @@ -38,6 +38,10 @@ These exact strings. Do not paraphrase them per page. | Agents way: prompt | Paste into any agent · Your agent reads the setup steps and picks the path that fits it. | guidance only: the first way in the homepage Agents section, over the setup prompt | | Agents way: terminal | From a terminal · Teaches your agent to search and run Skills in every project. | guidance only: the second way, over `npx skilld install skilld --global` | | Agents way: MCP | In ChatGPT, Claude, and other MCP apps · Add the server once. Then ask the chat to find a Skill. | guidance only: the third way, over the MCP server URL. Its link, "Setup steps for each app", opens `/developers?setup=mcp` | +| Home section: demos | See what skills make. · Each demo is one recorded run: the prompt, and what the Agent built with the Skill. | guidance only: the homepage demo section heading and line. The section hides below three demos | +| Demo panel | Demo · You say · Open live demo · Open in a new tab · Run it yourself | guidance only: the Skill page Demo panel. "Show screenshots" replaces "Open live demo" while the live output shows | +| Demo provenance | Agent output, recorded with {agent} ({model}) on {date} from {commit} | guidance only: the line beside the Demo heading. A demo is the Agent output, never the Skill author work, so the line always opens with "Agent output" | +| Demo outdated | Recorded on an older version of this Skill. | guidance only: under the Demo panel when the Skill moved past the recorded commit | | 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: developers | Developers | guidance only: the header menu trigger, and the group label in the mobile menu. The menu holds the four items below | diff --git a/GLOSSARY.md b/GLOSSARY.md index d830a2af..5a9163a4 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -14,6 +14,7 @@ Shared terms match the skilld CLI glossary (`skilld-dev/skilld/GLOSSARY.md`). Th | Artifact | skilld.dev API | Skill commit 1—1 Artifact | not shown | | source status | lockfile, skilld.dev API | Artifact 1—1 source status | "Verified", "Unverified", "Local" | | run | skilld CLI | Skill 1—1 run command | "run" | +| demo | Skill page, homepage | Skill 1—N demo | "demo" | | install | skilld CLI | Skill 1—1 install command | "install" | | fork | Agent, Skill page | Skill 1—N local copy | "fork" | | lockfile | skilld CLI | project 1—1 lockfile | "lockfile" | @@ -83,6 +84,16 @@ Collisions **Never:** try, preview, use once, ephemeral. +### demo + +**Is:** one recorded run of a Skill: a fixed prompt, the output an Agent made with the Skill, and how it was recorded (Agent, model, Skill commit, date). A human approves each one before it ships. + +**Use for:** the Demo panel on the Skill page, the homepage demo section, and "live demo" for the sandboxed output page. + +**Never:** preview, example output, showcase, sample. "Preview" is already a banned synonym for run. + +**Rule:** a demo shows the Agent's output, never the Skill author's work. It always names how it was recorded. + ### install **Is:** `skilld install`. Skill files land in the project and the lockfile records them. The opt-in second step. @@ -314,6 +325,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 ("run once off" in pitch copy) | One name for the transient path | +| showcase, sample, example output | demo | One name for a recorded run | | 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/app/components/HomeDemos.vue b/app/components/HomeDemos.vue new file mode 100644 index 00000000..a8aed458 --- /dev/null +++ b/app/components/HomeDemos.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/app/pages/index.vue b/app/pages/index.vue index ba57b981..d23c4ce3 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -2,6 +2,7 @@ import type { RecentPublishesResponse } from '~~/server/api/feed/recent-publishes.get' import type { RecentUpdateCard, RecentUpdatesResponse } from '~~/server/api/feed/recent-updates.get' import type { TrendingFeedResponse } from '~~/server/api/feed/trending.get' +import type { HomeDemoItem } from '../utils/home-demos' import { agentSetupPrompt } from '#shared/agent-setup' import { WRITING_COMPARISON_LINK } from '#shared/comparison-navigation' import { avatarProxyUrl, githubAvatarProxyUrl } from '#shared/image-proxy' @@ -91,6 +92,9 @@ if (import.meta.server) { serverTimingHeader.value = homeDataTimings.join(', ') } +// Below the fold, so it never holds up the first paint. +const { data: demosData } = useLazyFetch<{ items: HomeDemoItem[] }>('/api/skill-demos', { key: 'home-skill-demos' }) + const recentUpdates = computed(() => updatesData.value?.items ?? []) const recentPublishes = computed(() => publishesData.value?.items ?? []) @@ -335,6 +339,8 @@ function recentRepoDescription(item: RecentRepoUpdate): string { + +
import type { SkillAudit } from '~~/app/utils/skill-audit-overview' import type { TrendingAward } from '#shared/trending-award' +import type { SkillDemoView } from '../../server/utils/skill-demos' import type { ZipState } from '../utils/skill-zip' import type { SkillBehavior } from './_SkillBehaviors.vue' import { formatTimeAgo } from '@vueuse/core' @@ -20,6 +21,7 @@ import { resolveViewerLink } from '../utils/skill-viewer-link' import { resolveSkillZipEntries } from '../utils/skill-zip' import SkillBehaviors from './_SkillBehaviors.vue' import SkillCommandPanel from './_SkillCommandPanel.vue' +import SkillDemo from './_SkillDemo.vue' import SkillReceiptsPanel from './_SkillReceiptsPanel.vue' import SkillStarTrend from './_SkillStarTrend.vue' import SkillThirdPartyChecks from './_SkillThirdPartyChecks.vue' @@ -198,6 +200,8 @@ const skillFetch = useFetch( * the file is deleted. */ sourceGone: boolean + /** A recorded run of this Skill, when one is published. */ + demo: SkillDemoView | null tier: 'official-org' | 'official-user' | 'community' sourceFacts: SourceFacts tags: SkillTag[] @@ -1705,6 +1709,11 @@ useHead(computed(() => ({