Files
sproutclaw-data/agent/skills-disabled/ppt-master/skills/ppt-master/scripts/docs/svg-pipeline.md
shumengya 50edff80f5 feat: 导出 SproutClaw .sproutclaw 配置
包含 extensions、skills、prompts、settings、auth、models、mcp 等配置。
排除 node_modules、npm 缓存、sessions 等运行时数据。
2026-06-26 15:48:56 +08:00

13 KiB
Raw Blame History

SVG Pipeline Tools

Architecture rationale (why each artifact / step exists, deletion impact, two-consumer relationship between svg_finalize/ and native pptx conversion): see docs/technical-design.md "Post-Processing Pipeline".

These tools cover post-processing, SVG validation, speaker notes, recorded narration, and PPTX export.

Run these steps in order:

python3 scripts/total_md_split.py <project_path>
python3 scripts/finalize_svg.py <project_path>
python3 scripts/svg_to_pptx.py <project_path>

finalize_svg.py

Unified post-processing entry point. This is the preferred way to run SVG cleanup.

It aggregates:

  • embed_icons.py
  • crop_images.py
  • fix_image_aspect.py
  • embed_images.py
  • flatten_tspan.py
  • svg_rect_to_path.py

svg_to_pptx.py

Convert project SVGs into PPTX.

python3 scripts/svg_to_pptx.py <project_path>
python3 scripts/svg_to_pptx.py <project_path> --only native
python3 scripts/svg_to_pptx.py <project_path> --only legacy
python3 scripts/svg_to_pptx.py <template_import_output> --only native -s svg-flat
python3 scripts/svg_to_pptx.py <project_path> --no-notes
python3 scripts/svg_to_pptx.py <project_path> -t none
python3 scripts/svg_to_pptx.py <project_path> --auto-advance 3
python3 scripts/svg_to_pptx.py <project_path> --animation mixed --animation-duration 0.8
python3 scripts/svg_to_pptx.py <project_path> --no-merge   # strict line-fidelity mode (see below)
python3 scripts/notes_to_audio.py <project_path> --voice zh-CN-XiaoxiaoNeural
python3 scripts/svg_to_pptx.py <project_path> --recorded-narration audio

