dsh-office-kit 0.4.1 → 0.4.3

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 (116) hide show
  1. package/assets/skills/excel-live-control/SKILL.md +120 -148
  2. package/assets/skills/excel-live-control/container_tools/live_excel.py +9 -0
  3. package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
  4. package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
  5. package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
  6. package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
  7. package/assets/skills/excel-live-control/references/office-automation.md +127 -153
  8. package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
  9. package/assets/skills/excel-live-control/style_guidelines.md +56 -64
  10. package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
  11. package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
  12. package/assets/skills/office-documents/SKILL.md +24 -60
  13. package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
  14. package/assets/skills/office-documents/ooxml/comments.md +8 -8
  15. package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
  16. package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
  17. package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
  18. package/assets/skills/office-documents/references/docx-structure.md +11 -13
  19. package/assets/skills/office-documents/references/template-elicitation.md +11 -13
  20. package/assets/skills/office-documents/references/writing-quality.md +20 -20
  21. package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
  22. package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
  23. package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
  24. package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
  25. package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
  26. package/assets/skills/office-documents/tasks/create_edit.md +14 -16
  27. package/assets/skills/office-documents/tasks/equations.md +17 -28
  28. package/assets/skills/office-documents/tasks/fields_update.md +14 -16
  29. package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
  30. package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
  31. package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
  32. package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
  33. package/assets/skills/office-documents/tasks/images_figures.md +15 -25
  34. package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
  35. package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
  36. package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
  37. package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
  38. package/assets/skills/office-documents/tasks/read_review.md +9 -20
  39. package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
  40. package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
  41. package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
  42. package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
  43. package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
  44. package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
  45. package/assets/skills/office-documents/tasks/verify_render.md +11 -23
  46. package/assets/skills/office-documents/tasks/watermarks_background.md +11 -15
  47. package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +9 -9
  48. package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
  49. package/assets/skills/office-pdf/SKILL.md +36 -51
  50. package/assets/skills/office-pdf/references/form-fields.md +20 -20
  51. package/assets/skills/office-pdf/references/geometry.md +10 -10
  52. package/assets/skills/office-pdf/references/layout-quality.md +13 -13
  53. package/assets/skills/office-pdf/references/limits.md +12 -56
  54. package/assets/skills/office-pdf/tasks/annotations.md +5 -5
  55. package/assets/skills/office-pdf/tasks/create.md +6 -9
  56. package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
  57. package/assets/skills/office-pdf/tasks/forms.md +15 -15
  58. package/assets/skills/office-pdf/tasks/read.md +9 -9
  59. package/assets/skills/office-pdf/tasks/redact.md +18 -18
  60. package/assets/skills/office-pdf/tasks/stamp.md +10 -10
  61. package/assets/skills/office-presentations/SKILL.md +71 -91
  62. package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
  63. package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
  64. package/assets/skills/office-presentations/recipes/README.md +24 -35
  65. package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
  66. package/assets/skills/office-presentations/recipes/connectors.md +11 -12
  67. package/assets/skills/office-presentations/recipes/images.md +11 -12
  68. package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
  69. package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
  70. package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
  71. package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
  72. package/assets/skills/office-presentations/recipes/tables.md +14 -14
  73. package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
  74. package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
  75. package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
  76. package/assets/skills/office-presentations/references/finalization.md +10 -12
  77. package/assets/skills/office-presentations/references/native-bullets.md +14 -18
  78. package/assets/skills/office-presentations/references/native-evidence.md +18 -32
  79. package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
  80. package/assets/skills/office-presentations/references/templates.md +31 -60
  81. package/assets/skills/office-presentations/routing/google_slides.md +4 -4
  82. package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
  83. package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
  84. package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
  85. package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
  86. package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
  87. package/assets/skills/office-presentations/tasks/template-following.md +23 -28
  88. package/assets/skills/office-spreadsheets/SKILL.md +32 -39
  89. package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
  90. package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
  91. package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
  92. package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
  93. package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
  94. package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
  95. package/assets/skills/office-spreadsheets/references/charts.md +15 -34
  96. package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
  97. package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
  98. package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
  99. package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
  100. package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
  101. package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
  102. package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
  103. package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
  104. package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
  105. package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
  106. package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
  107. package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
  108. package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
  109. package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
  110. package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
  111. package/assets/skills/shared/annotation-recipes.md +98 -120
  112. package/assets/skills/shared/common-workflow.md +70 -80
  113. package/dist/index.js +105 -29
  114. package/package.json +1 -1
  115. package/postinstall.mjs +58 -17
  116. package/python/office_cli.py +70 -7
