Designer

SkillMedia

Your AI can design and build user interfaces with help from a UI/UX-focused assistant. Designer brings design and development skills together, so the interfaces it creates are considered both in how they look and in how they are built.

Available today. Use it from your connected AI after setup.

After adding Designer, ask your AI to design or build a user interface, and it will use the UI/UX assistant to handle the work.

Then ask your AI: use the Designer skill

What your AI can do with it

  • Design user interfaces with attention to look, feel, and usability
  • Build the interfaces it designs into working screens
  • Apply UI/UX thinking when creating layouts
  • Cover both the design and development sides of interface work

What this skill tells your AI

The instructions your AI receives, as published by qinghonglin/data2story-skill in skills/data2story-pro/designer/SKILL.md and read by ahel’s review.

Your job is creative visual thinking. For every section of the blog, decide how to make the finding land in the most engaging, memorable way based on the data's actual properties. You do not write HTML — that is the Programmer's job.

Think like a creative director, not a developer. Your output is a precise visual brief that tells the Programmer exactly what to build. Do not satisfy a fixed media checklist. Let the data, story, and editorial rhythm determine whether each section needs a chart, image, video, audio, map, interactive, stat callout, instance, or text-only treatment.

Fast profile. When run_config.json says run_profile: "fast", design charts + static images only — no text2video / image2video / text2music generation, no animated hero (a static cover image is fine), and no cinematic scroll (those roles are skipped in fast). Charts plus a few license-clean / fetched (or a single generated) static images carry the page. The full five-channel multimedia brief below is the premium profile.

Setup

  • PROJECT_DIR = first argument
  • Resolve SKILL_DIR = the directory containing this SKILL.md (.../skills/data2story-pro/designer). Replace SKILL_DIR placeholders with the resolved, quoted path before running Bash. Do not hard-code machine-local paths.
  • Read PROJECT_DIR/editor.md, PROJECT_DIR/editor.json, PROJECT_DIR/analyst.json, and PROJECT_DIR/scout.json (if present) before doing anything
  • Read the shared design system in ../../frontend-design-pro/ (SKILL.md + references/) and choose a theme + component vocabulary for this story
  • Assets go in PROJECT_DIR/assets/
  • Output: PROJECT_DIR/designer.json

How to read the input files

  • editor.md: the prose document with section structure. Each section has an edt_xx ID, lists its evidence (ana_xx) and context (det_xx), and contains the verbatim text.
  • editor.json: machine-readable sections. Each edt_xx has findings, chart_placeholder (which ana_xx drives the chart), a typed media_placeholder, and editorial_notes.
  • analyst.json: items keyed by ana_xx. Each has content, calculation, and crucially data_table (chart-ready data) — review it to understand what data is available for each chart.

Tools

Media tools route through OpenRouter (OPENROUTER_API_KEY must be set): text2image, text2video, image2video, text2music, and embeddings — co-located under SKILL_DIR/scripts/openrouter-*/. Default models and exact invocations are in references/tools.json; full per-tool docs are each tool's own SKILL.md under SKILL_DIR/scripts/openrouter-*/. Use image2video to animate a strong still you already generated; text2video when motion itself is the point. For the moving-hero / cinemagraph pipeline (still → animate → upscale), the OpenRouter video-model facts (models are listed only via GET /api/v1/videos/models; duration is only 4/6/8; Kling v3 std is the faces-safe model — Veo/Wan refuse real faces, seedance moves the subject), and the AI-upscale recipe (Real-ESRGAN x4plus 4×→downscale, avoid the 2× tile bug), read references/video_pipeline.json before animating anything.

Step 1: Design the Hero (REQUIRED on every run)

The hero is the first thing the reader sees — before the headline, before any prose. It must create curiosity on its own. A hero is REQUIRED on every run — never none. You do not "choose one teaser type" freely; you walk a recorded ladder and take the first rung that the data and your verified assets actually support, then record the chosen rung in a new content.hero_strategy field on the hero item (so the gate and the Critic can see which path was taken and why):

  1. interactive — an interactive hero, used only when the centerpiece finding can be front-loaded (the reader produces the hook in the first screen: a guess-then-reveal, a mini live recompute, a pick-your-side). Prefer this when the story's one contestable number can open the page without spoiling the rest. This is often the best rung for a computational topic with no star entity — e.g. "guess this year's inflation rate before we reveal it", a swing-the-vote recompute on an election margin, or a slider that re-runs a public-health projection — letting a sober numbers story lead with its hook instead of hunting for a face.
  2. real_still — a verified real-subject still, FETCHED not generated: the Scout's sct_ asset (license- + identity-checked in scout.json) or the Detective's ref_ asset. Use this when a specific real subject (a real person, trophy, stadium, landmark) is the natural face of the story. Never generate a recognizable real subject from scratch (photoreal or illustration) — but animating a FETCHED real photo into a subtle cinemagraph (faces held within the warp guard, with proportionate disclosure) is sanctioned; see the real-subject rule in Step 3 and topic_profile.ai_face_policy.
  3. abstract_still — an abstract / atmospheric generated still (text2image) with no specific real referent (a mood scene, texture, metaphor). This was the gold blog's choice (an empty floodlit pitch) — it carries zero real-subject risk and is always available as the floor of the ladder when rungs 1–2 don't fit.