Behavior:

  • Default output (default-flow mode, no -o):
    • exports/<project_name>_<timestamp>.pptx — native editable pptx (canonical output)
    • backup/<timestamp>/svg_output/ — copy of Executor SVG source, always written so the pptx can be rebuilt via finalize_svg → svg_to_pptx without re-running the LLM
  • --svg-snapshot (opt-in) additionally emits:
    • exports/<project_name>_<timestamp>_svg.pptx — SVG snapshot pptx for visual reference, sibling of the native pptx
    • Live preview already serves as the SVG visual reference for day-to-day use; the snapshot pptx is for distribution or frozen-state archival
  • Explicit -o/--output skips backup/; pair with --svg-snapshot to also emit the side-by-side _svg.pptx next to the chosen path
  • Paragraph merging is enabled by default and trades some SVG line-layout fidelity for PowerPoint editability:
    • Default: mergeable paragraph blocks (same x, dy clustered around one base line-height, optional larger gap for paragraph breaks) collapse into one editable text frame with multiple <a:p> and precise <a:lnSpc> / <a:spcBef>. Resizing the box reflows text inside it.
    • With --no-merge: every dy-stacked <tspan> becomes its own text frame — exact SVG line layout is preserved but a 12-line paragraph is 12 separate textboxes
    • Side effect: PowerPoint may wrap merged paragraphs to a different line count than the SVG source. Long body text (abstracts, multi-paragraph sections, reference lists) usually benefits from the default; pages with tight typographic alignment (covers, charts, tables) usually want --no-merge
    • Mergeable detection is conservative: only fires when the children form a clean paragraph block; mixed-layout <text> falls through to the default per-line path
  • Recommended source directory: svg_final/
  • For PPTX template-import workspaces, use -s svg-flat when you need a visual round-trip check. The layered svg/ tree is the machine-readable template source and intentionally does not inline inherited master / layout decoration into each slide.
  • Native mode is strict about unsupported visual SVG elements: if a visual element cannot be represented or safely preserved, export fails with the SVG file, element tag, and position instead of silently dropping content.
  • Native output uses content-hash media filenames, so identical images are reused and different images cannot overwrite each other by sharing a basename.
  • [Content_Types].xml is generated from the actual media extensions written into the PPTX. Unknown media extensions fail unless Python's mimetypes can identify them.
  • Native export writes to a temporary file first and publishes the requested PPTX only after conversion succeeds. A failed conversion does not replace the main output file.
  • SVG clip paths are still restricted for authored SVGs, but nested crop wrappers generated by PPTX import are mapped back to native picture crop / geometry when possible.
  • Speaker notes are embedded automatically unless --no-notes is used
  • Recorded narration is opt-in:
    • notes_to_audio.py uses edge-tts by default, or a configured cloud TTS provider (elevenlabs, minimax, qwen, cosyvoice), and generates one audio file per slide into audio/
    • Narration text is read strictly from the matching notes/*.md file; the script only skips Markdown heading lines (# ...) and does not summarize, rewrite, or filter delivery notes
    • --recorded-narration audio prepares PowerPoint's "recorded timings and narrations": every slide must have matching m4a / mp3 / wav audio, ffprobe must read every duration, and --animation-trigger on-click is rejected
    • --recorded-narration audio keeps speaker notes, embeds each matching audio file, and writes slide auto-advance timings from audio duration
    • --narration-audio-dir audio is the lower-level embedding path: it embeds whatever files match and allows partial audio coverage
    • This is intended for direct PowerPoint video export with "Use recorded timings and narrations"
    • Long-audio import and automatic long-audio splitting are not supported; keep narration assets page-level
    • Voice choices can be listed with python3 scripts/notes_to_audio.py --list-common-voices, python3 scripts/notes_to_audio.py --list-voices --locale zh-CN, or provider-specific --provider <name> --list-voices
  • Page transitions are controlled by -t/--transition; per-element entrance animations are controlled by -a/--animation
  • Per-element animation applies to top-level SVG <g id="..."> groups in z-order; aim for 38 content groups per slide. Page chrome (background / header / footer / decorations / watermark / page number, by id token) is skipped automatically
  • Start mode is set by --animation-trigger, mirroring PowerPoint's Start dropdown: after-previous (default, cascade with --animation-stagger spacing on slide entry), on-click (presenter-paced), with-previous (all together on slide entry)
  • on-click is for live presentations only; recorded narration rejects it because the tool does not generate object-level click timings
  • Flat SVG roots without top-level groups fall back to at most 8 visible primitives; beyond that, animation is skipped on the slide
  • auto (default) maps effect from the group's SVG id: information-dense elements get a single stable effect (chart→wipe, card-/step-/pillar-→fly, title/takeaway→fade); image-like ids (hero/figure-/image/img-/kpi) cycle through a richer visual pool (zoom/dissolve/circle/box/diamond/wheel) so multiple images vary across the deck; unmatched ids cycle through a fade/wipe/fly/zoom fallback pool
  • mixed (legacy) is deterministic: the first animated group on each slide uses fade, then later groups cycle through a larger 16-effect pool across the whole deck; random samples from that same legacy pool
  • --animation-duration controls per-element entrance length (default 0.4); --animation-stagger adds gap between elements in after-previous mode (default 0.5)
  • Optional object-level overrides live in <project>/animations.json or a path passed via --animation-config; build and validate them with animation_config.py scaffold|validate

Performance (legacy _svg.pptx PNG fallback, only when --svg-snapshot or --only legacy):

  • SVG→PNG is pre-rendered in a process pool before the main loop. Default workers = min(cpu, pages, 8); override with --workers N (set 1 for sequential, 0 is treated as sequential).
  • Results are cached at <project>/.cache/svg_png/ keyed by SVG content hash + size + active renderer (cairosvg vs svglib). Switching renderers naturally invalidates the cache; nothing to clean by hand.
  • --cache-dir <path> relocates the cache; --no-cache forces re-render without writing/reading the cache (handy when debugging rendering).
  • Native mode (--only native) is unaffected — that path embeds DrawingML shapes and never touches PNG.

Dependency:

pip install python-pptx

total_md_split.py

Split total.md into per-slide note files.

python3 scripts/total_md_split.py <project_path>
python3 scripts/total_md_split.py <project_path> -o <output_directory>
python3 scripts/total_md_split.py <project_path> -q

Requirements:

  • Each section begins with #
  • Heading text matches the SVG filename
  • Sections are separated by ---

svg_quality_checker.py

Validate SVG technical compliance.

python3 scripts/svg_quality_checker.py examples/project/svg_output/01_cover.svg
python3 scripts/svg_quality_checker.py examples/project/svg_output
python3 scripts/svg_quality_checker.py examples/project
python3 scripts/svg_quality_checker.py examples/project --format ppt169
python3 scripts/svg_quality_checker.py --all examples
python3 scripts/svg_quality_checker.py examples/project --export

Checks include:

  • viewBox
  • banned elements
  • width/height consistency
  • line-break structure

svg_position_calculator.py

Analyze and review supported chart coordinates after SVG generation.

Use this after svg_quality_checker.py passes, and only for chart types supported by this script: bar, pie / donut, radar, line / area / scatter, and grid. Area charts do not have a separate calculator mode: use calc line for the upper boundary points, then close the filled region to the plot area's bottom baseline (y_max) in the SVG.

Calculate expected coordinates

python3 scripts/svg_position_calculator.py calc bar --data "A:185,B:142" --area "130,155,1200,480" --bar-width 120
python3 scripts/svg_position_calculator.py calc line --data "0:50,10:80,20:120" --area "120,120,1200,600" --y-range "0,150"
python3 scripts/svg_position_calculator.py calc pie --data "A:35,B:25,C:20" --center "420,400" --radius 200
python3 scripts/svg_position_calculator.py calc grid --rows 2 --cols 3 --area "50,150,1230,670"

For an area chart, use the line output as the top boundary:

M first_x,first_y ... L last_x,last_y L last_x,y_max L first_x,y_max Z

Manually compare the calculator output with the coordinates already present in the generated SVG. If coordinates differ, update the SVG from the calc output, rerun svg_quality_checker.py, then repeat the coordinate review. The tool intentionally does not rewrite SVG files automatically.

Analyze (inspect existing SVG)

python3 scripts/svg_position_calculator.py analyze <svg_file>

Use this after SVG generation to inspect existing SVG geometry when manual comparison needs more context.

Advanced Standalone Tools

flatten_tspan.py

python3 scripts/svg_finalize/flatten_tspan.py examples/<project>/svg_output
python3 scripts/svg_finalize/flatten_tspan.py path/to/input.svg path/to/output.svg

svg_rect_to_path.py

python3 scripts/svg_finalize/svg_rect_to_path.py <project_path>
python3 scripts/svg_finalize/svg_rect_to_path.py <project_path> -s final
python3 scripts/svg_finalize/svg_rect_to_path.py path/to/file.svg

Use when rounded corners must survive PowerPoint shape conversion.

fix_image_aspect.py

python3 scripts/svg_finalize/fix_image_aspect.py path/to/slide.svg
python3 scripts/svg_finalize/fix_image_aspect.py 01_cover.svg 02_toc.svg
python3 scripts/svg_finalize/fix_image_aspect.py --dry-run path/to/slide.svg

Use when embedded images stretch after PowerPoint shape conversion.

embed_icons.py

python3 scripts/svg_finalize/embed_icons.py output.svg
python3 scripts/svg_finalize/embed_icons.py svg_output/*.svg
python3 scripts/svg_finalize/embed_icons.py --dry-run svg_output/*.svg

Replaces <use data-icon="chunk-filled/name" .../>, <use data-icon="tabler-filled/name" .../> and <use data-icon="tabler-outline/name" .../> placeholders with actual SVG path elements. Use for manual icon embedding checks outside finalize_svg.py.

PPT Compatibility Rules

Use PowerPoint-safe transparency syntax:

Avoid Use instead
fill=\"rgba(...)\" fill=\"#hex\" + fill-opacity
<g opacity=\"...\"> Set opacity on each child
<image opacity=\"...\"> Overlay with a mask layer

PowerPoint also has trouble with:

  • marker-based arrows
  • unsupported filters
  • direct SVG features not mapped to DrawingML