| 1 | > See [`shared-standards-core.md`](./shared-standards-core.md) §§1.4–1.5 for the native-shape metadata and validation contracts. |
| 2 | |
| 3 | # Native Shape Authoring Reference |
| 4 | |
| 5 | Use this reference during Executor SVG construction or project-owned canonical |
| 6 | template maintenance when native contours or supported shape/text operands can |
| 7 | express the intended object. Choose each contour from its page job before |
| 8 | deciding how to encode it, then use the simplest exact authoring form. Keep |
| 9 | faithful atoms independent unless one contour is required; materialize that |
| 10 | contour with a PowerPoint-style Boolean result, and use hand-authored freeform |
| 11 | only when those constructions fail. Neither helper writes a page. The preset |
| 12 | helper does not create the shape's own `p:txBody`; keep visible text outside the |
| 13 | atomic fragment. |
| 14 | |
| 15 | **Mandatory — complete vocabulary before contour selection**: In Create |
| 16 | Template, load this reference and |
| 17 | [`preset-shape-vocabulary.md`](./preset-shape-vocabulary.md) completely and |
| 18 | retain both as soon as `replication_mode` resolves to `standard` or `fidelity`, |
| 19 | before selecting any newly authored page or template contour. Do not load this |
| 20 | authored-construction bundle for `mirror`; it preserves source-owned geometry. |
| 21 | In every other valid authoring context, read the preset vocabulary completely |
| 22 | at authoring entry before selecting the first newly authored contour. It exposes |
| 23 | all 187 exact preset names under the Office gallery and objective contour |
| 24 | families. This is authoring-side capability knowledge, never a Strategist task |
| 25 | or Design Spec field. Reread only after context invalidation or a known file |
| 26 | change; a filtered query cannot replace the complete read. |
| 27 | |
| 28 | **Hard rule — direct structured calls**: `${SKILL_DIR}` below is the retained |
| 29 | absolute Skill root. After choosing a concrete lookup or authoring operation, |
| 30 | invoke that command once per argument set and read stdout directly. Do not |
| 31 | change CWD, encode executables or flag lists in scalar shell strings, batch |
| 32 | these calls through shell loops, merge stderr, or add a downstream parser when |
| 33 | `--compact` exists. |
| 34 | |
| 35 | `list --search` and `list --grouped --search` are optional spelling/location |
| 36 | helpers. Run `describe <name> --compact` only when a serious candidate needs |
| 37 | objective identity, adjustment, connector, path, connection-site, or |
| 38 | text-rectangle facts. Executor makes the final comparison through §§1–2.1; |
| 39 | filtered lookup cannot narrow the already-loaded vocabulary. |
| 40 | |
| 41 | ## 1. Contour Selection and Materialization Gate |
| 42 | |
| 43 | **Hard rule — contour before encoding**: choose the page-fit contour from the |
| 44 | intended job and active visual system across the full native vocabulary before |
| 45 | considering authoring syntax. Rectangle, rounded-rectangle, circle, and ellipse |
| 46 | contours are not an earlier visual tier merely because SVG has short primitive |
| 47 | syntax for them. Easier syntax is never the reason to select a contour. |
| 48 | |
| 49 | **Default — exact page-fit geometry before generic neutrality (may override when |
| 50 | neutrality itself communicates the page)**: Resolve relationship fit when the |
| 51 | content carries direction, sequence, membership, hierarchy, convergence, reveal, |
| 52 | or contrast. Independently resolve page-field / carrier fit from ownership, |
| 53 | focal hierarchy, boundary strength, and the active deck's edge / opening |
| 54 | language; `Structure=no` removes only relationship topology. Choose a plain |
| 55 | primitive, uniform grid, or no drawn carrier only when that lack of inflection |
| 56 | gives the reader a concrete benefit or avoids a false inference. Retain that |
| 57 | reader effect through authoring. Before that neutral result wins, name the |
| 58 | strongest fitting native / compound alternative and retain why its inflection |
| 59 | would add no reader benefit, create a false inference, weaken hierarchy, or |
| 60 | conflict with the page job. Quick speed, restrained style, readability, equal |
| 61 | importance, precedent, and shorter syntax alone do not qualify. |
| 62 | |
| 63 | **Hard rule — style does not narrow capability**: the active visual system may |
| 64 | weight contour fit and control paint, stroke, texture, density, and recurrence. |
| 65 | It never removes primitives, Office presets, independent composition, Boolean, |
| 66 | or necessary freeform from consideration. Style-specific syntax guidance |
| 67 | applies only to the named style-defining mark, not every functional page |
| 68 | contour. |
| 69 | |
| 70 | After contour selection, use the simplest exact materialization below. Do not |
| 71 | hand-author a freeform merely because an SVG path is convenient. |
| 72 | |
| 73 | | Selected result | Authoring form | |
| 74 | |---|---| |
| 75 | | Mirror/preserve input already owns native-shape metadata | Keep the existing object and metadata; never reselect its preset. | |
| 76 | | One exact non-Connector stock contour | Use an ordinary SVG primitive only when the exporter maps it to that same contour; otherwise run `preset_shape_svg.py render` and insert its complete stdout fragment. | |
| 77 | | A stock `bentConnector*` / `curvedConnector*` contour exactly expresses a bent or curved relationship and endpoint attachment is not required | Run `preset_shape_svg.py render --object-kind connector`; the result is an unconnected native Connector shape. | |
| 78 | | A straight relationship, divider, or leader | Write `<line>`; use a registered marker under [`shared-standards-core.md`](./shared-standards-core.md) §1.1 only when direction is meaningful. | |
| 79 | | A selected text/content boundary needs no filled surface | Use its exact authoring form with `fill="none"` and a visible stroke; keep its content as independent siblings. | |
| 80 | | Two or more selected native contours form the page construction but do not need one contour | Keep them as independently editable siblings in one ordinary semantic group; use §2.1 to compose the page-level geometry system. | |
| 81 | | Two or more supported closed-shape / resolvable-text operands require Union, Combine, Fragment, Intersect, or Subtract | Run `shape_boolean_svg.py render`, then replace the operands with every stdout path; the result remains ordinary editable custom geometry. | |
| 82 | | Exact native contours, their independent composition, and Boolean materialization cannot faithfully express the visual meaning or contour | Write ordinary `<path>` / `<polygon>` geometry; export keeps it as editable custom geometry. | |
| 83 | | The shape only resembles a preset | Never infer a preset; continue to the Boolean gate, then use freeform only if no faithful construction exists. | |
| 84 | |
| 85 | **Hard rule**: `preset_shape_svg.py` is the only authoring entry for |
| 86 | `data-pptx-authoring="preset"`. Never add `data-pptx-prst`, frame, adjustment, |
| 87 | or registry path data by hand. Insert the helper's complete compact `<g>` and |
| 88 | rerun the helper whenever its geometry, paint, or filter reference changes. |
| 89 | After selecting two or more objects for one current page or template |
| 90 | construction, use `render-batch --input -` to validate and emit their |
| 91 | independent fragments in one stdout round; the batch never chooses those |
| 92 | objects or their composition. |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ## 2. Vocabulary-Guided Preset Selection |
| 97 | |
| 98 | [`preset-shape-vocabulary.md`](./preset-shape-vocabulary.md) follows the Office |
| 99 | gallery taxonomy: Lines, Rectangles, Basic Shapes, Block Arrows, Equation |
| 100 | Shapes, Flowchart, Stars and Banners, Callouts, and Action Buttons. Its family |
| 101 | labels and objective identities expose the available contours without deciding |
| 102 | their page use. The optional semantic helper data does not redefine the |
| 103 | DrawingML registry or override Executor judgment. |
| 104 | |
| 105 | Apply this page-local sequence before drawing: |
| 106 | |
| 107 | | Pass | Action | Result | |
| 108 | |---|---|---| |
| 109 | | Job | State what the object must do for the reader before naming a shape. | Page role plus any real relationship, direction, aspect, text load, or literal scope. | |
| 110 | | Browse | Compare that job against the complete loaded vocabulary; move from Office category to contour family to exact name. | A small candidate set chosen by meaning, not syntax convenience. | |
| 111 | | Inspect | When exact facts could change the decision, run `describe --compact` directly for those candidates and compare identity, scope, adjustments, connector status, paths, text rectangle, and connection sites. | Objective geometry evidence without prescribed use. | |
| 112 | | Select | Choose the contour whose inference and visual character fit the page, including a neutral primitive when neutrality is useful. | One page-fit contour; no syntax decision yet. | |
| 113 | | Encode | Apply §1's materialization gate. | Ordinary SVG primitive, helper-authored preset, Boolean result, or necessary freeform. | |
| 114 | |
| 115 | Example location and inspection commands: |
| 116 | |
| 117 | ```bash |
| 118 | python3 "${SKILL_DIR}/scripts/preset_shape_svg.py" describe chevron --compact |
| 119 | python3 "${SKILL_DIR}/scripts/preset_shape_svg.py" list --search connector |
| 120 | ``` |
| 121 | |
| 122 | **Hard rule — semantic fit, not name association**: a preset name, topic word, |
| 123 | or metaphor is not evidence of use. Respect `literal_only` and `scope` before |
| 124 | visual preference. For example, a scroll is not a generic playbook carrier, a |
| 125 | lightning bolt is not generic price tension, `chartX` / `chartStar` / |
| 126 | `chartPlus` are partition symbols rather than charts, and a flowchart symbol |
| 127 | belongs only in an actual flowchart. An action-button preset supplies visual |
| 128 | geometry only; it never creates an action or hyperlink. |
| 129 | |
| 130 | The vocabulary exposes contours; Executor chooses them, and §1 chooses syntax. |
| 131 | It never requires `rect`, `ellipse`, `line`, or any other primitive to pass |
| 132 | through the preset helper. Export never scans or upgrades existing geometry. |
| 133 | |
| 134 | **Shape-first diagram rule**: use `<line>` for straight thin relationships; |
| 135 | use an exact connector-family preset for a stock bent or curved contour; use a |
| 136 | block-arrow / chevron preset for a solid direction. Resort to an open freeform |
| 137 | path only when those native constructions cannot faithfully express the |
| 138 | relationship, data geometry, or locked hand-drawn / organic style. Newly |
| 139 | authored connector-family presets remain unconnected and do not gain attachment |
| 140 | semantics. Existing Connector topology imported from a source PPTX remains |
| 141 | owned by the preserve/mirror round-trip contract. |
| 142 | |
| 143 | **Forbidden — false native semantics**: |
| 144 | |
| 145 | - a catalog entry with `literal_only=true` when the depicted literal concept is |
| 146 | absent, or a `flowchart` / `navigation` scope outside that real context; |
| 147 | - `actionButton*` when navigation or trigger behavior is expected; the helper |
| 148 | maps its visual preset geometry only and never creates an action or hyperlink; |
| 149 | - `chartX`, `chartStar`, or `chartPlus` as a substitute for native charts; |
| 150 | - logo, icon glyph, illustration, brand contour, or data-chart marks. |
| 151 | |
| 152 | ### 2.1 Compound page geometry |
| 153 | |
| 154 | **Trigger**: after the page or prototype's communication / slot job, composition |
| 155 | anchors, and any applicable topology under |
| 156 | [`executor-structure.md`](./executor-structure.md) are resolved, but before |
| 157 | writing coordinates, resolve the page-scale geometry move that best carries its |
| 158 | background field, content zoning, focal hierarchy, or reading path. Apply §1's |
| 159 | exact-fit decision and compare the useful lenses below. Before repeating stacked |
| 160 | rectangles / rounded cards or uniform equal columns, compare a page-field, |
| 161 | outline, nesting, or continuity construction and the relevant contour family's |
| 162 | exact members. Readability of the first workable arrangement does not close this |
| 163 | gate. |
| 164 | This applies whether the per-page Structure result is `no` or `yes`; it never |
| 165 | creates a decoration requirement. |
| 166 | |
| 167 | | Pass | Action | Result | |
| 168 | |---|---|---| |
| 169 | | Page job | Name the page-scale geometry move and its jobs: surface, boundary, focal mark, shared region, counterweight, or any source-backed direction / reveal. | One composition direction and a small set of functional zones; no shape names yet. | |
| 170 | | Decompose | Separate visible content from geometric atoms. Identify which atoms need independent movement, paint, or reuse and which contour must become one object. | Editable siblings plus any explicit Boolean operand set. | |
| 171 | | Select | Choose the contour family, then its exact member from the job, full native vocabulary, and edge / corner / opening behavior; retain the reader effect when the result is generic or undrawn. | Page-fit native atoms without syntax bias. | |
| 172 | | Compose | Establish page frame, scale, z-order, and negative space with independent atoms. Keep text, images, icons, data marks, and non-merged accents outside Boolean operands. | One page-level geometry system, not a collection of unrelated decorations. | |
| 173 | | Materialize | Run the preset helper for each adopted preset. Run the Boolean helper only for contours that require Merge Shapes semantics, then replace those operands with its stdout paths. | Valid authoring SVG ready for native export. | |
| 174 | |
| 175 | **Composition lenses — not a checklist**: |
| 176 | |
| 177 | | Lens | Use when it strengthens the resolved page | |
| 178 | |---|---| |
| 179 | | Page field | Let one large surface, outline, aperture, or off-canvas contour organize major zones instead of wrapping every content unit in a card. | |
| 180 | | Outline carrier | Use `fill="none"` plus a coherent stroke on a frame, arc, bracket, band, or other faithful contour when bare text needs ownership without a heavy filled card. | |
| 181 | | Nested fields | Visually nest an inset contour, secondary surface, badge, port, or focal shape inside / across a larger field to create hierarchy; keep them as siblings unless one contour must merge. | |
| 182 | | Continuity | Align or overlap independent shapes across zones so geometry reinforces the intended reading path. | |
| 183 | | Depth and contrast | Combine filled, outlined, offset, and negative-space atoms; use Boolean only when the contour itself must change. | |
| 184 | | Deck language | Reuse a corner, arc, slant, notch, or layering logic with page-fit variation rather than cloning one composition. | |
| 185 | |
| 186 | **Default — running deck geometry check (may override for literal pages or |
| 187 | isolated template prototypes)**: After each generated page, retain |
| 188 | `page job → composition move → contour / edge language`; append `relationship → |
| 189 | topology` only for `Structure=yes`, then compare before the next. Repeat only for |
| 190 | the same page job / relationship or deliberate continuity; section, equal |
| 191 | weight/density, style, and precedent are insufficient. Create no artifact or |
| 192 | second pass. |
| 193 | |
| 194 | **Boolean decision gate**: |
| 195 | |
| 196 | | Required result | Construction | |
| 197 | |---|---| |
| 198 | | Stock contour already expresses the job | Keep that exact contour and materialize it through §1; do not rebuild it from other shapes or Boolean operands. | |
| 199 | | Shapes overlap or layer but must remain independently editable | Keep separate primitives / presets in one ordinary semantic group; do not merge them. | |
| 200 | | One continuous outer silhouette | `union`; use `combine` only for intentional symmetric negative regions. | |
| 201 | | A true hole, edge cut, or reveal | `subtract`, with the visible body first and cutout operands after it. | |
| 202 | | Only the common covered region should remain | `intersect`. | |
| 203 | | Exclusive and shared regions need separate styling or motion | `fragment`, retaining every required result path as an independent shape. | |
| 204 | |
| 205 | **Authoring-to-export map**: |
| 206 | |
| 207 | | SVG authoring form | Native PPTX result | |
| 208 | |---|---| |
| 209 | | Ordinary `<rect>`, rounded `<rect>`, `<circle>`, `<ellipse>`, or `<line>` | Matching editable preset geometry / line shape. | |
| 210 | | Complete `preset_shape_svg.py` fragment | One exact `a:prstGeom` shape, or `p:cxnSp` for an authored connector preset. | |
| 211 | | `shape_boolean_svg.py` result path | Editable `a:custGeom`; the final contour is retained, not replayable Merge Shapes history. | |
| 212 | | Parent semantic group containing independent atoms and content | A grouped page construction whose child shapes remain separately editable. | |
| 213 | |
| 214 | **Reference — not a constraint**: derive the operand count, preset choices, |
| 215 | geometry, paint, rotation, and grouping from the current page. A strong compound |
| 216 | construction may use only independent presets, only one Boolean result, or a mix; |
| 217 | there is no Boolean quota and no catalog of allowed combinations. |
| 218 | |
| 219 | **Hard rule — merge only geometry that must become one contour**: never merge |
| 220 | text, images, icons, or otherwise independent accents merely to simplify the |
| 221 | SVG tree. Boolean materialization discards editable operand history; preserve |
| 222 | siblings whenever one-object contour semantics are unnecessary. |
| 223 | |
| 224 | --- |
| 225 | |
| 226 | ## 3. Fragment Generation |
| 227 | |
| 228 | `render` emits one selected object. `render-batch` atomically emits multiple |
| 229 | already-selected objects for one current page or template construction. |
| 230 | Generated project pages choose each object's solid paint from the current page |
| 231 | context, using `spec_lock.md` roles as reusable anchors rather than an exhaustive |
| 232 | palette; `create-template` takes colors from the confirmed brief and template |
| 233 | `design_spec.md`. Mirror/preserve input keeps the source object's paint instead |
| 234 | of regenerating this authored form. |
| 235 | |
| 236 | ```bash |
| 237 | python3 ${SKILL_DIR}/scripts/preset_shape_svg.py render rightArrow \ |
| 238 | --id p03-growth-arrow \ |
| 239 | --frame 160 210 320 112 \ |
| 240 | --fill "#2563EB" \ |
| 241 | --stroke none \ |
| 242 | --adjust "adj1=val 50000" |
| 243 | ``` |
| 244 | |
| 245 | When one native effect is justified, append `--filter-id softShadow`. |
| 246 | `softShadow` must already be one direct page-level `<defs><filter>` id under |
| 247 | [`svg-effects.md`](./svg-effects.md) §6.4. Omit the option otherwise. |
| 248 | |
| 249 | For a stock bent / curved contour that does not require endpoint attachment: |
| 250 | |
| 251 | ```bash |
| 252 | python3 ${SKILL_DIR}/scripts/preset_shape_svg.py render bentConnector3 \ |
| 253 | --id p03-flow-connector \ |
| 254 | --object-kind connector \ |
| 255 | --frame 420 180 220 140 \ |
| 256 | --fill none \ |
| 257 | --stroke "#475569" \ |
| 258 | --stroke-width 2 |
| 259 | ``` |
| 260 | |
| 261 | Every connector-family preset requires `--object-kind connector`, `--fill none`, |
| 262 | and a visible stroke. It exports as an unconnected `p:cxnSp`; a connector |
| 263 | preset can never be authored as an ordinary `shape`. |
| 264 | |
| 265 | **Hard rule — stdout-only exception**: the helper prints one or more |
| 266 | deterministic `<g>` fragments. Read that output and insert it with the normal |
| 267 | page/template `apply_patch` edit. A batch JSON array is transient input for |
| 268 | already-selected objects in the current construction, never a project resource |
| 269 | or multi-page plan. Do not redirect output into `svg_output/`, loop over |
| 270 | pages/templates, or let the helper choose layout. The main Agent still authors |
| 271 | each complete SVG page and reusable template explicitly. |
| 272 | |
| 273 | --- |
| 274 | |
| 275 | ## 4. Atomic Fragment Contract |
| 276 | |
| 277 | The helper emits one compact logical group. Metadata and base paint are written |
| 278 | once on the group; its direct children are the visible paths regenerated from |
| 279 | the locked preset registry. |
| 280 | |
| 281 | | Component | Ownership | |
| 282 | |---|---| |
| 283 | | Logical `<g data-pptx-authoring="preset">` | Stable id, object kind, preset, frame, adjustments, explicit local base paint, and an optional helper-authored shape filter reference. | |
| 284 | | Direct `<path>` children | Ordered browser-visible registry layers. A child writes only a path-specific fill/stroke override when the preset requires one. | |
| 285 | | Deliberately absent transport fields | No hidden carrier, preview wrapper, `data-pptx-part`, or stored fingerprint belongs in project-authored SVG. Those fields remain part of expanded PPTX import/round-trip transport. | |
| 286 | |
| 287 | **Hard rule**: treat the returned group as atomic. Keep it as the content group |
| 288 | without `data-pptx-bounds` when it stands alone; `data-pptx-frame` owns its |
| 289 | object geometry. When it needs labels, icons, or other decorations, put the |
| 290 | preset and those siblings in a separate bounded parent content group; never put |
| 291 | them inside the preset group itself. Do not edit the direct paths; they are |
| 292 | validation evidence generated from the registry, not a freehand contour surface. |
| 293 | |
| 294 | Canonical page/template authoring also keeps paint and opacity off ancestor |
| 295 | groups that contain the preset. Compatible ancestor paint still exports under |
| 296 | the general SVG composition rules, but the checker warns because the atom is no |
| 297 | longer paint-self-contained; rerun the helper with channel alpha instead. |
| 298 | |
| 299 | On a structured template, a validated authored-preset group is one semantic |
| 300 | atom. It may be Slide-local, the single carrier of an `object` slot, or a direct |
| 301 | Master/Layout fixed atom. This narrow exception does not permit ordinary nested |
| 302 | `<g>` structures in Master/Layout layers or placeholder carriers. The template |
| 303 | workflow may add the registered structural ownership attributes to the complete |
| 304 | helper group; it still must not alter preset metadata, paint, the filter |
| 305 | reference, or direct paths. |
| 306 | |
| 307 | **Frame coordinate space**: `--frame x y w h` is expressed in the coordinate |
| 308 | space where you insert the fragment. At the page root that is page coordinates; |
| 309 | inside a `<g transform="translate(…)">` use **group-local** coordinates — the |
| 310 | ancestor transform stacks on top, so page-absolute values would double-offset |
| 311 | the shape off-canvas. Keep the helper's exact space-separated ordinary-decimal |
| 312 | `data-pptx-frame` spelling; compact authoring does not accept alternate numeric |
| 313 | spellings. |
| 314 | |
| 315 | **Regeneration rule**: rerun the helper when preset, frame, adjustment, fill, |
| 316 | stroke, stroke width, or the filter id changes. Moving, scaling, rotating, or |
| 317 | flipping the complete logical group is allowed; zero-scale transforms and |
| 318 | shear/skew are forbidden, and the transformed frame must remain inside |
| 319 | DrawingML's coordinate range. Stroke width must remain inside DrawingML's |
| 320 | line-width range. To freely edit the contour, replace the whole fragment with |
| 321 | ordinary SVG rather than modifying a generated direct path. |
| 322 | |
| 323 | For a canonical reusable template, the complete helper fragment may remain as |
| 324 | an executable exemplar. A final-page adaptation may copy it unchanged only |
| 325 | when all registry metadata, frame, adjustments, paint, and the optional filter |
| 326 | reference remain unchanged; otherwise regenerate the complete compact group. |
| 327 | |
| 328 | --- |
| 329 | |
| 330 | ## 5. Boundaries |
| 331 | |
| 332 | | Concern | Behavior | |
| 333 | |---|---| |
| 334 | | Shape text | Keep visible SVG `<text>` outside the atomic fragment. It remains editable but may export as a grouped text box rather than the preset's own `p:txBody`. | |
| 335 | | Connector attachment | Authoring helper v1 creates an unconnected `p:cxnSp` and does not accept endpoint/site metadata. Do not hand-add it. The imported-shape contract may preserve an attachment that already exists in a source PPTX; creating a new attached connector is currently unsupported. | |
| 336 | | Action button behavior | `actionButton*` presets map visual geometry only. No action, navigation target, or hyperlink is created automatically. | |
| 337 | | Gradient/pattern paint | Authoring helper v1 accepts solid HEX paint only. Use ordinary SVG when a complex paint treatment is essential. | |
| 338 | | Shadow/glow | Shape presets may reference one existing [`svg-effects.md`](./svg-effects.md) §6.4 filter through `--filter-id`; it applies once to the complete native shape. Connector presets, multiple effects, child-path filters, and other effect graphs remain unsupported. | |
| 339 | | Multi-path darken/lighten | Direct visible layers use the shared normalized paint behavior from the PPTX importer. Their registry-derived HEX values are authorized derivatives of the selected base color and need no separate lock row. | |
| 340 | | Expanded compatibility | Existing helper-authored carrier/preview fragments remain readable as ordinary Slide-local input and receive a non-blocking migration warning; they do not become structured fixed atoms or object-slot carriers. Imported expanded fragments remain the lossless mirror/preserve form. | |
| 341 | | External edits | Any registry-path, style, or semantic mismatch fails quality check and export; regenerate the fragment. | |
| 342 | |
| 343 | **Validation**: `svg_quality_checker.py` independently rerenders every compact |
| 344 | authored preset from registry metadata and compares its direct visible paths |
| 345 | and paint. It also validates the optional shape filter through the shared |
| 346 | [`svg-effects.md`](./svg-effects.md) §6.4 contract. The exporter performs the |
| 347 | same validation, then expands the compact group only in memory to reuse the |
| 348 | lossless native-shape conversion path. |
| 349 | Compatible expanded authored input remains under its separate carrier/preview |
| 350 | freshness contract. |
| 351 | |
| 352 | --- |
| 353 | |
| 354 | ## 6. Shape Boolean Materialization |
| 355 | |
| 356 | **Trigger**: Current page construction has two or more supported shape/text operands |
| 357 | whose faithful result calls for PowerPoint-style Union, Combine, Fragment, |
| 358 | Intersect, or Subtract. Executor decides this directly from the actual content, |
| 359 | complete native inventory, and explicit user/template constraints; no upstream |
| 360 | suggestion or planning field is required. |
| 361 | |
| 362 | ```bash |
| 363 | python3 ${SKILL_DIR}/scripts/shape_boolean_svg.py render <svg-file> \ |
| 364 | --operation subtract \ |
| 365 | --source body \ |
| 366 | --source cutout \ |
| 367 | --id result |
| 368 | ``` |
| 369 | |
| 370 | | Concern | Contract | |
| 371 | |---|---| |
| 372 | | Sources | Closed `path`, `polygon`, `rect`, `circle`, `ellipse`, one validated unfiltered compact authored shape preset, or supported horizontal implicit-LTR direct `<text>` with a resolvable exact OpenType weight/style (`--font-dir` adds search roots). Text becomes glyph geometry and is no longer editable text. A filtered preset is not a Boolean operand; materialize the geometry without the effect, then reapply one supported filter to the result. Open geometry, groups, nested text, images, definitions, and nested SVG viewports fail closed. | |
| 373 | | Primary shape | The first `--source` supplies result paint. For `subtract`, all later operands are removed from that primary geometry. Explicit paint flags override only their named channels. | |
| 374 | | Coordinates | Ancestor and local transforms are baked into SVG-root coordinate space. Place stdout in the primary operand's z-order with no additional transform; never reinsert it under an original transformed ancestor. Root-coordinate space does not require each result path to be a direct `<svg>` child. | |
| 375 | | Placement | Ordinary Slide-local results belong in the applicable untransformed direct-root semantic `<g>` with its normal `id` / `data-pptx-bounds`. Master/Layout results remain direct-root path atoms and redeclare `data-pptx-layer`. One non-fragment result may be the direct `data-pptx-carrier="true"` child of an `object` slot. | |
| 376 | | Fragment roles | Fragment paths may share one ordinary Slide-local semantic group, but remain separate shapes and cannot collectively claim one carrier or one Master/Layout atom. Helper output inherits no structural role metadata from its operands; redeclare only the final layer/carrier/role contract. | |
| 377 | | Result | `union`, `combine`, `intersect`, and `subtract` emit one ordinary `<path>`. `fragment` emits stable sibling paths named `<id>-1`, `<id>-2`, ... in top/left/bottom/right/area order. | |
| 378 | | Winding | Results use explicit nonzero contour direction and never emit `fill-rule`, `clip-rule`, `clip-path`, `mask`, or Merge Shapes metadata. Operands that depend on even-odd fill, clipping, or masking fail closed. | |
| 379 | | Preservation | This helper authors new geometry only. Never use it to merge or split mirror/preserve source structure. | |
| 380 | |
| 381 | Operation semantics match PowerPoint's visible Merge Shapes result: `union` |
| 382 | keeps every covered region, `combine` keeps the symmetric difference, |
| 383 | `intersect` keeps only common coverage, `subtract` removes every later source |
| 384 | from the primary, and `fragment` returns each atomic filled region. The PPTX |
| 385 | stores the materialized freeform geometry, not replayable operation history. |
| 386 | |
| 387 | **Hard rule — stdout-only replacement**: The helper never writes the source |
| 388 | page. In one normal `apply_patch` edit, remove every selected operand and insert |
| 389 | every returned path in root coordinate space at the primary operand's z-order, |
| 390 | using the placement contract above. Fragment paths remain separate shapes; an |
| 391 | ordinary semantic group does not turn them into one structural atom. |
| 392 | |
| 393 | --- |
| 394 | |
| 395 | ## 7. Shape-Only Modelling Techniques |
| 396 | |
| 397 | Applies to any page built from shapes, **with or without images** — a text-only, |
| 398 | data-only, or icon-only deck reaches these the same way. Each technique below is |
| 399 | plain geometry plus gradient paint, so all of it survives native export. |
| 400 | |
| 401 | ### 7.1 Alternating light/dark gradient = dimensional form |
| 402 | |
| 403 | The single highest-yield shape technique. A cylinder, metallic band, dimensional |
| 404 | numeral, or curved panel is produced by one gradient whose stops **alternate |
| 405 | light and dark** across the shape — light · dark · light for a three-stop ramp, |
| 406 | or light · dark · light · dark · light for a five-stop one. The alternation |
| 407 | imitates a curved surface catching light twice; a plain two-stop ramp always |
| 408 | reads flat no matter how strong the contrast. |
| 409 | |
| 410 | Keep every stop on one hue and vary only lightness, hold one light direction for |
| 411 | the whole page, and remove strokes so adjacent facets meet cleanly. For a |
| 412 | cylinder, apply the alternating ramp across the body and cap it with an ellipse |
| 413 | carrying its own shallower ramp. The same light logic applies across separate |
| 414 | facets of any folded form. |
| 415 | |
| 416 | ### 7.2 Reflection without a reflection effect |
| 417 | |
| 418 | Native reflection is `Bake-required` ([`svg-effects.md`](./svg-effects.md) §6.12), |
| 419 | so build it from geometry instead: |
| 420 | |
| 421 | 1. Duplicate the object and flip it with `transform="translate(0, 2·y_bottom) scale(1, -1)"`. |
| 422 | 2. Keep only the top **10–25 %** of the flipped copy — that is all a reflection |
| 423 | ever shows. |
| 424 | 3. Lay a rectangle over it filled with a gradient running from fully transparent |
| 425 | at the object's base to the page background color at the cut line, so the |
| 426 | copy dissolves into the page. |
| 427 | 4. Drop the whole reflection to roughly **60–70 %** opacity. |
| 428 | |
| 429 | Seat rows of certificates, product shots, logo tiles, and cylinders this way. Do |
| 430 | not add a blur — it will not survive export, and a short gradient fade already |
| 431 | reads correctly at slide scale. |
| 432 | |
| 433 | ### 7.3 Fragment as a modelling tool, not just a boolean |
| 434 | |
| 435 | `fragment` (§6) is the fastest way to build layered diagrams from one silhouette: |
| 436 | lay evenly distributed bars across a triangle and fragment it into pyramid tiers; |
| 437 | cross a circle with two bars for a quadrant wheel; slice an annulus radially for |
| 438 | ring segments. Every piece inherits the parent contour, so the assembly stays |
| 439 | perfectly registered — impossible to achieve by drawing the tiers separately. |
| 440 | |
| 441 | Distribute the cutting bars with a constant step before fragmenting; uneven tiers |
| 442 | read as a mistake rather than a hierarchy. Paint the resulting pieces with one |
| 443 | gradient family per §7.1 so the stack reads as a single solid. |
| 444 | |
| 445 | ### 7.4 Soft edges without the soft-edge effect |
| 446 | |
| 447 | Feathered edges are `Bake-required` ([`svg-effects.md`](./svg-effects.md) §6.12), |
| 448 | but the four jobs they normally do are all reachable with gradients: |
| 449 | |
| 450 | | Intent | Build instead | |
| 451 | |---|---| |
| 452 | | Contact shadow under an object | Ellipse filled with a `radialGradient` from dark-transparent at the centre to fully transparent at the rim | |
| 453 | | Spotlight / stage pool | Cone or ellipse filled with a gradient fading to transparent at its far end, at low opacity over the scene | |
| 454 | | Object dissolving into the page | Overlay a rectangle whose gradient runs from transparent to the exact page background hex | |
| 455 | | Hiding an object while keeping it live | Full transparency, or a background-registered fill ([`image-layout-patterns.md`](./image-layout-patterns.md) `#M1-08`) | |
| 456 | |
| 457 | A radial or linear alpha ramp reads the same as a feathered edge at slide scale |
| 458 | and, unlike a filter, exports intact. Never approximate a soft edge with a stack |
| 459 | of stroked outlines — the banding is visible on projection. |
| 460 | |
| 461 | ### 7.5 Ground plane and staging |
| 462 | |
| 463 | An object floating in empty canvas looks pasted on. Give it a surface: a wide |
| 464 | shallow ellipse or trapezoid beneath it, filled with a gradient that fades to the |
| 465 | background at its edges, optionally with a soft dark ellipse directly under the |
| 466 | object as contact shadow. A trapezoid narrowing away from the viewer reads as a |
| 467 | receding floor; a cylinder or slab reads as a pedestal. |
| 468 | |
| 469 | Keep the plane low-contrast — it is staging, not content. This is what makes |
| 470 | certificate rows, product hero shots, and trophy/award pages look composed |
| 471 | rather than floating, and it costs two shapes. |
| 472 |