dsh-office-kit 0.2.0 → 0.3.1
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/CAPABILITY.md +147 -68
- package/README.md +3 -1
- package/assets/skills/excel-live-control/SKILL.md +234 -0
- package/assets/skills/excel-live-control/container_tools/live_excel.py +1589 -0
- package/assets/skills/excel-live-control/domain_guidance/financial_models.md +86 -0
- package/assets/skills/excel-live-control/domain_guidance/healthcare.md +58 -0
- package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +53 -0
- package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +53 -0
- package/assets/skills/excel-live-control/references/office-automation.md +207 -0
- package/assets/skills/excel-live-control/references/read_only_qna.md +59 -0
- package/assets/skills/excel-live-control/style_guidelines.md +87 -0
- package/assets/skills/excel-live-control/workflows/create_workflows.md +78 -0
- package/assets/skills/excel-live-control/workflows/edit_workflows.md +72 -0
- package/assets/skills/office-documents/SKILL.md +90 -77
- package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +86 -0
- package/assets/skills/office-documents/ooxml/comments.md +40 -0
- package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +66 -0
- package/assets/skills/office-documents/ooxml/rels_and_content_types.md +62 -0
- package/assets/skills/office-documents/ooxml/tracked_changes.md +53 -0
- package/assets/skills/office-documents/references/docx-structure.md +83 -0
- package/assets/skills/office-documents/references/template-elicitation.md +49 -0
- package/assets/skills/office-documents/references/writing-quality.md +49 -0
- package/assets/skills/office-documents/render_docx.py +99 -0
- package/assets/skills/office-documents/scripts/a11y_audit.py +201 -0
- package/assets/skills/office-documents/scripts/accept_tracked_changes.py +158 -0
- package/assets/skills/office-documents/scripts/add_tracked_replacements.py +155 -0
- package/assets/skills/office-documents/scripts/append_blocks.py +115 -0
- package/assets/skills/office-documents/scripts/apply_template_styles.py +111 -0
- package/assets/skills/office-documents/scripts/captions_and_crossrefs.py +109 -0
- package/assets/skills/office-documents/scripts/comments_add.py +143 -0
- package/assets/skills/office-documents/scripts/comments_apply_patch.py +121 -0
- package/assets/skills/office-documents/scripts/comments_extract.py +92 -0
- package/assets/skills/office-documents/scripts/comments_strip.py +81 -0
- package/assets/skills/office-documents/scripts/content_controls.py +199 -0
- package/assets/skills/office-documents/scripts/core_properties.py +131 -0
- package/assets/skills/office-documents/scripts/docx_kit.py +594 -0
- package/assets/skills/office-documents/scripts/docx_ooxml_patch.py +232 -0
- package/assets/skills/office-documents/scripts/docx_table_to_csv.py +106 -0
- package/assets/skills/office-documents/scripts/fields_materialize.py +73 -0
- package/assets/skills/office-documents/scripts/fields_report.py +66 -0
- package/assets/skills/office-documents/scripts/flatten_ref_fields.py +69 -0
- package/assets/skills/office-documents/scripts/footnotes_report.py +84 -0
- package/assets/skills/office-documents/scripts/google_docs_title_sanitize.py +103 -0
- package/assets/skills/office-documents/scripts/heading_audit.py +88 -0
- package/assets/skills/office-documents/scripts/images_audit.py +87 -0
- package/assets/skills/office-documents/scripts/insert_note.py +133 -0
- package/assets/skills/office-documents/scripts/insert_ref_fields.py +97 -0
- package/assets/skills/office-documents/scripts/insert_toc.py +91 -0
- package/assets/skills/office-documents/scripts/internal_nav.py +153 -0
- package/assets/skills/office-documents/scripts/make_fixtures.py +176 -0
- package/assets/skills/office-documents/scripts/merge_docx_append.py +246 -0
- package/assets/skills/office-documents/scripts/privacy_scrub.py +138 -0
- package/assets/skills/office-documents/scripts/redact_docx.py +120 -0
- package/assets/skills/office-documents/scripts/render_and_diff.py +108 -0
- package/assets/skills/office-documents/scripts/replace_text.py +161 -0
- package/assets/skills/office-documents/scripts/section_audit.py +98 -0
- package/assets/skills/office-documents/scripts/set_protection.py +99 -0
- package/assets/skills/office-documents/scripts/style_lint.py +118 -0
- package/assets/skills/office-documents/scripts/style_normalize.py +110 -0
- package/assets/skills/office-documents/scripts/table_geometry.py +174 -0
- package/assets/skills/office-documents/scripts/watermark_add.py +55 -0
- package/assets/skills/office-documents/scripts/watermark_audit_remove.py +74 -0
- package/assets/skills/office-documents/scripts/xlsx_to_docx_table.py +124 -0
- package/assets/skills/office-documents/tasks/accessibility_a11y.md +45 -0
- package/assets/skills/office-documents/tasks/captions_crossrefs.md +49 -0
- package/assets/skills/office-documents/tasks/clean_tracked_changes.md +49 -0
- package/assets/skills/office-documents/tasks/comments_manage.md +59 -0
- package/assets/skills/office-documents/tasks/compare_diff.md +40 -0
- package/assets/skills/office-documents/tasks/create_edit.md +107 -0
- package/assets/skills/office-documents/tasks/equations.md +59 -0
- package/assets/skills/office-documents/tasks/fields_update.md +44 -0
- package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +50 -0
- package/assets/skills/office-documents/tasks/footnotes_endnotes.md +38 -0
- package/assets/skills/office-documents/tasks/forms_content_controls.md +48 -0
- package/assets/skills/office-documents/tasks/headings_numbering.md +55 -0
- package/assets/skills/office-documents/tasks/images_figures.md +63 -0
- package/assets/skills/office-documents/tasks/multi_doc_merge.md +43 -0
- package/assets/skills/office-documents/tasks/navigation_internal_links.md +38 -0
- package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +45 -0
- package/assets/skills/office-documents/tasks/protection_restrict_editing.md +41 -0
- package/assets/skills/office-documents/tasks/read_review.md +50 -0
- package/assets/skills/office-documents/tasks/redaction_anonymization.md +42 -0
- package/assets/skills/office-documents/tasks/sections_layout.md +54 -0
- package/assets/skills/office-documents/tasks/style_lint_normalize.md +44 -0
- package/assets/skills/office-documents/tasks/tables_spreadsheets.md +64 -0
- package/assets/skills/office-documents/tasks/templates_style_packs.md +53 -0
- package/assets/skills/office-documents/tasks/toc_workflow.md +39 -0
- package/assets/skills/office-documents/tasks/verify_render.md +50 -0
- package/assets/skills/office-documents/tasks/watermarks_background.md +35 -0
- package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +47 -0
- package/assets/skills/office-documents/troubleshooting/run_splitting.md +36 -0
- package/assets/skills/office-pdf/SKILL.md +73 -56
- package/assets/skills/office-pdf/references/form-fields.md +56 -0
- package/assets/skills/office-pdf/references/geometry.md +44 -0
- package/assets/skills/office-pdf/references/layout-quality.md +41 -0
- package/assets/skills/office-pdf/references/limits.md +58 -0
- package/assets/skills/office-pdf/scripts/extract_text.py +172 -0
- package/assets/skills/office-pdf/scripts/forms.py +556 -0
- package/assets/skills/office-pdf/scripts/metadata.py +161 -0
- package/assets/skills/office-pdf/scripts/page_ops.py +198 -0
- package/assets/skills/office-pdf/scripts/redact_region.py +347 -0
- package/assets/skills/office-pdf/scripts/render_pages.py +207 -0
- package/assets/skills/office-pdf/scripts/split_pages.py +155 -0
- package/assets/skills/office-pdf/scripts/stamp_overlay.py +199 -0
- package/assets/skills/office-pdf/tasks/annotations.md +98 -0
- package/assets/skills/office-pdf/tasks/create.md +75 -0
- package/assets/skills/office-pdf/tasks/edit-pages.md +71 -0
- package/assets/skills/office-pdf/tasks/forms.md +67 -0
- package/assets/skills/office-pdf/tasks/read.md +62 -0
- package/assets/skills/office-pdf/tasks/redact.md +72 -0
- package/assets/skills/office-pdf/tasks/stamp.md +60 -0
- package/assets/skills/office-presentations/SKILL.md +141 -87
- package/assets/skills/office-presentations/container_tools/add_slides.py +143 -0
- package/assets/skills/office-presentations/container_tools/core_properties.py +127 -0
- package/assets/skills/office-presentations/container_tools/create_montage.py +133 -0
- package/assets/skills/office-presentations/container_tools/inspect_presentation_layout_geometry.py +292 -0
- package/assets/skills/office-presentations/container_tools/inspect_presentation_package_integrity.py +164 -0
- package/assets/skills/office-presentations/container_tools/native_chart_title_gate.py +151 -0
- package/assets/skills/office-presentations/container_tools/native_quantitative_chart_gate.py +206 -0
- package/assets/skills/office-presentations/container_tools/native_table_arithmetic_gate.py +219 -0
- package/assets/skills/office-presentations/container_tools/ooxml_helpers.py +352 -0
- package/assets/skills/office-presentations/container_tools/preview_render.py +382 -0
- package/assets/skills/office-presentations/container_tools/render_slides.py +146 -0
- package/assets/skills/office-presentations/container_tools/replace_text.py +175 -0
- package/assets/skills/office-presentations/container_tools/template_source_fidelity_gate.py +236 -0
- package/assets/skills/office-presentations/domain_guidance/finance.md +66 -0
- package/assets/skills/office-presentations/recipes/README.md +71 -0
- package/assets/skills/office-presentations/recipes/autolayout.md +88 -0
- package/assets/skills/office-presentations/recipes/connectors.md +83 -0
- package/assets/skills/office-presentations/recipes/images.md +80 -0
- package/assets/skills/office-presentations/recipes/master-and-layouts.md +127 -0
- package/assets/skills/office-presentations/recipes/native-charts.md +87 -0
- package/assets/skills/office-presentations/recipes/rich-text-runs.md +86 -0
- package/assets/skills/office-presentations/recipes/speaker-notes.md +65 -0
- package/assets/skills/office-presentations/recipes/tables.md +88 -0
- package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +71 -0
- package/assets/skills/office-presentations/recipes/theme-tokens.md +87 -0
- package/assets/skills/office-presentations/references/authoring-workflow.md +65 -0
- package/assets/skills/office-presentations/references/finalization.md +63 -0
- package/assets/skills/office-presentations/references/native-bullets.md +78 -0
- package/assets/skills/office-presentations/references/native-evidence.md +67 -0
- package/assets/skills/office-presentations/references/style-guidelines.md +66 -0
- package/assets/skills/office-presentations/references/templates.md +76 -0
- package/assets/skills/office-presentations/routing/google_slides.md +45 -0
- package/assets/skills/office-presentations/tasks/apply-annotations.md +83 -0
- package/assets/skills/office-presentations/tasks/charts-tables-notes.md +79 -0
- package/assets/skills/office-presentations/tasks/create-deck.md +106 -0
- package/assets/skills/office-presentations/tasks/edit-deck.md +93 -0
- package/assets/skills/office-presentations/tasks/inspect-and-verify.md +107 -0
- package/assets/skills/office-presentations/tasks/template-following.md +132 -0
- package/assets/skills/office-presentations/template_following_scripts/check_template_fidelity.py +183 -0
- package/assets/skills/office-presentations/template_following_scripts/inspect_template_deck.py +161 -0
- package/assets/skills/office-presentations/template_following_scripts/make_contact_sheet.py +118 -0
- package/assets/skills/office-presentations/template_following_scripts/prepare_template_starter_deck.py +246 -0
- package/assets/skills/office-presentations/template_following_scripts/validate_template_plan.py +192 -0
- package/assets/skills/office-spreadsheets/SKILL.md +105 -101
- package/assets/skills/office-spreadsheets/container_tools/add_chart.py +243 -0
- package/assets/skills/office-spreadsheets/container_tools/add_image.py +114 -0
- package/assets/skills/office-spreadsheets/container_tools/append_rows.py +129 -0
- package/assets/skills/office-spreadsheets/container_tools/diff_workbooks.py +313 -0
- package/assets/skills/office-spreadsheets/container_tools/inspect_workbook.py +405 -0
- package/assets/skills/office-spreadsheets/container_tools/recalc_gate.py +287 -0
- package/assets/skills/office-spreadsheets/container_tools/set_cells.py +142 -0
- package/assets/skills/office-spreadsheets/container_tools/sheet_ops.py +141 -0
- package/assets/skills/office-spreadsheets/container_tools/style_cells.py +140 -0
- package/assets/skills/office-spreadsheets/recipes/charts.md +66 -0
- package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +69 -0
- package/assets/skills/office-spreadsheets/recipes/data-tables.md +58 -0
- package/assets/skills/office-spreadsheets/recipes/named-ranges.md +41 -0
- package/assets/skills/office-spreadsheets/recipes/number-formats.md +72 -0
- package/assets/skills/office-spreadsheets/recipes/sparklines.md +43 -0
- package/assets/skills/office-spreadsheets/references/charts.md +63 -0
- package/assets/skills/office-spreadsheets/references/domain/financial-models.md +40 -0
- package/assets/skills/office-spreadsheets/references/domain/healthcare.md +22 -0
- package/assets/skills/office-spreadsheets/references/domain/marketing.md +28 -0
- package/assets/skills/office-spreadsheets/references/domain/research.md +22 -0
- package/assets/skills/office-spreadsheets/references/formula-patterns.md +78 -0
- package/assets/skills/office-spreadsheets/references/style-guidelines.md +69 -0
- package/assets/skills/office-spreadsheets/references/workbook-structure.md +60 -0
- package/assets/skills/office-spreadsheets/routing/google-sheets.md +36 -0
- package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +37 -0
- package/assets/skills/office-spreadsheets/tasks/annotations.md +51 -0
- package/assets/skills/office-spreadsheets/tasks/create-workbook.md +66 -0
- package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +38 -0
- package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +69 -0
- package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +38 -0
- package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +57 -0
- package/assets/skills/shared/annotation-recipes.md +252 -0
- package/assets/skills/shared/check_runtime.py +260 -0
- package/assets/skills/shared/common-workflow.md +139 -0
- package/assets/skills/shared/scripts/ensure_raster_image.py +187 -0
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/index.js +246 -89
- package/package.json +1 -1
- package/postinstall.mjs +92 -82
- package/python/office_cli.py +213 -254
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Theme tokens
|
|
2
|
+
|
|
3
|
+
## Mechanics
|
|
4
|
+
|
|
5
|
+
The theme part (`ppt/theme/theme1.xml`) holds two palettes and two font lists:
|
|
6
|
+
|
|
7
|
+
- `dk1/lt1/dk2/lt2/accent1..6/hlink/folHlink` — every `RGBColor` you *do not*
|
|
8
|
+
set falls back to one of these, and PowerPoint's "theme colors" picker edits
|
|
9
|
+
them for the whole deck.
|
|
10
|
+
- `majorFont` / `minorFont` — the heading and body typefaces inherited by every
|
|
11
|
+
run without an explicit font.
|
|
12
|
+
|
|
13
|
+
So: write `RGBColor.rgb` when a colour must never change, and reference a theme
|
|
14
|
+
colour when the user may re-skin the deck. A deck with hard-coded hex
|
|
15
|
+
everywhere cannot be re-branded, which is usually why the user supplied a
|
|
16
|
+
template.
|
|
17
|
+
|
|
18
|
+
## Recipe: define the palette once, use it everywhere
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
"<python>" - <<'PY'
|
|
22
|
+
from pptx import Presentation
|
|
23
|
+
from pptx.dml.color import RGBColor
|
|
24
|
+
from pptx.util import Inches, Pt
|
|
25
|
+
from pptx.enum.dml import MSO_THEME_COLOR
|
|
26
|
+
|
|
27
|
+
PALETTE = {
|
|
28
|
+
"ink": RGBColor(0x16, 0x1D, 0x28),
|
|
29
|
+
"muted": RGBColor(0x5F, 0x6B, 0x7A),
|
|
30
|
+
"accent": RGBColor(0xD9, 0x8B, 0x1E),
|
|
31
|
+
"rule": RGBColor(0xD6, 0xDC, 0xE4),
|
|
32
|
+
}
|
|
33
|
+
TYPE = {"title": Pt(34), "body": Pt(18), "caption": Pt(12)}
|
|
34
|
+
|
|
35
|
+
prs = Presentation()
|
|
36
|
+
prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5)
|
|
37
|
+
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|
38
|
+
|
|
39
|
+
def put(text, left, top, width, size, colour, bold=False):
|
|
40
|
+
box = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(0.6))
|
|
41
|
+
frame = box.text_frame
|
|
42
|
+
frame.word_wrap = True
|
|
43
|
+
frame.margin_left = frame.margin_right = 0
|
|
44
|
+
run = frame.paragraphs[0].add_run()
|
|
45
|
+
run.text = text
|
|
46
|
+
run.font.size = size
|
|
47
|
+
run.font.bold = bold
|
|
48
|
+
run.font.color.rgb = PALETTE[colour]
|
|
49
|
+
return box
|
|
50
|
+
|
|
51
|
+
put("Automation Review", 0.9, 2.4, 11.5, TYPE["title"], "ink", bold=True)
|
|
52
|
+
put("Warehouse network · FY2026", 0.9, 3.3, 11.5, TYPE["body"], "muted")
|
|
53
|
+
put("Source: FY2026 capital plan", 0.9, 6.7, 6.0, TYPE["caption"], "muted")
|
|
54
|
+
prs.save("themed.pptx")
|
|
55
|
+
print("palette keys:", sorted(PALETTE), "theme colour sample:", MSO_THEME_COLOR.ACCENT_1)
|
|
56
|
+
PY
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Reading the theme you were given
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from pptx import Presentation
|
|
63
|
+
prs = Presentation("template.pptx")
|
|
64
|
+
theme = prs.slide_masters[0].part.part_related_by(
|
|
65
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
|
|
66
|
+
)
|
|
67
|
+
blob = theme.blob.decode("utf-8", "ignore")
|
|
68
|
+
print("accent1" in blob, "majorFont" in blob)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`template_following_scripts/inspect_template_deck.py` already reports the font
|
|
72
|
+
names it finds in the theme, so check there before introducing a new typeface.
|
|
73
|
+
|
|
74
|
+
## Pitfalls this avoids
|
|
75
|
+
|
|
76
|
+
- Two similar hexes drifting apart across slides (`#161d28` on one slide,
|
|
77
|
+
`#171e29` on the next) because the colour was retyped instead of referenced.
|
|
78
|
+
- A serif body font set from taste rather than from the theme, so the deck
|
|
79
|
+
contradicts the template it was built in.
|
|
80
|
+
- `font.color.theme_color = MSO_THEME_COLOR.ACCENT_1` *and* `font.color.rgb`
|
|
81
|
+
on the same run: the last assignment wins and the theme reference vanishes.
|
|
82
|
+
|
|
83
|
+
## CLI fast path
|
|
84
|
+
|
|
85
|
+
`pptx create` uses the default template's theme. For a branded deck, start from
|
|
86
|
+
the supplied template (see [master-and-layouts](master-and-layouts.md)) rather
|
|
87
|
+
than recolouring a blank deck.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Authoring workflow
|
|
2
|
+
|
|
3
|
+
## What a deck is, mechanically
|
|
4
|
+
|
|
5
|
+
A `.pptx` is a zip of XML parts: one `presentation.xml` naming the slide order, one
|
|
6
|
+
part per slide, a slide master per theme, a layout per family, chart parts with
|
|
7
|
+
embedded workbooks, notes parts, and a media folder. Everything the reader sees
|
|
8
|
+
comes from those parts, which is why the verification loop reads the file back
|
|
9
|
+
instead of trusting the code that wrote it.
|
|
10
|
+
|
|
11
|
+
Three consequences shape the whole workflow:
|
|
12
|
+
|
|
13
|
+
1. **Geometry is explicit.** Nothing reflows on open except autofit. If two
|
|
14
|
+
shapes overlap in the XML, they overlap on screen.
|
|
15
|
+
2. **Inheritance is real.** A slide draws its background, type sizes and bullet
|
|
16
|
+
glyphs from its layout and master. Overriding at slide level is a per-slide
|
|
17
|
+
decision; overriding at master level is a deck decision.
|
|
18
|
+
3. **Data can stay alive.** A native chart or table keeps its numbers in the
|
|
19
|
+
file and can be checked; a screenshot cannot.
|
|
20
|
+
|
|
21
|
+
## The loop
|
|
22
|
+
|
|
23
|
+
1. **Decide the story**: one sentence per slide, in order, before any XML. A
|
|
24
|
+
slide without a sentence is a slide the audience will not read.
|
|
25
|
+
2. **Pick the frame**: slide size from the target (`13.333 × 7.5 in` is the 16:9
|
|
26
|
+
default; check `prs.slide_width` of a supplied template, never assume).
|
|
27
|
+
3. **Place, top-down**: background, chrome, title, body, evidence. Later shapes
|
|
28
|
+
paint over earlier ones.
|
|
29
|
+
4. **Fill or delete every placeholder.** An empty placeholder is visible in edit
|
|
30
|
+
view and prints "Click to add text".
|
|
31
|
+
5. **Render, look, fix.** `container_tools/render_slides.py` then `read_image` on
|
|
32
|
+
every PNG. Repeat until nothing surprises you.
|
|
33
|
+
|
|
34
|
+
## The numbers that keep a deck readable
|
|
35
|
+
|
|
36
|
+
| Element | Value | Why |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Slide size | 13.333 × 7.5 in | 16:9; 10 × 5.625 in for 16:9 in "wide" templates |
|
|
39
|
+
| Margin | 0.6–0.9 in | Below 0.5 in a projector crops it |
|
|
40
|
+
| Title | 28–36 pt, bold | 44 pt only on covers |
|
|
41
|
+
| Body | 18 pt minimum | The back row rule |
|
|
42
|
+
| Caption / source | 12–14 pt | Never below 11 pt |
|
|
43
|
+
| Line spacing | 1.1–1.2 | Tighter crowds ascenders |
|
|
44
|
+
| Gap between blocks | 0.2–0.4 in | The eye groups by proximity |
|
|
45
|
+
| Footer zone | bottom 0.55 in | Keep text out of it |
|
|
46
|
+
|
|
47
|
+
Convert once and keep the numbers in EMU or inches, not mixed: `Inches(x)` in
|
|
48
|
+
code, `x * 914400` when you must talk to the XML directly.
|
|
49
|
+
|
|
50
|
+
## Deciding slide count
|
|
51
|
+
|
|
52
|
+
One idea per slide. If a slide has two headlines competing, it is two slides. If
|
|
53
|
+
it has one headline and a table too large to read at 14 pt, the table becomes an
|
|
54
|
+
appendix slide and the body slide states the conclusion in one line.
|
|
55
|
+
|
|
56
|
+
A presentation of N minutes needs roughly N/2 content slides at 60–90 seconds
|
|
57
|
+
each, plus a cover and a closing ask.
|
|
58
|
+
|
|
59
|
+
## Where the detail lives
|
|
60
|
+
|
|
61
|
+
- Type, colour, density and cover art: [style-guidelines](style-guidelines.md).
|
|
62
|
+
- Bullets that read as sentences: [native-bullets](native-bullets.md).
|
|
63
|
+
- Charts, tables and notes as evidence: [native-evidence](native-evidence.md).
|
|
64
|
+
- Supplied templates: [templates](templates.md).
|
|
65
|
+
- Pre-delivery checklist: [finalization](finalization.md).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Finalization checklist
|
|
2
|
+
|
|
3
|
+
Run this before `present`. It exists because every item on it has shipped a
|
|
4
|
+
broken deck at least once.
|
|
5
|
+
|
|
6
|
+
## The file
|
|
7
|
+
|
|
8
|
+
- [ ] Opens: `"<python>" "<cli>" pptx read --input deck.pptx` returns slides.
|
|
9
|
+
- [ ] Package is coherent:
|
|
10
|
+
`"<python>" "<skill>/container_tools/inspect_presentation_package_integrity.py" --input deck.pptx`
|
|
11
|
+
→ `passed: true`, no dangling relationships, media and charts present.
|
|
12
|
+
- [ ] Slide count matches the intent; nothing left over from an earlier draft.
|
|
13
|
+
- [ ] Core properties set:
|
|
14
|
+
`"<python>" "<skill>/container_tools/core_properties.py" --input deck.pptx --title "..." --author "..."`
|
|
15
|
+
(an untitled deck shows up as "PowerPoint Presentation" in every file list).
|
|
16
|
+
|
|
17
|
+
## The content
|
|
18
|
+
|
|
19
|
+
- [ ] Every placeholder is filled or deleted — no "Click to add text".
|
|
20
|
+
- [ ] No default chart title ("Chart Title") survives:
|
|
21
|
+
`"<python>" "<skill>/container_tools/native_chart_title_gate.py" --input deck.pptx`.
|
|
22
|
+
- [ ] Totals are arithmetic:
|
|
23
|
+
`"<python>" "<skill>/container_tools/native_table_arithmetic_gate.py" --input deck.pptx --contracts totals.json`.
|
|
24
|
+
- [ ] Charts have their data in the file (portable mode passes) and categories
|
|
25
|
+
are in a meaningful order.
|
|
26
|
+
- [ ] Numbers in the deck agree with the numbers in the source data, at the
|
|
27
|
+
precision shown.
|
|
28
|
+
- [ ] Speaker notes carry the provenance of the non-obvious numbers.
|
|
29
|
+
|
|
30
|
+
## The layout
|
|
31
|
+
|
|
32
|
+
- [ ] Geometry gate passes:
|
|
33
|
+
`"<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx --json-out geometry.json`
|
|
34
|
+
→ `passed: true`; review findings read and consciously accepted.
|
|
35
|
+
- [ ] Nothing outside the slide edge, nothing overlapping the footer zone.
|
|
36
|
+
- [ ] Titles are one or two lines; no title ends in a full stop.
|
|
37
|
+
- [ ] Body text is at least 18 pt, captions at least 12 pt.
|
|
38
|
+
- [ ] One idea per slide, one emphasis per paragraph.
|
|
39
|
+
|
|
40
|
+
## The look
|
|
41
|
+
|
|
42
|
+
- [ ] Rendered at viewing size and actually looked at:
|
|
43
|
+
`"<python>" "<skill>/container_tools/render_slides.py" --input deck.pptx --out-dir preview`
|
|
44
|
+
then `read_image` on each PNG (or on the contact sheet from
|
|
45
|
+
`"<skill>/template_following_scripts/make_contact_sheet.py`).
|
|
46
|
+
- [ ] Text is not clipped, ellipsised or shrunk to illegibility.
|
|
47
|
+
- [ ] Photographs are not stretched; their sources are listed.
|
|
48
|
+
- [ ] Charts read at thumbnail size: the point is visible before any label.
|
|
49
|
+
- [ ] The cover and closing slide both say something.
|
|
50
|
+
|
|
51
|
+
## Delivery
|
|
52
|
+
|
|
53
|
+
- [ ] The file lives in the user's workspace, not in a temp directory.
|
|
54
|
+
- [ ] Output name is either new (`deck.pptx`) or `<original>-edited.pptx`.
|
|
55
|
+
- [ ] `present` called; the reply states what changed in one sentence and, for
|
|
56
|
+
edits, both paths.
|
|
57
|
+
|
|
58
|
+
## When rendering is unavailable
|
|
59
|
+
|
|
60
|
+
`render_slides.py --engine draft` draws a geometry preview with PyMuPDF when no
|
|
61
|
+
office suite is installed. It is honest about being approximate: type is drawn
|
|
62
|
+
at declared sizes in a substitute face, and layout chrome is not rendered. Use
|
|
63
|
+
it to catch overlap, overflow and placement — not to judge typography.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Bullets that read as sentences
|
|
2
|
+
|
|
3
|
+
## The shape of a bullet
|
|
4
|
+
|
|
5
|
+
A bullet is a claim, not a label. Two forms work:
|
|
6
|
+
|
|
7
|
+
- **Claim + consequence**: "Picking is 41% of floor labour hours — travel is the
|
|
8
|
+
cost, not the pick."
|
|
9
|
+
- **Number + meaning**: "12 minutes per order lost to aisle travel."
|
|
10
|
+
|
|
11
|
+
Forms that do not work: a single noun ("Efficiency"), a truncated clause
|
|
12
|
+
("Picking accounts for…"), a list of three adjectives, or a bullet that restates
|
|
13
|
+
the slide title.
|
|
14
|
+
|
|
15
|
+
## Length and count
|
|
16
|
+
|
|
17
|
+
- One line, two at the absolute maximum, per bullet on a 16:9 slide.
|
|
18
|
+
- Three to five bullets. Six is a signal to split; eight is a document.
|
|
19
|
+
- No sub-sub-bullets. If a bullet needs a child, the parent was a section.
|
|
20
|
+
- Keep bullets grammatically parallel: all sentences, or all noun phrases.
|
|
21
|
+
|
|
22
|
+
## Native bullet glyphs
|
|
23
|
+
|
|
24
|
+
Bullets in PowerPoint are paragraph properties, not characters. A bullet
|
|
25
|
+
character typed into the text ("• Picking…") is a bullet that cannot re-indent,
|
|
26
|
+
cannot change level, and looks different from every other bullet in the deck.
|
|
27
|
+
|
|
28
|
+
Set them properly:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
"<python>" - <<'PY'
|
|
32
|
+
from pptx import Presentation
|
|
33
|
+
from pptx.util import Inches, Pt
|
|
34
|
+
from pptx.enum.text import PP_ALIGN
|
|
35
|
+
|
|
36
|
+
prs = Presentation()
|
|
37
|
+
prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5)
|
|
38
|
+
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|
39
|
+
box = slide.shapes.add_textbox(Inches(0.9), Inches(1.8), Inches(11.0), Inches(3.6))
|
|
40
|
+
frame = box.text_frame
|
|
41
|
+
frame.word_wrap = True
|
|
42
|
+
|
|
43
|
+
for index, text in enumerate((
|
|
44
|
+
"Picking is 41% of floor labour hours",
|
|
45
|
+
"Aisle travel costs 12 minutes per order",
|
|
46
|
+
"Manual cycle counts stop the line twice a week",
|
|
47
|
+
)):
|
|
48
|
+
paragraph = frame.paragraphs[0] if index == 0 else frame.add_paragraph()
|
|
49
|
+
paragraph.text = text
|
|
50
|
+
paragraph.font.size = Pt(20)
|
|
51
|
+
paragraph.space_after = Pt(12)
|
|
52
|
+
paragraph.level = 0
|
|
53
|
+
paragraph.alignment = PP_ALIGN.LEFT
|
|
54
|
+
# PowerPoint's own bullet: a literal glyph in the paragraph's pPr
|
|
55
|
+
paragraph._pPr.set("marL", str(Inches(0.3)))
|
|
56
|
+
paragraph._pPr.set("indent", str(-Inches(0.3)))
|
|
57
|
+
bu = paragraph._pPr.makeelement(
|
|
58
|
+
"{http://schemas.openxmlformats.org/drawingml/2006/main}buChar", {"char": "•"}
|
|
59
|
+
)
|
|
60
|
+
paragraph._pPr.append(bu)
|
|
61
|
+
|
|
62
|
+
prs.save("bullets.pptx")
|
|
63
|
+
print("bullets:", len(frame.paragraphs))
|
|
64
|
+
PY
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The `marL`/`indent` pair is what pulls the second line of a wrapped bullet under
|
|
68
|
+
the text instead of under the glyph — the most common "malformed bullet" defect
|
|
69
|
+
in generated decks.
|
|
70
|
+
|
|
71
|
+
## Anti-patterns
|
|
72
|
+
|
|
73
|
+
- Bullets as a script: a slide is not a transcript, the speaker notes are.
|
|
74
|
+
- Fake bullets via "– " or "→ " prefixes in the text; they do not indent.
|
|
75
|
+
- Six bullets of equal weight where one is the actual point. Make the point the
|
|
76
|
+
title and the bullets the evidence.
|
|
77
|
+
- Numbered lists where the order does not matter, and bullet lists where it
|
|
78
|
+
does.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Evidence on slides: charts, tables, notes
|
|
2
|
+
|
|
3
|
+
"Evidence" is anything on a slide that claims a fact: a number, a chart, a
|
|
4
|
+
table, a quotation. The rules below keep it checkable.
|
|
5
|
+
|
|
6
|
+
## Native or it did not happen
|
|
7
|
+
|
|
8
|
+
| Claim | Correct form | Wrong form |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| Trend over time | Native chart with categories and series | Screenshot of a chart |
|
|
11
|
+
| Exact figures | Native table | Image of a spreadsheet |
|
|
12
|
+
| A single number | A bold run in a sentence | A one-bar chart |
|
|
13
|
+
| A process | Shapes plus connectors | Image of a flowchart |
|
|
14
|
+
|
|
15
|
+
The wrong column has one shared defect: the audience cannot read it at projector
|
|
16
|
+
size and nobody can verify it. Native charts and tables also keep their numbers
|
|
17
|
+
in the package, which is what lets `container_tools/native_quantitative_chart_gate.py`
|
|
18
|
+
and `container_tools/native_table_arithmetic_gate.py` check them.
|
|
19
|
+
|
|
20
|
+
## Charts
|
|
21
|
+
|
|
22
|
+
- The chart title says what the chart means. The slide title says the conclusion.
|
|
23
|
+
Two titles, two jobs — if they are the same sentence, drop the chart title
|
|
24
|
+
(`chart.has_title = False`) rather than repeat it.
|
|
25
|
+
- Bars start at zero. Lines may start elsewhere only if the axis is labelled.
|
|
26
|
+
- Categories in the order the audience thinks in (Q1..Q4, not alphabetised).
|
|
27
|
+
- Label the few numbers that matter, not every point. Ten data labels is a
|
|
28
|
+
table with rounded corners.
|
|
29
|
+
- One axis. Two y-axes on a slide chart is a way to imply a correlation that may
|
|
30
|
+
not exist.
|
|
31
|
+
- Source and window in the caption: "Driver logs, FY2026, 12 sites".
|
|
32
|
+
|
|
33
|
+
## Tables
|
|
34
|
+
|
|
35
|
+
- Column order follows the reader's question: what, then how much, then change.
|
|
36
|
+
- Header row is bold and distinct; total row is bold and separated.
|
|
37
|
+
- Numbers right-aligned, one decimal convention per column.
|
|
38
|
+
- A total is arithmetic the reader can check. Fill it from the data, never by
|
|
39
|
+
eye, and let the table arithmetic gate confirm it.
|
|
40
|
+
- Do not put units in every cell; put them in the header.
|
|
41
|
+
- A table with more than about 7 rows belongs in an appendix, with the slide
|
|
42
|
+
stating the conclusion.
|
|
43
|
+
|
|
44
|
+
## Speaker notes as provenance
|
|
45
|
+
|
|
46
|
+
Notes are where "where did this number come from" lives, so the presenter can
|
|
47
|
+
answer without the slide turning into a footnote.
|
|
48
|
+
|
|
49
|
+
- One note per non-obvious number: source, date range, and any caveat.
|
|
50
|
+
- The sentence you will actually say, in spoken words.
|
|
51
|
+
- No bullet-stacking in notes; notes are prose.
|
|
52
|
+
- Notes are invisible to the render loop — verify them from the file, not the
|
|
53
|
+
PNGs. `container_tools/inspect_presentation_package_integrity.py` counts
|
|
54
|
+
`notesSlides`, and the package dump shows their text.
|
|
55
|
+
|
|
56
|
+
## Fidelity gates
|
|
57
|
+
|
|
58
|
+
Before presenting a deck that carries numbers:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
"<python>" container_tools/native_quantitative_chart_gate.py --input deck.pptx --all-slides
|
|
62
|
+
"<python>" container_tools/native_table_arithmetic_gate.py --input deck.pptx --contracts totals.json
|
|
63
|
+
"<python>" container_tools/native_chart_title_gate.py --input deck.pptx
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each prints one JSON object whose `passed` field is the decision. A failing gate
|
|
67
|
+
is not advisory: it means the slide asserts something the file cannot support.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Style guidance
|
|
2
|
+
|
|
3
|
+
## The type scale
|
|
4
|
+
|
|
5
|
+
Three sizes are enough: title, body, caption. A fourth size is a decision the
|
|
6
|
+
audience has to make, and they will make it wrongly.
|
|
7
|
+
|
|
8
|
+
| Role | Size | Weight | Colour |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| Cover title | 40–48 pt | Bold | Ink |
|
|
11
|
+
| Slide title | 28–36 pt | Bold or semibold | Ink |
|
|
12
|
+
| Body | 18–22 pt | Regular | Ink |
|
|
13
|
+
| Lead-in number | Same as body + bold | Bold | Accent |
|
|
14
|
+
| Caption, source | 12–14 pt | Regular | Muted |
|
|
15
|
+
|
|
16
|
+
Rules that carry the rest:
|
|
17
|
+
|
|
18
|
+
- One typeface family. A second family means "different voice", so use it for
|
|
19
|
+
one thing (a quote, a code line) and nothing else.
|
|
20
|
+
- Bold is emphasis, not decoration: at most one bold phrase per paragraph.
|
|
21
|
+
- All-caps for a 2–4 word label is a design choice; all-caps for a sentence is
|
|
22
|
+
a readability tax.
|
|
23
|
+
- Left-align body text. Centred paragraphs longer than two lines are hard to
|
|
24
|
+
track back to the next line.
|
|
25
|
+
|
|
26
|
+
## Colour
|
|
27
|
+
|
|
28
|
+
- One ink, one muted, one accent, plus the template's own rule colour. More
|
|
29
|
+
than that and the accent stops meaning "look here".
|
|
30
|
+
- Contrast is a correctness issue: body text on white needs a dark ink
|
|
31
|
+
(roughly luminance ratio 4.5:1), and text over a photograph needs a scrim,
|
|
32
|
+
not luck.
|
|
33
|
+
- Never encode meaning in colour alone — an accent bar showing the direction of
|
|
34
|
+
a metric also needs an arrow or a word.
|
|
35
|
+
- Chart series colours come from the theme; a sixth series colour is a signal
|
|
36
|
+
that the chart has too many series.
|
|
37
|
+
|
|
38
|
+
## Density
|
|
39
|
+
|
|
40
|
+
- Body blocks stop at about 6 lines of 18 pt on a 16:9 slide before the eye
|
|
41
|
+
stops at the middle.
|
|
42
|
+
- A table on a slide reads at up to about 7 rows × 4 columns. Beyond that it is
|
|
43
|
+
an appendix, and the slide should carry the one row that matters.
|
|
44
|
+
- Whitespace is a layout element, not leftover space: leave at least 0.6 in
|
|
45
|
+
between content blocks and the slide edge.
|
|
46
|
+
- One idea per slide. If the title needs "and", split.
|
|
47
|
+
|
|
48
|
+
## Cover art direction
|
|
49
|
+
|
|
50
|
+
A cover carries three things: the title, the context line, and the visual that
|
|
51
|
+
sets the tone. Keep them separate roles.
|
|
52
|
+
|
|
53
|
+
- Abstract geometry, a photograph of the actual subject, or a flat colour field
|
|
54
|
+
all work. Clip art of a handshake does not.
|
|
55
|
+
- If the visual is photographic, darken it (a scrim at 40–60% black) under the
|
|
56
|
+
text rather than hoping the text lands on a dark region.
|
|
57
|
+
- If no suitable image exists, use a colour field plus an accent rule. An
|
|
58
|
+
invented diagram pretending to be a photograph is worse than a plain cover.
|
|
59
|
+
- Encode the deck's palette: if the accent is amber, the cover visual should
|
|
60
|
+
contain amber, not a random sunset.
|
|
61
|
+
- Never ship a screenshot of a tool, a UI or another slide as cover art.
|
|
62
|
+
|
|
63
|
+
## Closing slides
|
|
64
|
+
|
|
65
|
+
The last slide restates the ask in one line and nothing else. "Thank you" alone
|
|
66
|
+
wastes the slot the audience is still looking at while they gather their things.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Working from a supplied template
|
|
2
|
+
|
|
3
|
+
## Why templates win
|
|
4
|
+
|
|
5
|
+
A template already answers branding, type scale, slide families and chrome. The
|
|
6
|
+
cheapest correct deck puts the user's content into the template's own slides
|
|
7
|
+
and leaves the design alone. Rebuilding the look from a screenshot produces a
|
|
8
|
+
near-miss that reads as "someone remade our deck in a hurry".
|
|
9
|
+
|
|
10
|
+
## Order of operations
|
|
11
|
+
|
|
12
|
+
1. **Inspect the template** before judging it:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
"<python>" "<skill>/template_following_scripts/inspect_template_deck.py" --template brand.pptx --out-dir template-inspect
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It writes `template-inspect.ndjson` (per slide: layout, placeholders with
|
|
19
|
+
index, kind, rect and text, background art) and `template-manifest.json`
|
|
20
|
+
(slide size, aspect, layout names, theme fonts, which slides carry
|
|
21
|
+
full-bleed art).
|
|
22
|
+
|
|
23
|
+
2. **Choose the slide families you need** — cover, section, content, table,
|
|
24
|
+
chart, closing. You want the *fewest* source slides that cover those roles.
|
|
25
|
+
|
|
26
|
+
3. **Write the frame map** — a JSON plan that names, per output slide, which
|
|
27
|
+
source slide it duplicates and what happens to each element
|
|
28
|
+
(`rewrite`, `rewrite-and-reposition`, `fill-placeholder`, `replace`,
|
|
29
|
+
`delete`, `keep`).
|
|
30
|
+
|
|
31
|
+
4. **Validate the plan** before building:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
"<python>" "<skill>/template_following_scripts/validate_template_plan.py" --plan frame-map.json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
It rejects unknown actions, out-of-range zones, new primitives without an
|
|
38
|
+
explicit justification, and any attempt to edit a brand or chrome element.
|
|
39
|
+
|
|
40
|
+
5. **Build the starter deck**, then fill it:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
"<python>" "<skill>/template_following_scripts/prepare_template_starter_deck.py" --template brand.pptx --plan frame-map.json --out starter.pptx
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The starter deck contains only the slides you kept, in your order, with the
|
|
47
|
+
placeholders filled. From there `container_tools/add_slides.py` and the
|
|
48
|
+
recipes extend it.
|
|
49
|
+
|
|
50
|
+
6. **Check fidelity** against the source:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
"<python>" "<skill>/template_following_scripts/check_template_fidelity.py" --template brand.pptx --final starter.pptx --plan frame-map.json
|
|
54
|
+
"<python>" "<skill>/container_tools/template_source_fidelity_gate.py" --template brand.pptx --final starter.pptx --requirements fidelity.json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Both print JSON with a `passed` boolean. Leftover placeholders, drifted
|
|
58
|
+
layout rects and opaque panels covering inherited artwork are failures, not
|
|
59
|
+
style opinions.
|
|
60
|
+
|
|
61
|
+
## Reading a template's own geometry
|
|
62
|
+
|
|
63
|
+
`container_tools/inspect_presentation_layout_geometry.py --input brand.pptx`
|
|
64
|
+
prints every shape's rect in inches, which is what you address when a slide's
|
|
65
|
+
placeholder needs a value that fits its frame.
|
|
66
|
+
|
|
67
|
+
## Rules
|
|
68
|
+
|
|
69
|
+
- Placeholders keep their index; fill by index rather than adding a textbox on
|
|
70
|
+
top of a placeholder.
|
|
71
|
+
- Never restyle the master to match a screenshot you were given. If the brand
|
|
72
|
+
colours are wrong, ask; guessing produces a deck the brand team rejects.
|
|
73
|
+
- If the template has no suitable family for a slide (say, a two-column
|
|
74
|
+
comparison), say which family you added and why, rather than silently
|
|
75
|
+
inventing a look.
|
|
76
|
+
- Keep the template's slide size. Changing it invalidates every inherited rect.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Handing a deck to Google Slides
|
|
2
|
+
|
|
3
|
+
Google Slides imports `.pptx`, and mostly survives it. What it does not survive
|
|
4
|
+
is worth designing around.
|
|
5
|
+
|
|
6
|
+
## What converts cleanly
|
|
7
|
+
|
|
8
|
+
- Text frames, bullet levels, speaker notes, slide size and order.
|
|
9
|
+
- Native tables and native charts (data comes across with the chart).
|
|
10
|
+
- Pictures, shapes, solid fills and theme colours.
|
|
11
|
+
|
|
12
|
+
## What converts badly
|
|
13
|
+
|
|
14
|
+
| Feature | What happens | Do instead |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Custom `buChar` glyphs and `marL/indent` | Indent shifts, glyphs fall back | Use plain paragraph levels; check the bullet indent after import |
|
|
17
|
+
| Elbow/curved connectors | Re-anchored or detached | Straight connectors between facing sides |
|
|
18
|
+
| Font not on the reader's machine | Substituted, wider, text reflows | Stick to fonts both environments have, and re-check overflow after import |
|
|
19
|
+
| Text-to-fit-shape autosize | Keeps the shrunk size | Fixed frames with measured text |
|
|
20
|
+
| Animations and transitions | Partially dropped | Do not rely on them for meaning |
|
|
21
|
+
| Embedded workbook charts | Data retained, formatting re-derived | Re-apply axis/label settings in Slides if they matter |
|
|
22
|
+
| Master-level chrome via spTree surgery | Usually kept, occasionally duplicated | Prefer layout-level placeholders |
|
|
23
|
+
|
|
24
|
+
## The workflow
|
|
25
|
+
|
|
26
|
+
1. Build the deck as a normal `.pptx` — nothing Slides-specific is needed.
|
|
27
|
+
2. Render and inspect the PNGs locally first; fix overflow before importing.
|
|
28
|
+
3. Upload to Drive, open with Google Slides, and check these in order: title
|
|
29
|
+
wrapping, bullet indentation, connector attachment, chart axes, notes.
|
|
30
|
+
4. If the deck will be edited by other people in Slides, keep shapes distinct
|
|
31
|
+
and named (right-click → rename) so comments and edits are unambiguous.
|
|
32
|
+
|
|
33
|
+
## Sharing
|
|
34
|
+
|
|
35
|
+
- "Anyone with the link" plus a view-only role is the default for a deck that
|
|
36
|
+
should not be edited in place.
|
|
37
|
+
- Export back to `.pptx` when the user needs a file; Slides' export does not
|
|
38
|
+
preserve everything either, so state which version is authoritative.
|
|
39
|
+
- Comments and suggestions do not travel in the `.pptx` round trip.
|
|
40
|
+
|
|
41
|
+
## When the user asks for a Slides-native link
|
|
42
|
+
|
|
43
|
+
Deliver the `.pptx` (that is what this pack produces), state the upload path,
|
|
44
|
+
and list the three things to check after import: font substitution, bullet
|
|
45
|
+
indent, chart axes. Claiming a clean conversion without those checks is a guess.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Task: apply an annotation payload
|
|
2
|
+
|
|
3
|
+
The user draws on a rendered slide and sends back an `office-annotations` block.
|
|
4
|
+
Treat it as a change request with coordinates, not as editor state.
|
|
5
|
+
|
|
6
|
+
## 1. Re-create the geometry the user drew on
|
|
7
|
+
|
|
8
|
+
Annotations refer to the preview the user saw. Render the same way so the
|
|
9
|
+
coordinates mean the same thing:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
"<python>" "<skill>/container_tools/render_slides.py" --input deck.pptx --out-dir preview
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Slide index = `page` in the payload, 1-based. Keep the PNGs — you will compare
|
|
16
|
+
the same slide before and after.
|
|
17
|
+
|
|
18
|
+
## 2. Resolve each annotation to shapes
|
|
19
|
+
|
|
20
|
+
The region is normalised 0–1 on that slide image. Map it to inches:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
left_in = region.left * slide_width_in
|
|
24
|
+
top_in = region.top * slide_height_in
|
|
25
|
+
width_in = region.width * slide_width_in
|
|
26
|
+
height_in = region.height * slide_height_in
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then select candidate shapes whose bounding box overlaps that rect, largest
|
|
30
|
+
overlap first:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
"<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx --json-out geometry.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`geometry.json` lists every shape per slide with `left`, `top`, `width`,
|
|
37
|
+
`height` in inches, plus its text. Two overlapping shapes (a title over a
|
|
38
|
+
background panel) are common: use the annotation's `text` to disambiguate —
|
|
39
|
+
match it against each candidate's text, and prefer an exact or prefix match.
|
|
40
|
+
|
|
41
|
+
## 3. Decide the smallest edit
|
|
42
|
+
|
|
43
|
+
| Requirement reads like | Do this |
|
|
44
|
+
|---|---|
|
|
45
|
+
| "change this wording" | run-level replace on that shape ([edit-deck](edit-deck.md)) |
|
|
46
|
+
| "move this down" | set `left/top` on that shape only |
|
|
47
|
+
| "make this bigger" | set font size on the runs of that shape, then re-check fit |
|
|
48
|
+
| "this overlaps the table" | resize the shape, or the table, not the whole slide |
|
|
49
|
+
| "recolour" | change the run colour, not the theme |
|
|
50
|
+
| "add a line here" | the rect is a position, not an insertion point: add the shape at that rect, matching nearby type |
|
|
51
|
+
|
|
52
|
+
Never restyle a slide to satisfy a region. The region identifies *what*, the
|
|
53
|
+
requirement says *how much*.
|
|
54
|
+
|
|
55
|
+
## 4. Apply, write a copy, re-render
|
|
56
|
+
|
|
57
|
+
Mutations go through this pack's tools (`replace_text.py`, `add_slides.py`,
|
|
58
|
+
`core_properties.py`) or a focused `python-pptx` snippet — always to
|
|
59
|
+
`<original>-edited.pptx`.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
"<python>" "<skill>/container_tools/replace_text.py" --input deck.pptx --find "old" --replace "new" --out deck-edited.pptx
|
|
63
|
+
"<python>" "<skill>/container_tools/render_slides.py" --input deck-edited.pptx --out-dir preview-after
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 5. Confirm, in words
|
|
67
|
+
|
|
68
|
+
Open the same slide number and check the region now looks right. Report which
|
|
69
|
+
shape you changed, what changed, and the slide number.
|
|
70
|
+
|
|
71
|
+
## When it cannot be mapped
|
|
72
|
+
|
|
73
|
+
- Empty region, or no shape overlaps it → say that the region covers blank
|
|
74
|
+
space and ask what object was meant.
|
|
75
|
+
- Overlapping candidates that `text` does not disambiguate → name both and ask.
|
|
76
|
+
- The requirement is about something the file has no geometry for (a font that
|
|
77
|
+
is not installed, a transition) → say so plainly.
|
|
78
|
+
- The region covers a chart or table whose values would need to change → state
|
|
79
|
+
that values come from the data, and ask for the corrected figures rather than
|
|
80
|
+
editing the rendered numbers.
|
|
81
|
+
|
|
82
|
+
Never guess silently. "I changed the title on slide 3; the region also touched
|
|
83
|
+
the subtitle, which I left alone" is a good answer. Silence plus a diff is not.
|