Generate a canonical <deck-*> Custom Element for this reveal.js presentation framework - a reusable slide widget defined once and referenced by tag: a D3 chart, a zoomable concept map / circle packing, an SVG diagram, a GSAP hero animation, or an interactive Alpine demo (stepper, quiz, meter, tokeniser-style click-through). Use when the user says "build me a component/widget", "new reusable slide element", "make a <deck-...>", "a chart/diagram/interactive component", "an animated demo", or "something reusable across slides". Creates components/<kebab>/index.js (repo root - deck content, not src/); src/components/registry.js auto-discovers it, no manual registration. Optionally emits a slide. Refuses to redefine a component that already exists.
Resources
1Install
npx skillscat add gregshallardau/ai-training-101/artefact-builder Install via the SkillsCat registry.
artefact-builder
Before anything: read docs/framework-conventions.md,src/components/README.md, and reference/component-styles.md.
The hard rule: compose from .box / .chip, don't reinvent them
Component implementations live at the repo-root components/ (deck
content, same standing as slides/); the base class, registry, and shared
style vocabulary they import are framework machinery in src/components/ and
never move.
Any generic card, tag, pill, or row-of-either need in a new component is.box / .chip (+ .token-row for a wrapping chip row) fromSHARED_STYLES (@/components/shared-styles.js) - import it, never copy
its rules (a hand-pasted copy is the one thing guaranteed to drift the next
time shared-styles.js changes). This is the same "compose, never invent"
instinct slide-builder enforces for slides, one layer down for components.
Bespoke component CSS is reserved for what those two tiers genuinely can't
express - SVG paths/connectors, canvas drawing, physics-driven layout (a
force-directed map and the like).
This is exactly what would have stopped two earlier components from each
independently declaring the same "row of chips" CSS as a bespoke .line
before .token-row existed in the shared vocabulary - import SHARED_STYLES
(which includes .chip and .token-row), don't re-derive them.
Inputs
- component name (kebab) -> tag
deck-<name> - purpose / behaviour
- which semantic custom properties it should consume
- observed attributes (name -> meaning)
- whether to also emit a slide, and roughly where (numbering delegated to
slide-builderconventions)
Read (detect state)
docs/framework-conventions.md,src/components/README.md,src/components/deck-element.js(base-class API).components/(repo root) - list its folders (this is the manifest;src/components/registry.jsauto-discovers whatever is here, there is no
separate list to parse). If acomponents/<name>/folder (ordeck-<name>
tag) already exists -> STOP. Print itsindex.jspath and offer to help
edit it instead. Never overwrite.src/styles/vars/semantic.css- parse:rootand every[data-theme]
block into the set of valid semantic names. Also parse rootdeck.css'sTOPIC COLOURSsection for any--topic-<name>/--topic-<name>-fgpairs
the deck has defined - these are also valid, deck-owned semantics, just not
insemantic.css. For each custom property the component wants: if there is
no matching semantic (tier-2 or--topic-*), warn, list the nearest
names, and do not invent a primitive - tell the user to extendsemantic.css/deck.css'sTOPIC COLOURS, or runskin-builder.slides/+slides/README.md- only if emitting a slide.Before hand-writing any chip/box/colour-modifier CSS, run
npm run check:vocab- it confirmsdeck.cssandsrc/components/shared-styles.jshaven't drifted. On failure, fixshared-styles.jsto matchdeck.css, never the reverse, before continuing.Pick the recipe for the artefact kind and read it:
Kind (from the purpose) Recipe chart, graph, plot, data-bound viz reference/d3-chart.mdconcept map, topics/ideas in space, circle packing, zoom-into-a-topic reference/d3-circle-pack.mddiagram, schematic, layers, flow, boxes-and-arrows, labelled picture reference/svg-diagram.mdhero title, section-break, one big entrance animation reference/gsap-hero.mdinteractive with its own internal state: quiz, game, tokeniser-style click-through reference/alpine-interactive.md0-100 circular fill, confidence/completion dial reference/radial-meter.mda number ticking up to a target on slide arrival reference/animated-counter.mdrow of big numbers with labels (KPI strip) reference/stat-tiles.mdhorizontal pipeline/process walkthrough, "you are here" indicator reference/timeline-stepper.mdhorizontal bars comparing a few labelled values reference/confidence-bars.mdanything else (badge, card, static widget) inline from reference/component-template.js
Write
Run
scripts/make-component.jsto do the mechanical scaffold - do not
hand-write the skeleton:node scripts/make-component.js --name <kebab> --kind <kind>(
<kind>is one of the Read-step-6 table's keys:chart,circle-pack,diagram,hero,interactive,radial-meter,animated-counter,stat-tiles,timeline-stepper,confidence-bars, orbasic.) It aborts
(matching the Read step 2 check) ifcomponents/<name>/already exists,
and writescomponents/<name>/index.js(repo root) fromreference/component-template.jswith<Name>/<name>substituted -SHARED_STYLESis already imported and prepended in the template. Use--dry-runfirst if unsure. Nothing else to register -src/components/registry.jsauto-discovers it at build time; the script
does not (and must not) touchregistry.js. This is the mechanical part
done; nothing here is kind-specific yet.Flesh out
render()/static stylesin the generatedindex.jsper the
recipe picked in Read step 6. Pull any further shared visual pieces fromSHARED_STYLES(button, chip, chip row (.token-row), note, meter, box) -
never re-declare a per-artefact class pile.optional:
slides/NN-<slug>.html-<section id="<slug>" data-slug="<slug>"><deck-<name> ...></deck-<name>></section>,
scaffolded viaslide-builder'sscripts/make-slide.js(numbering delegated
there, not re-derived here).
Never touch other components, src/components/* (machinery), src/styles/**,
or the root deck.css.
Procedure
- Reads above; if the component exists, STOP (the script also enforces this).
- Validate requested custom properties are a subset of the semantic set; halt on
any that is not (with near-matches). - Run
scripts/make-component.js(see Write step 1) to scaffold. - Fill in
index.jsper the chosen recipe:static observedAttributes(if
any),static styles(${SHARED_STYLES}plus semantic-var-only rules of
its own), idempotent render. - Optional slide, via
scripts/make-slide.js. - Report: new file path, how to drop the tag on a slide, and that
npm start
picks it up (auto-discovered, no registry edit needed).
Consistency
Enforce the existing-component check. Semantic custom properties only - never a
primitive, never a raw literal, never per-slide CSS, never a bespoke class pile
(import SHARED_STYLES from @/components/shared-styles.js, never copy its
rules - see component-styles.md). A component may import from @/lib/* (GSAP / D3
/ Alpine); keep D3 imports lazy. Alpine markup in a shadow root needsAlpine.initTree(this.shadowRoot) behind a ready-guard - seereference/alpine-interactive.md. Say "CSS custom property" / "CSS variable",
never "token".