# Presentation Artifacts and PPTX Preview

CoWork treats generated PowerPoint decks as first-class presentation artifacts. The current model is review-first: users can inspect slides in the task feed, a resizable right sidebar, or fullscreen mode, then request changes through the same follow-up composer used for spreadsheet and document artifacts. Direct slide editing controls are not part of v1.

Presentation artifacts are one surface of the broader [Everything Workbench](everything-workbench.md): generated knowledge-work files open in-place, can be reviewed in context, and keep the follow-up composer beside the artifact.

## Supported Formats

In-app preview:

- `.pptx`

Recognized PowerPoint-style artifacts with external-app and folder actions:

- `.ppt`
- `.pptm`
- `.potx`
- `.potm`
- `.ppsx`
- `.ppsm`

The shared detection and labels live in `src/shared/presentation-formats.ts`. Cards are labeled as `Presentation · PPTX`, `Presentation · PPT`, and so on.

## Artifact Surfaces

Generated presentations can appear from `file_created`, `file_modified`, `artifact_created`, task primary-output metadata, and assistant text that mentions a local presentation path such as `artifacts/output.pptx`.

The task feed renders a compact presentation card:

- orange PowerPoint-style icon
- filename
- `Presentation · <format>` metadata
- default **Open** action
- dropdown actions for external apps and **Open in folder**

For `.pptx`, default **Open** routes to the in-app right-sidebar preview. For legacy or non-previewable PowerPoint formats, default opening falls back to the external app path.

## Viewer Experience

The reusable viewer is split between:

- `src/renderer/components/PresentationArtifactViewer.tsx`
- `src/renderer/components/PresentationViewer.tsx`

Sidebar mode:

- opens in the persisted resizable artifact sidebar
- keeps the main task feed visible to the left
- includes fullscreen and close controls
- shows deck-level copy, external open, and folder actions

Fullscreen mode:

- expands the presentation viewer across the app content area
- keeps the functional follow-up composer overlay
- keeps the latest-turn or working context frame above the composer
- filters the context frame after a follow-up so only events emitted after that prompt are shown
- refreshes the active preview when a matching presentation output event is emitted

Viewer layout:

- slide thumbnails in the left rail
- previous/next navigation and a slide counter in the top toolbar
- zoom selector
- a white canvas with the active slide top-aligned and centered
- rendered slide image when available
- text fallback when rendered images are not available yet
- speaker notes below the slide

## Loading Model

Presentation preview loading is intentionally two-phase so opening a deck is fast.

Fast phase:

- parses the `.pptx` package directly
- extracts slide titles, text, and speaker notes
- reuses already-cached slide PNGs when present
- returns immediately without invoking expensive renderers

Render phase:

- renders missing slide PNGs in the background
- updates the open viewer in place when high-fidelity images are ready
- shares in-flight rendering work across sidebar/fullscreen opens
- reuses cached slide images when reopening the same deck

The preview state is exposed through `presentationPreview.renderStatus`:

- `cached`: all available slide images were loaded from cache
- `rendering`: text/notes are visible while image rendering continues
- `rendered`: the full image render finished
- `text_only`: text/notes are available but image rendering did not produce slides
- `failed`: preview extraction or rendering failed in a recoverable way

`renderMessage` can explain the current state, for example `Rendering slide previews...`.

## IPC Contract

`readFileForViewer` accepts:

```ts
{
  presentationRenderMode?: "fast" | "full";
}
```

`fast` returns text, notes, and cached images only. `full` runs the renderer pipeline and returns the enriched preview.

`FileViewerResult.data.presentationPreview` includes deck metadata, slide count, render status, and slide entries. Rendered slides prefer `imageUrl` so cached PNGs can be served as local preview media URLs instead of embedding every image as base64. `imageDataUrl` remains as a compatibility fallback.

The media URL helper is exported from `src/electron/media/index.ts`, and the CSP allows `media:` images in renderer surfaces.

## Rendering Pipeline

The preview service is `src/electron/utils/PptxPreviewService.ts`.

Render priority:

1. Codex bundled `@oai/artifact-tool` presentation renderer.
2. Local `soffice` conversion to PDF plus `pdftoppm` page rendering.
3. Text-only slide and speaker-note preview.

`PptxPreviewService` is used as a singleton from the Electron IPC layer so render cache and in-flight render dedupe are shared across preview surfaces.

The cached PNGs live under the existing PPTX preview cache. The cache manifest lets fast mode reuse already-rendered slide images without rerunning artifact-tool or LibreOffice.

## Generation Model

Both presentation generation tool names route through the shared generator:

- `generate_presentation`
- `create_presentation`

The shared generator is `src/electron/utils/document-generators/pptx-generator.ts`.

Generation behavior:

- uses Codex's bundled `@oai/artifact-tool` runtime first
- falls back to `pptxgenjs` when the bundled runtime is missing or fails
- registers the generated `.pptx` as a task artifact with the correct MIME type

The bundled `kami` skill remains available for explicit editorial slide-deck workflows when the user asks for Kami by name. General presentation generation should use the native presentation tools and Codex presentation runtime by default.

## Follow-Up Editing

Presentation artifacts do not expose direct slide-edit controls in v1. Edits happen through follow-up prompts:

1. The user opens the deck in fullscreen mode.
2. The user describes a change in the functional composer.
3. The agent updates or regenerates the `.pptx`.
4. The viewer waits until the follow-up work completes, then reloads `readFileForViewer` for the matching deck.
5. The preview shows fresh text immediately and refreshed slide images when rendering completes.

This keeps the deck review experience responsive without introducing a partial PowerPoint clone.

## Implementation Files

- `src/shared/presentation-formats.ts`
- `src/electron/utils/PptxPreviewService.ts`
- `src/electron/utils/document-generators/pptx-generator.ts`
- `src/electron/utils/codex-artifact-tool-runtime.ts`
- `src/electron/ipc/handlers.ts`
- `src/electron/preload.ts`
- `src/electron/media/media-protocol.ts`
- `src/renderer/components/PresentationArtifactCard.tsx`
- `src/renderer/components/PresentationArtifactViewer.tsx`
- `src/renderer/components/PresentationViewer.tsx`
- `src/renderer/components/InlinePresentationPreview.tsx`
- `src/renderer/styles/index.css`

## Verification

Focused tests:

```bash
npx vitest run \
  src/electron/utils/__tests__/PptxPreviewService.test.ts \
  src/renderer/components/__tests__/presentation-artifact-card.test.ts \
  src/renderer/components/__tests__/presentation-artifact-viewer.test.ts
```

Build checks:

```bash
npm run build:react
npm run build:electron
npm run type-check
```

Manual smoke checks:

- Generate a small `.pptx` deck.
- Confirm the compact presentation card appears without expanding a hidden output row.
- Click **Open** and verify the right-sidebar viewer opens.
- Confirm slide text or cached images appear immediately.
- Confirm rendered slide images replace text fallback after background rendering.
- Toggle fullscreen and verify the follow-up composer and latest-turn/working context frame remain functional.
- Submit a follow-up edit and confirm the preview refreshes after the deck is updated.
