imagineer

$npx mdskill add QinghongLin/data2story-skill/imagineer

Over-generate interactive concepts from findings for Editor curation.

  • Solves the need to ideate many hands-on concepts from data and narrative.
  • Depends on Analyst's client_model for feasibility checks.
  • Decides by generating one concept per finding worth making interactive.
  • Delivers imagineer.json with candidate concepts for the Editor.

SKILL.md

.github/skills/imagineerView on GitHub ↗
---
name: imagineer
description: "Fan out MANY candidate interactive concepts from the data + narrative — the ideation pool the Editor curates a hero + supporting set from. Deliberate over-generation: one concept per finding worth making hands-on, each declaring its archetype, purpose, what the reader produces, and an honest feasibility (node-checked against the Analyst's client_model). Builds NOTHING on-page — img_xx concepts are internal and never reach HTML. Outputs imagineer.json after the Analyst, before the Editor."
argument-hint: "[PROJECT_DIR]"
allowed-tools: Bash(*), Read, Write, Glob
---

# Imagineer

Your job is **ideation, not construction**. You read the findings and the narrative and you fan out a wide pool of candidate *interactive concepts* — ways a reader could **produce** a finding (run the model, guess-then-reveal, enter their own value, play the odds) instead of just reading it. You deliberately **over-generate**: propose one concept for every finding worth making hands-on, even the marginal ones. The Editor curates this pool down to a hero + a ranked supporting set; the Interaction Engineer builds only what the Editor keeps.

You build **nothing on the page**. Your `img_xx` ids are **internal** — a planning vocabulary the Editor reads. They never reach the HTML, are tagged on no element, and are added to no provenance tuple. Your one job is to make the candidate pool rich, honest about feasibility, and bound to real findings.

## Setup
- `PROJECT_DIR` = first argument.
- `SKILL_DIR` = the directory containing this `SKILL.md` (`.../skills/data2story-pro/imagineer`).
- Read `PROJECT_DIR/analyst.json` — its `items` give you the findings (`ana_xx`: `label`, `content`, `data_table`, and any **`client_model`**). The `client_model`s are what make `explorable_recompute` concepts feasible; note which findings carry one.
- Read `PROJECT_DIR/detective.json` — for the shared **[`topic_profile`](../references/topic_profile.json)** (the S3 classifier: `is_computational` / `is_visual` / `tags`) that gates how hard you fan out.
- Read `PROJECT_DIR/editor.md` + `editor.json` **if they already exist** (the spine — which finding is the lead, the section order); they may not yet, since you usually run before the Editor. When absent, work straight from `analyst.json` and mark the lead candidate yourself.
- Output: `PROJECT_DIR/imagineer.json` (write incrementally).

## When to run (and when to stay light)
Key this off the shared **[`topic_profile`](../references/topic_profile.json)** (the same two-condition default the Cinematographer uses, read from `detective.json`; if absent, classify the dataset yourself the same way and record it). The pool's size should track what the data can actually support:

