Merge Google Slides workflow into Slide Factory
This commit is contained in:
parent
ec8ba8dff8
commit
a010792eef
6 changed files with 344 additions and 9 deletions
20
README.md
20
README.md
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
118
apps/web/public/google-slides-workflow.html
Normal file
118
apps/web/public/google-slides-workflow.html
Normal 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>
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
docs/google-slides-workflow.md
Normal file
81
docs/google-slides-workflow.md
Normal 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.
|
||||||
100
schemas/google-slides-deck-spec.schema.json
Normal file
100
schemas/google-slides-deck-spec.schema.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue