Uh oh!
There was an error while loading. Please reload this page.
Redesign /skills as a dashboard with a code-editor-style file browser - #15
Merged
Conversation
- Nav had no direct path to the standalone /skills tree browser — only a small "Browse every file" text link buried inside the in-page catalog section. Added a proper "Browse Skills" button next to Install CLI. - Added app/skills/loading.tsx using a new TextMorph primitive, so the navigation into /skills has a visible in-between state instead of nothing happening until the route resolves.
- Reskin /skills into a sidebar dashboard shell: icon rail on desktop (with plain label tooltips, no fake flyout submenus for routes that have no real children), horizontal labeled strip on mobile. Nav gains a fourth item, Prompt Inputs. - Rebuild the file content pane as a real tabbed editor: multiple open files, shiki syntax highlighting (dual light/dark theme sourced from the existing --syntax-* token palette), a scroll-position minimap, and a status bar. - Markdown files get a dedicated reading mode: collapsible outline rail, focus mode that dims other sections, and a frontmatter card that parses each skill's name/description/version instead of dumping the raw YAML block as a run-on paragraph. - Add a local-only markdown Edit mode: block/mark toolbar, a live split preview, Copy/Revert actions. Explicitly not wired to persist anywhere - these files are read live from the repo, not user drafts, so no fake "Saved" indicator. - Add Prompt Inputs: a hand-built agent composer (auto-growing textarea, model select, animated send/stop) whose "Use a skill" action inserts the real trigger phrases straight out of each skill's own SKILL.md frontmatter, not invented copy. - Add a GooeyTextReveal heading treatment on the Browse skills title. - Fix a real responsive bug: the tree pane had no flex-1/height cap below the lg breakpoint, so it grew to fit all rows unclamped and starved the file pane down to 0px height once a file was selected. Visualize interactions and Playground remain real 404s - not built yet, not faked. New deps: shiki, gsap, @gsap/react (SplitText is bundled free as of gsap 3.13+, no Club GreenSock registry needed).
Markdown rendering: - The list detector required every line in a block to start with a marker, but these docs wrap long items across source lines and nest sub-bullets by indentation. The first wrapped item failed the test, so whole lists fell through to the paragraph branch and rendered as one run-on sentence with the markers inline. Group by marker + indentation instead, keeping nested bullets as real children. - Support ### headings (previously rendered as literal "### text"). - Loosen list spacing so items read as separate points. Editor modes: - Preview and Source read the on-disk file while Edit's split preview read the draft, so switching away from Edit silently showed the original while the tab dot still claimed a live edit. All three now render the same value. File tree: - Per-extension icons and colors drawn from the existing --syntax-* palette, which already ships light and dark values, so the tree tints correctly in both themes. Folders take the classic amber, dimmed while collapsed. Editor tabs use the same mapping. - Selected row uses the reference file-tree's pink accent.
- Add components/ui/code-block.tsx from a provided reference: prism highlighting themed from a single accent hex, line numbers, and a copy button. Two adaptations were needed — the original targets Tailwind v4 (`bg-(--cb-bg)`) and this project is on v3.4, so custom property utilities are rewritten as `bg-[var(--cb-bg)]`; and v3 can't apply an opacity modifier to a variable colour, so alpha tints are precomputed as their own vars. Surface colours are wired to the existing --bg-*/--text-*/--border-* tokens so it matches the site. - Markdown fences now render through it, so every code sample in a skill doc is copyable instead of being inert preformatted text. - Source is a link to the file on GitHub rather than a third local mode. Reading raw source is something GitHub already does better — blame, history, permalinks — and Preview/Edit are what benefit from being here. Non-markdown files render inline through the same CodeBlock, which retires the bespoke gutter and minimap. - Drop shiki: nothing imports it now that one highlighter covers both markdown fences and whole files. - Tint scrollbars to --border-strong. The browser default painted a bright white bar down the dark panes that read as a UI element rather than chrome. - Fall back to execCommand when the async clipboard API rejects, not only when it is absent — it can exist and still fail on permissions or an unfocused document, where copy previously did nothing at all.
- Add components/motion/pixel-liquid-bg.tsx from a provided reference: a Navier-Stokes fluid sim with Bayer dithering, pixelation, film grain, and an auto-demo driver that yields to the cursor. three was already a dependency, so this adds none. - One behavioural change from the reference: the whole WebGL stack is skipped under prefers-reduced-motion. A permanently-moving full-bleed background is exactly what that setting is for, and skipping init rather than freezing a frame also spares the GPU the work. - Mount it behind the skills layout. Panels move onto translucent surfaces via color-mix so the fluid reads as a slow glow rather than a wallpaper competing with the text — Tailwind v3 cannot apply an opacity modifier to a var colour, hence color-mix over `/82`. The backdrop blur is deliberately light: a heavy one smears the pixel dither into flat colour, which is the whole look. - The overlay is pointer-events-none, which is safe because the sim tracks the cursor on window rather than on its own element, so it still reacts while clicks pass through to the UI.
The layout panels were already translucent, but the cards inside them — the file browser, the tree panel, code blocks, the frontmatter card, the meta chips, the prompt composer — were still fully opaque and covered almost the whole content area, so the fluid background had nowhere to show and read as though it were not there at all. Add --glass-surface/--glass-frame/--glass-elevated to globals.css and move those surfaces onto them, each with a light backdrop blur. Defining the tints once means the whole dashboard is tuned from one place: raise the percentages to calm the background down, lower them to let more through. They resolve against whichever --bg-* the active theme sets, so one definition covers light and dark, and they exist as tokens at all because Tailwind v3 cannot apply an opacity modifier to a var colour.
The dashboard read as murky: the cards were only just translucent enough to tint the fluid behind them without ever letting it through, and dark was the only mode available, so a dark background under dark panels had nowhere to go. - Add a theme toggle to the skills header. It reuses the contract the site already has rather than introducing a second one: the `.dark` class on <html>, persisted under "ai-devkit-theme", pre-applied by the no-flash script in app/layout.tsx. Initial state is read from the DOM that script already touched, so there is no provider to desync from and no flash on first paint. - Drop the glass tints from 72/62/70% to 38/30/40% and the content column to 45%, with a wider backdrop blur to keep text legible over the moving colour underneath.
The skills cite each other by their cmk: handle — 108 references across 34 skills, dense enough to be worth seeing rather than described. The tab that was meant to show that has been returning a 404 since the dashboard was scaffolded; this fills it from data already on disk. - lib/skill-graph.ts derives the graph at build time from the same skills/ tree the browser reads, so there is no second source to keep in sync. Handles are matched in frontmatter descriptions and body prose alike, since both carry real references. A file's own name is excluded — every SKILL.md opens by declaring `name: cmk:<self>`, which would otherwise give all 34 skills a self-loop. - Circular chord layout rather than a force simulation: with this many edges a physics layout settles differently on every load, so nothing in the picture can be referred back to. Fixed positions keep a hub where you left it, and cost no animation frames next to the fluid background already running on this page. Hover traces a skill's references, click pins it, the side panel lists both directions. - Coordinates are rounded before they hit the DOM. Full-precision floats serialise differently on server and client, which React reported as a hydration mismatch on every label in the ring. - Add components/ui/blur-highlight.tsx (React Bits Pro, licensed copy — the registry install needs a components.json and a licence key, neither present here) and use it for the page intro. One fix against the reference: HighlightWrapper was declared inside the render map, so it was a fresh component identity every render and React remounted it each time, restarting the sweep. It is hoisted to module scope.
Six skills ship an eval.json — a list of scenarios, each a prompt plus the assertions its output has to satisfy. As raw JSON it reads as a wall of escaped strings, so it now renders as what it is: numbered scenario cards with the prompt quoted and the assertions as a checklist. An Evals/Raw toggle keeps the original a click away, and the shape is sniffed rather than assumed, so a JSON file that is not an eval file still renders as code. Liquefy theming is applied across the skills pages: - styles.css is imported, not tailwind.css. The latter is explicitly a Tailwind v4 interop layer and this project is on v3.4, so the token sheet is used directly and --lq-* values are read as plain CSS variables. The sheet is safe to layer in: its :root block only defines --lq-* properties, everything else is scoped under .lq-provider. - LiquefyProvider takes its theme from the `.dark` class this site already sets pre-paint, rather than running a second source of truth that could disagree with the existing toggle. - The --glass-* tokens are declared on .lq-provider, not :root. A custom property is substituted at computed-value time on the element that declares it, and --lq-* only exists from .lq-provider down — declared at :root, --lq-glass-soft resolved to its fallback before any card could inherit it, leaving Liquefy's theme with no effect on the surfaces. :root keeps plain fallbacks for anything outside a provider.
The rail's hover labels were cut off a few pixels past the rail's edge, leaving a sliver instead of a readable label. Not clipping — paint order. backdrop-filter makes the aside a stacking context, so the tooltips' z-30 is resolved inside it and cannot lift them above anything outside. The aside and the content column both sat at z-10, and at equal z the later sibling wins, so the content column painted over every tooltip past its left edge. All five labels extend past it, so all five were affected. The aside moves to z-20.
Catalog, detail, workspace, graph and prompt inputs each derived their own idea of what a skill is. They now share one contract built from skills/ at build time: handle, title, summary, triggers, sections, files and both reference directions, resolved in a single pass and cached for the build. Skill identifiers arrive as `<id>` from links and `cmk:<id>` from a SKILL.md, so one helper normalizes both and rejects anything that could not name a directory. The pages were always statically generated, so "Live from repository" was never true. The snapshot names the branch, the commit and the time the build read them instead, and the same correction lands on the catalog copy that claimed skills were read live.
/skills opened on an empty reader next to a file tree, which asked people to know a filename before they could learn anything. It now opens as a catalog: cards carrying the handle you would type, what the skill does, and the phrase that triggers it, over ranked search across names, triggers, prose, categories, related skills and file paths, plus category and capability filters, sorting and deep-linkable state. From 1440px a detail panel sits beside the list and follows the selection, so the page is never an empty reader. Narrower viewports drop the panel and a card opens /skills/<id>, which is also where a ?skill= deep link resolves there. The panel and the page are one component at two densities: the panel folds workflow and files away, the page opens them and appends the rendered document.
…ation The editor is a peer of the catalog and the detail page, not a later step: every card, panel, detail page, graph node and file row opens it directly. It is scoped to one skill with SKILL.md already open, so there is no "pick one of 34 folders" step, and the tree sits on the left where every file browser people already use puts it. Preview, Source and Edit are three modes over one buffer, and the active file and mode are written to the URL so a link to "this file, in Source" survives a refresh. /skills/workspace?skill=&file=&mode= is the shareable form and resolves onto the per-skill page; rendering it in place would ship all 455KB of skill text to someone who wants one skill's files. Drafts are scratch buffers that never reach the repository, so nothing here claims otherwise: no Saved state, a draft marked in words on both the tab and the tree, a Revert that arms before it discards, and a close that asks whether to keep the draft or revert it. They live in sessionStorage per skill, so leaving the route and coming back does not quietly throw work away. The editor itself loads on the first Edit rather than riding along with every read.
Blur was stacking four deep in the workspace, over a WebGL field running behind the one surface people read and type into for minutes at a time. The shell keeps a single blurred layer; the workspace opts out of translucency through scoped tokens so nested surfaces inherit it; and the animated backdrop is a masked band on the surfaces you scan and absent from the one you work in. PixelLiquidBg probes for a context and hands it straight back, so a browser without WebGL falls through to a static gradient instead of throwing, and repeated navigation does not spend the handful of contexts a browser allows. The gooey heading reveal releases its alpha-crushing filter when it finishes and has a wall-clock fallback, because a reveal that starts and never completes left the page's own heading invisible. The icon rail grows labels once there is room for them, the nav keeps Skills active inside a skill's routes, the file drawer is a real dialog with focus trapping and return, the file tabs are a real tablist with arrow navigation, and the graph gains a list view so all 34 skills are reachable by keyboard. Graph and prompt inputs both take a skill through the URL.
…e does Prompt Inputs compared the ?skill= parameter to skill directory names directly, so a cmk:-prefixed link — the form a SKILL.md advertises and the form every other surface accepts — silently matched nothing and left the composer on its default text. It now goes through the shared normalizer, so one link means one skill everywhere.
Measured from rendered elements rather than from tokens, two things failed. The shared dark --text-tertiary came out at 3.67:1 on this shell's card surfaces, under the 4.5:1 small text asks for, and here it carries real information: trigger phrases, categories, the repository snapshot. And #82AAFF, which reads well as ink on dark, measured 1.96:1 as ink on a light surface, where it was colouring the card's primary action. Tertiary is brightened locally, the way .intro-panel-text already does for the marketing sections, so the rest of the site's hierarchy is untouched. The accent becomes a token that darkens in light mode; tints, fills and borders keep the original hue, since those are backgrounds rather than text. Written as text-[color:var(--accent)] because Tailwind cannot tell whether a bare var() is a colour or a length and silently emits neither. Both themes now clear AA: dark runs 4.76 to 14.47, light 4.80 to 15.57.
The graph's colours are meaning, not decoration: a node's fill says whether it is the skill you pinned, an edge's stroke says which direction the reference runs. Both were literal #82AAFF and #F472B6, which measure near 1.9:1 on a light card — under the ~3:1 a meaningful non-text graphic asks for. They are semantic tokens per theme now, measuring 8.22 and 7.13 on dark, 5.59 and 6.44 on light. Pinning also stopped meaning anything the moment the cursor moved, because hover replaced the selection outright. Hover still traces, but the pin keeps its own marker throughout, and that marker is a halo plus a ring plus a fill rather than a colour swap alone. Nodes are focusable with a visible focus ring, Enter and Space pin, and the trace transition drops under prefers-reduced-motion. Playground was a nav item pointing at a deliberate 404. A placeholder page would only add a surface with nothing in it, so the item is gone until the thing exists and /skills/playground redirects to the catalog, which keeps any link already in the wild landing somewhere real. Card summaries also reserve two lines, so the Open workspace actions sit on one baseline across a row instead of stepping with the text.
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/skillsinto a sidebar dashboard shell — icon rail on desktop (plain label tooltips, no fake flyout submenus for routes with no real children), horizontal labeled strip on mobile. Nav gains a fourth item, Prompt Inputs.--syntax-*token palette), a scroll-position minimap, and a status bar.name/description/versioninstead of dumping the raw YAML block as a run-on paragraph.SKILL.mdfrontmatter, not invented copy.GooeyTextRevealheading treatment on the Browse skills title.flex-1/height cap below thelgbreakpoint, so it grew to fit all rows unclamped and starved the file pane down to 0px height once a file was selected.Visualize interactions and Playground remain real 404s — not built yet, not faked.
New deps:
shiki,gsap,@gsap/react(SplitText is bundled free as of gsap 3.13+, no Club GreenSock registry needed).This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full
/skillsdashboard rebuild.Test plan
tsc --noEmitcleannext lintcleanUpdate:
/skillsredesigned as three peer surfaces/skillsis now a catalog, a skill detail surface and a full file workspace, allfirst class. The editor and its local drafts were not deferred or reduced; they
gained a Source mode, drafts that survive navigation, a confirming Revert and
deep links carrying file and mode.
Deliberate decision, not a spec deviation
Skill metadata (category, version, file count, reference count) sits in the
detail header beside the identity rather than in a separate block below
Related skills. Category and version read as identity, the reader sees context
before workflow, and the header stays compact without pushing the primary CTA
down. Flagging it here so review does not treat it as an oversight.
Verification
Run after stopping every dev server and
rm -rf .next:type-check,lint,build(84 static pages) andgit diff --checkall pass.1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
at 762px and 834px. No horizontal overflow at any width.
mounts the inspector, 1440 to 1280 unmounts it and drops
skillfrom the URL.No 40px panel, no stale selection.
?skill=,?skill=cmk:,/skills/[skillId], workspace?file=&mode=, graph?skill=, prompt inputs?skill=all resolve, with oneshared id normalizer behind them.
tree and the tab. Revert arms before discarding.
in the workspace; the probe releases its context.
14.47, light 4.80 to 15.57. All AA for small text.
Not verified
Automated accessibility audit (axe or Lighthouse) did not run: the devtools
integration could not attach to its browser profile in this environment. A
genuine window-drag resize is also untested; the window manager refused to
resize a maximized window, so the live-resize result above uses a dispatched
event. Large-markdown render timing and memory profiling beyond WebGL context
counting were not measured.
Closing items (
0d003af)dark, 5.59 and 6.44 on light, against the ~3:1 a meaningful non-text graphic
asks for. The pin is a halo plus a ring plus a fill and survives hovering
another node; nodes are focusable with Enter and Space to pin; the trace
transition drops under
prefers-reduced-motion./skills/playgroundredirects to thecatalog, so nothing routes to a 404 and no empty placeholder page was added.
Open workspaceactions align acrossa row.
Documented exception: the idle edge mesh measures 1.39 on dark and 2.55 on
light, below 3:1. That is deliberate. The edges that carry the answer are the
traced ones, which use the node colours above, and the same relationships are
available as text in the inspector and the List view. Raising 108 idle edges to
3:1 would turn context into noise.