Merge Google Slides workflow into Slide Factory

This commit is contained in:
Codex 2026-06-09 10:31:33 -07:00
parent ec8ba8dff8
commit a010792eef
6 changed files with 344 additions and 9 deletions

View file

@ -33,6 +33,20 @@ source content
This is deliberately local-first. It proves the core source-to-deck loop before This is deliberately local-first. It proves the core source-to-deck loop before
production hosting, auth, persistence, or full LLM orchestration. production hosting, auth, persistence, or full LLM orchestration.
## Google Slides Workflow
The older AgentPlane Google Slides project has been merged into this repo as
workflow guidance and a future renderer contract:
```text
docs/google-slides-workflow.md
schemas/google-slides-deck-spec.schema.json
```
Use that path for branded Google Slides generation: copy the template first,
inventory native containers, fill existing object IDs, delete unused slides, and
render thumbnails/contact sheets for visual QA.
## Quick Start On MBS ## Quick Start On MBS
```bash ```bash
@ -165,9 +179,8 @@ docs/
/Users/tars/AgentPlane/projects/google-slides /Users/tars/AgentPlane/projects/google-slides
``` ```
For branded Google Slides, use brand-safe mode: copy the template, inventory For branded Google Slides, use brand-safe mode as documented in
native containers, fill existing object IDs, delete unused slides, and render `docs/google-slides-workflow.md`.
thumbnails/contact sheets for visual QA.
## Suggested Next Session ## Suggested Next Session
@ -190,4 +203,3 @@ Recommended v0.2 priorities:
5. Add PPTX visual QA: render thumbnails or PDF previews and catch overflow. 5. Add PPTX visual QA: render thumbnails or PDF previews and catch overflow.
6. Add style-pack save/load workflow and template import. 6. Add style-pack save/load workflow and template import.
7. Add Google Slides renderer using the existing template-container workflow. 7. Add Google Slides renderer using the existing template-container workflow.

View file

@ -0,0 +1,118 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Google Slides Workflow - Slide Factory</title>
<style>
:root {
color: #172033;
background: #f4f6fa;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 24px;
}
main {
max-width: 900px;
margin: 0 auto;
}
a {
color: #172033;
font-weight: 750;
}
.eyebrow {
margin: 0 0 4px;
color: #f05a28;
font-size: 12px;
font-weight: 800;
text-transform: uppercase;
}
h1 {
margin: 0 0 18px;
font-size: 30px;
}
h2 {
margin: 28px 0 10px;
font-size: 18px;
}
p,
li {
line-height: 1.55;
}
code,
pre {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
}
pre {
overflow-x: auto;
padding: 14px;
border: 1px solid #d8dee9;
border-radius: 8px;
background: #fff;
}
.back {
display: inline-flex;
margin-bottom: 18px;
text-decoration: none;
}
</style>
</head>
<body>
<main>
<a class="back" href="/">Back to Slide Factory</a>
<p class="eyebrow">Merged prior work</p>
<h1>Google Slides Workflow</h1>
<p>
Slide Factory now supersedes the older AgentPlane Google Slides project
as the active slide-generation product. The reusable Google Slides work
remains the brand-safe renderer pattern for future native Slides output.
</p>
<h2>Brand-Safe Flow</h2>
<ol>
<li>Copy the template deck.</li>
<li>Generate a template inventory.</li>
<li>Choose slides by native container pattern.</li>
<li>Fill existing text containers by object ID.</li>
<li>Delete unused template slides.</li>
<li>Render thumbnails and a contact sheet for visual QA.</li>
</ol>
<h2>Contract</h2>
<p>
The current PPTX-oriented DeckSpec should be adapted into the
container-oriented Google Slides schema before mutating a copied
template.
</p>
<pre>schemas/google-slides-deck-spec.schema.json</pre>
<h2>Local Prior Art</h2>
<pre>/Users/tars/AgentPlane/projects/google-slides
/Users/tars/.codex/skills/google-slides/scripts/</pre>
<h2>Handoff Evidence</h2>
<p>
Native Slides output should return the deck title, presentation ID, edit
URL, source template, target folder, contact sheet path, brand-safe
status, and any overflow or weak-template-match risks.
</p>
</main>
</body>
</html>

View file

@ -1,6 +1,6 @@
import React, { DragEvent, useMemo, useRef, useState } from "react"; import React, { DragEvent, useMemo, useRef, useState } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { Download, FileText, Image as ImageIcon, Loader2, Paperclip, Upload, WandSparkles, X } from "lucide-react"; import { Download, ExternalLink, FileText, Image as ImageIcon, Loader2, Paperclip, Upload, WandSparkles, X } from "lucide-react";
import "./styles.css"; import "./styles.css";
type DeckResult = { type DeckResult = {
@ -116,10 +116,16 @@ function App() {
<p className="eyebrow">Slide Factory</p> <p className="eyebrow">Slide Factory</p>
<h1>Source to deck</h1> <h1>Source to deck</h1>
</div> </div>
<div className="topbar-actions">
<a className="secondary-action" href="/google-slides-workflow.html">
<ExternalLink size={16} />
Google Slides workflow
</a>
<button className="primary-action" onClick={createDeck} disabled={busy}> <button className="primary-action" onClick={createDeck} disabled={busy}>
{busy ? <Loader2 className="spin" size={18} /> : <WandSparkles size={18} />} {busy ? <Loader2 className="spin" size={18} /> : <WandSparkles size={18} />}
{busy ? "Building" : "Build deck"} {busy ? "Building" : "Build deck"}
</button> </button>
</div>
</header> </header>
<div className="main-grid"> <div className="main-grid">

View file

@ -40,6 +40,14 @@ button {
margin-bottom: 18px; margin-bottom: 18px;
} }
.topbar-actions {
display: flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 10px;
}
.eyebrow { .eyebrow {
margin: 0 0 4px; margin: 0 0 4px;
color: #f05a28; color: #f05a28;
@ -82,6 +90,7 @@ h1 {
color: #172033; color: #172033;
background: #fff; background: #fff;
border: 1px solid #d8dee9; border: 1px solid #d8dee9;
text-decoration: none;
} }
.icon-action { .icon-action {
@ -243,6 +252,15 @@ textarea {
padding: 16px; padding: 16px;
} }
.topbar {
align-items: flex-start;
flex-direction: column;
}
.topbar-actions {
justify-content: flex-start;
}
.main-grid { .main-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }

View file

@ -0,0 +1,81 @@
# Google Slides Workflow
Slide Factory supersedes the older AgentPlane Google Slides project as the
active slide-generation product. The older project remains useful as a
brand-safe Google Slides renderer pattern and is now folded into this repo as
implementation guidance.
## Source
Prior project:
```text
/Users/tars/AgentPlane/projects/google-slides
```
Key reusable assets:
- Template inventory workflow.
- Container/object-id mapping.
- Brand-safe deck mutation rules.
- Contact sheet visual QA.
- Container-oriented deck spec schema.
## Operating Rule
Treat Google Slides templates as design systems. A Slide Factory Google Slides
renderer should copy a template first, inspect its native containers, then fill
existing text containers by object ID. It should create new page elements only
when the user explicitly permits that or when no usable container exists.
## Brand-Safe Flow
1. Copy the template deck.
2. Generate a template inventory.
3. Choose slides by container pattern.
4. Delete existing text and insert generated text into existing containers.
5. Delete unused template slides.
6. Render thumbnails and a contact sheet.
7. Patch copy density before changing layout geometry.
## Local Skill Scripts
The current implementation helpers still live in the local Codex skill until
they are ported into Slide Factory packages:
```text
/Users/tars/.codex/skills/google-slides/scripts/
```
Primary scripts:
- `slides_template_inventory.py`
- `slides_contact_sheet.py`
- `slides_structured_deck.py`
- `slides_container_map.py`
## Contract Bridge
Slide Factory's current `DeckSpec` is PPTX-oriented. Google Slides export should
use an adapter step that maps the internal `DeckSpec` into the container-based
Google Slides schema at:
```text
schemas/google-slides-deck-spec.schema.json
```
Do not mutate live/private Google Drive files directly from the planner. The
renderer should work from a copied template deck and return the edit URL,
presentation ID, source template, target folder, and contact sheet evidence.
## Handoff Evidence
At handoff, include:
- Deck title.
- Presentation ID and edit URL.
- Source template and folder.
- Auth account used.
- Contact sheet path.
- Whether brand-safe mode was used.
- Slides with overflow risk or weak template matches.

View file

@ -0,0 +1,100 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://agentplane.local/projects/slide-factory/google-slides-deck-spec.schema.json",
"title": "Slide Factory Google Slides Deck Spec",
"type": "object",
"required": ["title", "slides"],
"additionalProperties": false,
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"template_id": {
"type": "string",
"minLength": 1
},
"folder_id": {
"type": "string",
"minLength": 1
},
"brand_safe": {
"type": "boolean",
"default": true
},
"slides": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/slide"
}
}
},
"$defs": {
"slide": {
"type": "object",
"required": ["containers"],
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"cover_or_close",
"section_divider",
"title_body",
"two_column",
"three_column",
"image_plus_text",
"toc_or_timeline",
"table",
"single_statement",
"visual_or_blank"
]
},
"template_slide": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"minLength": 1
}
]
},
"title": {
"type": "string"
},
"containers": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/container"
}
},
"speaker_notes": {
"type": "string"
}
}
},
"container": {
"type": "object",
"required": ["text"],
"additionalProperties": false,
"properties": {
"role": {
"type": "string",
"examples": ["title", "subtitle", "body", "column", "callout", "label"]
},
"text": {
"type": "string"
},
"bullets": {
"type": "boolean",
"default": false
}
}
}
}
}