AI Resources
SKILL.mdmarkdown
---
name: "PowerPoint"
description: "Create, edit, render, verify, and export PowerPoint slide decks. Use when Codex needs to build or modify a deck, presentation deck, slide deck, slides, PowerPoint, PPT, or visually ambitious editable .pptx file."
---

# PowerPoint

Use this skill whenever the user asks Codex to create, generate, edit, revise, improve, render, verify, or export a deck, presentation deck, slide deck, slides, PowerPoint, PPT, or PPTX file, unless the user explicitly requests a different slide skill or tool.

This is the internal PPTX workflow for visually ambitious editable decks.

## Core Contract

- Use the existing installed `@oai/artifact-tool` JS package which exists in the default Codex workspace dependencies node_modules for final deck construction, scratch preview rendering, internal editable-text verification, and `.pptx` export. Use the bundled workspace Node.js and Python runtimes for local builders and helper scripts.
- Run builder files from a writable conversation-specific temp or workspace directory, not from the managed dependency directory.
- For JavaScript builders, do not use `NODE_PATH`; ensure bundled packages resolve through normal Node package lookup from the builder file.
- If needed, create a local `node_modules` directory link or Windows junction to the bundled `node_modules`; do not copy bundled dependency directories or import internal package files directly.
- Prefer to use a single executable JavaScript builder (.mjs); patch and rerun the same builder file when iterating. Do not put script bodies in shell heredocs or inline shell script bodies, or keep extra workspace-local builder copies.
- Final user-facing response: Must include a short summary of the deck/slides created or edited, plus standalone Markdown link(s) only to final `.pptx` artifact(s). Use a Markdown link whose label is `<deck or slide title> - <filename>` and whose target is the platform-appropriate absolute filesystem path to the final `.pptx`. If there are multiple requested final decks, put each final `.pptx` Markdown link on its own line. Do not wrap final artifact links in backticks or code fences, and do not put them in bullets, headings, or prose sentences.
- The final response summary must describe only the user-visible result. Do not mention implementation details such as `artifact_tool`, artifact-tool, `@oai/artifact-tool`, the Node/JS builder, copied builder scripts, package manifests, export workflow, verification workflow, rendered previews, or internal tooling unless explicitly requested.
- Do not link to or mention support files such as previews, images generated by image-gen or fetched by web, narrative plans, verification records, scripts, package manifests, or scratch files unless explicitly requested. Keep support files on disk if useful.
- Do not display intermediate generated images, rendered preview PNGs, screenshots, contact sheets, or verification images in chat unless the user explicitly asks to see them. Save imagegen outputs and rendered previews as scratch files, inspect them privately, and surface only the final `.pptx` artifact link in the final response.
- If the artifact-tool Node environment is missing, install or refresh the Codex runtime bundle before building.
- Do not use the Python deck-authoring client for final deck construction. Do not start, repair, or depend on the artifact-tool Python RPC daemon.
- If you need to read PDFs locally, use the Codex primary runtime Python with `pypdf` since we don't have the javascript version installed.
- Use the platform-native imagegen tool for generated art plates.
- Helper scripts in this skill are Node.js scripts. Do not use Python helper scripts for the JS skill path.
- Use generated reference images directly and let the deck builder place them with `fit: "cover"`.
- Keep the pro workflow quality bar: text-free art-direction plates, deterministic editable design-system geometry, scratch rendered previews, editability checks, and native chart verification.
- Do not use `PptxGenJS`, `pptxgenjs_helpers`, `python-pptx`, LibreOffice rendering, or screenshot-only slides.
- For data charts, graphs, plots, trend lines, bars/columns, scatterplots, pie/donut charts, treemaps, and maps, use native artifact-tool chart objects via `slide.charts.add(...)`. Do not hand-draw these with shapes, connectors, dots, or text boxes when the chart API can represent them.
- Use shapes for cards, labels, icons, non-data diagrams, connectors, annotations, and decorative structure. Shape-drawn sparklines or microcharts are exceptions only when native chart APIs cannot represent the visual; record the exception in scratch verification notes instead of mentioning it in the final response.
- Do not make ImageMagick, `montage`, or `magick` part of the required authoring path. Contact sheets are optional and must never block `.pptx` export, rendered previews, or lightweight verification.
- During eval harness runs, do not spawn sub-agents or delegate. Finish the deck, verification, and final response in the current agent so the run does not fail on model-selection or handoff issues.