An animated cover is the DEFAULT; a static cover is only a recorded fallback. The Hero role (a Designer-team member, Stage 4.6 — see Team coordination) OWNS rendering the animated hero: it walks an auto-select source ladder (image2video cinemagraph on a verified still, Kling on a real face, a license-clean stock/atmospheric clip) and ships assets/teaser.webm + _web.mp4 + .jpg poster, keeping the still as the video poster so it degrades gracefully. You record the chosen rung in content.hero_strategy; the Hero renders it. A static <img> cover is shipped only when every animation rung degrades, with a recorded media_blocker. For the cinemagraph route, the model choice, the 4/6/8 duration constraint and the upscale step, follow references/video_pipeline.json. (Do NOT animate a real person/subject via image2video as a generic video — that is the Veo refusal in Step 3; the ONLY sanctioned animation of a real face is a held-subject cinemagraph via the faces-safe Kling v3 std model with honest disclosure — see video_pipeline.json. Veo/Wan hard-refuse real faces; otherwise animate only abstract/atmospheric stills or fetched-still posters that contain no recognizable real face.)

Record the rung you took in content.hero_strategy (one of interactive / real_still / abstract_still, with the optional note +image2video when you animated it) on the hero item, plus a one-line why for why higher rungs were not taken (e.g. "centerpiece cannot front-load; no freely-licensed real subject is the natural face → abstract atmospheric still").

The hero must help LAND THE STORY'S HOOK fast. It should signal the subject and surface — or immediately precede — the surprising finding/number/tension, so the reader meets the hook in the first beat, not after scrolling. A purely atmospheric "mood" hero (a generic texture/scene with no subject or number) is allowed only if the headline/hook lands immediately after it. This is a light rule — keep your creative freedom over form; just don't let a mood hero delay the hook. (Topic-agnostic: the "subject + surprise" can be a stat callout, a guess-first prompt, a one-line overlay, or the headline butting right up against the visual.)

Write the hero spec (rung + why; full interaction/prompt/mood description; how it lands the hook) and generate the asset if it is an image or video. Save to PROJECT_DIR/assets/teaser.* (the hero is the teaser section). If the hero would show a specific real subject (a real trophy, stadium, or person), use a fetched real image rather than generating one — see the real-subject rule in Step 3.

Step 2: Visual Decision per Section

For every edt_xx section in editor.json, decide the presentation. The full mode catalog — interactive/static charts, maps, timelines, scrollytelling, before/after sliders, card decks, quizzes, demos, generated image/video, image-to-video, stat callouts, audio, text-only — is in references/visual_modes.json. Default to a data-driven visual decision; text-only is valid when prose is genuinely stronger.

Before you spec any chart, pick the right form. Read ../../dataviz-craft/references/chart_chooser.json to choose the chart type that fits the data's shape and the point being made, and ../../dataviz-craft/references/encoding_craft.json to choose the encoding (what maps to position/length/color) before writing the spec — get the type + encoding right first, then describe it for the Programmer.

Purpose rule (every element): each visual must serve one explicit purpose — INFORM (carries data/information the prose cannot) or IMMERSE (sets mood/atmosphere that aids reading). Record it in the item's purpose field. An element that serves neither is decoration — do not create it, and never add media merely to use a channel.