- **Fan out widely** when **`is_computational` is true** (the headline is a reproducible calculation — a probability, rate, ranking, model output, aggregate): these are the findings a reader can re-run, so `explorable_recompute` / `tune_the_assumption` / `scored_quiz` concepts are all on the table. Propose several.
- **Fan out moderately** when **`is_visual` is true** but the lead is not computational: `guess_then_reveal` / `personal_input` / scrollytelling concepts still let the reader produce a finding without a model.
- **An abstract topic is still a first-class flagship target** — read **[`../../frontend-design-pro/references/abstract_excellence.json`](../../frontend-design-pro/references/abstract_excellence.json)** to choose the engagement + narrative moves before deciding how hard to fan out. When **`is_computational` is true but `is_visual` is false** (finance, web-analytics, elections, pure statistics, benchmarks), the page wins on insight + transparency, not photos: the runnable-verify layer FAVORS these topics, and an `explorable_recompute` / `tune_the_assumption` on the computed headline is strong hero material — propose them. Reach also for `personal_input` "where you land" whenever the data has rows the reader fits into (income, age, region, score).
- **Engagement floor (purely-descriptive sub-case) — now a HARD floor** — when **BOTH `is_computational` and `is_visual` are false** (no computed headline to re-run, no imagery): you **MUST propose ≥1 simple engagement-floor concept** — a `personal_input` / `personal_input_where_you_land` or a `sortable` (`sortable_table`) (a `scored_quiz` also qualifies) on a **descriptive** finding (where you land in the distribution, sort the catalog yourself) — so the Editor isn't forced to ship an empty/charts-only page. This is NOT forced decoration: the restraint still holds — do not force a concept onto a finding with no reader-producible payoff. The ONLY sanctioned way to ship **zero** interactives on a resolved descriptive topic is for an explicit `engagement_blocker` reason to be recorded (e.g. the data has no row a reader fits into AND no entity set to sort). You are the one who **proposes** that blocker, but the contract gate (`missing_engagement_floor`) reads the honored reason **only** from `interaction.meta` (NOT from your `imagineer.json`) — so your recorded reason is **advisory**, and the Interaction Engineer must **propagate** it into `interaction.meta.engagement_blocker` (alias `engagement_floor_reason`) for the gate to honor it. "Ship zero with no recorded blocker" is **no longer allowed**: it hard-errors at the contract gate (`missing_engagement_floor`). (`privacy_sensitive` topics are auto-exempt.) When you propose the blocker, note in **one** item why the pool is near-empty (a clean editorial column + the signature annotated chart is acceptable) so the Editor sees the omission is intentional, and STOP.

Record the resolved `is_computational` / `is_visual` in `meta` so the Editor sees the gate you applied. On a resolved descriptive topic where you propose shipping zero interactives, also record an **advisory** copy of the escape field in `meta` — `engagement_blocker` (the honest reason no reader-fits-in lever exists; the alias `engagement_floor_reason` is also read here) — as your proposed blocker for the downstream roles. This recorded copy is advisory only: the contract gate (`missing_engagement_floor`) does NOT read it from `imagineer.json` — it reads the honored reason from `interaction.meta`. The Interaction Engineer must write the honored `engagement_blocker` / `engagement_floor_reason` into `interaction.meta` for the gate to pass.

## Step 1 — Walk the findings, propose a concept per hands-on opportunity
Go through every `ana_xx`. For each finding a reader could plausibly **produce** rather than read, draft a candidate `img_xx`. Be generous — a marginal concept the Editor cuts costs nothing; a finding you never imagined can't be curated. Pick the `archetype` from the interaction taxonomy:

- **explorable_recompute** — the finding has a `client_model`: the reader changes an input and the output re-derives live. The strongest hero material.
- **tune_the_assumption** — the reader sets an assumption delta (a slider) → the model re-runs against the cached published baseline → deltas re-render. Generalizes a model-output headline.
- **guess_then_reveal** / **scored_quiz** — for "you assume X but actually Y": the reader commits a guess, then the real value (from the `data_table`) lands.
- **personal_input** — the reader enters their own value → pull their row / percentile from the `data_table` → "you're here."
- **playable_game** — the lightest self-contained loop that makes the finding *felt* (e.g. repeatedly choosing under the data's real odds, watching the aggregate converge to the published rate).
- **scrollytelling** — when one finding is a sequence/funnel the reader steps through.

Mark exactly the concepts that could carry the whole piece with `hero_candidate: true` (usually the explorable on the lead finding); the rest `false`. The Editor makes the final hero call.

## Step 2 — Bind each concept to a real finding + an honest feasibility
Every concept must be **earnable**, not aspirational:
- `finding` = the **single** `ana_xx` the reader produces. (Two concepts may target the same finding — that's fine here; the Editor's curation forbids two *built* supporting elements sharing one finding, but the ideation pool may explore alternatives.)
- `needs.data_table` = the `ana_xx` whose `data_table` supplies the at-rest published numbers.
- `needs.client_model` = the exact `code/<file>.js:fn` reference when the archetype recomputes, else `null`.
- `reader_produces` = one line on what the reader *generates* (not what they see) — "nudge a team's Elo, watch champion odds re-derive", not "a chart of odds."
- `sketch` = a one-line build hint (controls → output): "slider(Elo)+dropdown(team)+button -> animated bars."

## Step 3 — node-check feasibility (honest, not hopeful)
For any concept whose `needs.client_model` is set, **confirm the model is real and runnable** the way the Interaction Engineer does (`interaction/SKILL.md` Step 4): `node` a quick call to the referenced function with a plausible input shape, e.g.

```
node -e "const m=require('PROJECT_DIR/code/client_model.js'); console.log(m.simulate(200,{}))"
```

Set `feasibility`:
- **high** — the model runs and returns the expected shape (or, for a no-model archetype, the `data_table` is present and chart-ready);
- **medium** — plausible but needs a wrapper the Analyst hasn't emitted, or the `data_table` needs reshaping;
- **low** — the model errors, is missing, or the data can't support the concept honestly.

Don't inflate. A `low` concept the Editor sees and cuts is better than a `high` claim the Builder can't deliver. If a referenced `client_model` doesn't exist yet but the finding warrants one, record the concept at `medium` and note in `sketch` that the Analyst should emit it.

## Output — `imagineer.json`
Write incrementally (read-add-write). **Shape (consumed by the Editor + Interaction Engineer):** `items` is a dict keyed by `img_xx` (NOT a list). Full schema in [`references/schema.json`](references/schema.json):

```json
{
  "meta": { "role": "imagineer", "is_computational": true, "is_visual": true },
  "items": {
    "img_01": {
      "label": "Re-run the champion-odds model",
      "finding": "ana_01",
      "archetype": "explorable_recompute",
      "purpose": "INFORM",
      "reader_produces": "nudge a team's Elo, watch champion odds re-derive",
      "needs": { "client_model": "code/client_model.js:simulate", "data_table": "ana_01" },
      "feasibility": "high",
      "sketch": "slider(Elo)+dropdown(team)+button -> animated bars",
      "hero_candidate": true
    },
    "img_02": {
      "label": "Guess the gap before the reveal",
      "finding": "ana_05",
      "archetype": "guess_then_reveal",
      "purpose": "IMMERSE",
      "reader_produces": "commit a guess for the gap, feel the correction when the real value lands",
      "needs": { "client_model": null, "data_table": "ana_05" },
      "feasibility": "high",
      "sketch": "slider(your guess) -> reveal guess bar vs real bar from data_table",
      "hero_candidate": false
    }
  }
}
```

`purpose` is **INFORM** (the reader produces a number/insight the prose can't hand over) or **IMMERSE** (the reader produces a *feeling* — the correction lands, the odds shift under their hands). A concept that is neither is decoration — don't propose it.

## References
- [`references/schema.json`](references/schema.json) — full `imagineer.json` structure + field notes.
- [`../references/topic_profile.json`](../references/topic_profile.json) — the shared S3 classifier the "When to run" gate keys off (`is_computational` / `is_visual`).
- [`../../frontend-design-pro/references/interaction_playbook.json`](../../frontend-design-pro/references/interaction_playbook.json) — the `interaction_taxonomy` + recipes the `archetype` values name; read it to keep archetypes real.
- [`../../frontend-design-pro/references/abstract_excellence.json`](../../frontend-design-pro/references/abstract_excellence.json) — the POSITIVE flagship playbook for dry / abstract / computational topics (`is_visual=false`): the reframe hook, `personal_input` "where you land", the signature annotated chart, scale/analogy, the runnable-verify transparency lever, and the descriptive engagement floor. Read it whenever the topic is abstract.
- Reuse the feasibility-check pattern from `../interaction/SKILL.md` Step 4 (`node` a `client_model` call).

Done when the Editor has a rich, honest pool of candidate interactive concepts — each bound to a real finding, declaring its archetype + purpose + what the reader produces, with a node-checked feasibility — to curate a hero + supporting set from. The pool deliberately over-generates; the Editor decides what survives, and only what the Editor curates is ever built.

More from QinghongLin/data2story-skill

SkillDescription
analystExhaustively profile a dataset and list ALL possible analyses — distributions, correlations, rankings, trends, group comparisons, anomalies. Reads detective.json for context. Runs after the Detective/Scout, before the Editor. Outputs analyst.json with ana_xx IDs and chart-ready data_tables.
auditorAudit a generated Data2Story blog for build correctness across ALL modalities by ACTUALLY RENDERING it in a real headless browser (when available) — catching blank/0-width charts, broken/oversized media, desktop+mobile overflow, and dead interactions that source inspection cannot see — then having vision agents review the screenshots, playtesting every interactive, and walking the flagship capability contract. Plus VIEW every image for a wrong/AI-faked subject. Fixes layout in place; sends content-correctness problems back to the owning role. Use at Stage 6 after the Programmer assembles index.html and before the Critic; re-runs each revision round. Triggers: a built index.html exists, or you need to confirm charts/media/interactions actually render.
cinematographerDesign the MANDATORY cinematic scroll experience (every blog ships one): a full-bleed, scroll-driven background — primarily from the Scout's verified real imagery — plus the global motion choreography, so the narrative unfolds like a film as the reader scrolls. Owns the BACKGROUND layer + page-level motion (not the Designer's per-section visuals, not the Interaction centerpiece — it stages them inside the scroll). Outputs cinematographer.json (cin_xx scenes). There is no off path: a topic with no sourceable real imagery falls back to a generative-atmosphere or data-driven-spine background, never to a bare column.
copywriterName the piece — re-write the masthead (headline + standfirst + kicker), every section title, and every figure/photo/table caption to a research-driven titling standard, killing the AI-tell patterns (the 'flat statement. flat counter-statement.' two-beat above all) a competent default falls into. Reads editor.md/json + analyst.json + the resolved topic_profile; writes copywriter.json — STRINGS ONLY (masthead{headline,standfirst,kicker}, items{edt_xx:{title}, des_xx:{caption}}), each backed by a real ana_*. Names, never edits: it touches no finding, no number, no data-* id, no layout — so the Verify layer is untouched and the Programmer renders the masthead + figcaptions from copywriter.json verbatim. Runs at Stage 3.5, after the Editor, before the Designer.
criticReview a finished Data2Story blog against the 5 quality rubric dimensions (visual_design, narrative_pacing, data_method_transparency, claim_data_alignment, insight_value), score each 1-7 with on-page evidence, and emit critic.json with pass/fail + targeted, surgical send-back instructions. Verifies every load-bearing claim/asset against its traceability chain before scoring; applies the caveat-survival, honest-accuracy, and third-party-attribution caps. Does NOT rewrite content — scores and sends back. Use at Stage 6.5 after the Auditor and after verify.py has produced verifier.json; re-runs each revision round. Triggers: a built index.html plus verifier.json exist, or you need to judge whether the article is actually good.
data2storyData Journalist Agent (Data2Story) — orchestrator: turn a dataset into a blog. Runs detective → analyst → editor → designer → programmer → auditor → inspector in sequence. Creates a versioned project folder for each run.
data2story-proUse to turn a dataset into a verifiable multimedia blog (a data story / data-driven article / interactive dashboard from a dataset). Orchestrator for the Data Journalist Agent (Data2Story): a 7-team newsroom (14 agents) running detective → scout → analyst → imagineer → editor → copywriter → designer → interaction → hero → cinematographer → programmer → auditor → critic → inspector in sequence. Trigger when the user hands over a dataset (CSV/JSON/folder/path) and wants a published story, blog post, or interactive report built from it. Creates a versioned project folder per run.
dataviz-craftA shared reference library for editorial-grade data-visualization craft — Vega-Lite-first with a D3 fallback for charts Vega-Lite can't express. Read by the Designer at chart selection (intent → ranked chart type), the Programmer at implementation (editorial Vega-Lite recipes, annotation layers, axis/label de-clutter, encoding craft), and the Auditor/Critic for chart-quality review. It encodes the FT Visual Vocabulary intent taxonomy, the Cleveland–McGill channel-accuracy ordering, the BBC bbplot de-clutter ruleset, and colorblind-safe encoding rules. Not a pipeline stage — a craft source, like frontend-design.
designerRead editor.md, editor.json, and analyst.json. Make data-driven creative visual decisions for every section — teaser, charts, images, videos, audio, maps, and interactive demos when they fit the data. Generate selected assets. No HTML. Outputs designer.json with des_xx IDs.
detectiveResearch external context for a dataset — domain background, history, related studies, and why this data matters. Outputs detective.json (structured findings with det_xx IDs) before any analysis begins.