# Presentation

> >

- **Type:** Skill
- **Install:** `agentstack add skill-codagent-ai-and-scene-presentation`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Codagent-AI](https://agentstack.voostack.com/s/codagent-ai)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Codagent-AI](https://github.com/Codagent-AI)
- **Source:** https://github.com/Codagent-AI/and-scene/tree/main/skills/presentation

## Install

```sh
agentstack add skill-codagent-ai-and-scene-presentation
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Presentation skill

Build **evolving-scene presentations**: one shared diagrammatic canvas where
entities morph across steps while captions and navigation guide the audience.
Each presentation is a self-contained folder under `src/presentations//`
that composes the reusable **scene kit** at `src/presentation-kit/`.

## When to use

- User asks to create, build, or generate a presentation or talk
- User asks to modify, update, or add steps to an existing presentation
- Project lacks the scene kit or presentation infrastructure and needs bootstrapping
- User asks to update, resync, or pull the latest scene kit into a project whose
  vendored `src/presentation-kit/` has fallen behind the skill (see
  [Updating the vendored kit](#updating-the-vendored-kit))

## Procedure

Work through these phases in order. Do not skip self-verify.

### 1. Gather requirements

Ask **one question at a time**. Cover:

1. **Topic** — what the presentation is about
2. **Visual style** — accents, mood, density (sparse diagram vs. rich layout)
3. **High-level sections** — the major parts of the story, in order
4. **Each step** — after the sections are agreed, flesh them out one by one.
   A "step" means one navigable beat in the presentation: the caption/title plus
   the scene state shown for that moment.
5. **Per-step visuals** — which entities appear, how they relate, and what
   morphs between steps

Rules:

- Do **not** assume details the user can still provide
- Allow the user to proceed with **partial detail** and iterate later — no hard
  completeness gate
- Do **not** start by asking how long the talk should be or how many steps it
  should have. First establish the high-level sections, then expand each section
  into steps. Ask about length/count only after that structure exists, or when
  the user explicitly asks the agent to decide or fill in details.
- If the user says the length/count is TBD, accept that and continue by shaping
  the high-level sections before implementing any steps.
- Define skill-specific terms the first time they are used in user-facing
  conversation. For example: a "step" is one navigable beat of the talk; a
  "hero" entity is the main visual object that carries continuity across the
  scene. Do not front-load a glossary; define terms just before they matter.
- If the prompt already contains topic, style, and all step details, proceed to
  scaffold/generate without further questions
- For **key or complex steps**, optionally draw an **ASCII mockup** of the layout
  and ask the user to confirm before building. Use mockups selectively, not for
  every step

### 2. Resolve target + scaffold if needed

Before creating or modifying a presentation, ensure three **contract anchors**
exist. Detection is **contract-level** (presence of the anchor, not byte-identical
files). Cosmetic differences do not trigger re-scaffolding.

| Anchor | What to look for |
|--------|------------------|
| **Build setup** | `vite.config.ts`, `package.json` with a `build` script |
| **Scene kit** | `src/presentation-kit/types.ts`, `Presentation.tsx`, `Stage.tsx` |
| **Presentation index** | `src/presentations/index.ts` exporting a `presentations` registry |

**Target resolution:**

| Context | Scaffold location |
|---------|-------------------|
| Empty directory, or an existing standalone JS app (a `package.json` at the root, non-monorepo) | Repository root (`.`) |
| Monorepo (`workspaces` in `package.json`, `pnpm-workspace.yaml`, or `packages/` / `apps/` layout) | Self-contained app under `presentations/` |
| Non-empty repo that is **not** a JS app (no root `package.json` — e.g. a Python/Go/Rust project) | Self-contained app under `presentation/` |
| Anchors already present | Use existing app; scaffold only missing anchors |

**Monorepo detection signals:** `package.json` `workspaces`, `pnpm-workspace.yaml`,
or files under `packages/` or `apps/`.

**Why non-JS repos nest:** the bootstrap is a full Vite + React app. Dropping its
`package.json`, `vite.config.ts`, and `src/` at the root of a Python/Go/Rust repo
would collide with the existing project, so the scaffold lands in a dedicated
`presentation/` subfolder instead. Only a truly empty directory or a repo that is
already a JS app gets scaffolded in place at the root.

**Scaffolding steps:**

1. Determine which anchors are missing (all, some, or none)
2. Copy missing pieces from `templates/bootstrap/` in this skill directory.
   Template paths are relative to this `SKILL.md` file, not necessarily to the
   user's current working directory.
   The bootstrap `package.json` ships a neutral `presentation-app` name —
   rename it to suit the target project (e.g. the repo or monorepo package
   name) before installing.
3. **Install dependencies** — never assume they are present. The scaffold must
   ensure this full set:
   - **Runtime:** `react`, `react-dom`, `motion`, `lucide-react`
   - **Dev/build:** `vite`, `@vitejs/plugin-react`, `typescript`,
     `@types/react`, `@types/react-dom`, `@types/node`, the eslint stack
     (`@eslint/js`, `eslint`, `eslint-plugin-react-hooks`,
     `eslint-plugin-react-refresh`, `globals`, `typescript-eslint`), and
     `playwright` (for render checks)
4. Run `npm install` in the resolved target directory

**Non-empty project without scaffolding:** state the resolved target location
(e.g. "I will scaffold into `presentations/`") and proceed only after the user
confirms.

**Already scaffolded:** skip scaffolding and go directly to generate/modify.

Utility helpers in `scaffold.ts` (alongside this file) implement anchor
detection, monorepo heuristics, and target resolution for automated checks.

### 3. Generate or modify

#### Create a new presentation

1. Derive a **slug** from the title (kebab-case, e.g. `how-to-use-this-skill`)
2. Create `src/presentations//` from `templates/presentation/`:
   - `entities.ts` — stable `layoutId` namespace for every morphing entity
   - `steps/*.tsx` — one file per step; each exports a `Step` object
   - `Talk.tsx` — imports all steps, renders ``
3. Add presentation-owned styling if the user wants a designed look. The kit is
   BYO styles: no colors, fonts, borders, spacing scale, or framework defaults
   are provided by the scaffold. Default to plain CSS in a presentation-local
   stylesheet. Use Tailwind or another styling system only when the host project
   already uses it or the user explicitly requests it.
4. Register in `src/presentations/index.ts`:

```ts
{
  slug: '',
  title: '',
  load: () => import('.//Talk'),
},
```

5. Preserve all existing registry entries — new presentations must not break others

#### Modify an existing presentation

1. **Identify the target** from the user's request
2. If unspecified or ambiguous, **lists the existing presentations** from
   `src/presentations/index.ts` and asks which to modify
3. Ask only about the **requested changes** (steps, entities, style) — do not
   re-walk the full create flow
4. Make scoped edits to that presentation's `entities.ts`, `steps/*`, or `Talk.tsx`

### 4. Self-verify

Before reporting success:

1. Run `npm run build` in the presentation app directory — must complete with no
   type errors
2. Run a **render check** on the presentation route — at minimum, the first step
   must render without runtime or console errors. Use `npm run verify` when
   available (full multi-step check), or start `npm run preview` and open the
   route in a browser / Playwright
3. Run a **visual composition check** in a browser. Capture or inspect
   screenshots of the first step, the last step, and any dense/key steps at a
   normal desktop viewport; for responsive-sensitive presentations, also inspect
   a narrow viewport. Prefer `npm run inspect -- ` when available; it
   writes project-local screenshots under `artifacts/presentation-inspection/`
   so Playwright resolves from the project's installed dependencies. The helper
   waits for morph/fade animations to settle before each screenshot and prints
   advisory warnings for text/chrome collisions, visually identical active
   navigation states, and unpolished attribution. Check the screenshots and
   warnings for accidental overlap, clipped/off-canvas content, unreadable
   stacking, missing active TOC/progress styling, and collisions with chrome
   such as captions, progress dots, table of contents, or navigation buttons.
   `npm run verify` catches crashes and console errors; it does not prove the
   scene is visually correct.
4. If any check fails, **fix the issues and re-check** — never report success
   on broken output

If Chromium is missing, run `npx playwright install chromium`. Do not run
`--with-deps` unless the environment has OS package privileges and actually
needs browser system dependencies.

### Output format

Report completion in this structure:

1. **Action** — created or modified, with presentation title and route (`/`)
2. **Files changed** — list of paths written or edited
3. **Verification** — commands run (`npm run build`, render check), visual
   composition check performed, and their result
4. **Follow-ups** — any unresolved questions or partial details the user may want to iterate on (omit if none)

## Updating the vendored kit

The scene kit is **vendored** (shadcn-style): every project owns a copy at
`src/presentation-kit/` rather than depending on a package. That copy does not
update itself when the skill does — there is no version to bump. When the skill
ships a kit fix (a new prop, a bug fix), a project's copy must be **resynced**.

The source of truth is the snapshot this skill ships at
`templates/bootstrap/src/presentation-kit/`, refreshed whenever the plugin is
updated (`claude plugin update`). The `sync-kit.mjs` script (alongside this file)
diffs that snapshot against a project's vendored copy and rewrites it on demand.

**When to resync:** the user reports the kit is out of date, asks to pull kit
updates, or a kit fix shipped in the skill needs to reach an existing project.

**Steps** (run from the consuming project root):

1. **Report drift** — diff the project's copy against the snapshot:

   ```bash
   node /sync-kit.mjs
   ```

   Exit `0` = in sync; exit `1` = files differ (the diff is printed). Local edits
   to the vendored copy show up as drift too — that is expected, like
   `shadcn diff`.

2. **Apply** — rewrite the project's copy to match the snapshot:

   ```bash
   node /sync-kit.mjs --apply
   ```

   Added and changed files are written; **target-only files are left untouched**
   (the script never deletes), so local-only additions survive. Pass an explicit
   path as the last argument to target a non-default kit location.

3. **Re-apply local theming, then verify** — if the project had local edits the
   snapshot overwrote, review with `git diff` and re-apply them. Then run
   `npm run build` and a render check (per [Self-verify](#4-self-verify)) before
   reporting done.

Resyncing the kit does **not** touch a project's presentations or its host
config (the `` props it passes) — only the kit files. If a kit
update adds a capability the host should opt into (e.g. a new slot), call that
out so the user can wire it up in their `Talk.tsx`.

## Composing the scene kit

Presentations import from `src/presentation-kit/`. Each presentation supplies
only its own entities and step scenes.

### Step contract

```ts
interface Step = Record> {
  id: string          // stable key for AnimatePresence
  era: string         // table-of-contents section label
  title: string      // presenter-mode one-liner
  caption: string    // browse-mode paragraph
  groupKey?: string  // consecutive steps with same groupKey are not remounted
  payload?: P
  Scene: ComponentType }>
}
```

For strongly typed grouped scenes, define a payload type and use `Step`
for the steps, scene props, and `` boundary
instead of casting each `payload`.

```tsx
type PhasePayload = { active: 'idea' | 'system'; count: number }

function GroupedScene({ step }: { step: Step }) {
  const payload = step.payload
  return {/* render from payload */}
}

const STEPS: Step[] = [
  {
    id: 'idea',
    era: 'shape',
    title: 'The idea appears',
    caption: 'A first shape lands.',
    groupKey: 'main-scene',
    payload: { active: 'idea', count: 1 },
    Scene: GroupedScene,
  },
]

export default function Talk() {
  return 
}
```

### Entity continuity (`layoutId`)

Define stable ids in `entities.ts`. Any node that should **morph** across steps
must use the same `layoutId`:

```ts
export const ENTITIES = { hero: 'hero', flow: 'flow' } as const
```

### Smooth morph authoring rules

The original reference implementation relies on authoring discipline as much as
kit code. Follow these rules when generating or modifying step scenes:

- Use a **persistent scene** with shared `groupKey` and `step.payload` for
  consecutive beats that represent one evolving diagram. Do not split a single
  evolving picture into many unrelated `Scene` components unless the whole
  composition should intentionally remount.
- Put stable `layoutId`s only on the entity that should morph. A new visual
  object gets a new id; the same conceptual object keeps the same id.
- Do not put transform or opacity styling directly on an element with
  `layoutId` (`scale`, `rotate`, `opacity`, or Tailwind equivalents such as
  `scale-*`, `rotate-*`, `opacity-*`). Motion uses transforms and opacity during
  layout projection; combine those on a child or wrapper only when it is not the
  shared layout entity.
- Do not put conflicting positioning styles on one element, especially
  `position: relative` plus `position: absolute` through mixed classes. For
  relative offsets, use relative positioning and offsets without adding
  absolute positioning; for true absolute placement, put the absolute
  positioning on a non-`layoutId` wrapper and verify the layout still matches
  the intended design.
- When fixing a smooth-morph issue in an existing presentation, preserve the
  intentional composition. If cards or callouts are meant to overlap, keep that
  overlap and move only the unsafe positioning/opacity/transform utilities to a
  wrapper. Do not flatten, spread out, or otherwise redesign the scene just to
  satisfy the wrapper rule.
- Use `Appear` only for newcomers. Continuing entities with a shared `layoutId`
  should persist and morph; they should not fade out and back in.
- **Let the layout re-center; do not pin it.** The signature move of an
  evolving scene is that each step lays itself out around whatever is currently
  on screen and then *re-aligns* when the next entity appears — one box centered
  alone, two boxes balanced, a row that spreads to frame the tray that grew
  beneath it. Because every entity carries a `layoutId`, those re-alignments
  animate for free. Achieve it by keeping the composition **content-sized and
  centered** (natural widths, `justify-content`/`align-items: center`,
  `align-self: stretch` to match a sibling's width), and let flow do the
  positioning. Do **not** freeze positions with fixed pixel/`ch` widths, fixed
  stage widths, reserved empty slots, or `align-items: flex-start` pinning —
  those hold entities still across steps and kill the re-centering, which is the
  most striking thing the framework does. If two entities must share an edge
  (e.g. a header row framing a panel below it), give them a shared width by
  construction (`align-self: stretch` against a common parent, or one CSS var
  both consume) rather than hardcoding a number. When you need to stop a
  *transient* overshoot during a swap (an exiting element and an entering one
  briefly widening a row), stack them in one grid cell — do not solve it by
  fixing the whole row's width.
- Keep browse-mode chrome in mind while composing scenes. The table of contents
  can occupy the left side on wide browse viewports, and captions/progress/nav
  occupy the lower band. Avoid dense horizontal rows that only fit the raw
  880px stage in isolation;

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Codagent-AI](https://github.com/Codagent-AI)
- **Source:** [Codagent-AI/and-scene](https://github.com/Codagent-AI/and-scene)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-codagent-ai-and-scene-presentation
- Seller: https://agentstack.voostack.com/s/codagent-ai
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