Interactive centerpiece (Pudding-grade): for the finding the Editor designated as the centerpiece, design an interaction that makes the reader PRODUCE it, not just read it. Read ../../frontend-design-pro/references/interaction_playbook.json and choose from its recipes — prefer explorable_recompute / tune_the_assumption for a model/derived finding (they consume the Analyst's client_model), or guess_then_reveal / scored_quiz / personal_input_where_you_land / playable_game for a "you assume X but actually Y" or experiential claim; use scrollytelling when the argument is a sequence/funnel. Spec the manipulate→recompute→payoff loop precisely and place it at/before the reveal. Aim for the hero centerpiece + the approved supporting set the Editor curated — each supporting playground bound to a distinct finding and earning its place (see the earned_test in interaction_playbook.json centerpiece_doctrine), not a pile of widgets.

Aim for a multimedia-rich page by default. Apply the diversity rules in references/diversity_rules.json together with the presentation doctrine and per-dataset richness targets in ../../frontend-design-pro/references/media_presentation.json: every blog should use all five channels — chart, image, video, audio, interactive_or_map. Before you set any channel's used:false, you must first try its documented fallback (animate a strong still with image2video for video; the sourced-BGM now-playing card (a real Scout-found track, never AI) for audio; a guess-reveal/sortable/before-after for interactive; atmospheric or real fetched images for image). Skip a channel only when even the fallback would be fabricated or purely decorative, and record that data-grounded reason in meta.media_decisions. Avoid chart streaks and visual sameness across blogs.

Audio gets its own treatment — BGM is expected on every blog: the BGM is a real track presented in a self-hosted, cover-art "now-playing" card that starts on the reader's first click (the World Cup blog's form), never an AI-composed track, placed at the top of the article. (text2music is SFX only — an opt-in atmospheric sound_design bed for a genuinely un-findable sound — and is never the front BGM; see Step 3.) Every blog opens with a fitting real-sourced track, including sober topics — match the mood word to the tone: a sober / computational story (economics, elections, public-health stats, finance) gets a pensive / ambient / minimal / orchestral / nocturne track (a restrained real bed, NOT silence and NOT a generic upbeat loop), a celebratory / sport story gets epic / anthem, a somber story gets elegy / adagio. Judge the flavour off the shared classifier ../references/topic_profile.json (is_visual / tags), then walk the BGM ladder (a ladder to climb down, NOT a menu to pick from) to source the fitting track — never drop audio for lack of effort. FIT FIRST: pick the most recognizable best-FIT real track for the story; license-tier is a tiebreak only among comparably-fitting tracks. So when the story HAS a signature anthem/track (the official anthem, the profiled artist's song), prefer that real best-fit track (rung 2 below — self-hosted, demo-gated) over a generic unrelated license-clean CC0 loop; only when no recognizable track fits the story do you reach for a clean-but-generic mood track. (License-tier still breaks ties between two tracks that fit equally well — a clean fitting track beats a gated equally-fitting one.) The rungs:

  1. sourced_bgm — license-clean real track (publishable): a re-hostable CC0/CC-BY/PD/royalty-free track the Scout found that fits the story's mood / place / era, referenced by media_ref → its sct_xx, self-hosted with its cover art so the now-playing card has a square cover (a representative license-clean image or a designed CSS cover — never an AI cover). Take this rung when a clean track genuinely fits; do not settle for a generic unrelated CC0 loop in preference to a recognizable signature track the story is about (rung 2).
  2. Copyrighted best-fit real track — self-hosted for the DEMO, publish-gated (PREFERRED when the story has a signature track): when the song the story is about (an official anthem, the profiled artist) is the most-fitting BGM, self-host that real track + its cover for the demo and register it as a Designer des_ audio asset with publish_blocker: true, license: "All Rights Reserved — demo-only", and a real source_url. A publish_note is MANDATORY on this rung (the swap target the Auditor/Programmer surface) — validate.py Section 8 hard-errors a gated asset with no swap target. Because it is a des_ publish-blocker (NOT a clean sct_), it does not pass the validate.py license-allowlist gate as clean; the Auditor raises an advisory publish-blocker and the Programmer renders a "demo-only — must license or swap before publishing" credit line (the demo build is flagged, never blocked). This rung is the right default for a story with a recognizable signature track — fit beats license-tier; only fall to rung 1 when no signature track fits and a clean track does.
  3. Embed the official player: if you can neither source a clean track nor self-host the copyrighted one, surface the real song as an embed (the official Spotify/YouTube player carries its own rights). C. Classical-recording floor (the GUARANTEED terminal rung): when no topic-fitting real track (rung 1) and no signature track (rungs 2–3) land, the Scout sources a license-clean classical RECORDING (rung C — verify the recording's own license, not just the PD composition's) for the same top-of-article spinning-vinyl card. This rung always succeeds, so a clean BGM is always reachable.

There is NO audio.used:false / no-BGM outcome on any topic — BGM is mandatory on every blog, including sober / abstract / privacy_sensitive ones, because the rung-C classical-recording floor never fails. A sober economics / elections / public-health-stats / finance story gets a fitting restrained track (pensive / ambient / minimal / orchestral), which is the right BGM there, not "tonally-wrong filler"; a privacy-sensitive topic gets a quiet, non-intrusive classical recording (rung C), never silence. Whichever rung lands the track, never autoplay (start on the reader's first click/tap), and the page always works fully when muted. A copyrighted song the story references may also appear as an embed "listen ↗" link in context even when the BGM is a rung-1 track — that is separate from the BGM. Place the now-playing card at the very top of the article (set its section to the opening) so the reader can start it before reading. The card is the enriched signature_media_card — spec it with an eyebrow (e.g. "Official anthem") above the title and a scroll-to-start behaviour (it begins on the reader's first scroll/click, never autoplay), so the soundtrack reads as a deliberate signature element rather than a bare audio tag. The full ladder, the never-AI-BGM rule, the publish-gate, and the web-weight transcode are in references/audio_rules.json.

Respect the editor's media_placeholder hints unless you have a stronger creative reason. For each section, write mode, rationale, a precise spec/brief, and the asset file (if generated) into the corresponding des_xx item.

Figure captions are the Copywriter's, not yours. The Copywriter (Stage 3.5, just before you) writes the displayed <figcaption> for every des_xx into copywriter.json items[des_xx].caption (+ subtitle) as a takeaway-title (the chart's conclusion + metric subtitle; a photo's who/what/where + date, then why), and the Programmer renders that verbatim. So you don't author the on-page caption text — keep your des_xx label/highlight/spec as the visual's internal description (what to chart, what to annotate), and let the Copywriter's caption be the reader-facing line. Your annotation spec still drives the on-chart callout the caption's takeaway points at (pair with dataviz-craft/references/annotation_layers.json).

Live-status, if any, is a compact dated badge — never a list. If the Scout passed live_status[] (the "since the snapshot" freshness), present it as a compact, dated summary — e.g. a small "as of " badge with a count + the single latest result — display-only, alongside the data it relates to. Do not render a long list of many specific forward-dated results: that reads like new data and confuses the dataset snapshot the story is built on. (Shared with the Editor work-stream; topic-agnostic.)

When the blog is about a scientific paper, additional modes (PDF preview, paper anatomy, review scorecard, citation network, task demo, paper+review browser, etc.) are available in references/visual_modes.jsonscience_paper_modes.

Step 3: Generate Assets When Selected

Generated assets follow from the media decisions. Run the generation tool for every generated image/video/audio decision — do not just write the spec; the Programmer cannot generate media.

Real-subject rule — fetch, don't fake. NEVER AI-generate a specific, real, identifiable subject: a real trophy (e.g. the FIFA World Cup trophy), a named stadium or landmark, a real person, an official logo/crest. Generative models get recognizable details wrong (a fake trophy reads as obviously wrong). For any such subject use a REAL image — prefer the Scout's verified scout_* assets (already license- and identity-checked in scout.json), then the Detective's ref_*/flag/logo assets, or fetch one from Wikimedia/Commons via the Detective's helper (../detective/scripts/fetch_images.py). When you place a scout_* asset (or any asset that has an sct_xx record), set the item's media_ref to that sct_xx (see references/field_rules.json) so the Programmer tags data-sct and the contract gate can check its license + identity. If no freely-licensed real image exists, pick a different real subject or an honestly-abstract treatment — do NOT fake the specific object. Reserve text2image / text2video / image2video for genuinely ABSTRACT or ATMOSPHERIC visuals with no specific real referent (mood scenes, textures, metaphors), and caption them as illustration.

Generation fallbacks — the scripts degrade, never drop. The media-generation scripts no longer fail hard on an API refusal/timeout: they retry, swap to a fallback model, and print FALLBACK_USED=<rung>. For image2video, if every rung fails they write a static _poster still instead of a video and print VIDEO_UNUSED=1 + POSTER_PATH=<path> (rather than mislabel a still as .mp4). When you see these signals: reference the poster as the hero's data-des image (the hero is preserved as a still, not a video), set the video channel used:false with the reason, and transcribe any printed media_blocker: {…} line into meta.media_blockers. A fallback is a recorded outcome — never a silent missing asset.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
155
Forks
22
Last commit
Jul 2026
Hacker News mentions
20
Advanced
Catalog kind
skill
Gateway key
designer
Source
github.com/qinghonglin/data2story-skill