@@ -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
- the picture is stretched — a deliberate choice for a full-bleed background,
9
- a mistake for a product photo.
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
- keyed by content hash.
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 will look soft on a projector. Check `Image.open(...).size`.
61
- 2. One dominant image per slide. A slide with a hero and three thumbnails is two
62
- slides.
63
- 3. Full-bleed backgrounds need text contrast handled deliberately — a dark
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 a table as "evidence": it is unreadable at
74
- projector size and unverifiable. Use a native chart or table.
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, and where you make a change decides how many slides it
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
- and the shapes every slide inherits (title bar, accent rule, logo).
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** — holds its own shapes plus *placeholder overrides*: text, and also
13
- position, if someone dragged a placeholder.
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 to know:** `master.shapes` and `layout.shapes` are read-only in
24
- `python-pptx` (`MasterShapes` has no `add_shape`). Chrome shapes are therefore
25
- built on a scratch slide and their XML moved into the master's shape tree.
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 is what clears the `empty_placeholder` review finding in
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
- When the user supplies a template, do not rebuild its look — put content into
98
- its placeholders. The inspection script prints each layout's placeholders with
99
- index, kind and rect, which is what you need to address them:
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
- a placeholder for every non-empty slot, so index-based addressing is stable.
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
- and the next slide of the same family misbehaves again.
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
- view is empty.
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 for three reasons:
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
- the marks. Category order is the series' own order — sort before you pass it,
17
- because a chart does not sort.
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 that repeats the slide title — the title says what the chart
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" placeholder text in a shipped deck.
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` is what stops the legend from stealing
77
- plot height and squashing the bars.
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 a thing PowerPoint respects for mixed content; it
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
- `line_spacing`) apply to the whole paragraph and are safe to set once.
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 you want the reader to remember gets its own run, and usually a
66
- weight change — not a second bullet.
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. Keep one family of emphasis per deck: bold+accent for numbers, italic+muted
70
- for provenance. Three competing emphases read as decoration.
71
- 4. Strings that repeat (units, currency, product names) belong in a variable so
72
- a later edit does not leave two spellings.
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 set beforehand is gone.
78
- - A run with no `font.size` inherits the layout's size, which is 44 pt on a
79
- title layout — footnote markers become headlines.
80
- - Building the paragraph by f-string with `**` markers that PowerPoint does not
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
- you are writing.
9
+ writing.
10
10
 
11
- Notes are not visible in the render. That means a notes problem cannot be caught
12
- by looking at the PNGs: check them with `pptx read` or by reading the XML back.
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, notes are invisible when the deck is sent as a PDF.
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; each intended paragraph should be `add_paragraph()` so the notes
56
- pane and the presenter view indent them.
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 with
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
- setting them is mandatory, because `add_table` splits the width evenly.
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
- then runs into whatever sits below.
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, which is most of the row. Reduce them when rows are tight.
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, and keep decimals
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
- let `container_tools/native_table_arithmetic_gate.py` prove it from the file.
73
- - Units belong in the header (`Orders`, `Touches`), not repeated in every cell.
74
- - Money keeps its currency in the header or the first row; `¥1,240` in every
75
- cell of a dense table is noise.
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 table whose declared height is smaller than its content: the last row is
81
- drawn below the intended block and collides with the footer.
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
- places it at 0.8 in from the left, full content width, at the running cursor.
88
- For a chosen rect, column widths or right-aligned numbers, use the recipe.
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` must be set explicitly on a new
11
- box or long lines run past the slide edge instead of wrapping.
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
- (which overlaps whatever is under the box) unless autosize is turned on.
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
- about `width_in * 96 / (0.55 * 28)` characters (0.55 average advance for a
49
- humanist sans), and each line needs `1.2 * 28 / 72` inches of height. Leave the
50
- estimate in the script, then let the render confirm it.
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 the text at 18 pt, later edited to 32 pt, now overlaps the
62
- table below. Frame height follows the *largest* run, so size text first.
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
- 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.
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` on one slide,
77
- `#171e29` on the next) because the colour was retyped instead of referenced.
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
- on the same run: the last assignment wins and the theme reference vanishes.
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, mechanically
3
+ ## What a deck is
4
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.
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 shape the whole workflow:
10
+ Three consequences:
12
11
 
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
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; 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.
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**: 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
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 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.
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
- ## The numbers that keep a deck readable
32
+ ## Layout numbers
35
33
 
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 |
34
+ Type, colour and density: [style-guidelines](style-guidelines.md).
46
35
 
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.
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
- ## Deciding slide count
44
+ One unit only: `Inches(x)` in code, `x * 914400` for raw XML. Never mix EMU and
45
+ inches.
51
46
 
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.
47
+ ## Deciding slide count
55
48
 
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.
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 and cover art: [style-guidelines](style-guidelines.md).
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 as evidence: [native-evidence](native-evidence.md).
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`. It exists because every item on it has shipped a
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 up as "PowerPoint Presentation" in every file list).
14
+ (an untitled deck shows as "PowerPoint Presentation" in every file list).
16
15
 
17
16
  ## The content
18
17
 
19
- - [ ] Every placeholder is filled or deleted — no "Click to add text".
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 numbers in the source data, at 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 is at least 18 pt, captions at least 12 pt.
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
- - [ ] The cover and closing slide both say something.
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 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.
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.
@@ -8,24 +8,21 @@ A bullet is a claim, not a label. Two forms work:
8
8
  cost, not the pick."
9
9
  - **Number + meaning**: "12 minutes per order lost to aisle travel."
10
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.
11
+ Forms that fail: a single noun ("Efficiency"), a truncated clause ("Picking
12
+ accounts for…"), three adjectives in a row, or a bullet that restates the slide
13
+ title.
14
14
 
15
15
  ## Length and count
16
16
 
17
17
  - One line, two at the absolute maximum, per bullet on a 16:9 slide.
18
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.
19
+ - No sub-sub-bullets. A bullet needing a child means the parent was a section.
20
20
  - Keep bullets grammatically parallel: all sentences, or all noun phrases.
21
21
 
22
22
  ## Native bullet glyphs
23
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:
24
+ Bullets are paragraph properties, not characters. A typed bullet ("• Picking…")
25
+ cannot re-indent, cannot change level, and looks unlike every other bullet.
29
26
 
30
27
  ```python
31
28
  "<python>" - <<'PY'
@@ -64,15 +61,14 @@ print("bullets:", len(frame.paragraphs))
64
61
  PY
65
62
  ```
66
63
 
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.
64
+ The `marL`/`indent` pair pulls a wrapped bullet's second line under the text
65
+ instead of under the glyph — the most common "malformed bullet" defect in
66
+ generated decks.
70
67
 
71
68
  ## Anti-patterns
72
69
 
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.
70
+ - Bullets as a script: a slide is not a transcript; the speaker notes are.
71
+ - Fake bullets via "– " or "→ " prefixes; they do not indent.
72
+ - Six bullets of equal weight where one is the point. Make the point the title,
73
+ the bullets the evidence.
74
+ - Numbered lists where order does not matter, bullets where it does.