## Node Authoring Surface

Start deck authoring in a local builder file with:

```ts
const {
  Presentation,
  PresentationFile,
} = await import("@oai/artifact-tool");
```

For existing decks, also import `FileBlob`:

```ts
const { FileBlob, PresentationFile } = await import("@oai/artifact-tool");
const pptx = await FileBlob.load("input.pptx");
const presentation = await PresentationFile.importPptx(pptx);
```

Default new deck size is 16:9 at `1280x720`:

```ts
const presentation = Presentation.create({
  slideSize: { width: 1280, height: 720 },
});
```

Write final deck deliverables in the chosen output directory, using an `outputs` subdirectory named for the unique thread id unless the user gives an explicit output folder. The final deck artifact is `output.pptx`; any agent-authored `narrative_plan.md` created during planning is a support file. Keep previews, inspect records, reference images, and verification scratch in the deck-specific scratch directory under `tmp/slides`. Use the filesystem paths resolved in the current environment.

## Using artifact_tool Presentation APIs

Use this quick surface first when editing the JS builder. It is a curated subset of the full TypeScript presentation API, not the full reference.

### Build rules
- Use `@oai/artifact-tool` from Node for final deck construction, rendering, editable-text verification, and `.pptx` export.
- All size and positioning units are pixels unless a specific API notes otherwise.
- Author meaningful content as editable PowerPoint objects: `slide.shapes`, `shape.text`, `slide.tables`, `slide.charts`, and `slide.speakerNotes`.
- Always use `slide.charts.add(...)` for data-backed charts and graphs that the API can express; do not construct bar, line, scatter, pie, treemap, map, axis, series, or data-label systems out of raw shapes/text boxes.
- Treat native charts as designed slide elements, not default exports: set chart fonts, label sizes, gridlines, axis lines, legend placement, series colors/strokes, and plot area styling so the chart matches the rest of the slide.
- Use imagegen output as text-free visual plates only; keep real slide words, labels, numbers, tables, and chart text in editable objects.
- Common geometry strings include `"rect"`, `"roundRect"`, `"ellipse"`, `"rightArrow"`, and `"connector"`; use `geometry: "custom"` with `customPaths` when a preset cannot express the vector shape.
- Render with `presentation.export({ slide, format: "png", scale: 1 })` before final export, and use scratch inspect records to confirm important copy is editable.

### Conventions and gotchas
- New deck: `Presentation.create({ slideSize: { width: 1280, height: 720 } })`.
- `Presentation` is the in-memory deck object; `PresentationFile` is for `.pptx` import/export.
- Existing deck: `PresentationFile.importPptx(await FileBlob.load("input.pptx"))`.
- Export: `const pptx = await PresentationFile.exportPptx(presentation); await pptx.save("output.pptx")`.
- Rendering: `await presentation.export({ slide, format: "png", scale: 1 })`.
- Fill values can be theme aliases or hex strings: `"accent1"`, `"background1"`, `"text1"`, `"#FF6600"`, `"#11223380"`.
- Stroke values use `{ style: "solid" | "dashed" | "dotted" | "dash-dot" | "dash-dot-dot", fill, width }`.
- Gradient stop offsets are `0..100000`; rotation is in degrees.
- Set font faces with `typeface`.
- Style assignment is paragraph-scoped: `shape.text.get("word").style = "heading1"` styles the whole paragraph and clears inline overrides. Apply inline overrides after assigning styles.
- `shape.text.insets` and `fontSize` are pixels, but `spacingBefore` and `spacingAfter` are 1/100 point.
- Use `fit: "cover"` to fill a frame with possible cropping; use `fit: "contain"` to preserve the entire image.
- For local images, read bytes with `readImageBlob(...)` and pass an exact `ArrayBuffer` as `{ blob: await readImageBlob(path) }`.
- For line charts, set `chart.lineOptions.grouping = "standard"` before export. Leaving grouping unset can produce repair-prone PowerPoint chart XML.
- Avoid `chart.chartFill` in PPTX exports for now; prefer a panel/background shape behind the chart plus `chart.plotAreaFill`. If whole chart-space styling is required, verify the file opens in PowerPoint without repair.
- Match chart typography to the slide: set `chart.titleTextStyle.typeface`, `chart.legend.textStyle.typeface`, `chart.xAxis.textStyle.typeface`, `chart.yAxis.textStyle.typeface`, and `chart.dataLabels.textStyle.typeface` to the same body/title font family used elsewhere.

