返回 ppt-master
svg-effects.md
根目录 / skills / ppt-master / references / svg-effects.md
1 > See [`shared-standards-core.md`](./shared-standards-core.md) for the mandatory SVG foundation.
2
3 # SVG Effects and Geometry Specification
4
5 Authority for advanced paint, effects, transforms, freeform/radial geometry, and constructed visual styles. Default and Quick Generate load it before SVG authoring; other SVG-authoring routes follow their workflow trigger.
6
7 **Cross-reference map**: unqualified §1, §2, and §4 references point to [`shared-standards-core.md`](./shared-standards-core.md); §6 references are local to this file.
8
9 ## 6. Advanced SVG Effects and Authoring Techniques
10
11 **Mandatory**: Default and Quick Generate read this file completely before SVG
12 authoring and keep its compatible techniques in active construction vocabulary.
13 Before finalizing each page, run the §6.1 selection procedure and Visual Job
14 Router. Use §6.13 when diagnosed jobs benefit from one coordinated page recipe.
15
16 **Default — situational use (may override when plain construction is stronger)**:
17 “Advanced” means capability depth, not an effect quota. During page authoring,
18 recall relevant techniques from content, hierarchy, legibility, semantics,
19 rhythm, and style; apply those that materially help.
20
21 ### 6.1 Availability, Precedence, and Fidelity
22
23 | Decision layer | Authority |
24 |---|---|
25 | Technical validity | Required / Forbidden / Conditional contracts in this file |
26 | Project values | Default: `<project_path>/spec_lock.md` anchors plus retained Design Spec/page context; Quick: anchors resolved in the current context |
27 | Aesthetic fit | Locked or Quick-resolved `visual_style` / `visual_style_behavior` |
28 | Per-page choice | Content purpose, hierarchy, legibility, semantics, and rhythm |
29
30 **Mandatory — job-first effect selection**: establish the editable semantic
31 skeleton first, then diagnose effect jobs before treating the page as complete.
32 Plain construction remains valid only when that diagnostic finds no unresolved
33 visual job.
34
35 | Pass | Decision |
36 |---|---|
37 | Skeleton / diagnose | Establish native information, relationships, and hierarchy. Before completion, check image/text integration, plane separation, focus, state/direction, material/style, and the recurring motif; keep plain construction when none needs treatment. |
38 | Surface / select | Name the target, confirm its owning subsection and fidelity, then use the Router. Choose a compatible technique that fully performs the job; prefer simpler/native-stable alternatives only when communication is equal. `Approximate` requires review, not automatic rejection. |
39 | Integrate / stop | Align paint, contour, light, hierarchy, and z-order; combine only techniques with different jobs. Check legibility, editability, density, fidelity, and style; simplify failures, use legal alternatives, and bake only the smallest pixel-dependent layer. Keep authoritative text/data native. |
40
41 #### Visual Job Router
42
43 **Reference — not a quota**: route diagnosed problems through this table. A
44 page may use no listed technique, one technique, or several techniques with
45 different jobs.
46
47 | Diagnosed visual problem | Candidate technique | Authority / stop |
48 |---|---|---|
49 | Meaningful direction, continuous value, or center focus is missing | Linear/radial gradient or channel alpha | §6.2 / §6.3; otherwise keep solid paint |
50 | Picture/card/overlay elevation or boundary is unclear | Object or picture/carrier shadow, restrained glow, or hairline | §6.4; equal peers stay flat; one light direction |
51 | Native copy and image do not integrate | Scrim, fade, wash, vignette, off-center spotlight, or faux glass | §6.5 and the Image-Treatment Implementation Map; verify contrast; no backdrop blur |
52 | Relationship state, direction, continuity, or boundary is unclear | Draft/optional/future → dash; direction → marker; undirected → solid; continuous flow → gradient stroke; repeated boundary → frame/contour/crop edge; exact grid → multi-subpath | §6.6 / §6.3; every line needs a job |
53 | Short display text needs notation or silhouette | Removed/former → strike; eyebrow distinction → tracking; display silhouette → outline/gradient; luminous metric → glow; semantic list → native bullet | §6.7 / §6.4; no decorative body-copy treatment |
54 | Tilt, repetition, or reversible asset direction helps composition | Rotate, translate/mirror, or local `<use>` | §6.8; never mirror text, logos, or directional evidence |
55 | Resolved style needs hand, print, pixel, facets, layers, ribbon, or line-plus-area | Matching constructed recipe | §6.11; no generic decorative freeform |
56 | Meaning needs an unmatched silhouette, radial hierarchy, gauge, or custom route | Freeform, explicit arc/sector, or calculated arrowhead | §6.9 / §6.10; prefer an equal stock shape/marker |
57 | Look depends on dense texture, source blur, per-pixel composite, reflection, or skew | Native-safe alternative or prepared/baked asset | §6.12; text/data stay editable |
58
59 #### Image-Treatment Implementation Map
60
61 **Reference — not a constraint**: when image composition names one of these
62 modifier or prepared-asset treatments, resolve its implementation here.
63 `Effect-only` keeps a visible capability here without restoring a layout ID.
64
65 | Image handles / treatment | Construction / boundary |
66 |---|---|
67 | `M2 · 01/03/04/08/09` · scrim, wash, fade, grid | Explicit solid/linear/radial layers over one picture; §6.2 / §6.3 / §6.5 |
68 | `M2 · 06/07` · atmospheric wash, watermark/receded field | Reduced picture alpha + optional wash; subordinate to native content; §6.2 / §6.5 |
69 | `M2 · 02/05` · vignette or spotlight | Radial layer with movable `fx/fy` or `cx/cy`; outer geometry `Approximate`; §6.3 / §6.5 |
70 | `M3 · 04` · lifted picture panel / visible overlay edge | Picture/carrier shadow, glow, or hairline; shadow one support shape for a framed/captioned panel; §6.4 |
71 | `M3 · 01/02/05` · frame, print frame, contour/cut edge | Registered native stroke/path; §6.6 |
72 | `M3 · 03; M1 · 09` · rotation, misregistration, Riso offset | Transform + explicit duplicate layers; §6.8 / §6.11 |
73 | `M1 · 03` + effect-only forms · paper cut, facets/folds, ribbon, staging | Ordered paths/facets + consistent paint/light; §6.11 / [`native-shape-authoring.md`](./native-shape-authoring.md) §7 |
74 | `M1 · 01/02/04–08` · crop, opening, subtraction, reveal | Direct clip or materialized Boolean; no `<mask>`; [`shared-standards-core.md`](./shared-standards-core.md) §1.2 / [`native-shape-authoring.md`](./native-shape-authoring.md) §6 |
75 | Effect-only · faux glass | Visible field + translucent panel + highlight; no blur or frosted-crop substitution; §6.5 |
76 | `A1 · 02–04; A3 · 02/03` · blur, duotone, blend, frost, desaturation | Prepared local bitmap/composite/derivative; registered frost is a blurred derivative; §6.12 |
77
78 **Reference — illustrative colors**: colors below demonstrate syntax only;
79 generated pages choose paint from the Default locked or Quick-resolved identity
80 anchors, visual style, content semantics, and current composition. A contextual
81 tint, gradient stop, shadow/glow paint, or one-off display color need not
82 already be a persistent identity role;
83 promote it only when it becomes a recurring named role. Fidelity labels are defined
84 in [`shared-standards-core.md`](./shared-standards-core.md). Review an `Approximate` result in native PPTX
85 when the effect carries material meaning.
86
87 ---
88
89 ### 6.2 Color, Alpha, and Opacity
90
91 Compatible paint grammar includes recognized named colors, `rgb()` / `rgba()`,
92 `hsl()` / `hsla()`, and `#RGB` / `#RGBA` / `#RRGGBB` / `#RRGGBBAA`. The
93 converter also tolerates legacy bare 3/4/6/8-digit hexadecimal tokens.
94
95 **Default — canonical generated paint tokens (may preserve compatible
96 alternatives)**: New `svg_output/` and reusable template SVGs write solid paint
97 as uppercase six-digit `#RRGGBB`. `fill` / `stroke` may instead use lowercase
98 `none` or the exact local reference form `url(#id)`. Named colors, lowercase or
99 short/alpha HEX, functional colors, and bare legacy HEX remain supported input.
100 The quality checker prints an optional canonical rewrite as a recommendation
101 warning; it does not require modification or block export.
102 Explicit empty, malformed, or unrecognized paint values are errors in both
103 Checker and exporter preflight; neither converts unknown intent into
104 `noFill` or default black. Omitted properties still follow their own element
105 contract, such as SVG's default fill or §6.3's required gradient-stop color.
106
107 | Intent | Canonical authoring | Native result / fidelity |
108 |---|---|---|
109 | Solid fill or text paint | `fill="#RRGGBB"` | Solid DrawingML paint; `Native-stable` |
110 | Fill/text alpha | Opaque `fill` + `fill-opacity="0..1"` | Fill/run alpha; `Native-stable` |
111 | Stroke alpha | Opaque `stroke` + `stroke-opacity="0..1"` | Line/outline alpha; `Native-stable` |
112 | Gradient-stop alpha | Opaque `stop-color` + `stop-opacity="0..1"` | Per-stop alpha; `Native-stable` |
113 | Shadow/glow alpha | Opaque `flood-color` + `flood-opacity="0..1"` | Glow is `Native-stable`; outer shadow is visually calibrated `Approximate` within §6.4 |
114 | Picture fade | `<image opacity="0..1">` | Picture `<a:alphaModFix>`; `Native-stable` |
115 | One atomic whole-object fade | Non-group element `opacity="0..1"` | Alpha compiled into its supported paint/effect channels; `Native-normalized` |
116 | Pattern alpha | Opaque pattern child paint + child fill/stroke opacity | Conditional; [`native-data-interface.md`](./native-data-interface.md) |
117 | CSS color alpha | Alpha-bearing named/functional/HEX paint | `Native-normalized`; recommendation warning only |
118 | Group fade | `<g opacity>` compatibility | `Approximate`; fidelity warning; §2.2 |
119
120 ```text
121 effective fill alpha
122 = color alpha × ancestor group opacity × element opacity × fill-opacity
123 ```
124
125 **Default — opaque color authority (may preserve compatible alpha colors)**:
126 New generated SVG puts alpha on the semantic channel that owns it. Existing or
127 intentional alpha-bearing color tokens remain convertible; they normalize into
128 the matching DrawingML color/alpha channels.
129
130 **Default — channel-specific alpha (may override for one atomic whole-object
131 fade)**: use `fill-opacity`, `stroke-opacity`, `stop-opacity`, or
132 `flood-opacity` when only that channel fades. Use element `opacity` only when
133 an image or one non-group atomic object intentionally fades all of its
134 supported paint/effect channels together. Do not use element `opacity` as an
135 alias for `rgba()` on a fill-only object.
136
137 **Default — alpha grammar (may preserve compatible alternatives)**: write
138 `opacity`, `fill-opacity`, `stroke-opacity`, `stop-opacity`, and
139 `flood-opacity` as finite unitless numbers from `0` to `1`. The converter also
140 accepts finite numeric values that SVG/CSS clamps into that interval;
141 `stop-opacity` and `flood-opacity` additionally accept finite percentages. The
142 checker reports those supported non-default spellings as recommendation warnings.
143 Malformed or non-finite values are errors in both Checker and exporter
144 preflight; neither substitutes an opaque default for unknown intent.
145 `fill="transparent"` / `stroke="transparent"` become no fill/line; use a color
146 plus alpha when a painted transparent layer must remain represented. Prefer
147 descendant alpha over group opacity when isolated compositing matters (§2.2).
148
149 PPTX import is a user-input boundary, not generated authoring. Tolerant mode
150 retains recognized color semantics, omits only unsupported paint properties,
151 and records the decision in `conversion-report.json`; `--strict` keeps the
152 closed parser checks. See
153 [`conversion.md`](../scripts/docs/conversion.md#import-compatibility-and-recovery-boundary).
154 ---
155
156 ### 6.3 Gradients and Paint Effects
157
158 | Concern | Contract |
159 |---|---|
160 | Definition | Direct `<linearGradient>` / `<radialGradient>` child of `<defs>` with unique `id` |
161 | Reference | Exact local `url(#id)` |
162 | Stops | ≥2 direct `<stop>` children; explicit color; finite non-decreasing offset in `0..1` or `0%..100%` (ties form hard edges); optional alpha |
163 | Coordinates | `objectBoundingBox` only. Generated values: `0..1`; omitted linear axis = `(0,0) → (1,0)`. Only import-normalized linear projections may reach `-0.105..1.105`; radial values stay in `0..1`, and their effective focus must lie inside the circle centered at `(0.5,0.5)` with radius `0.5` |
164 | Forbidden | External/quoted refs, `href` inheritance, `gradientTransform`, `spreadMethod`, CSS gradients |
165
166 | Target | Contract and fidelity |
167 |---|---|
168 | `<rect>`, `<circle>`, `<ellipse>`, `<path>`, `<polygon>` fill/stroke | Linear `Native-normalized`; radial `Approximate` |
169 | `<line>` / `<polyline>` | Gradient stroke only; linear `Native-normalized`, radial `Approximate` |
170 | `<text>` / non-positional `<tspan>` | Gradient fill only; no gradient text outline |
171 | `<image>` | No gradient paint; use §6.5 overlays |
172
173 Linear export preserves stops/alpha and reduces direction to an angle;
174 coincident endpoints are invalid. Radial export preserves the effective focus
175 (`fx/fy`, otherwise `cx/cy`) as a point-focused circle; its outer center and
176 radius normalize to `0.5`, so distinct outer `cx/cy` and `r` are dropped. A
177 focus outside that canonical circle is invalid because SVG renderers clamp it
178 to the circumference while DrawingML retains the rectangle coordinates;
179 reverse import centers such a source focus and records a diagnostic.
180 Gradient strokes stay editable;
181 reverse import may keep the first stop only. Stop alpha multiplies element opacity.
182 PPTX import normalizes gradients and reports degradation;
183 `--strict` keeps the closed parser contract. See
184 [`conversion.md`](../scripts/docs/conversion.md#import-compatibility-and-recovery-boundary).
185 Checker/exporter preflight share this validation.
186 Gradient-stop colors are contextual paint values. Keep them coherent with the
187 deck anchors and page intent; they are not required to duplicate existing
188 Default `spec_lock.colors` literals or Quick-resolved anchors.
189
190 **Hard rule — non-degenerate gradient geometry**: an `objectBoundingBox`
191 gradient stroke requires non-zero intrinsic width and height. SVG stroke width
192 does not expand that object bounding box, so a perfectly horizontal or vertical
193 gradient ribbon disappears even when its stroke is thick. Author such a ribbon
194 as a closed shape with gradient `fill`, or use a path whose intrinsic geometry
195 has both dimensions. Checker and exporter reject the degenerate stroke form.
196
197 ```xml
198 <defs>
199 <linearGradient id="flow" x1="0" y1="0" x2="1" y2="0">
200 <stop offset="0%" stop-color="#2563EB"/>
201 <stop offset="100%" stop-color="#10B981" stop-opacity="0.7"/>
202 </linearGradient>
203 </defs>
204 <path d="M100 200 C260 80 420 320 620 180" fill="none"
205 stroke="url(#flow)" stroke-width="12"/>
206 ```
207
208 Preset patterns are a separate PPT interface in [`native-data-interface.md`](./native-data-interface.md).
209
210 ---
211
212 ### 6.4 Shadows, Glow, and Elevation
213
214 Filters are native-effect metadata, not a general pixel-filter surface.
215
216 | Concern | Contract |
217 |---|---|
218 | Definition/reference | Direct `<defs><filter id="...">` child with unique id; direct `filter="url(#id)"` attribute, never inline style |
219 | Public targets | `<rect>`, `<circle>`, `<image>`, `<path>`, `<text>`; an exact outer `<g filter>` is also registered when its sole visual child is one clipped `<image>` |
220 | Required primitive | `feDropShadow` or `feGaussianBlur` |
221 | Generated glow form | Zero-offset `feDropShadow` with flood paint, or the complete blur + flood + composite + merge graph below; never bare blur |
222 | Required parameters | Explicit `stdDeviation` on either effect primitive; explicit `dx`, `dy`, and `flood-opacity` on `feDropShadow`; explicit `flood-opacity` on `feFlood`; explicit `slope` on linear `feFuncA` |
223 | Accepted helpers | `feOffset`, `feFlood`, `feComposite`, `feMerge`, `feMergeNode`, `feComponentTransfer`, linear `feFuncA` |
224 | Alpha transfer | Linear `feFuncA` maps multiplicative `slope` only; `intercept` is unsupported |
225 | Blur sampling | `feGaussianBlur edgeMode` is unsupported; native effects do not expose the SVG edge-sampling modes |
226 | Primitive coordinates | Omit `primitiveUnits` or use `userSpaceOnUse`; `objectBoundingBox` coordinates are unsupported |
227 | Numeric values | Finite unitless values; non-negative `stdDeviation`; finite `dx` / `dy`; `feFuncA slope` within `0..1`; mapped glow `rad = stdDeviation × 9525`, shadow `blurRad = stdDeviation × 2 × 9525`, and shadow `dist = hypot(dx,dy) × 9525` must round into DrawingML `0..27273042316900` |
228 | Classification | Meaningful non-zero offset → one outer shadow; zero/no offset → one glow |
229 | Fidelity | `Approximate`; one filter becomes one DrawingML effect |
230
231 Flood opacity, linear `feFuncA slope`, and element opacity multiply. The
232 converter-only historical path may also multiply flood-color alpha and
233 ancestor group opacity.
234 Native export does not preserve filter-region, `in/in2/result`, merge order, or
235 composite topology. Other primitives, multiple independent effects, filters on
236 `<tspan>` / ordinary `<g>` / unsupported targets are forbidden; apply the
237 effect to supported objects or use explicit layers.
238 Special `<g filter>` carriers are limited to the exact single clipped-image
239 form in §6.5, the hash-locked
240 `data-pptx-part="geometry-preview"` transport in §1.4—a direct child of an
241 imported preset object referencing the hidden geometry carrier's filter—and the
242 exact imported picture-crop carrier in §6.5, which keeps the effect outside its
243 viewport. Neither authorizes ordinary group filters or creates a second
244 PowerPoint object.
245 PPTX import maps one classifiable shape/connector/picture outer shadow or glow
246 to this contract. Unsupported effects and outer-shadow variants whose scale,
247 skew, alignment, or rotation semantics cannot be retained become import
248 diagnostics instead of a silently simplified authoring surface. See
249 [`conversion.md`](../scripts/docs/conversion.md#import-compatibility-and-recovery-boundary)
250 for tolerant, strict, and release-handling behavior.
251 The quality checker and exporter preflight enforce the same definition,
252 reference, primitive, target, and numeric-value contract. Missing required
253 geometry and malformed values are never replaced by effect defaults during
254 native export.
255
256 ```xml
257 <defs>
258 <filter id="softShadow" x="-15%" y="-20%" width="130%" height="150%">
259 <feDropShadow dx="0" dy="6" stdDeviation="8"
260 flood-color="#000000" flood-opacity="0.10"/>
261 </filter>
262 <filter id="expandedShadow" x="-15%" y="-20%" width="130%" height="150%">
263 <feGaussianBlur in="SourceAlpha" stdDeviation="8" result="b"/>
264 <feOffset in="b" dx="0" dy="6" result="o"/>
265 <feFlood flood-color="#000000" flood-opacity="0.10" result="c"/>
266 <feComposite in="c" in2="o" operator="in" result="s"/>
267 <feMerge><feMergeNode in="s"/><feMergeNode in="SourceGraphic"/></feMerge>
268 </filter>
269 <filter id="titleGlow" x="-30%" y="-30%" width="160%" height="160%">
270 <feGaussianBlur in="SourceAlpha" stdDeviation="6" result="b"/>
271 <feFlood flood-color="#38BDF8" flood-opacity="0.45" result="c"/>
272 <feComposite in="c" in2="b" operator="in" result="g"/>
273 <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
274 </filter>
275 </defs>
276 ```
277
278 Even `feDropShadow` with `dx="0" dy="0"` becomes glow. Use an existing accent
279 color; black reads as diffuse shadow. Bare `feGaussianBlur` remains compatible
280 input but is never generated: preview blurs the object while export emits glow.
281
282 | Elevation | Use | `dy` | `stdDeviation` | Alpha |
283 |---|---|---:|---:|---:|
284 | Floor | Backgrounds, dividers, equal peers, body containers, decorative lines/icons, single-layer pages | — | — | — |
285 | Resting | Card over photo/panel, secondary callout | 2–4 | 4–8 | 0.06–0.10 |
286 | Raised | Primary CTA, focused card, overlay | 6–10 | 10–16 | 0.12–0.20 |
287 | Glow | Short display text, metric, focus accent | 0 offset | 4–8 | 0.35–0.55 |
288
289 **Default — one light source per page (may override when every affected layer
290 uses one deliberate alternative direction)**: every `feOffset` shadow on one
291 slide shares the same `dx`/`dy` direction (default `dx="0"`,
292 `dy="4"`–`dy="8"`, light from upper front). Contradictory shadow directions
293 make one plane read as several incompatible surfaces. A deliberate upward
294 paper-layer treatment flips every affected layer together; never mix
295 directions on the same plane.
296
297 **Reference — not a constraint**: use no more elevation categories than the
298 hierarchy needs; a page may reuse one category across several related objects.
299 Do not lift every peer card or stack strong shadow, border, gradient, and tint
300 on one container. Same-family colored shadow is reserved for a focal accent.
301 On dark backgrounds, prefer a light hairline or restrained glow; never glow body copy.
302 For older/strict renderers, replace a filter with two or three offset
303 translucent shapes behind the object:
304 alpha `0.03–0.05`, increasing offset/radius, and optional same-family tint near
305 `0.04` (`Native-stable`).
306
307 ---
308
309 ### 6.5 Image Treatments, Overlays, and Glass-like Surfaces
310
311 #### Image Carrier and Crop Contracts
312
313 | Need | Authoring contract | Fidelity |
314 |---|---|---|
315 | Cover/crop | Readable raster dimensions + aligned `slice` | Native `srcRect`; `Native-stable`; otherwise native crop cannot be guaranteed |
316 | Contain/fit | Aligned `meet` | Fitted picture frame; `Native-normalized` |
317 | Stretch | `preserveAspectRatio="none"` | Native stretched frame |
318 | Uniform fade | `<image opacity="...">` | Native picture alpha |
319 | Shaped picture | §1.2 image-only `clip-path` | Preset/custom picture geometry |
320
321 **Hard rule — closed image aspect-ratio grammar**: on `<image>`, omit
322 `preserveAspectRatio` for the default `xMidYMid meet`, use `none` alone for
323 stretch, or use one of the nine case-sensitive alignments (`xMinYMin`,
324 `xMidYMin`, `xMaxYMin`, `xMinYMid`, `xMidYMid`, `xMaxYMid`, `xMinYMax`,
325 `xMidYMax`, `xMaxYMax`) followed by explicit `meet` or `slice`. Generated SVG
326 always includes the mode on an aligned value. An alignment without a mode and
327 values needing whitespace normalization are compatible input and receive a
328 Checker recommendation. Empty values, `defer`, unknown/wrong-case alignments or
329 modes, `none` with a mode, and extra tokens are errors; the converter never
330 guesses a fallback.
331
332 **Hard rule — fit/clip interaction**: a non-trivial clip disables `meet`
333 frame-fit. Match the image box to the source ratio or use `slice`. Put one §6.4
334 filter directly on an unclipped `<image>`. For a clipped picture, keep
335 `clip-path` on the `<image>` and put the filter on an exact outer `<g>` whose
336 sole visual child is that image. Never combine `filter` and `clip-path` on the
337 same `<image>`: SVG would clip the preview effect while PowerPoint would not.
338 The carrier may keep object-local id, role, transform, and
339 `data-pptx-carrier`. It may own `data-pptx-layer="master|layout"` only when
340 the carrier itself is the direct fixed atom. It must not own
341 `data-pptx-placeholder`, `data-pptx-binding`, or chart/table replacement
342 metadata; keep slot ownership on the outer placeholder boundary.
343
344 **Hard rule — picture frames and sources are explicit and decodable**: every
345 SVG `<image>` has explicit positive `width`/`height` and exactly one non-empty
346 `href` or compatible `xlink:href`. A data URI must use a supported `image/*`
347 MIME type, valid strict base64 when marked
348 `base64`, a non-empty payload, and bytes that decode as the declared format.
349 An external asset must resolve, use a supported extension, be non-empty, and
350 decode as that extension. The registered formats are PNG, JPEG, GIF, WebP,
351 BMP, TIFF, SVG, EMF, and WMF. Explicit template substitution tokens may remain
352 unresolved only during template checking; export requires the resolved image.
353 Missing, ambiguous, corrupt, mislabeled, or unsupported sources are errors and
354 must never be dropped or packaged as invalid zero-byte media.
355
356 **Hard rule — nested SVG is picture-crop transport, not a general viewport**:
357 every non-root `<svg>` is the exact wrapper accepted by the shared crop parser:
358
359 | Part | Required form |
360 |---|---|
361 | Outer | Registered `x`, `y`, positive `width`/`height`; four ordinary-decimal unit coordinates in `viewBox`; `preserveAspectRatio="none"`; `overflow="hidden"` |
362 | Child | Exactly one direct empty `<image>` with one non-empty `href`/`xlink:href`, `x="0" y="0" width="1" height="1" preserveAspectRatio="none"` |
363 | Context | Only root SVG / ordinary visual `<g>` ancestors; outer may add `id`, supported `transform`, registered layer/carrier metadata, and `data-pptx-frame`, `data-pptx-object`, `data-pptx-shape-id`, `data-pptx-shape-name`, `data-pptx-shape-scope`; an exact imported picture carrier may hold its one §6.4 filter outside this viewport |
364 | Shape crop | Exact outer `data-pptx-crop="1"`; authored wrappers put the registered, locally resolving image-only clip on the inner image, using `userSpaceOnUse` geometry matching the visible `viewBox`; legacy imported outer clips remain compatible |
365
366 The inner image may add only registered `opacity` and that clip. Quantize the
367 `viewBox` without clamping: every signed crop fits
368 `-2147483648..2147483647`, with `l + r < 100000` and `t + b < 100000`.
369 Retain negative/outside-source crops exactly; write redundant `0 0 1 1` as a
370 plain `<image>`. Extra, indirect, or character content; unknown attributes;
371 malformed or unrepresentable crops; and general nested viewports fail. Checker
372 and converter share this parser.
373
374 #### Image Overlay and Material Techniques
375
376 | Overlay | Construction | Typical stops / alpha |
377 |---|---|---|
378 | Directional scrim | Linear rect, darkest beside text | `0%: 0.88; 55%: 0.30; 100%: 0` |
379 | Bottom title fade | Vertical rect over lower image | black `0 → 0.72` |
380 | Vignette/spotlight | Radial rect; place the hotspot with `fx/fy` or `cx/cy` inside the canonical focus circle; outer center/radius remain approximate | black `0 → 0.58` |
381 | Brand wash | Directional existing brand-color gradient | `0.80 → 0.10` |
382 | Grid scrim | Seamless no-stroke rect cells over one image; vary neighboring alpha narrowly and irregularly | Keep the field subordinate; a regular alternation reads as a checkerboard |
383 | Faux glass | Visible fields + diagonal linear panel (`0,0 → 1,1`) + highlight stroke; optional §6.4 elevation | white `0.38 → 0.12`; stroke about `0.55` |
384
385 Layer in document order: image → scrim/wash → text. True source/backdrop blur is
386 `Bake-required`; faux glass is explicit layering, not blur. Validate contrast
387 against the actual image. All overlay gradients follow §6.3 linear/radial
388 fidelity.
389
390 ---
391
392 ### 6.6 Lines, Connectors, Borders, and Markers
393
394 | Surface | Contract / native result |
395 |---|---|
396 | Solid stroke/width/alpha | `Native-stable` editable line |
397 | `4,4`; `6,3`; `2,2`; `8,4`; `8,4,2,4` (comma or space separators) | `dash`; `dash`; `sysDot`; `lgDash`; `lgDashDot` (`Native-normalized`) |
398 | Canonical custom dash | Exactly two positive finite unitless ordinary decimals (`dash gap`); export scales/quantizes against stroke width; `Native-normalized` |
399 | Compatible custom dash | Three or more positive finite unitless values are accepted but reduce to the first pair with a Checker recommendation; compatible numeric spellings also warn |
400 | `stroke-linecap` | `butt`, `round`, `square`; `Native-stable` |
401 | `stroke-linejoin` | `miter`, `round`, `bevel`; `Native-stable` |
402 | `vector-effect` | Exactly `none` or `non-scaling-stroke`; export resolves the choice into native line width (`Native-normalized`) |
403 | `stroke-dashoffset` | No general line mapping; allowed only as a direct finite unitless ordinary-decimal attribute on a §6.10 thick-circle shorthand (`px` suffix is compatible input and warns) |
404 | Gradient stroke | §6.3; re-import may flatten to first stop |
405 | `marker-start` / `marker-end` | §1.1 native line end; type `Native-normalized`, size `Approximate` (`sm/med/lg`) |
406
407 PPTX import treats unsupported line properties as source diagnostics: tolerant
408 mode retains the object and omits only the unsupported outline; `--strict`
409 retains the closed rejection behavior. See
410 [`conversion.md`](../scripts/docs/conversion.md#import-compatibility-and-recovery-boundary).
411
412 The dash grammar is closed: exact lowercase `none`, or at least two finite
413 unitless numbers separated by whitespace or one comma. Generated SVG uses
414 ordinary decimal spellings. A leading plus sign, exponent, trailing decimal
415 point, surrounding whitespace, or longer custom list is compatible input and
416 produces a non-blocking normalization recommendation. Unknown units, one-value
417 arrays, empty or repeated comma fields, non-finite values, and negative or zero
418 entries are errors. The only zero exception is a gap declared directly on the
419 §6.10 thick-circle element.
420
421 Generated cap, join, and `vector-effect` values use the exact lowercase tokens
422 in the table. Surrounding whitespace is compatible input and produces a
423 recommendation; every other token is an error.
424
425 Match marker paint to the parent stroke using the shape-specific channel from
426 §1.1: fill for closed/oval line ends and stroke for the open arrow. Use markers
427 for connectors and §6.10 calculated geometry for a manual diagonal arrowhead.
428 When exact grid spacing matters, use one multi-subpath path rather than a
429 fixed-density preset pattern:
430
431 ```xml
432 <path d="M40 0V120 M80 0V120 M0 40H120 M0 80H120"
433 fill="none" stroke="#2E6EA8" stroke-width="0.8"/>
434 ```
435
436 ---
437
438 ### 6.7 Advanced Text Treatments
439
440 **Hard rule — closed text property grammar**: generated text uses only the
441 values in the `Canonical authoring` column. Registered compatible input remains
442 convertible and receives a non-blocking normalization recommendation. Every
443 other value is invalid; the converter must not replace it with a default.
444
445 | Property | Canonical authoring | Compatible input | DrawingML mapping / rejection boundary |
446 |---|---|---|---|
447 | `font-weight` | `normal`, `bold`, or an exact integer hundred from `100` through `900` | `medium` → `500`; `semibold` → `600` | `normal` and `100..500` map to regular; `bold` and `600..900` map to `b="1"`; therefore numeric weights are `Native-normalized` |
448 | `font-style` | `normal` or `italic` | None | `italic` maps to `i="1"`; oblique, angle, relative, and CSS-wide values are invalid |
449 | `text-anchor` | `start`, `middle`, or `end` on `<svg>`, `<g>`, or `<text>` | None | Maps to left/center/right paragraph alignment plus normalized frame position; it is invalid on `<tspan>` because run-level anchoring has no mapping |
450 | `text-decoration` | `none`, `underline`, `line-through`, or `underline line-through` | `line-through underline` → canonical order | Maps to the single underline and strike run properties; unknown, repeated, or substring-like tokens are invalid |
451 | `letter-spacing` | Finite unitless ordinary decimal SVG px | The same ordinary decimal with `px`, `pt`, or `em`; normalize to unitless px | Maps to `a:rPr@spc`; the final value must fit DrawingML `-400000..400000`, and negative tracking must leave every generated DrawingML run with a positive estimated advance and its text frame with a positive extent; keywords, percentages, exponents, leading plus signs, trailing decimal points, non-finite values, and other units are invalid |
452
453 The registered text properties follow SVG inheritance, including declarations
454 on the root `<svg>`: inline `style` overrides the same element's direct
455 attribute, which overrides its ancestor. Relative font sizes and `em` tracking
456 resolve against the same effective inherited size in Checker and converter.
457 Every declaration is validated even when a later declaration overrides it, so
458 hidden garbage cannot bypass preflight.
459
460 The DrawingML character-spacing range is necessary but not sufficient for
461 negative tracking. After run assembly, each output run must retain a positive
462 estimated advance using the quantized `sz` and `spc` values that will actually
463 be written; a wider sibling run or paragraph line cannot hide a run whose
464 aggregate advance would reverse or collapse, which can reorder or drop
465 characters across PowerPoint-compatible renderers. The generated text frame
466 must also retain a positive horizontal and vertical extent. Checker rejects
467 directly measurable single-line violations, and the converter revalidates
468 every generated run and text frame before writing OOXML. It must not clamp,
469 take the absolute value of, or otherwise hide a non-positive advance or extent.
470 Adjacent authored runs with identical final DrawingML run properties form one
471 output run before sizing and validation; splitting text across equivalent
472 `<tspan>` nodes is not a tracking escape hatch. Tracking and width estimates
473 count the registered project text clusters rather than raw Unicode code points:
474 combining marks, variation selectors, emoji modifiers and ZWJ sequences,
475 paired regional indicators, and same-script virama conjuncts do not receive
476 internal spacing.
477 An unchanged imported native text body reuses the geometry carrier's positive
478 shape frame and attaches the preserved `txBody` payload instead of regenerating
479 runs or a text frame from the SVG estimate.
480
481 **Hard rule — element-specific text surface**:
482
483 - Inheritable text declarations belong only on `<svg>`, `<g>`, `<text>`, or
484 `<tspan>`; placing them on geometry, image, definition, or reuse elements is
485 an error rather than ignored decoration.
486 - `<text>` accepts `x`, `y`, registered paint/alpha/run properties, the text
487 properties above, `font-family`, `font-size`, direct `filter`, direct
488 `transform`, `xml:space`, `id`, and project `data-*` metadata.
489 - `<tspan>` accepts `x`, `y`, `dx`, `dy`, registered paint/alpha/run
490 properties, `font-family`, `font-size`, `font-weight`, `font-style`,
491 `letter-spacing`, `text-decoration`, `xml:space`, `id`, and project `data-*`
492 metadata. It does not accept `text-anchor`, `filter`, or `transform`.
493 - `word-spacing`, `dominant-baseline`, `alignment-baseline`, `baseline-shift`,
494 font shorthand/variant/stretch/feature/variation/synthesis controls,
495 `font-kerning`/`kerning`, `font-size-adjust`, `line-height`, text alignment,
496 indent/shadow/rendering controls, white-space/word-break/hyphenation
497 controls, `writing-mode`, `vertical-align`, `direction`, `unicode-bidi`, and
498 `text-transform` have no registered native mapping and are errors as direct
499 attributes or inline style.
500 - Any other unregistered `font-*` or `text-*` property is also an error; the
501 closed grammar must not grow through an ignored CSS spelling.
502
503 **Hard rule — project text whitespace**:
504
505 - `xml:space` is the project's closed authoring control for significant text
506 whitespace. It is valid only as an exact direct attribute on `<text>` or
507 `<tspan>`, accepts only the case-sensitive values `default` and `preserve`,
508 inherits through the text tree, and may be reset on a child `<tspan>`.
509 - The project maps this control to the visible Chromium/SVG2 behavior used by
510 Live Preview; it does not claim the legacy SVG 1.1 newline-deletion model.
511 XML line endings and tabs become U+0020 SPACE. In `default` mode, contiguous
512 U+0020 characters collapse across inline run boundaries and leading or
513 trailing default-mode spaces in the resulting text chunk are removed. In
514 `preserve` mode, every resulting U+0020 character remains significant.
515 - Only XML whitespace is normalized. NBSP, ideographic space, and other
516 Unicode spacing characters remain literal text and must not be rewritten by
517 a generic Unicode-whitespace regular expression.
518 - Source line breaks do not create PowerPoint paragraphs. Use the registered
519 positioned-`tspan`/paragraph structure for visual lines, and preserve DOM
520 text/tail order plus original style inheritance when normalizing that
521 structure.
522
523 These allowlists are additive to the global structural blacklist and the
524 paint, font-size, opacity, filter, and transform value contracts owned by their
525 respective sections; they do not weaken those contracts.
526
527 | Treatment | SVG surface | Result / boundary |
528 |---|---|---|
529 | Underline / strike / both | `text-decoration="underline"`, `line-through`, or both | `Native-stable`; both emits both run properties |
530 | Mixed runs | Non-positional `<tspan>` | One `Native-normalized` editable frame; §4.2 |
531 | Font size | Generated default is a finite unitless SVG px value; compatible `px`, `pt`, `pc`/`pica`, `in`, `cm`, `mm`, `q`, `em`, and `rem` values receive a recommendation warning only | Converted to SVG px, then editable DrawingML point size; unsupported units/percentages error |
532 | Tracking | §6.7 closed `letter-spacing` grammar | `Native-normalized`; compatible units normalize to SVG px before DrawingML conversion |
533 | Transparency | `opacity` / `fill-opacity` on text/run | `Native-normalized` run alpha, not isolated compositing |
534 | Gradient fill | §6.3 gradient on text/run | Editable fill; geometry normalizes |
535 | Outline | Solid `stroke`, `stroke-width`, `stroke-opacity` | `Native-normalized` editable run outline; re-import does not reconstruct it |
536 | Shadow/glow | §6.4 filter on `<text>` only | Shape shadow / run glow; `Approximate` |
537 | Native bullet | Leading `· • ● ▪ ■ ◆ ◇ ◦ ‣` + non-empty content | `·`/`•` → `•`; others unchanged; color/alpha from marker run; font/size follow text |
538
539 ```xml
540 <text x="100" y="200" font-size="20" xml:space="preserve">Current <tspan
541 fill="#999999" text-decoration="line-through">old</tspan> value</text>
542 ```
543
544 Use strikethrough for removed/former values; it is ordinary notation, not a
545 style-exclusive effect. Imported double underline/strike normalizes to single.
546 Bullet detection allows optional leading whitespace, requires non-empty content,
547 and leaves non-leading decorative glyphs as ordinary text.
548 Keep body tracking normal; CJK tracking defaults near/below 2% of font size and
549 above 5% triggers review. Text outline is solid only. `textPath`, masks, blend
550 modes, generated effects, and text-image knockouts are outside editable text.
551
552 ---
553
554 ### 6.8 Transforms, Layering, and Static Reuse
555
556 | Surface | Contract / fidelity |
557 |---|---|
558 | `rotate(angle[, cx, cy])` | Geometry/image/text/ordinary group; `Native-normalized` |
559 | `translate(x y)` | Geometry/image/group; pure translation also safe on text; `Native-normalized` |
560 | Positive scale / negative mirror | Geometry/image or a group/use whose expanded visual subtree is geometry/image only; explicit pivot; `Native-normalized` |
561 | `matrix(a b c d e f)` | Geometry/image or the same geometry/image-only group/use; transformed axes finite, non-zero, orthogonal; excludes rounded rectangles and subtrees containing them; `Native-normalized` |
562 | Source order | Back-to-front PPT z-order; `Native-stable` |
563 | `<g opacity>` | Compatible approximate mapping; generated SVG prefers descendant alpha, §2.2 |
564 | Local `<use>` | §1.3 compile-time reuse; `Native-normalized` |
565
566 **Hard rule — closed transform grammar**: Use only lowercase `translate`,
567 `scale`, `rotate`, and `matrix` with exact finite unitless argument counts:
568 `translate` 1/2, `scale` 1/2, `rotate` 1/3, and `matrix` 6. Separate arguments
569 and operations with whitespace or one comma. Leading/trailing/repeated commas,
570 adjacent operations without a separator, units, unknown functions, and
571 incomplete input fail quality check and export. Generated numeric tokens use
572 ordinary decimals; a supported leading `+`, exponent, or trailing decimal point
573 remains compatible input and receives a non-blocking normalization warning.
574 Model-facing translation values, rotation centers, and matrix `e/f` use at
575 most two decimals under §1.4; angles, scale arguments, and matrix `a/b/c/d`
576 retain the precision required by the transform.
577
578 Set text size/position directly. A text transform is either a translate-only
579 list or one rotate operation; do not scale, matrix-transform, or mix operations
580 on text. A group containing text follows the same translate-only/single-rotate
581 limit. `skewX`, `skewY`, zero/non-orthogonal axes, and shear matrices are
582 forbidden. Native chart/table markers allow translate/scale only. The §6.10
583 thick-circle shortcut does not inherit general transform support. Positive
584 rotation is clockwise and pivoted rotation normalizes the native frame. Every
585 cumulative matrix, including transforms split across ancestors, must remain
586 finite, non-zero, and orthogonal; importer/live-editor matrices do not expand
587 the hand-authored contract.
588 Mirror around vertical pivot `cx` with
589 `translate(cx 0) scale(-1 1) translate(-cx 0)`; use the analogous Y sequence
590 for a horizontal pivot. During mirror materialization, imported PowerPoint
591 groups with an axis flip keep their geometry reflection, while each descendant
592 SVG text node receives the matching counter-reflection so browser previews keep
593 glyphs upright. The tool-side native record retains the source group flip.
594
595 Layer back-to-front: background/image → scrim/shadow → main geometry → labels /
596 icons → top annotation. Finalization and native export independently expand
597 `<use>` into cloned editable primitives; PowerPoint does not retain a symbol /
598 instance graph.
599
600 ---
601
602 ### 6.9 Freeform Shapes and Curves
603
604 | Input | Native normalization | Fidelity |
605 |---|---|---|
606 | `M/L/H/V`, absolute or relative | Absolute `M/L` | `Native-normalized` |
607 | `C` | Cubic Bézier | `Native-normalized` |
608 | `S/Q/T` | Explicit cubic controls | `Native-normalized` |
609 | `A` | Cubic segments of at most 90° | `Approximate` |
610 | `Z`; polygon/polyline | Closed/open freeform | `Native-normalized` |
611
612 **Hard rule — complete freeform grammar**: Generated `path@d` and
613 `polygon` / `polyline@points` use finite unitless ordinary decimals and only
614 the commands registered above. Native export consumes the complete attribute;
615 it never extracts recognizable fragments while ignoring other characters.
616 Finite scientific notation, a leading plus sign, and a trailing decimal point
617 remain read-compatible and receive recommendation warnings; generated SVG does
618 not write them. Unknown commands or characters, misplaced/repeated commas,
619 non-finite numbers, missing attributes, incomplete command groups, and odd
620 point counts are invalid. A path starts with `M` / `m`; `A` radii are
621 non-negative and both arc flags are exactly `0` or `1`. Each registered path
622 command accepts its uppercase absolute and lowercase relative form. Legal
623 separator-free arc flag sequences remain valid and are parsed as individual
624 flag tokens. A polygon has at least three coordinate pairs and a polyline at
625 least two.
626
627 **Validation**: Checker and native export consume the same parser in
628 [`paths.py`](../scripts/svg_to_pptx/drawingml/paths.py); native-object fallback
629 bounds reuse its normalized commands rather than a second path grammar.
630
631 Command identity, relative coordinates, shorthand, arc parameters, and original
632 handles are not retained. Geometry needs non-zero bounds. Before authoring a
633 freeform, apply [`native-shape-authoring.md`](./native-shape-authoring.md):
634 prefer an editable basic primitive, one exact Office preset, or a Boolean
635 materialization. Use a closed cubic path only for an organic silhouette those
636 cannot express, polygon/closed path for unmatched ribbons/facets, and an open
637 path only for a required data curve, custom route, or locked or Quick-resolved
638 hand-drawn / organic style. Straight relationships use `<line>`; exact stock bends/curves
639 use an authored native Connector preset. Multi-`M` paths remain available for
640 exact linework, and a [`shared-standards-core.md`](./shared-standards-core.md)
641 §1.2 path clip for unmatched organic pictures. Filled silhouettes end with
642 `Z`; open paths use `fill="none"`. Do not depend on
643 `fill-rule="evenodd"`; build explicit visible geometry or bake an essential
644 knockout.
645 For a fixed background, a background-colored overlay is also valid.
646
647 | Rounded rect input | Result |
648 |---|---|
649 | One positive radius, or `0 < rx == ry <= min(width,height)/2` | `Native-stable` adjustable `roundRect` without distorting transforms; the same short-side limit applies to one-radius input |
650 | `0 < abs(rx-ry) < 0.5px` after scaling | One normalized native radius; `Approximate` |
651 | `abs(rx-ry) >= 0.5px`, either positive | Cubic custom geometry; no radius handle; `Approximate` |
652 | Equal radius above half the short side | Native short-side clamp may differ from SVG; `Approximate` |
653
654 ---
655
656 ### 6.10 Radial Geometry, Donuts, Gauges, Sunbursts, and Diagonal Arrowheads
657
658 For center `(cx,cy)`, radius `r`, and degrees `θ`:
659
660 ```text
661 x = cx + r × cos(θ × π / 180)
662 y = cy + r × sin(θ × π / 180)
663 ```
664
665 For clockwise pie/donut sectors, default to `-90°` only when the chart starts at
666 12 o'clock. A full-circle percentage sector spans `percentage × 360°`;
667 large-arc is `1` above `180°`; outer sweep is `1`, inner return is `0`. Split
668 both outer and inner boundaries of a full ring into at least two arcs each.
669 Calculated endpoints survive subject to EMU rounding; `A` curves remain cubic
670 approximations. Verify all spans plus gaps against the planned sweep.
671 Explicit arc sectors are editable `Approximate` freeforms. Thin circles using a
672 §6.6 preset/two-number dash stay `Native-normalized` ellipse lines.
673
674 ```xml
675 <!-- 75% donut: center 400,400; outer 180; inner 100; -90° → 180°. -->
676 <path d="M400 220 A180 180 0 1 1 220 400
677 L300 400 A100 100 0 1 0 400 300 Z" fill="#2563EB"/>
678 ```
679
680 **Gauge**: require `max > min`, `p = clamp((value-min)/(max-min),0,1)`, and
681 `0 < planned clockwise sweep <= 360°`; value sweep is `p × planned sweep`.
682 `valueEndAngle = startAngle + valueSweep`; large-arc is `1` iff
683 `abs(valueSweep) > 180°`.
684 Omit the value sector at `p=0`. At `p=1` with `360°`, split both boundaries into
685 at least two arcs. Track/value share center, radii, start, and sweep flags.
686
687 **Sunburst — `Approximate`**: one explicit annular sector per node; each depth owns one radius
688 band and child angular intervals partition the parent. Do not use one `evenodd`
689 compound ring.
690
691 **Thick-circle shorthand — `Approximate`, non-position-sensitive only**:
692
693 - One circle per segment; `fill="none"`; the circle may use one `rotate` for its
694 start angle, and ancestor transforms must be translate-only.
695 - Exactly two non-preset finite unitless ordinary-decimal values (`dash gap`);
696 `stroke-dashoffset` is a direct finite unitless ordinary-decimal attribute.
697 - `0 < stroke-width < 2r`, `stroke-width/r >= 0.15`,
698 `0 < dash < 2πr`, `gap >= 0`, and `dash + gap >= 2πr - 1` SVG unit. The
699 one-unit tolerance exists only for integer-rounded circumference values.
700 - Native construction uses only the first dash and re-imports as a freeform.
701 Its native start is 90° counterclockwise from the SVG preview; use explicit
702 arcs whenever start angle, cap, or radial precision matters.
703
704 ```xml
705 <circle cx="400" cy="400" r="140" fill="none" stroke="#2563EB"
706 stroke-width="48" stroke-dasharray="615.75 263.90" stroke-dashoffset="0"/>
707 ```
708
709 **Diagonal polygon arrowhead**: for a non-zero line, calculate rather than use a
710 fixed triangle:
711
712 ```text
713 dx=x2-x1; dy=y2-y1; len=√(dx²+dy²); ux=dx/len; uy=dy/len
714 px=-uy; py=ux
715 tip=(x2,y2)
716 back1=(x2-ux×12+px×5, y2-uy×12+py×5)
717 back2=(x2-ux×12-px×5, y2-uy×12-py×5)
718 ```
719
720 Use §1.1 markers for ordinary connectors; the polygon is for a manually drawn
721 filled `Native-normalized` arrowhead. Example:
722 `<polygon points="370,430 365.6,417.8 358.2,424.6"/>`.
723
724 ---
725
726 ### 6.11 Constructed Technique Recipes
727
728 **Hard rule — explicit construction**: these are supported-layer recipes, not
729 browser-filter permissions.
730
731 **Reference — not a constraint**: use them only when they match the locked or
732 Quick-resolved style. Their curve recipes are explicit exceptions to the
733 Shape-first default above; they do not authorize decorative freeforms in
734 another style.
735
736 | Family | Technique | Use when | Construction / boundary |
737 |---|---|---|---|
738 | Material / depth | Faux glass | Visible field must remain present behind a panel | §6.5 translucent panel + highlight; no backdrop blur; `Native-normalized` |
739 | Material / depth | Paper cut | Ordered layers/openings carry the material language | Organic paths + one §6.4 shadow per layer, never the group; `Approximate` |
740 | Hand / print | Hand-drawn mark | Annotation, underline, or highlighter gesture | Rotated translucent bar + restrained `Q/C` paths + round caps; no roughness filter; `Native-normalized` |
741 | Hand / print | Ink wash | Brush mass or atmosphere | Same-family translucent curves/strokes; no feather/wet edge; `Native-normalized` |
742 | Hand / print | Riso offset | Deliberate print misregistration | Offset duplicate, second ink, lower alpha; no blend mode; `Native-normalized` |
743 | Hand / print | Pixel grid | Sparse hard-cell digital accent | Integer-aligned rect grid; `shape-rendering` preview-only; `Native-stable` |
744 | Hand / print | Halftone | Sparse screen modulation | Calculated circles; `Native-stable`; bake dense screens or use [`native-data-interface.md`](./native-data-interface.md) |
745 | Form / geometry | Faceted or folded form | Isometric object, folded ribbon, dimensional numeral/band | Shared vertices, one light direction, same-hue alternating paint per [`native-shape-authoring.md`](./native-shape-authoring.md) §7.1; no 3D; `Native-normalized` |
746 | Form / geometry | Gradient ribbon | Continuous directional energy, not faceted depth | Cubic gradient stroke or closed gradient-filled band; no mesh gradient; `Native-normalized`, re-import may flatten color |
747 | Data expression | Line plus area | Magnitude context beneath an exact reading edge | Subordinate low-alpha area first, crisp line above; `Native-normalized` |
748
749 **Minimal construction anchors**:
750
751 ```xml
752 <!-- Hand-drawn + ink. -->
753 <rect x="80" y="80" width="240" height="28" fill="#FDE68A"
754 opacity="0.72" transform="rotate(-1,200,94)"/>
755 <path d="M90 150 Q210 142 330 151" fill="none" stroke="#1F2937"
756 stroke-width="3" stroke-linecap="round"/>
757 <path d="M80 220 C160 160 250 180 330 230 Z" fill="#1F2937" opacity="0.16"/>
758 <path d="M90 240 C180 210 250 260 340 220" fill="none" stroke="#1F2937"
759 stroke-width="10" stroke-linecap="round" opacity="0.70"/>
760
761 <!-- Riso, pixel cells, sparse dots. -->
762 <text x="86" y="320" font-family="Arial, sans-serif" font-size="64"
763 fill="#EC4899" opacity="0.85">PRINT</text>
764 <text x="92" y="326" font-family="Arial, sans-serif" font-size="64"
765 fill="#2563EB">PRINT</text>
766 <g id="pixel-cells" shape-rendering="crispEdges" fill="#2563EB">
767 <rect x="400" y="80" width="16" height="16"/><rect x="416" y="80" width="16" height="16"/>
768 </g>
769 <g id="sparse-dots" fill="#EC4899"><circle cx="410" cy="140" r="3"/><circle cx="426" cy="140" r="6"/></g>
770
771 <!-- Isometric facets + line-over-area. -->
772 <g id="isometric-facets" transform="translate(520 160)">
773 <polygon points="0,0 80,-24 160,0 80,24" fill="#60A5FA"/>
774 <polygon points="0,0 0,48 80,72 80,24" fill="#3B82F6"/>
775 <polygon points="80,24 80,72 160,48 160,0" fill="#2563EB"/>
776 </g>
777 <path d="M760 260 L860 220 L960 250 L960 340 L760 340 Z" fill="#2563EB" opacity="0.10"/>
778 <path d="M760 260 L860 220 L960 250" fill="none" stroke="#2563EB" stroke-width="4"/>
779 ```
780
781 **Default — integer pixel grid (may override for deliberate irregular
782 treatment)**: avoid soft scaling; use explicit dots only for sparse editable
783 halftone and route dense full-slide texture to §6.12.
784
785 ---
786
787 ### 6.12 Unsupported Effects and Native-Safe Alternatives
788
789 | Unsupported intent | Do not author | Fidelity | Alternative |
790 |---|---|---|---|
791 | Source/backdrop blur; procedural texture | Plain blur, `feTurbulence`, `feDisplacementMap`, `feColorMatrix`, arbitrary filter graph | `Bake-required` | §6.4 effect, explicit geometry, translucent layers, or baked texture |
792 | Inner shadow, soft edge, reflection | Non-outer-shadow/glow graph | `Bake-required` | Explicit inset/highlight/shadow layers or image |
793 | Per-pixel compositing | Mask, blend mode, knockout, arbitrary alpha composite | `Bake-required` | Direct geometry; §1.2 image clip; otherwise bake |
794 | Exact custom tile | Unannotated `<pattern>` / `patternTransform` | `Bake-required` | Multi-subpath geometry, suitable [`native-data-interface.md`](./native-data-interface.md) preset, or bake |
795 | Sheared object | Skew/shear matrix | `Bake-required` | Pre-transform geometry path; bake text/image |
796
797 **Hard rule — blur semantics**: within §6.4, zero-offset `feGaussianBlur` means
798 glow; it does not blur the object or backdrop. Use a low-alpha raster for dense
799 grain and explicit circles/paths only for sparse editable marks.
800
801 Unsupported source effects remain visible where possible and retain their
802 import diagnostics. Resolve those diagnostics before release export; see
803 [`conversion.md`](../scripts/docs/conversion.md#import-compatibility-and-recovery-boundary).
804
805 ---
806
807 ### 6.13 Page-Level Composition Recipes
808
809 **Reference — not a quota**: use the planned page skeleton; when images are
810 active, select it through
811 [`image-layout-patterns.md`](./image-layout-patterns.md). Read each recipe
812 back-to-front and omit every layer without a distinct job.
813
814 | Page / deck job | Back-to-front stack | Stop |
815 |---|---|---|
816 | Cover | Hero field → optional scrim/wash → purposeful opening/contour → native title | Stop when copy is safe and title/field read together |
817 | Divider | Image band or quiet field → restrained wash → recurring geometry → number/title | Reuse deck language; add no effect family |
818 | Text-led explanation | Quiet field → recurring material/contour → native hierarchy → optional local emphasis | Emphasis clarifies the argument, never decorates body copy |
819 | Process / system | Context field → native relation lines → nodes/labels → optional state/direction focus | Every connector stays semantic; atmosphere must not obscure flow |
820 | Evidence / metric | Context field → local contrast → native leaders/labels/metric → optional focus/elevation | Claims stay native; atmosphere must not weaken evidence |
821 | Comparison | Matched planes → optional shared wash/divider → matched labels → one difference marker | Keep crop, elevation, and paint symmetric unless asymmetry is the claim |
822 | Closing / CTA | Receded field → echoed contour/gradient → native action → optional raised accent | Add no effect family or competing image |
823 | Cross-page motif | Reuse contour, gradient direction, line language, texture, or light logic; vary scale, crop, or position by page job | Preserve recognition without copying the page or adding novelty effects |
824
825 ---
826
826 lines MARKDOWN