Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Redesign /skills as a dashboard with a code-editor-style file browser - #15

Merged
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading
Aug 29, 2026
Merged

Redesign /skills as a dashboard with a code-editor-style file browser#15
harrymove-ctrl merged 18 commits into
mainfrom
feat/skills-browse-cta-and-loading

Conversation

@harrymove-ctrl

@harrymove-ctrlharrymove-ctrl commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reskin /skills into 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.
  • 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).

This started as the original "Browse Skills nav button + TextMorph loading transition" PR and grew substantially from there — the branch now covers the full /skills dashboard rebuild.

Test plan

  • tsc --noEmit clean
  • next lint clean
  • Verified live: file tree browsing, tab open/close, Preview/Source/Edit modes, markdown frontmatter card, Focus mode, Prompt Inputs composer + skill picker
  • Verified responsive at desktop/tablet/mobile breakpoints

Update: /skills redesigned as three peer surfaces

/skills is now a catalog, a skill detail surface and a full file workspace, all
first 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) and git diff --check all pass.

  • Breakpoints, reload at viewport: 390x844 one column, 768x1024 two columns,
    1280x800 two columns no inspector, 1440x900 and 1512x900 split with the panel
    at 762px and 834px. No horizontal overflow at any width.
  • Live resize (viewport change plus a dispatched resize event): 1280 to 1440
    mounts the inspector, 1440 to 1280 unmounts it and drops skill from the URL.
    No 40px panel, no stale selection.
  • Deep links: ?skill=, ?skill=cmk:, /skills/[skillId], workspace
    ?file=&mode=, graph ?skill=, prompt inputs ?skill= all resolve, with one
    shared id normalizer behind them.
  • Drafts: edit, leave the route, return, draft still present and marked in the
    tree and the tab. Revert arms before discarding.
  • WebGL: four client-side round trips leave one canvas on the catalog and none
    in the workspace; the probe releases its context.
  • Contrast measured from rendered elements, transitions disabled: dark 4.76 to
    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)

  • Graph colour is now semantic tokens per theme. Nodes measure 8.22 and 7.13 on
    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.
  • Playground is removed from the nav and /skills/playground redirects to the
    catalog, so nothing routes to a 404 and no empty placeholder page was added.
  • Card summaries reserve two lines so the Open workspace actions align across
    a 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.

- 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.
@harrymove-ctrlharrymove-ctrl mentioned this pull request Aug 15, 2026
3 tasks
- 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).
@harrymove-ctrlharrymove-ctrl changed the title feat: Browse Skills nav button + TextMorph loading transitionRedesign /skills as a dashboard with a code-editor-style file browserAug 19, 2026
hien-p added 15 commits August 23, 2026 15:40
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.
@harrymove-ctrl
harrymove-ctrl merged commit c29ea93 into mainAug 29, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@harrymove-ctrl@hien-p