Local image helper:
```ts
const fs = await import("node:fs/promises");

async function readImageBlob(imagePath) {
  const bytes = await fs.readFile(imagePath);
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
}
```

### Core deck and slide APIs
- `const { FileBlob, Presentation, PresentationFile } = await import("@oai/artifact-tool")`
- `const presentation = Presentation.create({ slideSize: { width: 1280, height: 720 } })`
- `const imported = await PresentationFile.importPptx(await FileBlob.load("input.pptx"))`
- `const pptx = await PresentationFile.exportPptx(presentation); await pptx.save("output.pptx")`
- `const slide = presentation.slides.add()`
- `const { slide, index } = presentation.slides.insert({ after: presentation.slides.getItem(0) })`
- `presentation.slides.getItem(0)`, `presentation.slides.items`, `presentation.slides.count`
- `slide.duplicate()`, `slide.moveTo(index)`, `slide.delete()`
- `slide.background.fill = "background1"` or a solid/gradient fill object

### Shapes and rich text
- `slide.shapes.add({ geometry, position, fill, line })`
- Common `geometry` values are non-exhaustive; use known preset names first and verify each shape by rendering the deck.
- `shape.position = { left?: number, top?: number, width?: number, height?: number, rotation?: number, horizontalFlip?: boolean, verticalFlip?: boolean }`
- `shape.fill = "accent1"`; `shape.line.width = 1.5`; `shape.rotation = 15`
- `shape.text = "Quarterly Results"` or `shape.text = ["Line 1", "Line 2"]`
- Round-rect corner control: `adjustmentList: [{ name: "adj", formula: "val 16667" }]`; `50000` is pill-like max rounding.
- `shape.text.fontSize = 28`, `shape.text.bold = true`, `shape.text.color = "text1"`
- `shape.text.typeface = "Aptos"`, `shape.text.alignment = "center"`, `shape.text.verticalAlignment = "middle"`
- `shape.text.insets = { left: 12, right: 12, top: 8, bottom: 8 }`
- `shape.text.autoFit = "shrinkText"` or `"resizeShapeToFitText"` only when needed.
- `shape.text.get("literal text").bold = true`, `shape.text.get("literal text").style = "heading1"`
- `shape.text.add("New paragraph")`, `shape.text.replace("Old", "New")`

Detached rich text:
```ts
const { Text } = await import("@oai/artifact-tool");
const block = Text.create(["Quarterly Business Review", "Q2 Execution Plan"]);
block.get("Quarterly Business Review").style = "title";
block.get("Quarterly Business Review").fontSize = 38;
block.get("Q2 Execution Plan").color = "accent1";
shape.text = block;
```

Connector example:
```ts
slide.shapes.add({
  geometry: "connector",
  kind: "elbow",
  from: sourceShape,
  fromIdx: 3,
  to: targetShape,
  toIdx: 1,
  line: { style: "solid", fill: "accent1", width: 2 },
  head: { type: "arrow", width: "med", length: "med" },
});
```

