html2pptx-local-mcp 1.1.20 → 1.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/docs/content.js +50 -16
- package/cli/dist/commands/edit.d.ts +1 -1
- package/cli/dist/commands/edit.js +30 -13
- package/cli/dist/index.js +0 -0
- package/lib/local-editor-server.js +316 -0
- package/lib/local-editor-state.js +45 -0
- package/lib/local-slide-editor-launcher.js +19 -18
- package/lib/pptx-studio-mcp-core.js +15 -9
- package/local-editor-app/app/api/edit-slide/local-health/route.js +16 -0
- package/local-editor-app/app/edit-slide/edit-slide-client.jsx +13153 -0
- package/local-editor-app/app/edit-slide/page.jsx +13 -0
- package/local-editor-app/app/globals.css +4 -0
- package/local-editor-app/app/layout.jsx +14 -0
- package/local-editor-app/components/studio/edit-property-panel.jsx +1061 -0
- package/local-editor-app/lib/edit-panel-value-normalizer.js +97 -0
- package/local-editor-app/lib/edit-slide-editor-helpers.js +120 -0
- package/local-editor-app/lib/edit-slide-url-security.js +247 -0
- package/local-editor-app/next.config.mjs +31 -0
- package/local-editor-app/package.json +7 -0
- package/mcp/pptx-studio-mcp-server.mjs +1 -1
- package/package.json +13 -2
- package/public/skills/html2pptx/SKILL.md +635 -0
- package/public/skills/html2pptx/references/automation-contract.md +68 -0
- package/public/skills/html2pptx/references/input-contract.md +107 -0
- package/public/skills/html2pptx/references/japanese-slide-design.md +273 -0
- package/public/skills/html2pptx/references/rewrite-patterns.md +218 -0
- package/public/skills/icon-generator/SKILL.md +133 -0
- package/public/skills/open-slide/SKILL.md +160 -0
- package/public/skills/publish-template/SKILL.md +215 -0
- package/public/skills/register-template/SKILL.md +142 -0
- package/scripts/install-mcp.mjs +28 -2
- package/scripts/install-skills.mjs +82 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Automation Contract
|
|
2
|
+
|
|
3
|
+
Use this reference when an agent needs the current public automation surface.
|
|
4
|
+
|
|
5
|
+
## Public REST Routes
|
|
6
|
+
|
|
7
|
+
- `GET /api/export/plans`
|
|
8
|
+
- Returns public plan metadata and the recommended commercial tier.
|
|
9
|
+
- `POST /api/export/jobs`
|
|
10
|
+
- Creates a commercial export job.
|
|
11
|
+
- `GET /api/export/jobs/{jobId}`
|
|
12
|
+
- Returns the current job state.
|
|
13
|
+
|
|
14
|
+
## Authentication
|
|
15
|
+
|
|
16
|
+
Use either:
|
|
17
|
+
|
|
18
|
+
- `Authorization: Bearer <api_key>`
|
|
19
|
+
- `x-api-key: <api_key>`
|
|
20
|
+
|
|
21
|
+
## Expected payload
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"html": "<section class=\"slide\">...</section>",
|
|
26
|
+
"css": ".slide { width: 1600px; min-height: 900px; }",
|
|
27
|
+
"fileName": "deck.pptx",
|
|
28
|
+
"autoEmbedFonts": false,
|
|
29
|
+
"metadata": {
|
|
30
|
+
"channel": "agent"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Job lifecycle
|
|
36
|
+
|
|
37
|
+
Typical states:
|
|
38
|
+
|
|
39
|
+
- `queued`
|
|
40
|
+
- `processing`
|
|
41
|
+
- `completed`
|
|
42
|
+
- `failed`
|
|
43
|
+
|
|
44
|
+
Completed jobs may include:
|
|
45
|
+
|
|
46
|
+
- `fileName`
|
|
47
|
+
- `mimeType`
|
|
48
|
+
- `fileBase64`
|
|
49
|
+
|
|
50
|
+
For agent-facing summaries, do not dump `fileBase64` unless explicitly required. Public API and MCP sanitize untrusted SVG and rasterize it before export.
|
|
51
|
+
|
|
52
|
+
## MCP mapping
|
|
53
|
+
|
|
54
|
+
The public stdio MCP server in this repo wraps the same REST routes:
|
|
55
|
+
|
|
56
|
+
- `html2pptx_list_export_plans`
|
|
57
|
+
- `html2pptx_create_export_job`
|
|
58
|
+
- `html2pptx_get_export_job`
|
|
59
|
+
- `html2pptx_wait_for_export_job`
|
|
60
|
+
|
|
61
|
+
### MCP response format
|
|
62
|
+
|
|
63
|
+
The MCP server defaults to `responseFormat: "both"`, returning:
|
|
64
|
+
|
|
65
|
+
1. **`resource` content block** — embedded PPTX as `blob` (base64), MCP spec compliant
|
|
66
|
+
2. **`text` content block** — `Download: <presigned URL>` for clients that cannot handle blob resources
|
|
67
|
+
|
|
68
|
+
This ensures compatibility with Claude Code and other MCP clients. Agents should extract the download URL from the text block and use `curl -s -L -o <fileName> "<url>"` to save the file locally.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Input Contract
|
|
2
|
+
|
|
3
|
+
Use this reference when deciding whether HTML/CSS is suitable for HTML-to-PPTX export.
|
|
4
|
+
|
|
5
|
+
## Core Rule
|
|
6
|
+
|
|
7
|
+
Accept slide-oriented HTML, not arbitrary webpages.
|
|
8
|
+
|
|
9
|
+
The ideal input is:
|
|
10
|
+
|
|
11
|
+
- fixed-size
|
|
12
|
+
- static at capture time
|
|
13
|
+
- self-contained
|
|
14
|
+
- visually complete without runtime application logic
|
|
15
|
+
|
|
16
|
+
## Accept
|
|
17
|
+
|
|
18
|
+
- One or more `.slide` roots
|
|
19
|
+
- Explicit slide dimensions
|
|
20
|
+
- Normal DOM text content
|
|
21
|
+
- `div`, `section`, `article`, `header`, `footer`
|
|
22
|
+
- `h1`-`h6`, `p`, `span`
|
|
23
|
+
- `ul`, `ol`, `li`
|
|
24
|
+
- `table`, `tr`, `th`, `td`
|
|
25
|
+
- `img`
|
|
26
|
+
- `svg`
|
|
27
|
+
- Basic forms of `input[type="text"]` and `textarea` when treated as simple text
|
|
28
|
+
|
|
29
|
+
## Accept with Possible Degradation
|
|
30
|
+
|
|
31
|
+
- `canvas`
|
|
32
|
+
- backdrop blur
|
|
33
|
+
- icon fonts and icon-only elements
|
|
34
|
+
- complex rounded clipping
|
|
35
|
+
- some generated gradient and border effects
|
|
36
|
+
- SVG that is accepted but may be sanitized and rasterized before export on public surfaces
|
|
37
|
+
|
|
38
|
+
These can export successfully while losing editability.
|
|
39
|
+
|
|
40
|
+
## Reject or Rewrite First
|
|
41
|
+
|
|
42
|
+
- `<script>` tags
|
|
43
|
+
- inline event handlers such as `onclick`
|
|
44
|
+
- `javascript:` URLs
|
|
45
|
+
- `iframe`
|
|
46
|
+
- `video`
|
|
47
|
+
- `audio`
|
|
48
|
+
- `embed`
|
|
49
|
+
- `object`
|
|
50
|
+
- app shells with navigation, tabs, drawers, filters, and runtime controls
|
|
51
|
+
- content that requires hydration, async data loading, or external bootstrapping
|
|
52
|
+
- long responsive pages intended for scrolling
|
|
53
|
+
|
|
54
|
+
## CSS That Usually Works
|
|
55
|
+
|
|
56
|
+
- `background-color`
|
|
57
|
+
- `background-image: linear-gradient(...)`
|
|
58
|
+
- `color`
|
|
59
|
+
- `opacity`
|
|
60
|
+
- `border-*`
|
|
61
|
+
- `border-radius`
|
|
62
|
+
- `box-shadow`
|
|
63
|
+
- `filter: blur()`
|
|
64
|
+
- `transform: rotate()`
|
|
65
|
+
- `position`
|
|
66
|
+
- `width`, `height`
|
|
67
|
+
- `padding`, `margin`
|
|
68
|
+
- `text-align`
|
|
69
|
+
- `font-family`, `font-size`, `font-weight`, `font-style`, `line-height`
|
|
70
|
+
- final layouts produced by Flexbox or Grid
|
|
71
|
+
|
|
72
|
+
## Slide Fit Best Practice
|
|
73
|
+
|
|
74
|
+
Every `.slide` must have `margin: 0; padding: 0; box-sizing: border-box; overflow: hidden; position: relative`. Backgrounds must be applied on the `.slide` itself, not on an inner wrapper. Content padding goes on an inner layout `div`, not on `.slide`. This ensures the slide fills the PowerPoint canvas edge-to-edge with no white gaps.
|
|
75
|
+
|
|
76
|
+
## Text Alignment Best Practice
|
|
77
|
+
|
|
78
|
+
Text inside background-colored elements (buttons, badges, cards) MUST NOT be a separate child element when possible. The PPTX converter splits background shapes and text boxes into independent objects, causing misalignment. Preferred approach: put text directly in the background element with explicit `width`, `height`, `text-align: center`, and flexbox centering. If a child element is necessary, give it `width: 100%` and `text-align: center`. Never rely on padding alone to size background elements — always use explicit dimensions.
|
|
79
|
+
|
|
80
|
+
## CSS That Commonly Causes Trouble
|
|
81
|
+
|
|
82
|
+
- `transform: scale()`
|
|
83
|
+
- `mix-blend-mode`
|
|
84
|
+
- `mask`
|
|
85
|
+
- `clip-path` chains
|
|
86
|
+
- `background-clip: text`
|
|
87
|
+
- filter stacks beyond simple blur
|
|
88
|
+
- viewport-driven responsive behavior without fixed slide dimensions
|
|
89
|
+
|
|
90
|
+
## Asset Constraints
|
|
91
|
+
|
|
92
|
+
Assume that fonts and images must be readable by the browser at export time.
|
|
93
|
+
|
|
94
|
+
Watch for:
|
|
95
|
+
|
|
96
|
+
- images without reliable CORS
|
|
97
|
+
- font files without reliable CORS
|
|
98
|
+
- tainted `canvas` output caused by cross-origin drawing
|
|
99
|
+
|
|
100
|
+
## Verdict Heuristic
|
|
101
|
+
|
|
102
|
+
Use this shorthand:
|
|
103
|
+
|
|
104
|
+
- `safe`: fixed-size, static, CORS-safe, mostly standard DOM/CSS
|
|
105
|
+
- `safe with degradation`: export likely succeeds but some regions rasterize
|
|
106
|
+
- `needs rewrite`: structure is web-like or effect-heavy, but content is salvageable
|
|
107
|
+
- `out of scope`: input behaves like an application or unsupported document
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Japanese Slide Design Reference
|
|
2
|
+
|
|
3
|
+
Use this reference when generating slides for Japanese audiences or when the user's request is in Japanese. These rules override generic defaults with Japan-specific typography, structure, and information design guidelines.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
1. **Conclusion first** — show the answer/proposal before the reasoning
|
|
8
|
+
2. **1 slide = 1 message** — if there are multiple claims, split into separate slides
|
|
9
|
+
3. **Density is contextual** — presentation mode (projecting) vs. handout mode (reading) have different text limits
|
|
10
|
+
4. **Alignment and grid** — Japanese audiences expect consistent alignment and visual hierarchy
|
|
11
|
+
5. **Restraint in color** — 3 colors max (base + main + accent), avoid raw/saturated primary colors
|
|
12
|
+
|
|
13
|
+
## Character Count Limits
|
|
14
|
+
|
|
15
|
+
| Element | Max characters | Notes |
|
|
16
|
+
|---------|---------------|-------|
|
|
17
|
+
| Slide title | 9-13 | Instant perception limit. Noun ending (体言止め) |
|
|
18
|
+
| Slide message (assertion) | 50 | One sentence, written as a complete claim |
|
|
19
|
+
| Single bullet / line | 40 | ~10 seconds to comprehend |
|
|
20
|
+
| Total per slide (presentation mode) | 105 | Target for projected slides |
|
|
21
|
+
| Total per slide (handout mode) | 200-285 | Use cards/boxes to organize density |
|
|
22
|
+
| Line length (projection) | 20-30 chars | For text read at a glance |
|
|
23
|
+
| Line length (reading) | 35-40 chars | For explanatory text |
|
|
24
|
+
|
|
25
|
+
## Slide Anatomy
|
|
26
|
+
|
|
27
|
+
Each slide has 3 distinct text layers:
|
|
28
|
+
|
|
29
|
+
1. **Title** (top) — short, objective, noun-ending. Labels the content, no claims. Example: "売上推移" not "売上が減少"
|
|
30
|
+
2. **Message** (below title) — one sentence, max 50 chars, contains the assertion with a comparison target and quantified difference. Example: "前年比15%増、目標を3ヶ月前倒しで達成"
|
|
31
|
+
3. **Body** — bullets, diagrams, or data supporting the message
|
|
32
|
+
|
|
33
|
+
## Deck Structure (Conclusion-First)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
表紙 → サマリー → アジェンダ(3-5項目) → 背景 → 課題 → 提案(結論) → 根拠 → 実行計画 → リスク → 結論・次アクション → 付録
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Section | Recommended visual |
|
|
40
|
+
|---------|-------------------|
|
|
41
|
+
| Background/Context | Bullet points |
|
|
42
|
+
| Problem/Issue | Graphs (quantitative evidence) |
|
|
43
|
+
| Solution/Proposal | Diagrams (flow, process, structure) |
|
|
44
|
+
| Effect/Benefit | Diagrams + graphs combined |
|
|
45
|
+
|
|
46
|
+
## Typography
|
|
47
|
+
|
|
48
|
+
### Font Stack
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
font-family: "Noto Sans JP", "BIZ UDPGothic", "Hiragino Kaku Gothic ProN", sans-serif;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- **Noto Sans JP** — primary (open source, cross-platform)
|
|
55
|
+
- **BIZ UDPGothic** — fallback (universal-design font, high readability)
|
|
56
|
+
- Gothic (sans-serif) for all business slides. Mincho (serif) only for formal/literary contexts
|
|
57
|
+
- When mixing Japanese and Latin, declare Latin font first: `"Inter", "Noto Sans JP", sans-serif`
|
|
58
|
+
|
|
59
|
+
### Font Sizes (1600x900px slides)
|
|
60
|
+
|
|
61
|
+
| Role | Size | Weight | line-height |
|
|
62
|
+
|------|------|--------|-------------|
|
|
63
|
+
| Slide title | 48-64px | 700 | 1.2-1.3 |
|
|
64
|
+
| Section heading | 36-44px | 700 | 1.3 |
|
|
65
|
+
| Body text | 24-30px | 400 | 1.6-1.7 |
|
|
66
|
+
| Caption / footnote | 16-18px | 400 | 1.4 |
|
|
67
|
+
| Data callout (big number) | 56-80px | 700 | 1.1 |
|
|
68
|
+
| Unit label (next to number) | 24-28px | 700 | - |
|
|
69
|
+
|
|
70
|
+
**Rules:**
|
|
71
|
+
- Maximum 3 font sizes per slide
|
|
72
|
+
- Japanese body text needs `line-height: 1.6` minimum (1.7 recommended). English-designed layouts with 1.4 will feel cramped
|
|
73
|
+
- `letter-spacing: 0.05em` for body, `0.02em` for headings
|
|
74
|
+
- Numbers should be large, units one size smaller: `<span style="font-size:56px">+15</span><span style="font-size:26px">%</span>`
|
|
75
|
+
- Never go below 16px on any slide element
|
|
76
|
+
|
|
77
|
+
### Japanese Typesetting CSS
|
|
78
|
+
|
|
79
|
+
```css
|
|
80
|
+
.slide {
|
|
81
|
+
line-break: strict; /* kinsoku shori (禁則処理) */
|
|
82
|
+
word-break: normal; /* never use break-all for Japanese */
|
|
83
|
+
overflow-wrap: break-word; /* fallback for long strings */
|
|
84
|
+
font-feature-settings: "palt" 1; /* tighter punctuation spacing */
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Kinsoku — Prohibited Line Breaks
|
|
89
|
+
|
|
90
|
+
Characters that must NOT start a line:
|
|
91
|
+
```
|
|
92
|
+
)〕]}〉》」』】、。,.?!ー・ぁぃぅぇぉっゃゅょァィゥェォッャュョ
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Characters that must NOT end a line:
|
|
96
|
+
```
|
|
97
|
+
(〔[{〈《「『【
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Punctuation Rules
|
|
101
|
+
|
|
102
|
+
- Use **full-width** punctuation in Japanese text (、。「」) — half-width causes baseline misalignment
|
|
103
|
+
- Exception: `?` and `!` may use half-width for visual tension
|
|
104
|
+
- Replace parentheses with `|` vertical bars or `[]` brackets where possible for cleaner appearance
|
|
105
|
+
|
|
106
|
+
## Color
|
|
107
|
+
|
|
108
|
+
### Palette Rule
|
|
109
|
+
|
|
110
|
+
3 colors maximum: **base + main + accent**
|
|
111
|
+
|
|
112
|
+
- Avoid pure/raw colors (原色) — use slightly gray-toned versions
|
|
113
|
+
- Avoid pure black (`#000000`) — use dark navy or charcoal (`#1a1a1a`, `#15286d`, `#1e293b`)
|
|
114
|
+
- Accent color only for critical emphasis points
|
|
115
|
+
|
|
116
|
+
### Contrast (WCAG AA + DADS)
|
|
117
|
+
|
|
118
|
+
| Element | Minimum ratio |
|
|
119
|
+
|---------|--------------|
|
|
120
|
+
| All text (any size) | 4.5:1 |
|
|
121
|
+
| Non-text UI elements (icons, borders) | 3:1 |
|
|
122
|
+
| Brand colors used as text | 4.5:1 (adjust brightness if needed) |
|
|
123
|
+
|
|
124
|
+
Note: Japan Digital Agency (DADS) removes the large-text exemption. Even 48px+ headings must meet 4.5:1.
|
|
125
|
+
|
|
126
|
+
### Do NOT rely on color alone
|
|
127
|
+
|
|
128
|
+
- Comparison/status must use labels + shape + icon, not just color
|
|
129
|
+
- Charts with thin lines: add text annotations near data points
|
|
130
|
+
- If brand color fails contrast, adjust brightness while keeping hue
|
|
131
|
+
|
|
132
|
+
## Layout
|
|
133
|
+
|
|
134
|
+
### Safe Margins
|
|
135
|
+
|
|
136
|
+
For 1600x900px slides: **64-80px horizontal, 48-64px vertical** (approximately 5% of dimensions)
|
|
137
|
+
|
|
138
|
+
### Alignment
|
|
139
|
+
|
|
140
|
+
- Left-align Japanese body text — never full-justify on slides (causes ugly gaps)
|
|
141
|
+
- Use Z-pattern (left-to-right, top-to-bottom) as default reading flow
|
|
142
|
+
- All elements must align to a consistent grid across slides
|
|
143
|
+
|
|
144
|
+
### Grid System
|
|
145
|
+
|
|
146
|
+
12-column grid with ~24px gutters works well for 1600x900:
|
|
147
|
+
|
|
148
|
+
```css
|
|
149
|
+
.grid { display: grid; grid-template-columns: repeat(12, 1fr); column-gap: 24px; }
|
|
150
|
+
.col4 { grid-column: span 4; }
|
|
151
|
+
.col6 { grid-column: span 6; }
|
|
152
|
+
.col8 { grid-column: span 8; }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Controlling Line Length
|
|
156
|
+
|
|
157
|
+
Use `max-width` to prevent lines from running too long:
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
.body { max-width: 1100px; } /* ~30-35 chars at 30px */
|
|
161
|
+
.reading { max-width: 1300px; } /* ~38-40 chars at 30px */
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Icons and Images
|
|
165
|
+
|
|
166
|
+
- Icons are **supplementary** — meaning must be conveyed by text, not icon alone
|
|
167
|
+
- One icon = one concept (do not pack multiple ideas into one icon)
|
|
168
|
+
- Use a single icon family consistently (do not mix outline and filled styles)
|
|
169
|
+
- Prefer rounded, simple shapes for approachable feel
|
|
170
|
+
- Minimum icon size: 20px for slides
|
|
171
|
+
|
|
172
|
+
## Japanese Base CSS Template
|
|
173
|
+
|
|
174
|
+
```css
|
|
175
|
+
.slide {
|
|
176
|
+
width: 1600px;
|
|
177
|
+
height: 900px;
|
|
178
|
+
margin: 0; padding: 0;
|
|
179
|
+
box-sizing: border-box;
|
|
180
|
+
overflow: hidden;
|
|
181
|
+
position: relative;
|
|
182
|
+
background: #ffffff;
|
|
183
|
+
color: #1a1a1a;
|
|
184
|
+
font-family: "Noto Sans JP", "BIZ UDPGothic", "Hiragino Kaku Gothic ProN", sans-serif;
|
|
185
|
+
line-break: strict;
|
|
186
|
+
word-break: normal;
|
|
187
|
+
font-feature-settings: "palt" 1;
|
|
188
|
+
}
|
|
189
|
+
.slide-inner {
|
|
190
|
+
position: absolute;
|
|
191
|
+
top: 0; left: 0;
|
|
192
|
+
width: 100%; height: 100%;
|
|
193
|
+
padding: 64px 80px;
|
|
194
|
+
box-sizing: border-box;
|
|
195
|
+
}
|
|
196
|
+
.title {
|
|
197
|
+
font-size: 56px;
|
|
198
|
+
font-weight: 700;
|
|
199
|
+
line-height: 1.25;
|
|
200
|
+
letter-spacing: 0.02em;
|
|
201
|
+
white-space: nowrap;
|
|
202
|
+
}
|
|
203
|
+
.message {
|
|
204
|
+
margin-top: 16px;
|
|
205
|
+
font-size: 28px;
|
|
206
|
+
font-weight: 500;
|
|
207
|
+
line-height: 1.5;
|
|
208
|
+
max-width: 1200px;
|
|
209
|
+
}
|
|
210
|
+
.h2 {
|
|
211
|
+
font-size: 40px;
|
|
212
|
+
font-weight: 700;
|
|
213
|
+
line-height: 1.3;
|
|
214
|
+
letter-spacing: 0.02em;
|
|
215
|
+
}
|
|
216
|
+
.body {
|
|
217
|
+
font-size: 28px;
|
|
218
|
+
line-height: 1.7;
|
|
219
|
+
letter-spacing: 0.05em;
|
|
220
|
+
max-width: 1100px;
|
|
221
|
+
}
|
|
222
|
+
.note {
|
|
223
|
+
font-size: 18px;
|
|
224
|
+
line-height: 1.5;
|
|
225
|
+
color: #595959;
|
|
226
|
+
}
|
|
227
|
+
.num {
|
|
228
|
+
font-size: 56px;
|
|
229
|
+
font-weight: 700;
|
|
230
|
+
line-height: 1.1;
|
|
231
|
+
}
|
|
232
|
+
.unit {
|
|
233
|
+
font-size: 26px;
|
|
234
|
+
font-weight: 700;
|
|
235
|
+
margin-left: 4px;
|
|
236
|
+
}
|
|
237
|
+
.cards {
|
|
238
|
+
display: flex;
|
|
239
|
+
gap: 20px;
|
|
240
|
+
}
|
|
241
|
+
.card {
|
|
242
|
+
flex: 1;
|
|
243
|
+
min-width: 0;
|
|
244
|
+
background: #f5f5f5;
|
|
245
|
+
border-radius: 16px;
|
|
246
|
+
padding: 24px;
|
|
247
|
+
box-sizing: border-box;
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Pre-Export Checklist (Japanese-Specific)
|
|
252
|
+
|
|
253
|
+
**Text quality:**
|
|
254
|
+
- [ ] Each slide has exactly 1 message
|
|
255
|
+
- [ ] Titles use noun endings (体言止め), messages are sentences
|
|
256
|
+
- [ ] No slide exceeds 105 chars (presentation mode) or 285 chars (handout mode)
|
|
257
|
+
- [ ] No bullet line exceeds 40 chars
|
|
258
|
+
- [ ] No unnatural line breaks (kinsoku violations)
|
|
259
|
+
- [ ] Punctuation is full-width (、。「」)
|
|
260
|
+
|
|
261
|
+
**Typography:**
|
|
262
|
+
- [ ] Body text line-height is 1.6+
|
|
263
|
+
- [ ] Font sizes follow 3-tier hierarchy
|
|
264
|
+
- [ ] Numbers are large, units are smaller
|
|
265
|
+
- [ ] All text has white-space:nowrap where appropriate
|
|
266
|
+
- [ ] Text containers have explicit width/min-width in px
|
|
267
|
+
|
|
268
|
+
**Visual:**
|
|
269
|
+
- [ ] Color palette is 3 colors or fewer
|
|
270
|
+
- [ ] All text contrast is 4.5:1+
|
|
271
|
+
- [ ] No meaning conveyed by color alone
|
|
272
|
+
- [ ] Consistent alignment across all slides
|
|
273
|
+
- [ ] Safe margins maintained (64-80px)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Rewrite Patterns
|
|
2
|
+
|
|
3
|
+
Use this reference when converting web markup into slide-safe HTML/CSS.
|
|
4
|
+
|
|
5
|
+
## Pattern 1: Page to Slide
|
|
6
|
+
|
|
7
|
+
Problem:
|
|
8
|
+
|
|
9
|
+
- full webpage
|
|
10
|
+
- header, sidebar, footer, scroll regions
|
|
11
|
+
- no single export root
|
|
12
|
+
|
|
13
|
+
Rewrite:
|
|
14
|
+
|
|
15
|
+
- create one `.slide` root
|
|
16
|
+
- move only presentation content into the slide
|
|
17
|
+
- remove navigation and utility chrome
|
|
18
|
+
- give the slide explicit width and height
|
|
19
|
+
|
|
20
|
+
## Pattern 2: Runtime Chart to Static Graphic
|
|
21
|
+
|
|
22
|
+
Problem:
|
|
23
|
+
|
|
24
|
+
- chart library renders to `canvas`
|
|
25
|
+
- chart appears only after runtime boot
|
|
26
|
+
|
|
27
|
+
Rewrite:
|
|
28
|
+
|
|
29
|
+
- replace with inline `svg` when possible
|
|
30
|
+
- otherwise replace with pre-rendered image
|
|
31
|
+
- if the chart is simple, rebuild it using normal DOM bars or a semantic `table`
|
|
32
|
+
|
|
33
|
+
Prefer SVG over canvas when editability matters.
|
|
34
|
+
|
|
35
|
+
## Pattern 3: Responsive Layout to Fixed Layout
|
|
36
|
+
|
|
37
|
+
Problem:
|
|
38
|
+
|
|
39
|
+
- layout depends on viewport width
|
|
40
|
+
- breakpoints change content flow
|
|
41
|
+
|
|
42
|
+
Rewrite:
|
|
43
|
+
|
|
44
|
+
- choose one explicit slide size
|
|
45
|
+
- pin widths, heights, padding, and gaps for that size
|
|
46
|
+
- author for the slide, not for arbitrary screens
|
|
47
|
+
|
|
48
|
+
## Pattern 4: Decorative Web Effects to Export-Safe Effects
|
|
49
|
+
|
|
50
|
+
Problem:
|
|
51
|
+
|
|
52
|
+
- heavy blur stacks
|
|
53
|
+
- blend modes
|
|
54
|
+
- masking
|
|
55
|
+
- layered clipping
|
|
56
|
+
|
|
57
|
+
Rewrite:
|
|
58
|
+
|
|
59
|
+
- replace with standard `linear-gradient(...)`
|
|
60
|
+
- replace blend effects with explicit color values
|
|
61
|
+
- replace masked shapes with simple rounded blocks or inline SVG
|
|
62
|
+
- keep decorative effects visually similar but structurally simpler
|
|
63
|
+
|
|
64
|
+
## Pattern 5: App UI to Presentation Card
|
|
65
|
+
|
|
66
|
+
Problem:
|
|
67
|
+
|
|
68
|
+
- tabs, filters, dropdowns, buttons, badges, and control chrome dominate the markup
|
|
69
|
+
|
|
70
|
+
Rewrite:
|
|
71
|
+
|
|
72
|
+
- keep the information-bearing state only
|
|
73
|
+
- turn controls into static labels when they explain context
|
|
74
|
+
- remove affordances that imply interaction
|
|
75
|
+
- present the resulting state as cards, tables, summaries, or diagrams
|
|
76
|
+
|
|
77
|
+
## Pattern 6: Unsafe Input to Safe Input
|
|
78
|
+
|
|
79
|
+
Problem:
|
|
80
|
+
|
|
81
|
+
- scripts
|
|
82
|
+
- event handlers
|
|
83
|
+
- `javascript:` URLs
|
|
84
|
+
|
|
85
|
+
Rewrite:
|
|
86
|
+
|
|
87
|
+
- remove executable code entirely
|
|
88
|
+
- keep only presentational markup and safe asset URLs
|
|
89
|
+
- ensure the exported preview document can render deterministically without running app logic
|
|
90
|
+
|
|
91
|
+
## Pattern 8: Pixel-Perfect Slide Fit
|
|
92
|
+
|
|
93
|
+
Problem:
|
|
94
|
+
|
|
95
|
+
- slide background does not fill the full PowerPoint canvas
|
|
96
|
+
- unwanted white margins or gaps appear around the slide edges
|
|
97
|
+
- padding on `.slide` pushes the background inward, leaving blank areas
|
|
98
|
+
|
|
99
|
+
Rewrite:
|
|
100
|
+
|
|
101
|
+
- set `margin: 0; padding: 0; box-sizing: border-box; overflow: hidden` on every `.slide`
|
|
102
|
+
- apply backgrounds (color, gradient, image) directly on the `.slide` element
|
|
103
|
+
- use an inner `div` with `position: absolute; top: 0; left: 0; width: 100%; height: 100%` for content padding
|
|
104
|
+
- never put content padding directly on the `.slide` when it has a background
|
|
105
|
+
- set `position: relative` on `.slide` so absolute children are scoped correctly
|
|
106
|
+
- use only fixed `px` units — never `%`, `vw`, `vh`, `em`, or `rem` for layout dimensions
|
|
107
|
+
|
|
108
|
+
## Pattern 7: Text Centering in Background-Colored Elements
|
|
109
|
+
|
|
110
|
+
Problem:
|
|
111
|
+
|
|
112
|
+
- text inside buttons, badges, or cards with `background-color`/`background` drifts to a wrong position in PPTX
|
|
113
|
+
- the PPTX converter maps the background `div` to a shape and the inner `span` to a separate text box — they become independent objects
|
|
114
|
+
- flexbox centering on the parent does not propagate into the PPTX text box
|
|
115
|
+
- padding-only sizing causes shape and text to misalign
|
|
116
|
+
|
|
117
|
+
Rewrite:
|
|
118
|
+
|
|
119
|
+
- do NOT nest `<span>` inside a background `<div>` for buttons — put text directly in the background element
|
|
120
|
+
- if nesting is needed, give the inner text element `width: 100%` and `text-align: center`
|
|
121
|
+
- always use explicit `width` and `height` on the background element (not padding-only sizing)
|
|
122
|
+
- add `text-align: center` and `display: flex; justify-content: center; align-items: center` to the container
|
|
123
|
+
|
|
124
|
+
This pattern applies to ALL elements where background and text must stay together: buttons, stat cards, badges, tags, CTAs, labels, progress indicators, etc.
|
|
125
|
+
|
|
126
|
+
## Pattern 9: Styled Tables — `<table>` vs div+flexbox
|
|
127
|
+
|
|
128
|
+
Problem:
|
|
129
|
+
|
|
130
|
+
- `<table>` with gradient backgrounds on `<th>` or `<td>` causes text to disappear or shrink to ~6pt in PPTX
|
|
131
|
+
- nested `<span>` and `<br/>` inside table cells lose content during conversion
|
|
132
|
+
- `border-collapse: separate` and complex cell styling break in native PPTX tables
|
|
133
|
+
|
|
134
|
+
Root cause: the PPTX converter maps `<table>` to a native PPTX table object, which does not support CSS gradients, and handles inline element nesting poorly.
|
|
135
|
+
|
|
136
|
+
Rewrite:
|
|
137
|
+
|
|
138
|
+
- for simple data tables with solid-color backgrounds and plain text, keep `<table>`
|
|
139
|
+
- for styled grids with gradient headers, rich cell content (bold titles + bullet lists), or per-cell border-radius, use div+flexbox rows instead
|
|
140
|
+
- each "row" is a `display: flex` container; each "cell" is a fixed-width div
|
|
141
|
+
- put text directly in the div (Pattern 7 applies) or use `<p>` tags for multi-line content — avoid `<span>` + `<br/>` combos
|
|
142
|
+
- apply background colors/gradients on the div, not on table elements
|
|
143
|
+
|
|
144
|
+
## Pattern 10: Text Wrapping and Splitting Prevention
|
|
145
|
+
|
|
146
|
+
Problem:
|
|
147
|
+
|
|
148
|
+
- text in flexbox/grid children wraps unexpectedly in PPTX output
|
|
149
|
+
- short text like year numbers ("2022") splits into "202" + "2"
|
|
150
|
+
- Japanese headings split mid-word
|
|
151
|
+
- headings, labels, stats, or single-line text gets broken across lines
|
|
152
|
+
- ALL flex/grid layouts are affected, not just `space-between`
|
|
153
|
+
|
|
154
|
+
Root cause: the PPTX converter calculates text box width from the HTML layout. Without explicit sizing, auto-sized children may receive far less width than the text needs — even `flex: 1` children can get narrow text boxes.
|
|
155
|
+
|
|
156
|
+
Rewrite:
|
|
157
|
+
|
|
158
|
+
- add `white-space: nowrap` on EVERY single-line text element (headings, labels, years, stats, names, badges)
|
|
159
|
+
- give ALL flex/grid children an explicit `width` or `min-width` in px — never rely on `flex: 1` alone
|
|
160
|
+
- for equal columns, calculate: `(container width - total gaps) / number of columns` and set explicitly
|
|
161
|
+
- for large font text (40px+), ensure the container is at least `(char count × font-size × 0.7)` px wide for Latin, `(char count × font-size × 1.1)` px wide for Japanese/CJK
|
|
162
|
+
- when in doubt, make the container wider than you think necessary — extra space is invisible, but truncated text is broken
|
|
163
|
+
|
|
164
|
+
This pattern is the single most common cause of PPTX conversion defects. Apply it to ALL layouts: timelines, grids, stat cards, headers, footers, comparison columns, navigation rows, and any element containing text.
|
|
165
|
+
|
|
166
|
+
## Template Skeleton
|
|
167
|
+
|
|
168
|
+
Use this as a default starting point:
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<!doctype html>
|
|
172
|
+
<html>
|
|
173
|
+
<head>
|
|
174
|
+
<meta charset="utf-8" />
|
|
175
|
+
<style>
|
|
176
|
+
body {
|
|
177
|
+
margin: 0;
|
|
178
|
+
background: #f3f4f6;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.slide {
|
|
182
|
+
width: 1600px;
|
|
183
|
+
height: 900px;
|
|
184
|
+
box-sizing: border-box;
|
|
185
|
+
padding: 56px;
|
|
186
|
+
background: #ffffff;
|
|
187
|
+
color: #111827;
|
|
188
|
+
font-family: Inter, Arial, sans-serif;
|
|
189
|
+
}
|
|
190
|
+
</style>
|
|
191
|
+
</head>
|
|
192
|
+
<body>
|
|
193
|
+
<section class="slide">
|
|
194
|
+
<h1>Title</h1>
|
|
195
|
+
<p>Slide-safe content.</p>
|
|
196
|
+
</section>
|
|
197
|
+
</body>
|
|
198
|
+
</html>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Rewrite Priorities
|
|
202
|
+
|
|
203
|
+
Apply fixes in this order:
|
|
204
|
+
|
|
205
|
+
1. make the export root explicit
|
|
206
|
+
2. remove runtime dependencies
|
|
207
|
+
3. fix unsupported assets and CORS risks
|
|
208
|
+
4. simplify unsupported CSS effects
|
|
209
|
+
5. improve editability by replacing raster-prone regions
|
|
210
|
+
|
|
211
|
+
## Response Pattern
|
|
212
|
+
|
|
213
|
+
When rewriting for a user, prefer this structure:
|
|
214
|
+
|
|
215
|
+
- `What changed`
|
|
216
|
+
- `Why it is safer for PPTX export`
|
|
217
|
+
- `What may still rasterize`
|
|
218
|
+
- `Rewritten HTML/CSS`
|