dsh-office-kit 0.4.2 → 0.4.4
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/assets/skills/excel-live-control/SKILL.md +119 -152
- package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
- package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
- package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
- package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
- package/assets/skills/excel-live-control/references/office-automation.md +127 -153
- package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
- package/assets/skills/excel-live-control/style_guidelines.md +56 -64
- package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
- package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
- package/assets/skills/office-documents/SKILL.md +24 -60
- package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
- package/assets/skills/office-documents/ooxml/comments.md +8 -8
- package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
- package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
- package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
- package/assets/skills/office-documents/references/docx-structure.md +11 -13
- package/assets/skills/office-documents/references/template-elicitation.md +11 -13
- package/assets/skills/office-documents/references/writing-quality.md +20 -20
- package/assets/skills/office-documents/scripts/add_tracked_replacements.py +4 -3
- package/assets/skills/office-documents/scripts/docx_kit.py +68 -27
- package/assets/skills/office-documents/scripts/heading_audit.py +3 -4
- package/assets/skills/office-documents/scripts/internal_nav.py +3 -1
- package/assets/skills/office-documents/scripts/merge_docx_append.py +104 -0
- package/assets/skills/office-documents/scripts/table_geometry.py +13 -3
- package/assets/skills/office-documents/scripts/watermark_add.py +6 -5
- package/assets/skills/office-documents/scripts/watermark_audit_remove.py +6 -4
- package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
- package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
- package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
- package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
- package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
- package/assets/skills/office-documents/tasks/create_edit.md +14 -16
- package/assets/skills/office-documents/tasks/equations.md +17 -28
- package/assets/skills/office-documents/tasks/fields_update.md +14 -16
- package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
- package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
- package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
- package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
- package/assets/skills/office-documents/tasks/images_figures.md +15 -25
- package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
- package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
- package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
- package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
- package/assets/skills/office-documents/tasks/read_review.md +9 -20
- package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
- package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
- package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
- package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
- package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
- package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
- package/assets/skills/office-documents/tasks/verify_render.md +11 -23
- package/assets/skills/office-documents/tasks/watermarks_background.md +10 -14
- package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +6 -6
- package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
- package/assets/skills/office-pdf/SKILL.md +36 -51
- package/assets/skills/office-pdf/references/form-fields.md +20 -20
- package/assets/skills/office-pdf/references/geometry.md +10 -10
- package/assets/skills/office-pdf/references/layout-quality.md +13 -13
- package/assets/skills/office-pdf/references/limits.md +12 -56
- package/assets/skills/office-pdf/tasks/annotations.md +5 -5
- package/assets/skills/office-pdf/tasks/create.md +6 -9
- package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
- package/assets/skills/office-pdf/tasks/forms.md +15 -15
- package/assets/skills/office-pdf/tasks/read.md +9 -9
- package/assets/skills/office-pdf/tasks/redact.md +18 -18
- package/assets/skills/office-pdf/tasks/stamp.md +10 -10
- package/assets/skills/office-presentations/SKILL.md +71 -91
- package/assets/skills/office-presentations/container_tools/preview_render.py +4 -1
- package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
- package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
- package/assets/skills/office-presentations/recipes/README.md +24 -35
- package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
- package/assets/skills/office-presentations/recipes/connectors.md +11 -12
- package/assets/skills/office-presentations/recipes/images.md +11 -12
- package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
- package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
- package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
- package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
- package/assets/skills/office-presentations/recipes/tables.md +14 -14
- package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
- package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
- package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
- package/assets/skills/office-presentations/references/finalization.md +10 -12
- package/assets/skills/office-presentations/references/native-bullets.md +14 -18
- package/assets/skills/office-presentations/references/native-evidence.md +18 -32
- package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
- package/assets/skills/office-presentations/references/templates.md +31 -60
- package/assets/skills/office-presentations/routing/google_slides.md +4 -4
- package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
- package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
- package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
- package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
- package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
- package/assets/skills/office-presentations/tasks/template-following.md +23 -28
- package/assets/skills/office-spreadsheets/SKILL.md +32 -39
- package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
- package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
- package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
- package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
- package/assets/skills/office-spreadsheets/references/charts.md +15 -34
- package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
- package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
- package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
- package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
- package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
- package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
- package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
- package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
- package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
- package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
- package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
- package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
- package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
- package/assets/skills/shared/annotation-recipes.md +98 -120
- package/assets/skills/shared/common-workflow.md +70 -80
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/python/office_cli.py +38 -4
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Mechanics
|
|
4
4
|
|
|
5
|
-
A connector is a line with two attachment sites. `add_connector` takes
|
|
6
|
-
|
|
7
|
-
boxes when they move.
|
|
8
|
-
|
|
9
|
-
nudged.
|
|
5
|
+
A connector is a line with two attachment sites. `add_connector` takes begin and
|
|
6
|
+
end shapes *plus* connection indices, which is what makes the line follow the
|
|
7
|
+
boxes when they move. Pass coordinates instead and you get a floating line: right
|
|
8
|
+
in the file you made, wrong the first time a box is nudged.
|
|
10
9
|
|
|
11
10
|
- `MSO_CONNECTOR.STRAIGHT | ELBOW | CURVE`
|
|
12
11
|
- `connector.begin_connect(shape, idx)` / `end_connect(shape, idx)`; `idx` is
|
|
@@ -59,19 +58,19 @@ PY
|
|
|
59
58
|
|
|
60
59
|
## Rules
|
|
61
60
|
|
|
62
|
-
1. Connect sides
|
|
63
|
-
|
|
61
|
+
1. Connect facing sides: right → left for a row, bottom → top for a column. A
|
|
62
|
+
line crossing its own boxes reads as an error.
|
|
64
63
|
2. Elbow connectors for orthogonal flows, straight for a single hop, curve almost
|
|
65
64
|
never.
|
|
66
|
-
3. Two crossing connectors in one diagram
|
|
67
|
-
|
|
65
|
+
3. Two crossing connectors in one diagram makes it a picture of a diagram; split
|
|
66
|
+
it.
|
|
68
67
|
4. Label the connector ("12 min", "auto") with a small textbox near its middle,
|
|
69
68
|
not with arrow direction alone.
|
|
70
69
|
|
|
71
70
|
## Pitfalls this avoids
|
|
72
71
|
|
|
73
72
|
- `add_connector` with free coordinates: the line is positioned but unattached,
|
|
74
|
-
and
|
|
73
|
+
and later edits break it silently.
|
|
75
74
|
- Arrowhead index confusion: arrowhead values are a bitmask enum, not a boolean.
|
|
76
75
|
- Connectors behind filled shapes because they were added before the boxes.
|
|
77
76
|
|
|
@@ -79,5 +78,5 @@ PY
|
|
|
79
78
|
|
|
80
79
|
There is no connector verb in `pptx create`; this recipe is the route. After
|
|
81
80
|
building, `container_tools/inspect_presentation_layout_geometry.py` flags
|
|
82
|
-
`connector_over_text` when a line crosses a text shape
|
|
83
|
-
|
|
81
|
+
`connector_over_text` when a line crosses a text shape — the failure mode you
|
|
82
|
+
cannot see in a thumbnail.
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
`add_picture(path, left, top, width=…, height=…)`:
|
|
6
6
|
|
|
7
|
-
- Give **width only** and the height follows the aspect ratio. Give both and
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- Give **width only** and the height follows the aspect ratio. Give both and the
|
|
8
|
+
picture stretches — deliberate for a full-bleed background, a mistake for a
|
|
9
|
+
product photo.
|
|
10
10
|
- `picture.crop_left/right/top/bottom` are fractions of the *source*; they crop
|
|
11
11
|
without changing the frame, which is how a "cover" fit is done.
|
|
12
|
-
- The bytes live in `ppt/media/`; the same file added twice is stored once,
|
|
13
|
-
|
|
12
|
+
- The bytes live in `ppt/media/`; the same file added twice is stored once, keyed
|
|
13
|
+
by content hash.
|
|
14
14
|
- `picture._element.nvPicPr.cNvPr.set("descr", "…")` is the alt text. Decks get
|
|
15
15
|
read aloud and exported; an untagged picture is an empty sentence.
|
|
16
16
|
|
|
@@ -57,11 +57,10 @@ PY
|
|
|
57
57
|
## Rules
|
|
58
58
|
|
|
59
59
|
1. Never upscale past the source resolution: a 900 px wide image at 8 in is
|
|
60
|
-
~110 ppi and
|
|
61
|
-
2. One dominant image per slide. A
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
scrim rectangle between picture and text, not hope.
|
|
60
|
+
~110 ppi and looks soft on a projector. Check `Image.open(...).size`.
|
|
61
|
+
2. One dominant image per slide. A hero plus three thumbnails is two slides.
|
|
62
|
+
3. Full-bleed backgrounds need deliberate text contrast — a dark scrim rectangle
|
|
63
|
+
between picture and text, not hope.
|
|
65
64
|
4. Alt text on every picture, in the language of the deck.
|
|
66
65
|
|
|
67
66
|
## Pitfalls this avoids
|
|
@@ -70,8 +69,8 @@ PY
|
|
|
70
69
|
name as the cause.
|
|
71
70
|
- `add_picture` after the text: the picture covers the words. Add backgrounds
|
|
72
71
|
first, or move them to index 2.
|
|
73
|
-
- Re-using a screenshot of a chart or
|
|
74
|
-
projector size
|
|
72
|
+
- Re-using a screenshot of a chart or table as "evidence": unreadable at
|
|
73
|
+
projector size, unverifiable. Use a native chart or table.
|
|
75
74
|
|
|
76
75
|
## CLI fast path
|
|
77
76
|
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Mechanics
|
|
4
4
|
|
|
5
|
-
A deck has three levels
|
|
5
|
+
A deck has three levels; where you make a change decides how many slides it
|
|
6
6
|
fixes:
|
|
7
7
|
|
|
8
|
-
- **Slide master** (`ppt/slideMasters/`) — theme fonts, colours, background,
|
|
9
|
-
|
|
8
|
+
- **Slide master** (`ppt/slideMasters/`) — theme fonts, colours, background, and
|
|
9
|
+
the shapes every slide inherits (title bar, accent rule, logo).
|
|
10
10
|
- **Slide layout** (`ppt/slideLayouts/`) — one per slide family (title, title and
|
|
11
11
|
content, section, blank…), each with named placeholders at fixed rects.
|
|
12
|
-
- **Slide** —
|
|
13
|
-
|
|
12
|
+
- **Slide** — its own shapes plus *placeholder overrides*: text, and position if
|
|
13
|
+
someone dragged a placeholder.
|
|
14
14
|
|
|
15
15
|
Editing a placeholder's *text* is a per-slide change. Editing the layout's
|
|
16
16
|
placeholder *rect* moves that frame on every slide of that family. Editing the
|
|
@@ -20,9 +20,9 @@ master's background moves it everywhere.
|
|
|
20
20
|
To change a slide's family, delete it and add a new one from the target layout —
|
|
21
21
|
losing its content, so plan families before filling them.
|
|
22
22
|
|
|
23
|
-
**One quirk
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
**One quirk:** `master.shapes` and `layout.shapes` are read-only in `python-pptx`
|
|
24
|
+
(`MasterShapes` has no `add_shape`). Build chrome shapes on a scratch slide and
|
|
25
|
+
move their XML into the master's shape tree.
|
|
26
26
|
|
|
27
27
|
## Recipe: restyle a family from the master
|
|
28
28
|
|
|
@@ -88,36 +88,36 @@ print("removed:", removed)
|
|
|
88
88
|
PY
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
This
|
|
91
|
+
This clears the `empty_placeholder` review finding in
|
|
92
92
|
`container_tools/inspect_presentation_layout_geometry.py`. Keep a placeholder you
|
|
93
93
|
still intend to fill, and never delete the one slide numbers are linked to.
|
|
94
94
|
|
|
95
95
|
## Reusing the source's own layouts
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
With a supplied template, do not rebuild its look — put content into its
|
|
98
|
+
placeholders. The inspection script prints each layout's placeholders with index,
|
|
99
|
+
kind and rect, which is what you need to address them:
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
102
|
"<python>" container_tools/inspect_presentation_layout_geometry.py --input template.pptx --json-out geometry.json
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
Then address a placeholder by index on the slide:
|
|
106
|
-
`slide.placeholders[1].text = "..."`. Slides created from a layout always have
|
|
107
|
-
|
|
106
|
+
`slide.placeholders[1].text = "..."`. Slides created from a layout always have a
|
|
107
|
+
placeholder for every non-empty slot, so index-based addressing is stable.
|
|
108
108
|
|
|
109
109
|
## Pitfalls this avoids
|
|
110
110
|
|
|
111
111
|
- Drawing the accent rule on every slide instead of the master: one edit later,
|
|
112
112
|
half the deck has two rules.
|
|
113
|
-
- Dragging a placeholder on a slide to fix one frame; the layout is untouched
|
|
114
|
-
|
|
113
|
+
- Dragging a placeholder on a slide to fix one frame; the layout is untouched and
|
|
114
|
+
the next slide of the same family misbehaves again.
|
|
115
115
|
- Appending the scratch shape to the master without `drop_rel`: the orphan slide
|
|
116
116
|
part stays in the package and `inspect_presentation_package_integrity.py`
|
|
117
117
|
reports a slide count mismatch.
|
|
118
118
|
- Adding a *blank* slide and a floating textbox where the template has a title
|
|
119
|
-
placeholder: the deck no longer answers to its own master, and the outline
|
|
120
|
-
|
|
119
|
+
placeholder: the deck no longer answers to its own master, and the outline view
|
|
120
|
+
is empty.
|
|
121
121
|
|
|
122
122
|
## CLI fast path
|
|
123
123
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A chart added with `slide.shapes.add_chart` is a real chart part
|
|
6
6
|
(`ppt/charts/chartN.xml`) with an embedded workbook
|
|
7
|
-
(`ppt/embeddings/*.xlsx`). That matters
|
|
7
|
+
(`ppt/embeddings/*.xlsx`). That matters:
|
|
8
8
|
|
|
9
9
|
- The audience can edit the numbers in PowerPoint; a picture of a chart cannot.
|
|
10
10
|
- The data is in the file, so a gate can check it. A screenshot cannot be
|
|
@@ -12,9 +12,9 @@ A chart added with `slide.shapes.add_chart` is a real chart part
|
|
|
12
12
|
- The chart inherits the slide's theme for colour and type, so charts match the
|
|
13
13
|
deck without per-chart styling.
|
|
14
14
|
|
|
15
|
-
`CategoryChartData` holds the numbers; `chart.plots[0]` holds the geometry of
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
`CategoryChartData` holds the numbers; `chart.plots[0]` holds the geometry of the
|
|
16
|
+
marks. Category order is the series' own order — sort before you pass it, because
|
|
17
|
+
a chart does not sort.
|
|
18
18
|
|
|
19
19
|
## Recipe
|
|
20
20
|
|
|
@@ -63,18 +63,18 @@ PY
|
|
|
63
63
|
## Rules for charted numbers
|
|
64
64
|
|
|
65
65
|
1. One idea per chart. Two series is fine; six is a table.
|
|
66
|
-
2. No chart title
|
|
66
|
+
2. No chart title repeating the slide title — the slide title says what the chart
|
|
67
67
|
*means* ("Throughput rose while touches fell"), the chart shows the numbers.
|
|
68
68
|
3. Start the value axis at zero for bars, and say so in the notes if you do not.
|
|
69
69
|
4. Data labels beat a value axis grid; pick one, not both.
|
|
70
|
-
5. Never leave the default "Chart Title"
|
|
70
|
+
5. Never leave the default "Chart Title" text in a shipped deck.
|
|
71
71
|
|
|
72
72
|
## Pitfalls this avoids
|
|
73
73
|
|
|
74
74
|
- `number_format` without `number_format_is_linked = False` reverts to the
|
|
75
75
|
workbook's format the next time PowerPoint refreshes the chart.
|
|
76
|
-
- `legend.include_in_layout = False`
|
|
77
|
-
|
|
76
|
+
- `legend.include_in_layout = False` stops the legend stealing plot height and
|
|
77
|
+
squashing the bars.
|
|
78
78
|
- Deleting the embedded workbook (by zipping/unzipping carelessly) turns the
|
|
79
79
|
chart into an uneditable picture in every downstream viewer.
|
|
80
80
|
|
|
@@ -9,11 +9,11 @@ replaces every run, so **format runs, never paragraphs**:
|
|
|
9
9
|
- `paragraph.text = "x"` — one run, all previous formatting gone.
|
|
10
10
|
- `run = paragraph.add_run(); run.text = "x"; run.font.bold = True` — formatting
|
|
11
11
|
survives and can differ inside the paragraph.
|
|
12
|
-
- `paragraph.font.size` is not
|
|
12
|
+
- `paragraph.font.size` is not something PowerPoint respects for mixed content; it
|
|
13
13
|
sets the default for later runs only. Set the size on every run you add.
|
|
14
14
|
|
|
15
|
-
Paragraph-level properties (`alignment`, `level`, `space_after`,
|
|
16
|
-
|
|
15
|
+
Paragraph-level properties (`alignment`, `level`, `space_after`, `line_spacing`)
|
|
16
|
+
apply to the whole paragraph and are safe to set once.
|
|
17
17
|
|
|
18
18
|
## Recipe
|
|
19
19
|
|
|
@@ -62,22 +62,22 @@ PY
|
|
|
62
62
|
|
|
63
63
|
## Rules
|
|
64
64
|
|
|
65
|
-
1. A number
|
|
66
|
-
|
|
65
|
+
1. A number the reader should remember gets its own run, usually with a weight
|
|
66
|
+
change — not a second bullet.
|
|
67
67
|
2. Superscripts, footnote markers and unit symbols are runs, not characters
|
|
68
68
|
smuggled into the sentence.
|
|
69
|
-
3.
|
|
70
|
-
|
|
71
|
-
4.
|
|
72
|
-
|
|
69
|
+
3. One family of emphasis per deck: bold+accent for numbers, italic+muted for
|
|
70
|
+
provenance. Three competing emphases read as decoration.
|
|
71
|
+
4. Repeated strings (units, currency, product names) belong in a variable so a
|
|
72
|
+
later edit does not leave two spellings.
|
|
73
73
|
|
|
74
74
|
## Pitfalls this avoids
|
|
75
75
|
|
|
76
76
|
- `paragraph.text = "Total: "` then `add_run()`: the first assignment already
|
|
77
|
-
replaced the frame's runs, so formatting
|
|
78
|
-
- A run with no `font.size` inherits the layout's size, which is 44 pt on a
|
|
79
|
-
|
|
80
|
-
- Building the paragraph by f-string with `**` markers
|
|
77
|
+
replaced the frame's runs, so earlier formatting is gone.
|
|
78
|
+
- A run with no `font.size` inherits the layout's size, which is 44 pt on a title
|
|
79
|
+
layout — footnote markers become headlines.
|
|
80
|
+
- Building the paragraph by f-string with `**` markers PowerPoint does not
|
|
81
81
|
interpret; markup in a deck is a run, not a syntax.
|
|
82
82
|
|
|
83
83
|
## CLI fast path
|
|
@@ -6,10 +6,10 @@ Notes live in `ppt/notesMasters/` plus one `ppt/notesSlides/notesSlideN.xml` per
|
|
|
6
6
|
slide, tied to the slide by a relationship. In `python-pptx` this is
|
|
7
7
|
`slide.notes_slide.notes_text_frame` — the notes slide is created on first
|
|
8
8
|
access, so reading it in a loop silently adds one per slide. Only touch it when
|
|
9
|
-
|
|
9
|
+
writing.
|
|
10
10
|
|
|
11
|
-
Notes are
|
|
12
|
-
|
|
11
|
+
Notes are invisible in the render, so a notes problem cannot be caught by looking
|
|
12
|
+
at the PNGs: check them with `pptx read` or by reading the XML back.
|
|
13
13
|
|
|
14
14
|
## Recipe
|
|
15
15
|
|
|
@@ -45,21 +45,21 @@ PY
|
|
|
45
45
|
12 sites").
|
|
46
46
|
- The answer to the question the slide invites.
|
|
47
47
|
- Nothing that belongs on the slide: if the audience needs it, put it on the
|
|
48
|
-
slide
|
|
48
|
+
slide — notes are invisible when the deck is sent as a PDF.
|
|
49
49
|
|
|
50
50
|
## Pitfalls this avoids
|
|
51
51
|
|
|
52
52
|
- Iterating `prs.slides` and *reading* `notes_slide` on a template with none:
|
|
53
53
|
every slide gains an empty notes part and the file grows.
|
|
54
54
|
- Long notes pasted as one paragraph with line breaks that only look like
|
|
55
|
-
paragraphs;
|
|
56
|
-
|
|
55
|
+
paragraphs; use `add_paragraph()` per intended paragraph so the notes pane and
|
|
56
|
+
presenter view indent them.
|
|
57
57
|
- Assuming notes render into the preview: they do not, so verify them from the
|
|
58
58
|
file.
|
|
59
59
|
|
|
60
60
|
## CLI fast path
|
|
61
61
|
|
|
62
62
|
`pptx create` writes slides without notes. The recipe above is the route; then
|
|
63
|
-
`pptx read --input deck-notes.pptx` does not print notes, so read them back
|
|
63
|
+
`pptx read --input deck-notes.pptx` does not print notes, so read them back from
|
|
64
64
|
`ppt/slides` sibling `notesSlide` parts via
|
|
65
65
|
`inspect_presentation_package_integrity.py` (it counts `notesSlides`).
|
|
@@ -6,11 +6,11 @@ A table in a deck is a grid of cells on a canvas; it does not reflow. Three
|
|
|
6
6
|
properties decide whether it reads as a table or as soup:
|
|
7
7
|
|
|
8
8
|
- **Column widths** are the layout. `table.columns[i].width = Inches(3.2)` —
|
|
9
|
-
|
|
9
|
+
mandatory, because `add_table` splits the width evenly.
|
|
10
10
|
- **Row heights** are a minimum. Text taller than the row pushes it open, which
|
|
11
|
-
|
|
11
|
+
runs into whatever sits below.
|
|
12
12
|
- **Cell margins** default to 0.1 in left/right and 0.05 in top/bottom on a
|
|
13
|
-
0.5 in row
|
|
13
|
+
0.5 in row — most of the row. Reduce them when rows are tight.
|
|
14
14
|
|
|
15
15
|
Header row emphasis (`table.first_row = True`) is a table style switch, not a
|
|
16
16
|
formatting guess: it turns on the theme's header fill and bold.
|
|
@@ -66,23 +66,23 @@ PY
|
|
|
66
66
|
|
|
67
67
|
## Numbers people trust
|
|
68
68
|
|
|
69
|
-
- Right-align numeric columns, left-align the label column,
|
|
69
|
+
- Right-align numeric columns, left-align the label column, keep decimals
|
|
70
70
|
consistent per column (`553`, not `553.0` next to `171`).
|
|
71
|
-
- A total row is a claim. Show enough rows that the reader can check it, and
|
|
72
|
-
|
|
73
|
-
- Units belong in the header (`Orders`, `Touches`), not
|
|
74
|
-
- Money keeps its currency in the header or
|
|
75
|
-
|
|
71
|
+
- A total row is a claim. Show enough rows that the reader can check it, and let
|
|
72
|
+
`container_tools/native_table_arithmetic_gate.py` prove it from the file.
|
|
73
|
+
- Units belong in the header (`Orders`, `Touches`), not in every cell.
|
|
74
|
+
- Money keeps its currency in the header or first row; `¥1,240` in every cell of
|
|
75
|
+
a dense table is noise.
|
|
76
76
|
|
|
77
77
|
## Pitfalls this avoids
|
|
78
78
|
|
|
79
79
|
- Even column widths turning "Q1" into a 4 in column while numbers crowd.
|
|
80
|
-
- A
|
|
81
|
-
|
|
80
|
+
- A declared height smaller than the content: the last row is drawn below the
|
|
81
|
+
intended block and collides with the footer.
|
|
82
82
|
- Colouring cells individually instead of letting `first_row` do the header.
|
|
83
83
|
|
|
84
84
|
## CLI fast path
|
|
85
85
|
|
|
86
|
-
`pptx create` accepts `{"table": {"headers": [...], "rows": [[...]]}}` and
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
`pptx create` accepts `{"table": {"headers": [...], "rows": [[...]]}}` and places
|
|
87
|
+
it at 0.8 in from the left, full content width, at the running cursor. For a
|
|
88
|
+
chosen rect, column widths or right-aligned numbers, use the recipe.
|
|
@@ -7,10 +7,10 @@ what you see:
|
|
|
7
7
|
|
|
8
8
|
- `left`/`top` are the **top-left corner** of the frame, not of the glyphs. A
|
|
9
9
|
28 pt line has roughly 4 pt of space above the cap height inside its frame.
|
|
10
|
-
- `width` is the wrap width. `word_wrap = True`
|
|
11
|
-
|
|
10
|
+
- `width` is the wrap width. Set `word_wrap = True` explicitly on a new box or
|
|
11
|
+
long lines run past the slide edge instead of wrapping.
|
|
12
12
|
- `height` is the *frame*, not the content: PowerPoint lets text spill below it
|
|
13
|
-
(
|
|
13
|
+
(overlapping whatever is under the box) unless autosize is on.
|
|
14
14
|
- Interior margins default to 0.1 in left/right and 0.05 in top/bottom. Setting
|
|
15
15
|
them to 0 makes the rect mean exactly what you measured.
|
|
16
16
|
|
|
@@ -44,10 +44,10 @@ PY
|
|
|
44
44
|
|
|
45
45
|
## Measuring before you place
|
|
46
46
|
|
|
47
|
-
Do not guess whether the text fits — compute it. A line of 28 pt text fits
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
Do not guess whether the text fits — compute it. A line of 28 pt text fits about
|
|
48
|
+
`width_in * 96 / (0.55 * 28)` characters (0.55 average advance for a humanist
|
|
49
|
+
sans), and each line needs `1.2 * 28 / 72` inches of height. Leave the estimate
|
|
50
|
+
in the script, then let the render confirm it.
|
|
51
51
|
|
|
52
52
|
```python
|
|
53
53
|
def fits(text: str, width_in: float, height_in: float, size_pt: float) -> bool:
|
|
@@ -58,8 +58,8 @@ def fits(text: str, width_in: float, height_in: float, size_pt: float) -> bool:
|
|
|
58
58
|
|
|
59
59
|
## Pitfalls this avoids
|
|
60
60
|
|
|
61
|
-
- A box sized to
|
|
62
|
-
|
|
61
|
+
- A box sized to text at 18 pt, later edited to 32 pt, now overlaps the table
|
|
62
|
+
below. Frame height follows the *largest* run, so size text first.
|
|
63
63
|
- `add_textbox` with `width=Inches(13.3)` on a 13.333 in slide plus default
|
|
64
64
|
margins = 0.2 in of overflow past the right edge. Subtract the margins.
|
|
65
65
|
- `MSO_ANCHOR.MIDDLE` on a title looks intentional on a cover and wrong on a
|
|
@@ -10,10 +10,9 @@ The theme part (`ppt/theme/theme1.xml`) holds two palettes and two font lists:
|
|
|
10
10
|
- `majorFont` / `minorFont` — the heading and body typefaces inherited by every
|
|
11
11
|
run without an explicit font.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
template.
|
|
13
|
+
Write `RGBColor.rgb` when a colour must never change; reference a theme colour
|
|
14
|
+
when the user may re-skin the deck. A deck with hard-coded hex everywhere cannot
|
|
15
|
+
be re-branded — usually why the user supplied a template.
|
|
17
16
|
|
|
18
17
|
## Recipe: define the palette once, use it everywhere
|
|
19
18
|
|
|
@@ -73,12 +72,12 @@ names it finds in the theme, so check there before introducing a new typeface.
|
|
|
73
72
|
|
|
74
73
|
## Pitfalls this avoids
|
|
75
74
|
|
|
76
|
-
- Two similar hexes drifting apart across slides (`#161d28`
|
|
77
|
-
|
|
75
|
+
- Two similar hexes drifting apart across slides (`#161d28` here, `#171e29`
|
|
76
|
+
there) because the colour was retyped instead of referenced.
|
|
78
77
|
- A serif body font set from taste rather than from the theme, so the deck
|
|
79
78
|
contradicts the template it was built in.
|
|
80
|
-
- `font.color.theme_color = MSO_THEME_COLOR.ACCENT_1` *and* `font.color.rgb`
|
|
81
|
-
|
|
79
|
+
- `font.color.theme_color = MSO_THEME_COLOR.ACCENT_1` *and* `font.color.rgb` on
|
|
80
|
+
the same run: the last assignment wins and the theme reference vanishes.
|
|
82
81
|
|
|
83
82
|
## CLI fast path
|
|
84
83
|
|
|
@@ -1,65 +1,60 @@
|
|
|
1
1
|
# Authoring workflow
|
|
2
2
|
|
|
3
|
-
## What a deck is
|
|
3
|
+
## What a deck is
|
|
4
4
|
|
|
5
|
-
A `.pptx` is a zip of XML parts:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
instead of trusting the code that wrote it.
|
|
5
|
+
A `.pptx` is a zip of XML parts: `presentation.xml` (slide order), one part per
|
|
6
|
+
slide, a slide master per theme, a layout per family, chart parts with embedded
|
|
7
|
+
workbooks, notes parts, a media folder. Read the file back; never trust the code
|
|
8
|
+
that wrote it.
|
|
10
9
|
|
|
11
|
-
Three consequences
|
|
10
|
+
Three consequences:
|
|
12
11
|
|
|
13
|
-
1. **Geometry is explicit.** Nothing reflows on open except autofit
|
|
14
|
-
|
|
15
|
-
2. **Inheritance is real.** A slide draws
|
|
12
|
+
1. **Geometry is explicit.** Nothing reflows on open except autofit; shapes that
|
|
13
|
+
overlap in XML overlap on screen.
|
|
14
|
+
2. **Inheritance is real.** A slide draws background, type sizes and bullet
|
|
16
15
|
glyphs from its layout and master. Overriding at slide level is a per-slide
|
|
17
|
-
decision;
|
|
18
|
-
3. **Data
|
|
19
|
-
|
|
16
|
+
decision; at master level a deck decision.
|
|
17
|
+
3. **Data stays alive.** A native chart or table keeps its numbers and can be
|
|
18
|
+
checked; a screenshot cannot.
|
|
20
19
|
|
|
21
20
|
## The loop
|
|
22
21
|
|
|
23
|
-
1. **Decide the story
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
3. **Place, top-down**: background, chrome, title, body, evidence. Later shapes
|
|
22
|
+
1. **Decide the story.** One sentence per slide, in order, before any XML.
|
|
23
|
+
2. **Pick the frame.** Slide size from the target: `13.333 × 7.5 in` is the 16:9
|
|
24
|
+
default; check `prs.slide_width` of a supplied template, never assume.
|
|
25
|
+
3. **Place, top-down.** Background, chrome, title, body, evidence; later shapes
|
|
28
26
|
paint over earlier ones.
|
|
29
|
-
4. **Fill or delete every placeholder.** An empty
|
|
30
|
-
|
|
31
|
-
5. **Render, look, fix.** `container_tools/render_slides.py
|
|
32
|
-
every PNG
|
|
27
|
+
4. **Fill or delete every placeholder.** An empty one shows in edit view and
|
|
28
|
+
prints "Click to add text".
|
|
29
|
+
5. **Render, look, fix.** `container_tools/render_slides.py`, then `read_image`
|
|
30
|
+
on every PNG; repeat until nothing surprises you.
|
|
33
31
|
|
|
34
|
-
##
|
|
32
|
+
## Layout numbers
|
|
35
33
|
|
|
36
|
-
|
|
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 |
|
|
34
|
+
Type, colour and density: [style-guidelines](style-guidelines.md).
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
| Value | Rule |
|
|
37
|
+
|---|---|
|
|
38
|
+
| Slide size | 13.333 × 7.5 in (16:9); 10 × 5.625 in for "wide" templates |
|
|
39
|
+
| Margin | 0.6–0.9 in; below 0.5 in a projector crops it |
|
|
40
|
+
| Line spacing | 1.1–1.2; tighter crowds ascenders |
|
|
41
|
+
| Gap between blocks | 0.2–0.4 in; the eye groups by proximity |
|
|
42
|
+
| Footer zone | bottom 0.55 in; keep text out |
|
|
49
43
|
|
|
50
|
-
|
|
44
|
+
One unit only: `Inches(x)` in code, `x * 914400` for raw XML. Never mix EMU and
|
|
45
|
+
inches.
|
|
51
46
|
|
|
52
|
-
|
|
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.
|
|
47
|
+
## Deciding slide count
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
One idea per slide; two competing headlines is two slides. One headline plus a
|
|
50
|
+
table too large for 14 pt makes the table an appendix, and the body slide states
|
|
51
|
+
the conclusion in one line. N minutes ≈ N/2 content slides at 60–90 seconds each,
|
|
52
|
+
plus a cover and a closing ask.
|
|
58
53
|
|
|
59
54
|
## Where the detail lives
|
|
60
55
|
|
|
61
|
-
- Type, colour, density
|
|
56
|
+
- Type, colour, density, cover art: [style-guidelines](style-guidelines.md).
|
|
62
57
|
- Bullets that read as sentences: [native-bullets](native-bullets.md).
|
|
63
|
-
- Charts, tables and notes
|
|
58
|
+
- Charts, tables and notes: [native-evidence](native-evidence.md).
|
|
64
59
|
- Supplied templates: [templates](templates.md).
|
|
65
60
|
- Pre-delivery checklist: [finalization](finalization.md).
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Finalization checklist
|
|
2
2
|
|
|
3
|
-
Run this before `present`.
|
|
4
|
-
broken deck at least once.
|
|
3
|
+
Run this before `present`. Every item has shipped a broken deck at least once.
|
|
5
4
|
|
|
6
5
|
## The file
|
|
7
6
|
|
|
@@ -12,19 +11,18 @@ broken deck at least once.
|
|
|
12
11
|
- [ ] Slide count matches the intent; nothing left over from an earlier draft.
|
|
13
12
|
- [ ] Core properties set:
|
|
14
13
|
`"<python>" "<skill>/container_tools/core_properties.py" --input deck.pptx --title "..." --author "..."`
|
|
15
|
-
(an untitled deck shows
|
|
14
|
+
(an untitled deck shows as "PowerPoint Presentation" in every file list).
|
|
16
15
|
|
|
17
16
|
## The content
|
|
18
17
|
|
|
19
|
-
- [ ] Every placeholder
|
|
18
|
+
- [ ] Every placeholder filled or deleted — no "Click to add text".
|
|
20
19
|
- [ ] No default chart title ("Chart Title") survives:
|
|
21
20
|
`"<python>" "<skill>/container_tools/native_chart_title_gate.py" --input deck.pptx`.
|
|
22
21
|
- [ ] Totals are arithmetic:
|
|
23
22
|
`"<python>" "<skill>/container_tools/native_table_arithmetic_gate.py" --input deck.pptx --contracts totals.json`.
|
|
24
23
|
- [ ] Charts have their data in the file (portable mode passes) and categories
|
|
25
24
|
are in a meaningful order.
|
|
26
|
-
- [ ] Numbers in the deck agree with the
|
|
27
|
-
precision shown.
|
|
25
|
+
- [ ] Numbers in the deck agree with the source data at the precision shown.
|
|
28
26
|
- [ ] Speaker notes carry the provenance of the non-obvious numbers.
|
|
29
27
|
|
|
30
28
|
## The layout
|
|
@@ -34,7 +32,7 @@ broken deck at least once.
|
|
|
34
32
|
→ `passed: true`; review findings read and consciously accepted.
|
|
35
33
|
- [ ] Nothing outside the slide edge, nothing overlapping the footer zone.
|
|
36
34
|
- [ ] Titles are one or two lines; no title ends in a full stop.
|
|
37
|
-
- [ ] Body text
|
|
35
|
+
- [ ] Body text at least 18 pt, captions at least 12 pt.
|
|
38
36
|
- [ ] One idea per slide, one emphasis per paragraph.
|
|
39
37
|
|
|
40
38
|
## The look
|
|
@@ -46,7 +44,7 @@ broken deck at least once.
|
|
|
46
44
|
- [ ] Text is not clipped, ellipsised or shrunk to illegibility.
|
|
47
45
|
- [ ] Photographs are not stretched; their sources are listed.
|
|
48
46
|
- [ ] Charts read at thumbnail size: the point is visible before any label.
|
|
49
|
-
- [ ]
|
|
47
|
+
- [ ] Cover and closing slide both say something.
|
|
50
48
|
|
|
51
49
|
## Delivery
|
|
52
50
|
|
|
@@ -57,7 +55,7 @@ broken deck at least once.
|
|
|
57
55
|
|
|
58
56
|
## When rendering is unavailable
|
|
59
57
|
|
|
60
|
-
`render_slides.py --engine draft` draws a geometry preview
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
`render_slides.py --engine draft` draws a PyMuPDF geometry preview when no office
|
|
59
|
+
suite is installed. Type is drawn at declared sizes in a substitute face and
|
|
60
|
+
layout chrome is not rendered. Use it to catch overlap, overflow and placement —
|
|
61
|
+
not to judge typography.
|