### Images, tables, charts, and notes
- `slide.images.add({ blob, fit: "cover", alt })`, `slide.images.add({ dataUrl, fit: "contain", alt })`, `slide.images.add({ uri, alt })`
- `image.position = { left, top, width, height }`
- `image.replace({ blob: replacementBlob, alt: "Updated hero" })`
- `image.crop = { left: 0.05, top: 0.05, right: 0.05, bottom: 0.05 }`
- `image.geometry = "roundRect"` or pass `geometry: "roundRect"` at creation for masks
- Text-free plate pattern:
  ```ts
  const plate = slide.images.add({
    blob: await readImageBlob("tmp/slides/pro-reference-images/slide-01.png"),
    fit: "cover",
    alt: "Text-free visual plate",
  });
  plate.position = { left: 0, top: 0, width: 1280, height: 720 };
  ```
- `const table = slide.tables.add([["Metric", "North", "EMEA"], ["Bookings", 120, 94]])`
- `const table = slide.tables.add({ rows, columns, left, top, width, height, values })`
- `table.getCell(row, col).value = "APAC"`, `table.setValues(matrix)`
- `table.merge({ startRow, endRow, startColumn, endColumn })`
- `table.style = "TableStyleMedium9"`; `table.columns.get(0).width = 220`
- `table.cells.block({ row, column, rowCount, columnCount }).fill = "#0F172A"`
- Use `slide.charts.add(...)` for every data-backed chart or graph; do not implement bar/line/scatter/pie/treemap/map charts with `slide.shapes.add(...)`.
- `const chart = slide.charts.add("line" | "bar" | "scatter" | "pie" | "treemap" | "map" | "bar3D")`
- `chart.position = { left, top, width, height }`
- `chart.title = "Quarterly Revenue"`, `chart.categories = ["Q1", "Q2", "Q3", "Q4"]`
- `const series = chart.series.add("Revenue"); series.values = [120, 140, 180, 210]; series.categories = chart.categories`
- `series.fill = "accent1"`; `series.stroke = { width: 2, style: "solid", fill: "accent1" }`
- `chart.hasLegend = true`; `chart.legend.position = "bottom"`
- `chart.barOptions.direction = "column"`; `chart.barOptions.grouping = "stacked"`
- `chart.dataLabels.showValue = true`; `chart.dataLabels.position = "outEnd"`
- For line charts: `chart.lineOptions.grouping = "standard"`; `chart.lineOptions.smooth = false`
- Match chart fonts to slide fonts: `chart.titleTextStyle.typeface = FONT.title`; `chart.legend.textStyle.typeface = FONT.body`; `chart.xAxis.textStyle.typeface = FONT.body`; `chart.yAxis.textStyle.typeface = FONT.body`; `chart.dataLabels.textStyle.typeface = FONT.body`
- Tune chart aesthetics with chart APIs: `chart.titleTextStyle.fill`, `chart.titleTextStyle.fontSize`, `chart.legend.textStyle.fontSize`, `chart.xAxis.textStyle.fontSize`, `chart.yAxis.textStyle.fontSize`, `chart.yAxis.majorGridlines`, `chart.xAxis.line`, `chart.yAxis.line`, `chart.plotAreaFill`, `series.fill`, and `series.stroke`
- Prefer a separate `slide.shapes.add({ geometry: "roundRect", ... })` panel behind the chart instead of `chart.chartFill` until chart-space fill export is verified.
- `slide.speakerNotes.setText("Presenter notes")`, `slide.speakerNotes.append(["Next point", "Final point"])`

### Theme, styles, auto-layout, and placeholders
- `presentation.theme.colorScheme = { name, themeColors: { accent1, accent2, bg1, bg2, tx1, tx2, ... } }`
- `presentation.theme.hexColorMap`
- `const style = presentation.styles.add("metricLabel")`; set `style.fontSize`, `style.bold`, `style.color`, `style.typeface`
- `presentation.styles.describe()` or `presentation.styles.describe("title")`
- Import `AutoLayout`, `AutoLayoutAlign`, and `AutoLayoutDirection` only when using auto-layout.
- `slide.autoLayout(shapes, { direction: AutoLayoutDirection.horizontal, frame: "slide", align: AutoLayoutAlign.topCenter, horizontalGap: 32, verticalPadding: 48 })`
- `AutoLayout.apply(slide, shapes, options)` is the static entrypoint.
- Use direct shapes/text for non-chart one-off generated layouts. If layout reuse is useful: `const layout = presentation.layouts.add("Title Slide")`; `layout.placeholders.add({ name: "Title", type: "title", index: 1, text: "Title" })`; `slide.setLayout(layout)`; `slide.placeholders.getItem("title").text = "Kickoff"`.

## Required Workflow

1. Plan the deck:
- Define audience, narrative arc, slide list, source plan, visual system, icon/style plan, and likely hero/diagram/crop assets.
- Create or update an agent-authored `narrative_plan.md` in the final output directory during this step unless the user explicitly asks for PPTX-only output. Include audience, objective, narrative arc, slide list, source plan, visual system, imagegen plan, asset needs, and editability plan. Do not rely on the JS builder to create or overwrite this file.
- If the source plan includes a local PDF, first extract readable text locally with runtime `pypdf`. Use web/source search only if local extraction fails, source data is incomplete, or the task requires current external context.
- Separate every slide into editable text and generated visual. Editable text includes titles, subtitles, body, callouts, dates, timeline labels, captions, tables, chart labels, code/UI text, and important diagram labels.
- Visible slide content must be audience-facing only. Do not put implementation metadata, process labels, or self-referential claims into the slide, such as "editable PowerPoint deck", "generated with imagegen", "built with artifact-tool", "native chart object", "verified output", or "AI-generated visual", unless the user explicitly asks for a process/methodology slide.
- Visual assets: do not use Python, SVG, canvas, or other programmatic drawing to create illustrative or decorative images. Do not substitute programmatic vector drawings for the deck's visual layer. Source visual assets through image search or imagegen instead, while still using native PowerPoint objects for editable text, charts, cards, labels, and structural layout.
- Plan visual coverage beyond the main concept: include decorative visuals, texture, atmosphere, motifs, supporting cutaways, object details, or contextual imagery where the slide would otherwise feel text-only.
- Before sourcing or generating each visual, decide its intended aspect ratio, placement, crop, and relationship to editable text. Prompt for that composition explicitly; for example, if text will sit on the left of a person image, ask imagegen to place the person on the right with calm space on the left.
- Use modern sans by default: `Poppins` for titles and `Lato` for body/captions. Use formal serif only when appropriate: `Caladea` headings and `Liberation Serif` body/captions.

2. Prepare native-imagegen prompts:
- Write one outline file with an intro paragraph and exactly one section per slide.
- Use this skill's `scripts/prepare_reference_prompts.js` to create one prompt per slide and a manifest with expected filenames.
- Ask for text-free art-direction plates: broad calm zones, atmosphere, texture, collage, hero imagery, motifs, unlabeled diagrams/charts, abstract UI chrome, placeholder strokes, and icon containers.
- Ask for both concept visuals and decorative/supporting visuals, not only one hero image.
- Do not ask imagegen for real slide words, labels, dates, chart text, table text, citations, logos, code, or readable annotations.
- Store selected generated reference images in `tmp/slides/pro-reference-images/` with exact names `slide-01.png`, `slide-02.png`, and so on.
- If native imagegen saves into the generated images directory under Codex home, copy or move only the selected final images into the reference directory. Do not leave project-bound reference assets only in the default generated-images location.
- Do not show intermediate imagegen outputs to the user. Treat generated plates as scratch assets for deck construction; inspect and select them privately, then keep the selected files under `tmp/slides/pro-reference-images/`.
- Generate slide 1 first as the visual-system setter. For slides 2..N, use slide 1 as a visual style reference when the platform supports it; otherwise carry slide 1's palette, motif, density, and image treatment in the prompt.
- By default, use a distinct generated or sourced image for each slide. Reuse the same image only when it is an intentional repeated background, texture, or branded motif.
- For slides after the first, use generated images as full-slide backgrounds only when the prompt and preview leave clear, low-detail calm regions behind foreground content. If a generated image competes with titles, charts, cards, labels, or other editable foreground objects, crop it into a side panel, hero frame, texture strip, or decorative accent instead of forcing it behind the whole slide.
- If a generated image is not exactly 16:9, do not preprocess it. The JS builder uses `fit: "cover"` to place it on the slide canvas.
- After the final `.pptx` is exported and verified, delete imagegen scratch files created for this run, including raw outputs in the default generated-images location and deck-specific reference plates, unless the user explicitly requested those image files as deliverables.

