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.
Files changed (32) hide show
  1. package/app/docs/content.js +50 -16
  2. package/cli/dist/commands/edit.d.ts +1 -1
  3. package/cli/dist/commands/edit.js +30 -13
  4. package/cli/dist/index.js +0 -0
  5. package/lib/local-editor-server.js +316 -0
  6. package/lib/local-editor-state.js +45 -0
  7. package/lib/local-slide-editor-launcher.js +19 -18
  8. package/lib/pptx-studio-mcp-core.js +15 -9
  9. package/local-editor-app/app/api/edit-slide/local-health/route.js +16 -0
  10. package/local-editor-app/app/edit-slide/edit-slide-client.jsx +13153 -0
  11. package/local-editor-app/app/edit-slide/page.jsx +13 -0
  12. package/local-editor-app/app/globals.css +4 -0
  13. package/local-editor-app/app/layout.jsx +14 -0
  14. package/local-editor-app/components/studio/edit-property-panel.jsx +1061 -0
  15. package/local-editor-app/lib/edit-panel-value-normalizer.js +97 -0
  16. package/local-editor-app/lib/edit-slide-editor-helpers.js +120 -0
  17. package/local-editor-app/lib/edit-slide-url-security.js +247 -0
  18. package/local-editor-app/next.config.mjs +31 -0
  19. package/local-editor-app/package.json +7 -0
  20. package/mcp/pptx-studio-mcp-server.mjs +1 -1
  21. package/package.json +13 -2
  22. package/public/skills/html2pptx/SKILL.md +635 -0
  23. package/public/skills/html2pptx/references/automation-contract.md +68 -0
  24. package/public/skills/html2pptx/references/input-contract.md +107 -0
  25. package/public/skills/html2pptx/references/japanese-slide-design.md +273 -0
  26. package/public/skills/html2pptx/references/rewrite-patterns.md +218 -0
  27. package/public/skills/icon-generator/SKILL.md +133 -0
  28. package/public/skills/open-slide/SKILL.md +160 -0
  29. package/public/skills/publish-template/SKILL.md +215 -0
  30. package/public/skills/register-template/SKILL.md +142 -0
  31. package/scripts/install-mcp.mjs +28 -2
  32. 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`