A reconstructed design system for dark, editorial, motion-heavy frontends —
packaged as an agent skill that works with OpenCode, Claude Code, and any
AGENTS.md-driven tool.
Everything here was extracted from a real production build (Astro + Tina CMS) and verified against source CSS. No content, copy, imagery, or fonts from the subject site are included.
A design system in a markdown file is only useful if an agent actually loads it before writing CSS. Skill directories are discovered automatically and advertised to the model by description, so the guidance arrives at the moment it is relevant rather than sitting in a README nobody opens.
git clone <this-repo> && cd editorial-dark
./install.sh # project-local
./install.sh --global # user-wide, all projectsCreates symlinks into all three discovery paths. Safe to re-run.
Project-local (./install.sh):
| Agent | Path used |
|---|---|
| OpenCode | .opencode/skills/editorial-dark/ |
| Claude Code | .claude/skills/editorial-dark/ |
| AGENTS.md tools | .agents/skills/editorial-dark/ |
With --global the OpenCode entry goes to
${XDG_CONFIG_HOME:-~/.config}/opencode/skills/ — OpenCode's documented
global location. (~/.opencode/skills/ also resolves at runtime and is watched
by the server, but it is not the documented path, so the installer uses the
documented one.) The .claude and .agents entries stay under $HOME.
Verified by installation. Both paths were tested on OpenCode 2.0.18:
- Symlink — registers with the correct ID
editorial-dark; all 8 reference files readable from its base directory.- HTTP catalog — the server fetches
index.jsonandeditorial-dark/editorial-dark.md, caches the 11 files under~/.cache/opencode/skills/<hash>/, and registers the same ID.The HTTP install also proves the version-busting design: OpenCode writes
.opencode-version=1e8b293bc33f, which is exactly the content hash inindex.json. Change a file, the hash changes, the client refetches.One caveat, and it is not what it first looked like. OpenCode's supporting-file list comes back empty in the skill payload — from a symlink and from the HTTP cache alike, so it is not a symlink artifact as originally suspected. This does not matter here, because
SKILL.mdenumerates every reference path explicitly instead of relying on that list. If you fork this skill, keep that table: it is what makes the supporting files discoverable.
OpenCode treats .claude/skills and .agents/skills as compatibility sources,
so the skill resolves across all three from a single installed directory.
Copy skills/editorial-dark/ into any of the three directories.
catalog/ is a ready-to-serve HTTP skill catalog. Point any agent at it and the
skill downloads on demand:
# regenerate after editing the skill
node scripts/build-catalog.mjsTwo details make this work, both handled by the build script:
- The entry file is served as
editorial-dark/editorial-dark.md, notSKILL.md. A root-levelSKILL.mdgets the literal IDSKILLinstead ofeditorial-dark, so the skill would install under the wrong name. versioninindex.jsonis a content hash of every served file. Clients cache by version, so a hand-edited version would leave users stuck on a stale copy forever.
node scripts/build-catalog.mjs --check fails if the committed catalog has
drifted from skills/; CI runs it on every push.
Ask an agent: "build me a dark editorial site with word-level text reveals" and check whether it reaches for the skill.
To see the system working first, run the example:
python3 -m http.server 8000 # from the repo root
open http://localhost:8000/example/example/README.md lists what it covers and the six real bugs it uncovered.
example/index.html working demo, zero dependencies
skills/editorial-dark/
├── SKILL.md entry point — rules, budget, traps
├── assets/
│ ├── tokens.css copy-paste design tokens
│ └── motion.css reveals, stagger, float, grain + driver
└── references/
├── tokens.md colour, type, scale, font substitution
├── motion.md the core: reveals, stagger, loops
├── transitions.md custom cursor, page transitions, scroll lock
├── layout.md gutter, 12-col, sticky cards, 3D carousel
├── components.md buttons, links, inputs, forms
├── accessibility.md reduced motion, noscript, focus, review
├── responsive.md breakpoints, svh/dvh, landscape
└── provenance.md what was extracted, what was excluded
SKILL.md carries only the rules. An agent reads one reference file when it
needs that topic — progressive disclosure, so it does not load 1,000 lines to
learn one thing.
cp skills/editorial-dark/assets/tokens.css src/styles/
cp skills/editorial-dark/assets/motion.css src/styles/Import tokens.css before any component styles. motion.css needs a
<noscript> block — see references/accessibility.md.
If you read nothing else:
- One easing curve.
--ease-out: cubic-bezier(.16, 1, .3, 1). A second curve makes the motion stop reading as one system. - CSS arms start states, JS drives motion. Six keyframes total in the reference build, one of which animates layout.
- Dim, don't hide. Text carrying meaning starts at 14% opacity, not 0.
- Every full-screen veil needs a failure timeout. Without one, a failed bundle locks the page permanently.
- Reduced motion changes layout, not just animation. A 3D carousel becomes a grid.
- The
--gutterdouble declaration. One line replaces a stack of media queries.
The reference build ships page transitions, a custom cursor, a pinned 3D carousel and per-word text animation in ~26 KB gzipped, with no framework runtime and no animation library.
Hold the line. IntersectionObserver plus CSS transitions covers the whole
system; adding GSAP costs more than the entire reference implementation.
CC BY 4.0 — free for commercial use, attribution only. See LICENSE.
The two typefaces in the original (Cabinet Grotesk, Zodiak) are commercial and
are not included. Free substitutes are listed in references/tokens.md.
General Sans is free on Fontshare and needs no substitution.
references/provenance.md records what was extracted, what was deliberately
left out, and which three initial claims were corrected during verification.
{ "$schema": "https://opencode.ai/config.json", "skills": ["https://archdityaa.github.io/editorial-dark/"] }