Run this skill's `scripts/prepare_reference_prompts.js` helper with the outline file, reference-image directory, slide count, deck size, and style guidance. Use platform-appropriate paths resolved from the current environment.

3. Generate the art plates:
- Use the platform-native imagegen tool once per slide prompt.
- Keep the final selected image for each slide as `slide-XX.png` in the reference directory from the manifest.
- Do not embed, attach, or link generated art plates in chat while working unless the user explicitly asks to review them.
- Do not generate or keep image-rendered words, numbers, table text, labels, logos, source text, or code as part of the plate.
- If a visual crop or isolated hero image is needed, prefer regenerating a cleaner text-free plate or placing the full plate with PowerPoint geometry. Avoid raster-cropping helpers in this JS skill path.

4. Build the editable deck in JS:
- Start from `scripts/init_pro_deck_builder_js.js` or write a bespoke Node builder with the same architecture: theme constants, slide data, source notes, `addText`, `addCard`, `addTitleBlock`, `addHeader`, `addPlate`, native chart helpers wrapping `slide.charts.add(...)`, table/card helpers, icon helpers, render/export helpers, and inspect-record helpers.
- Treat generated art plates as visual direction and crop sources. The authored JS layer owns text, cards, labels, native chart objects, icons, and important shapes.
- A full-slide generated art plate may sit behind the deterministic editable layer only when it is text-free.
- Keep internal implementation wording out of authored slide text and labels. Put methodology, editability, imagegen usage, source paths, and verification notes in scratch files, speaker notes, or the final response only when appropriate, not in the visible slide canvas.
- For local image files, read bytes with `fs.readFile`, pass an exact `ArrayBuffer` via `{ blob }`, and retain the source path only in scratch inspect records; do not rely on `{ path }` for final `exportPptx` media embedding.
- When using `scripts/init_pro_deck_builder_js.js`, keep the generated sibling `build/node_modules/@oai/artifact-tool` package link when the script creates one. Node resolves `@oai/artifact-tool` from the builder file's directory, so this makes shell-run eval builders import the default Codex runtime package while preserving `await import("@oai/artifact-tool")` in the builder.
- Do not put editable text into generated boxes by guesswork. Author matching editable boxes yourself, or place a clean authored card/panel over a broad calm art region.

To scaffold a builder, run this skill's `scripts/init_pro_deck_builder_js.js` helper with the deck id, output builder file, slide count, reference-image directory, and output deck directory. Use the deck-specific scratch directory for the builder file and selected reference images unless the task requires a different location.

Then edit `SLIDES`/`SOURCES` and slide-specific layout functions, render previews, verify, and export by running the generated builder in the existing Node environment.

Run local builder files from a workspace where `@oai/artifact-tool` is resolvable. Generate builders with `scripts/init_pro_deck_builder_js.js` so the builder directory has a local `build/node_modules/@oai/artifact-tool` package link to the default Codex runtime package and a `package.json` with `type: "module"`. Run the generated builder with the Node executable from Codex workspace dependencies, or with the platform-appropriate command printed by the init script.

Do not use a different `node` binary for `@oai/artifact-tool` builders unless you first prove the package resolves. Do not run `pnpm exec` from the repo root, and do not run a builder without a sibling or otherwise resolvable `node_modules/@oai/artifact-tool`; Node resolves the package from the builder path.

5. Verify:
- Render final slides from JS with `presentation.export({ slide, format: "png", scale: 1 })`; save previews under scratch `tmp/slides/<deck-id>/preview/`, not in the final output folder.
- Write scratch inspect records from JS helper wrappers. Each editable textbox record must include `kind`, `slide`, `role`, `text`, `textChars`, `textLines`, and `bbox`.
- Use the scratch inspect records to confirm major planned copy exists as editable text/table/chart/notes data, not only in images.
- Verify data charts are native chart objects: the builder should contain `slide.charts.add(...)` for every chart-like visual, and the exported PPTX should contain native chart XML parts such as `ppt/slides/charts/chart*.xml` when the deck includes charts.
- When inspecting rendered previews, treat charts as first-class design objects: chart typography should match the surrounding slide font system, colors should use the deck palette, axes/gridlines should be intentional and not default-heavy, labels and legends should be readable without crowding, and the chart should look visually integrated with the panel/card it sits in.
- For every native chart, use chart APIs to improve aesthetics before accepting a render: set `titleTextStyle`, `legend.textStyle`, `xAxis.textStyle`, `yAxis.textStyle`, `dataLabels.textStyle`, axis/gridline strokes, series fill/stroke, legend position, and `plotAreaFill` as appropriate. Do not accept mismatched default chart fonts or generic Office chart styling when the rest of the slide has a designed visual system.
- Track every render/verify attempt in scratch; the template appends one record each time previews and `output.pptx` are exported. Stop after 3 total render/verify/fix loops, including the initial render.
- List or open the generated preview files from the deck-specific preview directory using platform-appropriate filesystem tools, then inspect the resolved absolute preview paths at readable size before accepting the deck.
- Check every slide for overlapping elements, text overflow or clipping, decorative rules built for single-line text after a title wraps, footer/source collisions, gaps under 0.3", edge margins under 0.5" outside intentional headers/footers, uneven spacing, inconsistent alignment, low-contrast text/icons, excessive wrapping from narrow text boxes, leftover placeholder content, and table/card/layout-box font sizes that feel unnaturally small or visually timid for their containers.
- Check visible slide text for accidental process or implementation language. Remove phrases such as "editable PowerPoint deck", "generated with imagegen", "built with artifact-tool", "native chart object", "verified output", "this slide", "this deck", or other meta commentary unless it is genuinely audience-facing and explicitly requested.
- Font size should feel natural and aesthetically balanced for the layout: not so large that it overflows, wraps excessively, or collides with boundaries, but not so small that tables, labels, callouts, or card text look like footnotes unless they are genuinely footnotes/citations. Prefer increasing container size, reducing copy, simplifying a table, or splitting dense content before shrinking important text.
- Fix every actionable visual issue in the JS builder, rerender, and repeat until the slide is clean or the 3-loop cap is reached. Loop 1 is the initial render; loops 2 and 3 are the only allowed fix/rerender passes.
- Do not run `scripts/pro_deck_quality_check.js` for normal deck creation. It is reserved for explicit debug, eval, or manual investigation requests.

## Completion Criteria

Complete only when:
- The final deck is exported as `output.pptx`; any agent-authored `narrative_plan.md` remains a support file that is not surfaced unless requested.
- Internal implementation check only: the final deck is built, rendered, verified, and exported with the required runtime. Do not mention this tooling or workflow in the final response.
- Important copy was internally verified as editable.
- Data-backed charts and graphs use native `slide.charts.add(...)`; any shape-drawn sparkline/microchart exception is recorded in scratch verification notes.
- Rendered previews were inspected, and any actionable visual issues were fixed within the 3-loop cap.
- Temporary imagegen files created for this run were deleted after final export/verification and before the final response, unless the user explicitly requested those image files as deliverables.
- The final response includes a short summary of the deck/slides created or edited and standalone Markdown link(s) only to final `.pptx` artifact(s), using `<deck or slide title> - <filename>` as the link label and an absolute filesystem path as the target.
- The final response does not mention implementation details such as `artifact_tool`, artifact-tool, `@oai/artifact-tool`, the Node/JS builder, scripts, package manifests, export workflow, verification workflow, or internal tooling unless explicitly requested.
- The final response does not mention, show, embed, or link to `narrative_plan.md`, generated image plates, rendered previews, screenshots, contact sheets, verification records, scripts, package manifests, scratch files, or other support artifacts unless explicitly requested.

## References

Use the installed `@oai/artifact-tool` TypeScript presentation docs when they are available in the current environment. Do not assume local checkout-specific absolute paths exist in packaged installs.