Curriculum-driven capability factory. Read the curriculum + lesson content, detect which visual capabilities the content needs but the registry lacks, and have one subagent per gap AUTHOR the missing capability — across three parallel layers (SVG assets, primitives, special components) — each reusable, prop-driven, frame-disciplined, and wired into the drift-gated registry. Use proactively to grow the shared library ahead of (and across) lessons, or whenever a content scan surfaces capability gaps. Pairs with capability-registry-harness (the registration gate), visual-discipline / kids-eye / early-childhood-visual-taste (craft), and reuses the lesson-build W3b protocol.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Curriculum-driven capability factory. Read the curriculum + lesson content, detect which visual capabilities the content needs but the registry lacks, and have one subagent per gap AUTHOR the missing capability — across three parallel layers (SVG assets, primitives, special components) — each reusable, prop-driven, frame-disciplined, and wired into the drift-gated registry. Use proactively to grow the shared library ahead of (and across) lessons, or whenever a content scan surfaces capability gaps. Pairs with capability-registry-harness (the registration gate), visual-discipline / kids-eye / early-childhood-visual-taste (craft), and reuses the lesson-build W3b protocol.
Capability Gap-Filler
The library grows from what the curriculum demands, not from one-off scripts or per-lesson hand-patches. This skill is the methodology a subagent fleet uses to read content, find capability gaps, and BUILD the missing capabilities as reusable, registered craft.
It is orchestrated by .claude/workflows/capability-gap-filler.js. Each node here is a clean-room subagent given concrete inputs; this file is the operating contract.
The three layers — parallel, not a hierarchy
A "capability" is reusable visual craft. It lives at exactly one of three layers. None is lesser. They compose.
Layer
What it is
Has its own animation?
Home
Registered as
SVG asset
A fixed-form, on-palette illustrated object — a bundle, an animal, a prop. The visual material.
No (static art)
public/icons/<name>.svg (+ mono/)
asset-catalog.json (via icons:build)
Primitive
A prop-driven shape with self-contained animation — count/progress/state drive it. The teaching atom.
Yes
src/shape-primitives/<family>.tsx
primitives[] (family-gated)
Special component
A higher composite that COMBINES primitives + assets + motion into ONE self-contained animated teaching unit (e.g. ten sticks gather → become a roped bundle → conservation-peek, as a single reusable component).
Yes (and orchestrates others')
src/special-components/<Name>.tsx
specialComponents[] (barrel-gated)
Assets are the substrate. Primitives and special components are built on top of assets and each other. A lesson scene then composes registered capabilities at cue-relative frames — it never reinvents this craft inline (a crossfade hand-rolled in a scene is a special-component gap in disguise).
AssetMorph (src/motion-primitives/AssetMorph.tsx) is the reference special component: it composes StickGroup (primitive) + IconAsset (asset) + SparkleBurst (fx) into one frame-driven parametric→asset morph. New special components follow its shape.
The decision rule (per visual demand)
For every visual a KP needs, walk the rule and STOP at the first hit:
REUSE — an existing catalog entry already covers it (name it from src/capabilities/catalog-digest.md, incl. the 70+ <IconAsset> names). Default answer.
COMPOSE — existing primitives/assets composed in the lesson scene cover it. No new capability; note the composition.
BUILD a primitive — the demand is a NEW teaching atom that must count / progress / preserve identity / morph. Hand-code it parametric.
BUILD a special component — the demand is a recurring combination of pieces + a self-contained animation (a beat that more than one lesson will want). Author it as a composite.
MAKE an asset — the demand is a fixed-form decorative/representational object (no count/progress/state). IMPORT from the library if present; else GENERATE (trace pipeline, author-time) OR compose existing primitives. Never an asset for a teaching atom.
A "gap" is only real when steps 1–2 miss. Over-building is the failure mode — most demands REUSE.
Never reach for a status: deprecated capability — it is quarantined into the digest's "Deprecated" section and the gallery's Legacy band precisely because it is not the right way; use its supersededBy replacement instead (e.g. bundle-wrap → asset-morph).
Reading the curriculum (the demand source)
Content lives in /Users/tk/Desktop/Omniscience/curriculum_snapshot/*.json (人教版 Math G1–6, 统编版 Chinese G1–6, 人教版PEP English G3). Shape:
To extract VISUAL DEMANDS from a KP: read its content + the matching common_difficulties. The content names what must be SHOWN (objects to count, a number to write, a comparison to make); the difficulty names what the visual must make unmistakable (e.g. "无法有序观察" → an ordered-counting pointer; "同一数字表示不同事物" → a one-to-one set across DIFFERENT object kinds → asset variety + a cardinality special component). Tie every demand to a (sectionCode, kpTitle, importance, difficulty?) so the gap is justified, never invented.
The gap record (what each demand becomes)
{"demand":"show N different objects, each tagged with its count, to teach cardinality is kind-independent","from":{"section":"1.1","kp":"1~5的基数含义","importance":"key","difficulty":"同一数字表示不同事物"},"decision":"reuse | compose | build-primitive | build-special-component | make-asset","layer":"asset | primitive | special-component | (none if reuse/compose)","reuseId":"<catalog id, if reuse>","spec":"for a build: the component name, the prop-driven API (props that vary; NO baked topic), the pieces it composes, the self-contained animation, and the single hardest test frame + worst-case multiplicity to render."}
Authoring + registration (per layer) — REUSE the registry loop
Before authoring any build, follow the two-step component-creation law in primitive-builder/SKILL.md §"Building a named gap": (1) load the craft + concept skills, (2) design around the component's ONE teaching intention and draw only elements that serve it. A component is single-purpose for a concept — never a grab-bag of unrelated jobs, never a baked-in uncorrelated overlay/arrow/celebration/ring/tally, never a flourish that defaults on instead of being an explicit opt-in the caller requests. A special component COMBINES pieces, but it still has ONE teaching intention and composes only the pieces that serve it — combining is not licence to merge whatever is on hand. The decision rule above names WHICH layer; that law names HOW to build it.
The registry is code-as-truth and drift-gated: an exported-but-unregistered capability FAILS npm run registry:check and cannot be committed. Follow capability-registry-harness + the lesson-build W3b protocol exactly.
Primitive (src/shape-primitives/):
Implement in the right FAMILY file (counting/literacy/interaction/sketch.tsx) — prop-driven, lesson-agnostic (NEVER hardcode a topic, a Chinese string, or a specific value; everything comes from props). A brand-new standalone file is a stranded export that fails the gate; only add a family by registering MODULE_KIND+KIND_ORDER (build-registry.mjs) AND the kind union (schema.ts) AND KIND_ORDER/KIND_TITLE (catalog-digest.mjs).
Export the component + public types from src/shape-primitives/index.ts.
npm run registry:build → writes the catalog entry's structure + digest.
Author prose (intent/useWhen/avoidWhen/variants, flip status off undocumented) in src/capabilities/primitive-registry.json; re-run registry:build.
Add a demoProps entry for the component in src/component-gallery/demoProps.tsx (a centered render() + short key-variant strip; PLUS a unit = one instance at the component's DEFAULT size for a group-primitive). The gallery's true-size view renders it at 1:1 inside the 1280×720 frame (one unit + the typical group, or a composite's focal render) — VERIFY the default reads at a focal size there; if too small, raise the component's default size and re-render (don't ship a speck, don't fake it with a footprint number — kids-eye §1.6). A registered component with no demo FAILS registry:check via the gallery gate (check-gallery.mjs), so the Component Gallery is always complete.
npm run registry:check GREEN.
Special component (src/special-components/<Name>.tsx): same loop (incl. the step-5 demoProps entry), exported from src/special-components/index.ts and registered in the specialComponents[] tier. It COMPOSES registered primitives/assets/fx + named EASE.*/SPRING.* motion — ZERO raw motion literals, ZERO frame literals (its public API takes atFrame/startFrame/progress + cue-relative offsets from the caller; it never reads a master-timeline literal). Until the specialComponents tier exists, a composite MAY register through the motion-primitives barrel (the AssetMorph precedent) — name it in the spec.
Asset (public/icons/): IMPORT from the origin library if it exists (scripts/import-origin-icons.mjs) OR generate author-time (trace pipeline) OR compose. Land <name>.svg + mono/<name>.svg + <name>.meta.json (category + desc), then npm run icons:build (auto-emits asset-catalog.json + digest). Assets are committed (tiny + canonical).
Self-verification (every builder, before declaring done)
Render test stills at REAL render size: the single hardest frame AND the worst-case multiplicity (e.g. a primitive at 10×). A primitive that looks flat/ambiguous is a gap-filler bug — fix it here, never downstream. Use the gallery or a focused still.
npm run registry:check GREEN (or icons:build for assets) — this now includes the gallery gate, so a missing demoProps entry fails the check.
The capability is lesson-agnostic and reusable: prove a second imagined caller could use it with different props. If it only fits one lesson, it's mis-scoped — it's scene composition, not a capability.
Workflow shape (how this skill is orchestrated)
.claude/workflows/capability-gap-filler.js: Scope (index curriculum → sections) → Demand (one subagent per section: KP content+difficulties → visual demands) → Gap (barrier: dedup demands, diff vs catalog-digest.md → classified gap set) → Build (one subagent per gap; DESIGN fans out in parallel, REGISTER is serial because the barrel + registry:build + icons:build write shared files and parallel builds race) → Verify (registry:check + gallery QC + a completeness critic that asks "what curriculum demand is still uncovered?" — its answer is the next run's input). dryRun stops after Gap with the report, building nothing.