pptd-utils 2026.10.2.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pptd_utils-2026.10.2.dev3/.agents/reference/2026-09-19-implementation_plan.md +140 -0
- pptd_utils-2026.10.2.dev3/.agents/reference/2026-09-22-canvas_editor_rewrite_plan.md +122 -0
- pptd_utils-2026.10.2.dev3/.github/workflows/publish-pypi.yml +66 -0
- pptd_utils-2026.10.2.dev3/.gitignore +24 -0
- pptd_utils-2026.10.2.dev3/.ignore +5 -0
- pptd_utils-2026.10.2.dev3/.npmignore +15 -0
- pptd_utils-2026.10.2.dev3/AGENTS.md +41 -0
- pptd_utils-2026.10.2.dev3/PKG-INFO +120 -0
- pptd_utils-2026.10.2.dev3/README.md +76 -0
- pptd_utils-2026.10.2.dev3/app/.agents/skills/react-grab/SKILL.md +82 -0
- pptd_utils-2026.10.2.dev3/app/.gitignore +2 -0
- pptd_utils-2026.10.2.dev3/app/.oxlintrc.json +8 -0
- pptd_utils-2026.10.2.dev3/app/README.md +131 -0
- pptd_utils-2026.10.2.dev3/app/bun.lock +349 -0
- pptd_utils-2026.10.2.dev3/app/index.html +13 -0
- pptd_utils-2026.10.2.dev3/app/mockup.html +348 -0
- pptd_utils-2026.10.2.dev3/app/package-lock.json +1822 -0
- pptd_utils-2026.10.2.dev3/app/package.json +34 -0
- pptd_utils-2026.10.2.dev3/app/public/favicon.svg +1 -0
- pptd_utils-2026.10.2.dev3/app/public/icons.svg +24 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/Canvas.tsx +40 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/EditorOverlay.tsx +535 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/PropertyPanel.tsx +275 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/Root.tsx +84 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/SlideList.tsx +76 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/Stage.tsx +94 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/TextEditor.tsx +66 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/Tool.tsx +295 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/commands.ts +185 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/context.tsx +70 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/editorState.ts +55 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/helpers.ts +174 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/index.ts +9 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/pickers.tsx +136 -0
- pptd_utils-2026.10.2.dev3/app/src/Deck/textEdit.ts +73 -0
- pptd_utils-2026.10.2.dev3/app/src/FileExplorer.tsx +121 -0
- pptd_utils-2026.10.2.dev3/app/src/FilePreviewer.tsx +39 -0
- pptd_utils-2026.10.2.dev3/app/src/Pptd.tsx +69 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/Content.tsx +70 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/Layout.tsx +82 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/Root.tsx +45 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/context.tsx +26 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/helpers.ts +58 -0
- pptd_utils-2026.10.2.dev3/app/src/Previewer/index.ts +8 -0
- pptd_utils-2026.10.2.dev3/app/src/Renderer.tsx +85 -0
- pptd_utils-2026.10.2.dev3/app/src/SelectPopover.tsx +35 -0
- pptd_utils-2026.10.2.dev3/app/src/Shell.tsx +174 -0
- pptd_utils-2026.10.2.dev3/app/src/Viewer.tsx +28 -0
- pptd_utils-2026.10.2.dev3/app/src/anim.ts +134 -0
- pptd_utils-2026.10.2.dev3/app/src/index.css +106 -0
- pptd_utils-2026.10.2.dev3/app/src/index.ts +12 -0
- pptd_utils-2026.10.2.dev3/app/src/load.ts +136 -0
- pptd_utils-2026.10.2.dev3/app/src/main.tsx +14 -0
- pptd_utils-2026.10.2.dev3/app/src/render/Fill.tsx +71 -0
- pptd_utils-2026.10.2.dev3/app/src/render/RichText.tsx +174 -0
- pptd_utils-2026.10.2.dev3/app/src/render/charts/map.ts +567 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Chart.tsx +61 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Icon.tsx +55 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Image.tsx +54 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Line.tsx +84 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Shape.tsx +80 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Table.tsx +270 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/Text.tsx +45 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/fx.ts +16 -0
- pptd_utils-2026.10.2.dev3/app/src/render/elements/geometry.ts +143 -0
- pptd_utils-2026.10.2.dev3/app/src/select.ts +14 -0
- pptd_utils-2026.10.2.dev3/app/src/theme.ts +98 -0
- pptd_utils-2026.10.2.dev3/app/src/types.ts +263 -0
- pptd_utils-2026.10.2.dev3/app/src/useDragResize.ts +27 -0
- pptd_utils-2026.10.2.dev3/app/test/Deck.test.ts +33 -0
- pptd_utils-2026.10.2.dev3/app/test/FilePreviewer.test.ts +31 -0
- pptd_utils-2026.10.2.dev3/app/test/anim.test.ts +24 -0
- pptd_utils-2026.10.2.dev3/app/test/charts.test.ts +57 -0
- pptd_utils-2026.10.2.dev3/app/test/editor.test.ts +166 -0
- pptd_utils-2026.10.2.dev3/app/test/elements.test.ts +160 -0
- pptd_utils-2026.10.2.dev3/app/test/primitives.test.ts +159 -0
- pptd_utils-2026.10.2.dev3/app/test/resize.test.ts +177 -0
- pptd_utils-2026.10.2.dev3/app/test/smoke.test.ts +73 -0
- pptd_utils-2026.10.2.dev3/app/test/textEdit.test.ts +70 -0
- pptd_utils-2026.10.2.dev3/app/tsconfig.app.json +26 -0
- pptd_utils-2026.10.2.dev3/app/tsconfig.json +7 -0
- pptd_utils-2026.10.2.dev3/app/tsconfig.node.json +23 -0
- pptd_utils-2026.10.2.dev3/app/vite.config.ts +17 -0
- pptd_utils-2026.10.2.dev3/package.json +58 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/README.md +95 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/__init__.py +10 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/__main__.py +5 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/_shape_data.py +134 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/anim.py +367 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/charts_native.py +847 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/charts_raster.py +1019 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/fonts.py +130 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/icons.py +135 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/images.py +105 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/lines.py +180 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/main.py +285 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/render_text.py +241 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/rich.py +213 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/shapes.py +334 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/slides_image.py +128 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/style.py +253 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/tables.py +241 -0
- pptd_utils-2026.10.2.dev3/pptd_utils/xmlutil.py +109 -0
- pptd_utils-2026.10.2.dev3/pyproject.toml +37 -0
- pptd_utils-2026.10.2.dev3/scripts/gen_example_manifest.py +19 -0
- pptd_utils-2026.10.2.dev3/scripts/set_release_version.py +31 -0
- pptd_utils-2026.10.2.dev3/scripts/test_release_version.py +12 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/SKILL.md +183 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/dji-pocket4.pptd +53 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/manifest.json +42 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/accessories.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/activetrack.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/day_street.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/film_dancer.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/hero_sunset.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/horse_dusk.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/horse_dusk_bl.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/inhand.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/mic3.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/night_vlog.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/night_vlog_bl.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/osmoaudio.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/picnic.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/portrait.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/product_black.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/product_sq.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/slowmo_rollers.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/slowmo_skate.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/tripod_street.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/tripod_street_bl.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/vlog_dusk.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/01_cover.page +66 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/02_highlights.page +151 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/03_toc.page +172 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/04_chapter1.page +77 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/05_cmos.page +109 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/06_dlog.page +118 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/07_slowmo.page +123 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/08_zoom.page +109 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/09_chapter2.page +77 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/10_tracking.page +109 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/11_control.page +119 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/12_gimbal.page +109 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/13_chapter3.page +77 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/14_audio.page +114 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/15_battery.page +130 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/16_accessories.page +151 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/17_specs.page +114 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/18_price.page +139 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/manifest.json +12 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/media/blocks.svg +1 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/01_shapes.page +18 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/02_lines.page +7 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/03_image_icon.page +10 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/04_table.page +50 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/05_chart_cartesian.page +108 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/06_chart_xy.page +99 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/07_chart_misc.page +75 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/08_chart_radar_mix.page +73 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/torture.pptd +16 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/manifest.json +32 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/cabin-detail.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/cabin.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/charging.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-detail.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-front.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-side.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/hero.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/performance.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/tech-detail.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/tech.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-2.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-3.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-4.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-5.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-detail.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-exterior.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-hero.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-performance.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-tech-2.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-tech.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/01_cover.page +70 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/02_position.page +80 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/03_design.page +80 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/04_cabin.page +80 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/05_performance.page +72 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/06_range.page +71 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/07_intelligence.page +74 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/08_summary.page +80 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/xiaomi-yu7.pptd +30 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/manifest.json +19 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_cabin.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_cover.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_data.png +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_exterior.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_final.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_had.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_performance.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_safety.jpg +0 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/1_cover.page +80 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/2_overview.page +195 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/3_exterior.page +110 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/4_performance.page +130 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/5_cabin.page +133 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/6_had.page +159 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/7_safety.page +164 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/8_space_final.page +141 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/yu7.pptd +52 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/01/en/dusk-violet-consulting.md +177 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/02/en/indigo-due-diligence.md +208 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/03/en/pine-green-strategy.md +151 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/04/en/red-black-business.md +184 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/05/en/moss-green-transformation.md +163 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/06/en/map-strategy.md +125 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/01/en/honey-orange-memo.md +176 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/02/en/lake-blue-memo.md +124 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/03/en/xuan-paper-annual.md +179 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/04/en/lead-gray-quarterly.md +192 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/05/en/ink-green-market-trends.md +163 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/06/en/orange-tech.md +172 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/01/en/sky-blue-wayfinding.md +128 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/02/en/mist-blue-travelogue.md +187 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/03/en/warm-jade-annual-report.md +170 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/04/en/color-stripes-documentary.md +167 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/05/en/moon-white-imagery.md +157 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/06/en/red-white-business.md +186 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/01/en/cream-collage.md +127 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/02/en/silk-yellow-magazine.md +161 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/03/en/pine-soot-pictorial.md +171 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/04/en/gold-orange-type-journal.md +152 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/05/en/silver-gray-luxury-magazine.md +253 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/06/en/fresh-brand.md +152 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/01/en/pink-purple-diagnosis.md +146 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/02/en/teal-green-academic-defense.md +147 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/03/en/pastel-derivation.md +115 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/04/en/paper-white-courseware.md +112 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/05/en/blue-line-courseware.md +113 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/06/en/dark-themed-data.md +163 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/blue-line-courseware/design.md +81 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/deep-blue-atlas/design.md +97 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/paper-white-courseware/design.md +66 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/pastel-derivation/design.md +68 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/teal-green-academic-defense/design.md +90 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/wine-red-data/design.md +62 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/apricot-white-brief/design.md +84 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/indigo-due-diligence/design.md +67 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/marine-blue-research/design.md +75 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/moss-green-transformation/design.md +69 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/pine-green-strategy/design.md +73 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/red-black-growth/design.md +73 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/black-gold-ledger/design.md +94 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/ebony-ledger/design.md +72 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/honey-orange-memo/design.md +74 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/lake-blue-memo/design.md +75 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/prospect-annual/design.md +68 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/rice-paper-annual/design.md +62 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/aqua-charity-report/design.md +73 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/cream-collage/design.md +78 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/pine-soot-pictorial/design.md +65 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/silk-yellow-magazine/design.md +75 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/silver-gray-luxury-magazine/design.md +68 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/travel-green-handbook/design.md +75 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/blue-flame-brand/design.md +104 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/electric-violet-business/design.md +77 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/moon-white-imagery/design.md +62 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/sky-blue-wayfinding/design.md +84 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/warm-clay-works/design.md +111 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/warm-jade-annual-report/design.md +77 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/fonts.md +53 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/general-poster.md +241 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/pptd.md +2024 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/shapes.md +258 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/academic-research.md +136 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/analysis-decision.md +36 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/brand-creative.md +203 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/business-plan.md +50 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/education-training.md +256 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/management-report.md +38 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/tech-engineering.md +205 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories.md +34 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/README.md +95 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/__init__.py +10 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/__main__.py +5 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/_shape_data.py +134 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/anim.py +367 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/charts_native.py +847 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/charts_raster.py +1019 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/fonts.py +130 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/icons.py +135 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/images.py +105 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/lines.py +180 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/main.py +285 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/render_text.py +241 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/rich.py +213 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/shapes.py +334 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/slides_image.py +128 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/style.py +253 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/tables.py +241 -0
- pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/xmlutil.py +109 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/full.pptd +38 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/manifest.json +1 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/media/avatar.png +0 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/media/cover.jpg +0 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/1_rich.page +78 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/2_shapes_lines.page +91 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/3_table.page +84 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/4_chart_native.page +119 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/5_chart_native2.page +85 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/6_chart_raster.page +110 -0
- pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/7_media_anim.page +111 -0
- pptd_utils-2026.10.2.dev3/tests/run.py +55 -0
- pptd_utils-2026.10.2.dev3/theme.md +432 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Implementation Plan — `/app` PPTD Viewer
|
|
2
|
+
|
|
3
|
+
**Base:** mockup logic → Vite + React + TS. Deps: `js-yaml`, `echarts` (only). Every phase ends with the yu7 example deck rendering correctly.
|
|
4
|
+
|
|
5
|
+
## Phase 1 — Skeleton + Loader + Shell
|
|
6
|
+
**Deliverable:** upload folder → navigable deck.
|
|
7
|
+
- `app/` Vite scaffold (`react-ts`), `/` = viewer
|
|
8
|
+
- `src/load.ts` — port mockup loader: file map → `.pptd` parse → `pages[]` → blob URLs. Types for `Presentation/Page/ElementBase` in `src/types.ts`
|
|
9
|
+
- `src/Viewer.tsx` — canvas, scale-to-fit, `fit()` on resize
|
|
10
|
+
- `src/Shell.tsx` — toolbar (upload/drag-drop), thumb rail, ←/→, slide index
|
|
11
|
+
- **Exit check:** yu7 deck: cover text + bg images render, all 8 thumbs, keyboard nav
|
|
12
|
+
|
|
13
|
+
Implementation Handover Notes (Phase 1 — DONE):
|
|
14
|
+
- Stack: Vite 8 + React 19 + TS, bun-installed. Deps: `js-yaml@5` ONLY (echarts deliberately not yet added — phase 5).
|
|
15
|
+
- js-yaml v5 gotcha: **no default export in ESM build** — use `import { load as yamlLoad } from 'js-yaml'`. Cost ~20 min to find via a silent rolldown `MISSING_EXPORT`.
|
|
16
|
+
- `app/src/types.ts` — minimal PPTD types (only what Phase 1 consumes). Extend per phase, don't spec-dump.
|
|
17
|
+
- `app/src/load.ts` — `FileSource` abstraction (`read/url/list`) with 3 impls:
|
|
18
|
+
- `folderSource(File[])` — upload/drop; images become `URL.createObjectURL` blob URLs at source-construction time
|
|
19
|
+
- `httpSource(baseUrl)` — dev server; reads `manifest.json` (all relative paths) to find the root `.pptd`
|
|
20
|
+
- disk source only exists inside `app/test/smoke.test.ts` (not shipped)
|
|
21
|
+
- Example decks over HTTP: `scripts/gen_example_manifest.py` emits `manifest.json` per example deck (run once; not part of npm test). Dev proxy: `/example/*` → `localhost:5174` = `python3 -m http.server 5174` rooted at `skills/cowork-ppt/example/` (see `app/vite.config.ts`). No 5174 server → "load example" fails; upload/drop still works.
|
|
22
|
+
- `resolveSrc()` rewrites EVERY non-http `src` string recursively (backgrounds, image elements) — keyed relative to the `.pptd` dir. Page src refs are resolved at load; don't resolve again in renderers.
|
|
23
|
+
- `stripRoot()` strips the picked-folder prefix from `webkitRelativePath`. Drop path uses `webkitGetAsEntry` recursion (readEntries ≤100/call, looped).
|
|
24
|
+
- `Renderer.tsx` — Phase-1 element coverage: text (align/letterSpacing/lineHeight), shape rect+roundRect only (radius hardcoded 16 — replace in Phase 3 shapes), image (objectFit), chart = dashed placeholder. React style prop is a CSSProperties OBJECT — not a CSS string (tsc caught this).
|
|
25
|
+
- z-order = JSX map order over `page.elements` (later = higher). Do NOT add z-index.
|
|
26
|
+
- Tests: `cd app && bun test` — 5 tests, incl. real-deck load from disk + missing-page error path. `bunx tsc -b` clean; `vite build` passes (~85KB gzip).
|
|
27
|
+
- Dev runbook: `cd app && bun run dev` (5173) + `python3 -m http.server 5174 -d skills/cowork-ppt/example`.
|
|
28
|
+
- Known gaps → next phases: theme `$refs` unhandled (Phase 2 must resolve; yu7 uses them heavily), RichText escaped-only, line/icon/table unrendered (Phase 3/4), animations none (Phase 6).
|
|
29
|
+
|
|
30
|
+
## Phase 2 — Primitives
|
|
31
|
+
**Deliverable:** style engine, shared by all elements.
|
|
32
|
+
- `src/theme.ts` — `$ref` resolution (colors/textStyles/tableStyles), priority chains, defaults table (spec §1)
|
|
33
|
+
- `src/render/Fill.tsx` — solid / linear+radial gradient / image fill (background + element fills)
|
|
34
|
+
- `src/render/Border.tsx` + `Shadow.tsx` — box-shadow mapping, per-side borders (BorderSpec in Phase 4)
|
|
35
|
+
- `src/render/RichText.tsx` — `<p>/<span>/<strong>/<em>/<u>/<s>/<sup>/<sub>`, inline style attrs, `\n` paragraphs
|
|
36
|
+
- **Exit check:** gradient overlay + `$coverTitle` + letterSpacing render pixel-close vs soffice PNG
|
|
37
|
+
|
|
38
|
+
Implementation Handover Notes (Phase 2 — DONE):
|
|
39
|
+
- New files: `src/theme.ts` (theme ctx + resolution), `src/render/Fill.tsx` (fill/border/shadow → CSS), `src/render/RichText.tsx` (parser + component). Renderer.tsx rewritten to consume them; Shell injects `customFonts` via `<link data-pptd-font>`.
|
|
40
|
+
- Theme: `ThemeContext` carries `{colors, textStyles, tableStyles}`; `useTheme()` in each element component. `resolveColor('$x')` → hex, unknown ref → `#FF00FF` (visible miss). Priority chain (spec §1.1) implemented in `resolveTextStyle`: content fields > theme textStyle > defaults; spans/tags layer on top inside RichText.
|
|
41
|
+
- **Gradient angle mapping: CSS deg = spec angle + 90** (spec 0 = left→right = CSS 90deg). Phase 1 had `90-angle` — wrong; test now pins both 0 and 90.
|
|
42
|
+
- RichText parser: single-pass stack walker (`parseInline`), top-level `<p>` split with attr extraction, plain-text `\n` → paragraphs (spec shorthand). Segment CSS precedence: `tagCss` (semantic tags) > `spanCss` (inline decls); container carries base. Supported decls: color/background-color/font-size/font-family/font-weight (spans); text-align/line-height/margin-* (paragraphs). `<a>` → blue underline. LaTeX `\(...\)` NOT handled (no deck uses it; add KaTeX when needed).
|
|
43
|
+
- Fast-refresh/oxlint: hooks can't live in lowercase helpers — element renderers are components (`TextBlock`, `ShapeBox`, `ImageBox`).
|
|
44
|
+
- textStyle vertical align via flex column + justifyContent (top/middle/bottom). `distributed` → CSS `justify`.
|
|
45
|
+
- MiSans not bundled: decks render in system fallback unless `customFonts` provides a Google-Fonts CSS. Bundling MiSans = later decision, needs font files.
|
|
46
|
+
- Tests: 18 total (13 primitives incl. yu7's real stat-line markup, 5 loader). tsc + oxlint clean, build 86KB gzip.
|
|
47
|
+
- Still rough (by design): shapes are boxes (radius 16 non-rect) until Phase 3 SVG; ImageFill.opacity only honored on page background, not shape fills; Border per-side arrays = Phase 4 tables.
|
|
48
|
+
|
|
49
|
+
## Phase 3 — Elements (text/shape/line/image/icon)
|
|
50
|
+
- `src/render/elements/Text.tsx` — align [h,v], lineHeightPx, auto overflow
|
|
51
|
+
- `Shape.tsx` — top-30 `shapeName`s as SVG path defs + `adjustments`, custom `viewBox`+`path`, hollow winding rule, rotation/flip/opacity
|
|
52
|
+
- `Line.tsx` — bezier SVG, `curve` modes, 4 arrow types
|
|
53
|
+
- `Image.tsx` — crop→fit→cropShape pipeline
|
|
54
|
+
- `Icon.tsx` — Font Awesome 7 free webfont (bundled CSS, `fas:/far:/fab:`)
|
|
55
|
+
- **Exit check:** yu7 slides 1–5 visually match soffice exports
|
|
56
|
+
|
|
57
|
+
Implementation Handover Notes (Phase 3 — DONE):
|
|
58
|
+
- **Built:** `elements/{geometry.ts, Shape.tsx, Line.tsx, Image.tsx, Icon.tsx, Text.tsx, fx.ts}`; Renderer.tsx is now a thin dispatcher. `?deck=<name>` query param on `/` loads any example deck (QA harness uses this in phase 7).
|
|
59
|
+
- **Geometry** (`geometry.ts`): `shapeGeom(shapeName, w, h, adjustments)` → SVG path d in bounds coords; 20 presets (common-shapes table + trivial polygons); unknown → rect + console.warn. Adjustments are OOXML [0,100000] fractions with spec defaults — PowerPoint formulas approximated for non-example shapes (donut ring = min×adj, roundRect radius = min×adj clamped ½, star inner = 2×adj ratio). `resolveShapeDef` handles `custom` (user viewBox + path, evenodd for hollow).
|
|
60
|
+
- **SVG gotchas hit:** (1) CSS `background` doesn't paint SVG paths — fills must be `fill` attr; gradients need `<linearGradient/radialGradient>` defs (id = `fill-${elementId}`), CSS angle → bbox vectors via (sinθ, −cosθ), θ = spec+90. (2) Custom-shape path lives in the USER viewBox — svg viewBox must switch to `el.viewBox` when shapeName=custom (was bounds → giant blob). (3) Element wrapper divs need position/size from bounds — Phase-3 first cut had bare divs (size 0×0, svg collapsed).
|
|
61
|
+
- **Lines:** `linePath(points, curve)` — 2 pts straight; sharp/round = polyline; smooth = Catmull-Rom→cubic (tension 1/6, endpoints duplicated). `vector-effect="non-scaling-stroke"` keeps 840×1 viewBox lines from smearing stroke. Arrows = SVG markers, 5×strokeWidth viewport with viewBox 0 0 10 10 content (10× was PowerPoint-huge); auto-start-reverse orients start arrows; dash/dot via strokeDasharray (dot needs linecap round).
|
|
62
|
+
- **Image crop pipeline:** `cropFrame(crop)` → padded-frame % math (width = 1/cw etc.), object-fit on the padded frame gives cover/contain/fill of the sub-rect for free; negative insets pad transparent via offsets. cropShape → CSS `clip-path: path('…')`.
|
|
63
|
+
- **Icon:** FA via jsDelivr CDN `<link data-pptd-fa>` injected on first icon (fas→fa-solid etc.). ponytail: swap to bundled @fortawesome/fontawesome-free if offline rendering matters.
|
|
64
|
+
- **fx.ts:** rotation (CSS deg, clockwise ✓)/flip/opacity wrapper transform for shape/line/image/icon (spec: Text has none). fx on wrapper means rotation applies to border+shadow+clip together — correct.
|
|
65
|
+
- **theme fix:** `resolveTextStyle` now returns `lineHeight` (multiple, default 1) AND `lineHeightPx` separately — Phase 2 mixed them (lineHeightPx=20 would render as 20× multiplier). textStyleProps emits `"33px"` when px set.
|
|
66
|
+
- **Torture deck:** `skills/cowork-ppt/example/torture/` — 3 pages exercising every Phase-3 feature (shapes incl. custom hollow ring, all 4 arrow types + curve modes, crop/cropShape/fit/rotation on images, FA icons). Loaded via `/?deck=torture`. Keep as regression fixture. NOTE: spec's custom-path example uses degenerate single-arc circles (`A r,r 0 1 1 x±ε`) — Chromium picks the wrong center for the inner contour; write circles as two half-arcs.
|
|
67
|
+
- Tests: 32 total (14 element/geometry, 13 primitives, 5 loader). tsc + oxlint clean; build 286KB (88.9 gzip).
|
|
68
|
+
- **Exit check:** verified by screenshots — yu7 8 slides, animation deck 8, dji 18 (incl. wrap:false single-lines), torture 3. soffice pixel-diff = phase 7 harness.
|
|
69
|
+
- Known gaps (deliberate): pie/arc/chord/bracePair geometry; image-fill on shapes (SVG pattern); hollow cropShapes (CSS path() has no fill-rule); gradient/image fills on icons. Add when a deck needs them.
|
|
70
|
+
|
|
71
|
+
## Phase 4 — Table
|
|
72
|
+
- `Table.tsx` — CSS grid, `rowSpan/colSpan` with omitted-cell rule, `columnWidths/rowHeights` ratios, cell fills/borders, `firstRow/lastRow/firstCol/lastCol` style overrides, `$tableStyles`
|
|
73
|
+
- **Exit check:** spec's merged-cell example renders correct 3×3
|
|
74
|
+
|
|
75
|
+
Implementation Handover Notes (Phase 4 — DONE):
|
|
76
|
+
- **Built:** `render/elements/Table.tsx` (+ `CellStyle/TableStyleConfig/BorderSpec/Cell/TableElement` in types.ts; `Element` union extended). Absolute-positioned cells over ratio-computed col/row offsets — no CSS grid (grid+rowSpan conflicts with explicit ratio sizing; absolute needs no gap-collapse logic).
|
|
77
|
+
- **Pure logic exported for tests:** `buildGrid` (omitted-cell walk, dji `content:{text,align}` normalization), `resolveCellStyle`/`resolveCellBorders` (chain mirrors `scripts/pptd_utils/tables.py` exactly: cell > textStyle-theme > category(rowOverColumn) > bodyStyles(cycled by data-row idx) > cellStyle; table fill only under cell fill; per-side border chain with explicit-null clears, UNSET sentinel distinguishes absent from null). 7 new tests; 39 total.
|
|
78
|
+
- **Defaults:** fontSize 14, align center/middle, all four borders solid 1px black — matches converter CELL_DEFAULTS.
|
|
79
|
+
- **Cell text = RichText** (rich tags work in cells); container flex column + justifyContent = align[1]; textAlign = align[0].
|
|
80
|
+
- **Legacy quirks supported (ponytail: drop when dji deck regenerates on spec v2):** (1) `content:{text,align}` cell wrapper; (2) table style convenience keys `fontSize/bodyColor/headerBold/firstColumnColor/border` — mapped to cellStyle + firstRow(firstColumn) categories; headerBold only touches row 0, firstColumnColor only col 0; (3) 3-element BorderSpec `[t, lr, b]` (spec only defines 2/4 forms).
|
|
81
|
+
- **Null-border semantics:** `null` side = no border (component skips); only fully-unspecified side defaults to solid 1px black.
|
|
82
|
+
- **Torture page 4:** spec's `table-merged` example verbatim (2×2 merge, omitted cells) + a styled table (firstRow fill/bold/align, bodyStyles band, per-cell align override). Exit check verified in browser — merged region spans cols 0–1 rows 0–1, no phantom cells.
|
|
83
|
+
- Verified: dji-pocket4 page 17 (real legacy table), all 4 decks zero page errors. tsc/oxlint clean, build 89.2 gzip.
|
|
84
|
+
- Known gaps (deliberate): image fills in cells (needs object-fit layer); table shadow applies to wrapper only.
|
|
85
|
+
|
|
86
|
+
## Phase 5 — Charts (biggest phase)
|
|
87
|
+
- `src/render/elements/Chart.tsx` — ECharts wrapper, resize-aware
|
|
88
|
+
- `src/render/charts/` — mappers: `bar line area scatter bubble candlestick pie radar waterfall heatmap treemap sunburst sankey`
|
|
89
|
+
- cartesian shared: `AxisConfig` (label/axisLine/gridLine `boolean|Config`), barWidth/barGap/categoryGap
|
|
90
|
+
- non-cartesian: radar→`SpokeAxisConfig`, heatmap→visualMap=`colorbar`, waterfall→stacked-transparent trick
|
|
91
|
+
- `seriesDefaults` merge, per-series `dataLabel/marker/legend/title` styles
|
|
92
|
+
- **Exit check:** one synthetic page per chart type renders w/ correct data, colors, labels
|
|
93
|
+
|
|
94
|
+
Implementation Handover Notes (Phase 5 — DONE):
|
|
95
|
+
- **Deps:** `echarts@6.1.0` installed (bun). Bundle: 999KB / 327KB gzip — tree-shaken via `echarts/core` + per-chart `echarts/charts` + `echarts/components`; chart modules registered once in `ensureRegistered()` (`echarts/core` `use` aliased to `registerEcharts` for lint compliance).
|
|
96
|
+
- **Built:** `src/render/charts/map.ts` (pure `chartOption(el, theme)` PPTD→ECharts mapper, all 13 types) + `src/render/elements/Chart.tsx` (init/setOption(notMerge)/dispose, fixed bounds, frame fill/border/shadow). Renderer dispatches `'chart'` → `ChartBox`; placeholder removed. `ChartElement` chart frame/style fields added to `src/types.ts`.
|
|
97
|
+
- **Mapper:** bar/line/area (area→line+areaStyle, stream stack), scatter, bubble→ECharts `scatter` (v6 has no `BubbleChart`; triples + sqrt/linear/log `symbolSize` + `sizeRange`), candlestick + MA overlay, waterfall transparent-base stack + cumulative totals, pie donut/start-angle mapping, radar indicators/spoke axis, heatmap + continuous visualMap, treemap/sunburst parent hierarchy, sankey node dedupe. Axis configs, secondary axes, label/legend/title priority, `seriesDefaults` one-level merge, theme `$ref` colors, gradients, supported number formats implemented.
|
|
98
|
+
- **Regression fixes:** radar indicator metadata removed from series before `setOption`; `fmtNum` scientific precision corrected; scatter/bubble numeric axes inferred as `value`; theme lookup accepts both `$primary` and `primary` keys; no stale vite deps after cache clear.
|
|
99
|
+
- **Fixture:** torture pages 05–08 cover all 13 chart types and key options; manifest regenerated. Playwright screenshots `/tmp/p5_pg4.png`–`/tmp/p5_pg7.png`: all chart pages render without runtime errors. Notable visual result: valid theme colors, bubble sizing, radar/heatmap/hierarchy/sankey, mixed secondary axis.
|
|
100
|
+
- **Tests:** `app/test/charts.test.ts` added: `fmtNum`, defaults merge, bubble scaling/type, pie angle/radius, waterfall anchors, radar indicator. `45 pass / 0 fail / 116 expect() calls`; `tsc -b --force` clean; Vite build clean; oxlint only pre-existing warnings plus test import false positives, Chart hook lint fixed.
|
|
101
|
+
- **Known simplifications:** bar pictographic `symbol` ignored; `stack: stream` uses value-stack approximation; HLC candlestick (missing open) approximated by converter-side data assumptions; diverging colorScale linearly interpolated through 3 colors; geometry/gradient edge cases remain ponytailed in prior notes.
|
|
102
|
+
|
|
103
|
+
## Phase 6 — Animations
|
|
104
|
+
- `src/anim.ts` — entrance/exit/emphasis effects → CSS keyframes/WAAPI
|
|
105
|
+
- click-group state machine: `onClick/withPrevious/afterPrevious`, replay on slide enter
|
|
106
|
+
- motion-path: SVG path → `offset-path`
|
|
107
|
+
- **Exit check:** `xiaomi-yu7-ppt-animation` example plays groups in order
|
|
108
|
+
|
|
109
|
+
Implementation Handover Notes (Phase 6 — DONE):
|
|
110
|
+
- **Built:** `app/src/anim.ts` — animation model, default durations, trigger grouping, CSS animation styles, exit/entrance classification, motion-path support.
|
|
111
|
+
- **Effects:** appear/fade/fly/zoom/wipe/float/peek/rise entrance+exit variants; pulse, grow-shrink, spin, teeter, fill-color, transparency, color-pulse, motion-path.
|
|
112
|
+
- **Trigger state machine:** `onClick` starts a new group; `withPrevious` runs concurrently; `afterPrevious` runs sequentially. First group auto-plays when marked `withPrevious`/`afterPrevious`; page click advances one group at a time; page remount resets state.
|
|
113
|
+
- **Renderer integration:** `PageView` computes visible elements and active animation steps; animation wrappers preserve element-local transforms; animations remain scoped per page.
|
|
114
|
+
- **Motion paths:** CSS `offset-path: path(...)`; escaped quotes in path data. Fill/color effects use CSS custom properties.
|
|
115
|
+
- **Tests:** `app/test/anim.test.ts` added. 47 tests pass; `tsc -b --force` and Vite build pass.
|
|
116
|
+
- **Known simplifications:** transform-heavy effects use wrapper animation, so advanced simultaneous transform composition is not modeled; fill-color is CSS variable based and may not recolor complex SVG/image content; repeat semantics are numeric only. Upgrade during Phase 7 only if visual QA exposes a deck requirement.
|
|
117
|
+
|
|
118
|
+
## Phase 7 — QA harness + polish
|
|
119
|
+
- Dev-only route: side-by-side viewer vs `soffice` PNG (from existing `slides_image.py`), per-slide diff
|
|
120
|
+
- Speaker notes panel, fullscreen/present mode, poster sizes, error toasts
|
|
121
|
+
- README + npm scripts (`dev/build/test`)
|
|
122
|
+
|
|
123
|
+
Implementation Handover Notes (Phase 7 — DONE):
|
|
124
|
+
- **QA harness:** dev-only `?qa=<deck-folder>` route renders viewer vs soffice reference side by side (`.qa-split`), synced per slide (`←/→`/thumbs). References come from the existing converter CLI — `python3 -m pptd_utils png all <deck>.pptd` → `<stem>-png/slide_NN.png` inside the deck folder, served by the dev static server through the existing `/example` proxy. PNG dirs are gitignored. `LoadedProject.pptdPath` added so the viewer can derive the reference dir.
|
|
125
|
+
- **Polish:** speaker-notes panel (toolbar toggle, plain-text `page.notes`), present mode (`f` key/toolbar: fullscreen + rail/bar hidden via `.presenting`), success/error status toasts (auto-dismiss vs persistent). Poster sizes need no code: scale-to-fit is aspect-agnostic (project.size honored verbatim).
|
|
126
|
+
- **README:** rewritten (run, usage, animations, QA mode); `lint` npm script added.
|
|
127
|
+
- **Fixture:** torture page 01 gained a `notes` field (smoke test for the panel).
|
|
128
|
+
- **Regression caught by QA harness:** Phase 6 wrapper hid every non-animated element (`appear` treated as unstarted entrance). Fixed in `PageView`: only animated elements go through `animationStyle`; unanimated wrappers get no style. Also removed the `useEffect` state reset (React lint) in favor of keyed remount `useState` initializer.
|
|
129
|
+
- **Verified in browser:** QA side-by-side loads + syncs reference images; notes panel renders; present hides chrome; `xiaomi-yu7-ppt-animation` sequences `afterPrevious` steps correctly (mid-flight opacity checks; pending steps hold opacity 0 via `animation-fill-mode: both`). 47 tests pass; `tsc -b --force` clean; Vite build clean; oxlint: only pre-existing Fast Refresh warnings (test duplicate-declaration errors fixed).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
Progress Tracker
|
|
134
|
+
- [x] Phase 1 — DONE (Vite+React scaffold, FileSource loader, upload/drop/example-deck, thumb rail, scale-to-fit canvas, 5 smoke tests green)
|
|
135
|
+
- [x] Phase 2 — DONE (theme ctx + $ref resolution, Fill/Border/Shadow primitives, RichText parser+renderer, customFonts injection, 18 tests green, yu7 slides verified in browser)
|
|
136
|
+
- [x] Phase 3 — DONE (Shape/Line/Image/Icon/Text element components, 20 shape presets + custom paths, arrows + curve lines, crop→fit→cropShape, FA icons via CDN, 32 tests, all example decks + torture deck verified in browser)
|
|
137
|
+
- [x] Phase 4 — DONE (Table.tsx: omitted-cell grid walk, full style chain mirroring converter, per-side BorderSpec chain, dji legacy compat, 39 tests, spec merged-cell example + dji real table verified)
|
|
138
|
+
- [x] Phase 5 — DONE (ECharts mapper/wrapper for all 13 chart types, synthetic torture pages 05–08, 45 tests green, browser screenshots verified)
|
|
139
|
+
- [x] Phase 6 — DONE (CSS animation effects, trigger groups, page-entry replay, click advancement, motion-path, 47 tests)
|
|
140
|
+
- [x] Phase 7 — DONE (dev QA side-by-side vs soffice reference, notes panel, present mode, toasts, README + lint script, wrapper-visibility regression fix)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Canvas Editor Rewrite Plan
|
|
2
|
+
|
|
3
|
+
**Goal:** in-app direct manipulation editing of a loaded PPTD deck (Figma-style), covering the full element surface of the PPTD v2 spec (text, shape, line, image, icon, table, chart) plus page-level ops. Spec: `skills/cowork-ppt/reference/pptd.md`.
|
|
4
|
+
|
|
5
|
+
**What exists (keep):** immutable `patchProject` pipeline (Shell owns state), deck ctx (`tool/selectedId/editingId`), `DeckTool` palette, text in-place editing with spec-subset serializer, drag-move with live preview, selection/hover affordances in `PageView`, animation playback.
|
|
6
|
+
|
|
7
|
+
**Rewrite drivers:**
|
|
8
|
+
1. Editing logic is scattered across `PageView` (hover/drag/selection), `Stage` (gestures), `Canvas` (wiring) — adding resize/rotate/multi-select multiplies the tangle.
|
|
9
|
+
2. Every edit feature re-plumbs props through `Renderer` → `DeckView` → `PageView`. One `EditorOverlay` component should own ALL pointer interaction; renderers stay dumb.
|
|
10
|
+
3. Interaction math (screen↔canvas, scale, snap) needs one home.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
### Single interaction layer
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
DeckStage
|
|
20
|
+
├─ DeckTool (palette: V/T/R/… shortcuts)
|
|
21
|
+
├─ DeckCanvas (scaled #canvasWrap, renders DeckView + EditorOverlay)
|
|
22
|
+
│ ├─ DeckView (pure render: elements, animations, theme. NO pointer handlers beyond stopPropagation)
|
|
23
|
+
│ ├─ EditorOverlay (absolute inset-0, canvas-coordinate children; owns ALL editor pointer interaction)
|
|
24
|
+
│ │ ├─ HoverBox / SelectionBox (outline, 8 resize handles, rotation handle)
|
|
25
|
+
│ │ ├─ SnapGuides (smart guides while dragging/resizing)
|
|
26
|
+
│ │ └─ TextEditor (existing contentEditable overlay, now a child of overlay)
|
|
27
|
+
│ └─ (chart/table live edit popovers)
|
|
28
|
+
└─ SlideList / StatusBar
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `DeckView` keeps only presentational props. Selection/hover/`onElementMove` props **deleted**; overlay handles hit-testing by computing element boxes itself (data already in ctx).
|
|
32
|
+
- Overlay renders in the same scaled coordinate space as the canvas (`width/height` = page size, children positioned in canvas px; parent `#canvasWrap` already scales).
|
|
33
|
+
|
|
34
|
+
### State
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// ctx additions
|
|
38
|
+
type Selection = { ids: string[] } | null // multi-select foundation
|
|
39
|
+
interface EditorState {
|
|
40
|
+
tool: Tool // 'select' | 'text' | 'shape' | 'line' | 'pan'?
|
|
41
|
+
selection: string[]
|
|
42
|
+
editingId: string | null // in-place text edit
|
|
43
|
+
// history
|
|
44
|
+
undoStack: Patch[] // see Persistence
|
|
45
|
+
redoStack: Patch[]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- One `EditorState` reducer in Root instead of scattered `useState`s. Commands dispatch intents (`SELECT`, `MOVE`, `RESIZE`, `PATCH_TEXT`, `ADD_ELEMENT`, `DELETE`, `REORDER`, `UNDO`…); reducers produce the immutable `patchProject` calls **and** history entries.
|
|
50
|
+
|
|
51
|
+
### Persistence (new, do before properties panels)
|
|
52
|
+
|
|
53
|
+
Currently edits are memory-only; refresh loses them.
|
|
54
|
+
|
|
55
|
+
- `history.ts`: command pattern. Each command = `{ do: (p) => p, undo: (p) => p, label }`. Root keeps stacks; Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z.
|
|
56
|
+
- Autosave: serialize project back to PPTD YAML (use existing types + `js-yaml` dump) → `File System Access API` (`showSaveFilePicker`) when available, else download as zip (folder structure: `.pptd` + `pages/*.page` + `media/`). `media/` for new uploads only; existing media URLs stay untouched.
|
|
57
|
+
- Mark dirty state in Shell title/status bar.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Phases
|
|
62
|
+
|
|
63
|
+
### Phase E1 — Refactor onto EditorOverlay (pure move of existing behavior)
|
|
64
|
+
- New `EditorOverlay` owns hover box, selection box, click-to-select, empty-click deselect, drag-move, double-click-to-edit dispatch. `PageView` loses all editor pointer props.
|
|
65
|
+
- Selection state moves from `selectedId` to `selection: string[]`; every consumer updated.
|
|
66
|
+
- Commands: `MOVE`, `SELECT`, `DESELECT`, `ADD_TEXT` via reducer + history stacks (undo wired from day one — every subsequent phase gets undo for free).
|
|
67
|
+
- **Exit:** current behaviors identical; `bun test` + new reducer tests green; present mode & Pptd.tsx embed unaffected (overlay unmounted).
|
|
68
|
+
|
|
69
|
+
### Phase E2 — Resize + rotate
|
|
70
|
+
- 8 handles on SelectionBox (canvas-px aware, `dragScale` division stays). Corner = free resize with Shift = keep ratio; edges = single axis. Rotation handle above box (15° steps with Shift).
|
|
71
|
+
- Bounds-only resize for `text/shape/image/icon/table/chart`; `line` scales `viewBox` proportionally (spec: keep `viewBoxW:H = bounds.w:h`).
|
|
72
|
+
- Text resize does NOT auto-grow content (spec has no autofit); plain reflow.
|
|
73
|
+
- Minimum sizes; drag from handle replaces selection-drag during resize.
|
|
74
|
+
|
|
75
|
+
### Phase E3 — Element creation tools
|
|
76
|
+
- Tool palette grows: rectangle/ellipse/roundRect/arrow/line (R, O, then a shape picker popover listing common `shapeName`s from shapes.md — start with ~12, full 177 later or searchable).
|
|
77
|
+
- Drag on empty canvas → live preview box → pointer-up commits element (shape with default `fill` = theme primary; line with 2-point `viewBox`-normalized path).
|
|
78
|
+
- Image tool: click → file picker (also paste + drag-drop onto canvas) → uploads into `media/` (blob URL → saved on export; filesystem writes when FSA available) → `Image` element with `fit: cover`.
|
|
79
|
+
- Icon tool: search popover (iconify/FA7 free list) → places `Icon` element.
|
|
80
|
+
- Double-click on empty canvas → create text at point (Figma behavior), in edit mode.
|
|
81
|
+
|
|
82
|
+
### Phase E4 — Properties editing
|
|
83
|
+
- Floating context panel (right side, or floating toolbar above selection — pick at implementation time based on space) shown when selection non-empty and not editing:
|
|
84
|
+
- text: fontSize, color, bold/italic/underline, align, lineHeight, fontFamily (fonts.md list), backgroundColor
|
|
85
|
+
- shape/line: fill (solid/gradient editor), border (style/width/color), shadow
|
|
86
|
+
- image: fit mode, crop, border, shadow, replace
|
|
87
|
+
- icon: iconName, fill
|
|
88
|
+
- chart/table: data editor (small grid editor; chart = series/data table editor per spec encode rules — biggest single item, can ship read-only first)
|
|
89
|
+
- common: opacity, rotation, layer order (front/back buttons), elementId display
|
|
90
|
+
- Rich text: extend `textEdit.ts` serializer to full spec tag set already supported (`<ul>/<ol>/<li>` parsing, `<a href>`, list styles) + a mini inline format toolbar (B/I/U/S, color, font-size) driven by `document.execCommand` or manual `Selection` range surgery → serialize.
|
|
91
|
+
- Page properties: background fill editor (solid/gradient/image), notes textarea (speaker notes), pageType label.
|
|
92
|
+
|
|
93
|
+
### Phase E5 — Element/page management
|
|
94
|
+
- Delete/Backspace = delete selection (when not editing text); Ctrl+D duplicate (offset +16,+16); layer reorder shortcuts (`]`/`[`).
|
|
95
|
+
- Copy/paste (Ctrl+C/V) internal clipboard; paste external image from OS clipboard → new Image element.
|
|
96
|
+
- Drag elements between pages via SlideList (drop on thumbnail).
|
|
97
|
+
- Multi-select: Shift+click add/remove, marquee (drag on empty canvas with select tool = marquee, hold to distinguish from click), group move/resize (resize = shared delta only).
|
|
98
|
+
|
|
99
|
+
### Phase E6 — Undo/history polish + snapping
|
|
100
|
+
- Smart guides: while move/resize, align to other elements' edges/centers + page center; show magenta guides, snap within 6 canvas px.
|
|
101
|
+
- Optional grid (10px) with toggle.
|
|
102
|
+
- Arrow keys nudge 1px (Shift = 10px) when selection non-empty and not editing.
|
|
103
|
+
- History UI: undo/redo buttons in toolbar with disabled states.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Non-goals (explicit)
|
|
108
|
+
|
|
109
|
+
- PPTX export/import — cowork-ppt CLI already does lossless conversion; the editor saves PPTD only.
|
|
110
|
+
- Collaborative editing, comments, multiplayer.
|
|
111
|
+
- Animation timeline editor (animations render/play; editing the `animations` array can come via a later YAML-ish side panel — not in these phases).
|
|
112
|
+
- `distributed` align, LaTeX editing UI (renders fine; edit via text).
|
|
113
|
+
|
|
114
|
+
## Testing strategy
|
|
115
|
+
|
|
116
|
+
- Pure logic (reducer, command/undo, snapping math, serializer extensions, viewBox line math) → unit tests like existing `textEdit.test.ts`.
|
|
117
|
+
- Interaction (pointer flows) → keep minimal; overlay hit-test box computation is pure → tested.
|
|
118
|
+
- Every phase ends: `bun test`, `bunx tsc -b`, existing decks render unchanged in present + embed modes.
|
|
119
|
+
|
|
120
|
+
## Order rationale
|
|
121
|
+
|
|
122
|
+
Undo (E1) first so no phase ever ships destructive edits without escape. Resize before creation tools because resize is the highest-value single interaction after move. Creation before properties because empty-canvas → element flows unlock testing property panels on real elements. Chart/table data editors last (E4 tail) since they're the largest isolated chunk and can degrade to read-only.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Publish PyPI package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
PYTHONUNBUFFERED: "1"
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
verify:
|
|
16
|
+
runs-on: ubuntu-24.04
|
|
17
|
+
outputs:
|
|
18
|
+
version: ${{ steps.release.outputs.version }}
|
|
19
|
+
tag: ${{ steps.release.outputs.tag }}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v5
|
|
22
|
+
- uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
- name: Set dated release version
|
|
26
|
+
id: release
|
|
27
|
+
run: python scripts/set_release_version.py
|
|
28
|
+
- run: python -m pip install --upgrade pip build
|
|
29
|
+
- run: python -m pip install .
|
|
30
|
+
- run: python -m build
|
|
31
|
+
- run: python -m pip install twine
|
|
32
|
+
- run: python -m twine check dist/*
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
needs: verify
|
|
36
|
+
runs-on: ubuntu-24.04
|
|
37
|
+
permissions:
|
|
38
|
+
contents: write
|
|
39
|
+
environment: pypi
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v5
|
|
42
|
+
- uses: actions/setup-python@v6
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.11"
|
|
45
|
+
- name: Set verified release version
|
|
46
|
+
env:
|
|
47
|
+
RELEASE_VERSION: ${{ needs.verify.outputs.version }}
|
|
48
|
+
run: python scripts/set_release_version.py
|
|
49
|
+
- run: python -m pip install --upgrade pip build twine
|
|
50
|
+
- run: python -m build
|
|
51
|
+
- name: Publish to PyPI
|
|
52
|
+
env:
|
|
53
|
+
TWINE_USERNAME: __token__
|
|
54
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
55
|
+
run: python -m twine upload dist/*
|
|
56
|
+
- name: Tag published commit
|
|
57
|
+
env:
|
|
58
|
+
RELEASE_TAG: ${{ needs.verify.outputs.tag }}
|
|
59
|
+
run: |
|
|
60
|
+
git fetch origin --tags
|
|
61
|
+
if git show-ref --verify --quiet "refs/tags/$RELEASE_TAG"; then
|
|
62
|
+
test "$(git rev-list -n 1 "$RELEASE_TAG")" = "$GITHUB_SHA"
|
|
63
|
+
else
|
|
64
|
+
git tag "$RELEASE_TAG" "$GITHUB_SHA"
|
|
65
|
+
git push origin "refs/tags/$RELEASE_TAG"
|
|
66
|
+
fi
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
|
|
7
|
+
# macOS metadata
|
|
8
|
+
.DS_Store
|
|
9
|
+
|
|
10
|
+
# Packaged artifacts
|
|
11
|
+
*.tgz
|
|
12
|
+
*.zip
|
|
13
|
+
|
|
14
|
+
# Local skill install metadata
|
|
15
|
+
_user_meta.json
|
|
16
|
+
|
|
17
|
+
# graft's local graph cache — regenerable, not committed (run `graft build`).
|
|
18
|
+
/graft/
|
|
19
|
+
|
|
20
|
+
# QA reference PNGs — regenerable via `python3 -m pptd_utils png all <deck>.pptd`
|
|
21
|
+
skills/cowork-ppt/example/**/*-png/
|
|
22
|
+
|
|
23
|
+
# Agent Harness Directory
|
|
24
|
+
.pi
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# When .npmignore exists, npm ignores .gitignore for packing.
|
|
2
|
+
# Keep packaging exclusions here even if they already appear in .gitignore.
|
|
3
|
+
|
|
4
|
+
**/__pycache__/
|
|
5
|
+
**/__pycache__/**
|
|
6
|
+
*.py[cod]
|
|
7
|
+
**/*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
|
|
11
|
+
.DS_Store
|
|
12
|
+
_user_meta.json
|
|
13
|
+
|
|
14
|
+
*.tgz
|
|
15
|
+
*.zip
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- graft:start -->
|
|
2
|
+
## Graft — repo context graph
|
|
3
|
+
|
|
4
|
+
This repo is indexed in `graft/`: small linked markdown nodes that explain each
|
|
5
|
+
system and carry exact file:line spans, kept in sync with the code through git.
|
|
6
|
+
|
|
7
|
+
For ANY task here — understanding how something works, finding where code lives,
|
|
8
|
+
or scoping a change — get context from the graph before grepping or opening
|
|
9
|
+
source files. Re-ask freely (it's cheap) and reuse literal identifiers you
|
|
10
|
+
already have (symbol, error string, file name) as the query. New to this repo?
|
|
11
|
+
Run `graft map` first — a token-budgeted orientation (dir clusters, hubs,
|
|
12
|
+
hotspots), no LLM, no key.
|
|
13
|
+
|
|
14
|
+
- Run `graft ask "<your question>" --source` → ranked nodes with the relevant
|
|
15
|
+
code spans inlined (each hit's ≤8-line crux by default; `--full` for whole
|
|
16
|
+
definitions when the crux isn't enough). Match the tool to the task shape:
|
|
17
|
+
for understanding or editing, the top node IS the answer — cite its
|
|
18
|
+
`covers:` file:line spans and edit straight from `--source`. For
|
|
19
|
+
exhaustive tasks ("every occurrence / every caller of this pattern"), ranked
|
|
20
|
+
results are top-N, not complete — run `graft grep "<literal>"` instead
|
|
21
|
+
(exhaustive over indexed files, grouped by enclosing symbol), falling back
|
|
22
|
+
to raw `grep -rn` only for unindexed files.
|
|
23
|
+
- `graft skeleton <file>` → every definition's signature + span, ~10× cheaper
|
|
24
|
+
than reading the file; use it to skim an API surface.
|
|
25
|
+
- `graft callers <symbol>` gives precomputed, exact edges — who calls this.
|
|
26
|
+
Add `--direction out` for what it calls, or `--depth N` to walk
|
|
27
|
+
transitively for the full blast radius. For structural questions, skip
|
|
28
|
+
ranking and use this directly.
|
|
29
|
+
- Or browse: `graft/INDEX.md` lists every node; follow the links.
|
|
30
|
+
- Monorepos and folders of multiple repos rank fairly across sub-projects —
|
|
31
|
+
hits carry `[scope/]` labels naming which one they're from. Narrow with
|
|
32
|
+
`graft ask "<task>" --in <scope>/` once you know where you're working.
|
|
33
|
+
|
|
34
|
+
If a returned span is truncated ("+N more lines"), open the file at that exact
|
|
35
|
+
range before finalizing. Only open source files when a node genuinely lacks a
|
|
36
|
+
needed detail, and then at the exact file:line the node points to — never
|
|
37
|
+
re-read whole files.
|
|
38
|
+
|
|
39
|
+
After big code changes, refresh the graph with `graft build` (deterministic,
|
|
40
|
+
no API key, $0).
|
|
41
|
+
<!-- graft:end -->
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pptd-utils
|
|
3
|
+
Version: 2026.10.2.dev3
|
|
4
|
+
Summary: Offline PPTD v2 toolkit for converting editable presentations to PowerPoint
|
|
5
|
+
Author: binaryify
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: powerpoint,pptd,pptx,presentation
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Requires-Dist: lxml>=4.9
|
|
15
|
+
Requires-Dist: pillow>=9
|
|
16
|
+
Requires-Dist: python-pptx>=0.6.21
|
|
17
|
+
Requires-Dist: pyyaml>=6
|
|
18
|
+
Provides-Extra: fonts
|
|
19
|
+
Requires-Dist: brotli>=1; extra == 'fonts'
|
|
20
|
+
Requires-Dist: fonttools>=4; extra == 'fonts'
|
|
21
|
+
Provides-Extra: math
|
|
22
|
+
Requires-Dist: latex2mathml>=3; extra == 'math'
|
|
23
|
+
Requires-Dist: mathml2omml>=0.0.2; extra == 'math'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# pptd_utils
|
|
27
|
+
|
|
28
|
+
Offline PPTD toolkit — full-spec `.pptd` → `.pptx` converter + slide image export (collage / single slide). Pure Python, no browser required.
|
|
29
|
+
|
|
30
|
+
Built against the PPTD v2 spec (`skills/cowork-ppt/reference/pptd.md`, relative to the repo root).
|
|
31
|
+
|
|
32
|
+
## Install / dependencies
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
pip install python-pptx Pillow PyYAML
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Optional (graceful fallback if missing):
|
|
39
|
+
|
|
40
|
+
| Package | Unlocks | Fallback |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `latex2mathml` + `mathml2omml` | native equations (OMML) from `\( ... \)` | literal text |
|
|
43
|
+
| `fontTools` | customFonts (Google Fonts woff2 → embedded TTF) | fonts skipped |
|
|
44
|
+
|
|
45
|
+
Slide images additionally need **LibreOffice** (`soffice` on PATH).
|
|
46
|
+
|
|
47
|
+
## CLI
|
|
48
|
+
|
|
49
|
+
Install from PyPI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install pptd-utils
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Commands write beside the input path. `all` is the default; selections accept comma-separated 1-based slide numbers.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pptd check deck.pptd
|
|
59
|
+
pptd pptx deck.pptd
|
|
60
|
+
pptd png deck.pptd # all slides -> deck-png/
|
|
61
|
+
pptd png 1,2,3 deck.pptd # selected slides -> deck-png/
|
|
62
|
+
pptd png collage deck.pptd # contact sheet -> deck-collage.png
|
|
63
|
+
pptd pdf deck.pptd # all slides -> deck.pdf
|
|
64
|
+
pptd pdf 1,2,3 deck.pptd # selected slides -> deck.pdf
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
PNG and PDF export require LibreOffice (`soffice` on `PATH`).
|
|
68
|
+
|
|
69
|
+
## Python API
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pptd_utils import convert, build, verify
|
|
73
|
+
from pptd_utils import slides_image
|
|
74
|
+
|
|
75
|
+
convert("deck.pptd", "out.pptx") # build + verify + print summary
|
|
76
|
+
build("deck.pptd", "out.pptx") # -> (n_slides, n_fonts)
|
|
77
|
+
verify("deck.pptd", "out.pptx") # structural self-check (asserts)
|
|
78
|
+
|
|
79
|
+
slides_image.render_collage("deck.pptd", "collage.png",
|
|
80
|
+
tile_w=480, gap=20, bg="#1F2430")
|
|
81
|
+
slides_image.render_slide("deck.pptd", 3, "slide3.png")
|
|
82
|
+
slides_image.render_slide_images("deck.pptd", "outdir/",
|
|
83
|
+
slides=[1, 3, 5]) # -> [(n, Path), ...]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Supported features (PPTD v2)
|
|
87
|
+
|
|
88
|
+
| Area | Coverage |
|
|
89
|
+
|---|---|
|
|
90
|
+
| text | full HTML tag set (strong/em/u/s/sup/sub/a/br/ul/ol/span style attrs), LaTeX runs, gradient + shadow text, letterSpacing, lineHeight / lineHeightPx, bullets/numbering, vertical text, hyperlinks, highlight |
|
|
91
|
+
| shapes | all 130 preset shapeNames (adjustments), custom SVG paths (`M/L/H/V/C/S/Q/A/Z`, multi-subpath holes), rotation/flip/opacity, gradient/radial fills |
|
|
92
|
+
| lines | sharp / smooth / round (fillet) curves, arrows (head/tail), dash styles |
|
|
93
|
+
| images | fit cover/contain/fill, crop (inset + negative outset padding), cropShape (any preset or custom path), opacity, border, shadow |
|
|
94
|
+
| icons | Font Awesome 6/7 free (fas/far/fab), solid + gradient fill, outline, shadow |
|
|
95
|
+
| tables | rowSpan/colSpan merges, theme tableStyles + inline, per-cell style chains, BorderSpec (per-side / null-clear), gradient cell fills, fontSize auto-fit |
|
|
96
|
+
| charts — native (editable) | bar (stacked/clustered/horizontal), line (smooth/dash/markers), area, scatter, bubble, pie/donut, radar, secondary axes, dataLabels + numberFormat, embedded workbooks |
|
|
97
|
+
| charts — raster (Pillow PNG) | candlestick, waterfall, heatmap (linear/diverging + colorbar), treemap, sunburst, sankey, stream stacks, mixed scatter+cartesian |
|
|
98
|
+
| animations | 21 effects (entrance/emphasis/exit incl. motion-path) → full `p:timing` tree, click/withPrevious/afterPrevious, repeat, easing |
|
|
99
|
+
| transitions | fade |
|
|
100
|
+
| fonts | customFonts embedding (see optional deps) |
|
|
101
|
+
| misc | page backgrounds (solid/gradient/image), notes, themes ($refs), elementId → animation targeting |
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
- `pptx` generation: python-pptx + hand-built DrawingML for fills/effects/ordering; charts created via real chart parts (editable in PowerPoint) then plot XML rewritten; unsupported chart types rasterized at 2× and placed as pictures.
|
|
106
|
+
- images: each slide isolated into a one-slide pptx, rendered by LibreOffice headless, composed by Pillow.
|
|
107
|
+
(`ponytail:` one soffice run per slide — switch to single PDF + PyMuPDF for large decks.)
|
|
108
|
+
|
|
109
|
+
## Test
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
python3 tests/run.py # converts full-spec fixture + minimal + ml-smp, asserts structure
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Fixture `tests/fixtures/full/` exercises every feature area — use it as a syntax reference for your own decks.
|
|
116
|
+
|
|
117
|
+
## Notes
|
|
118
|
+
|
|
119
|
+
- Downloads (FA fonts, URL images/fonts) cache under `~/.cache/pptd_utils/`.
|
|
120
|
+
- Defaults follow the spec: MiSans font family, 18pt body, black text.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# pptd
|
|
2
|
+
|
|
3
|
+
Unofficial PPTD v2 toolkit for creating, editing, and exporting editable PowerPoint presentations. This is enhancement from [Open Kimi PPT Skills](https://github.com/acnlie/open-kimi-ppt-skill) with its reverse engineering, spec to presentation CLI.
|
|
4
|
+
|
|
5
|
+
## Install the CLI
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m pip install pptd-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The `pptd` and `pptd-utils` commands convert PPTD v2 projects offline. Slide image export additionally needs LibreOffice (`soffice`) on `PATH`.
|
|
12
|
+
|
|
13
|
+
## CLI
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pptd check deck/deck.pptd
|
|
17
|
+
pptd pptx deck/deck.pptd
|
|
18
|
+
pptd png deck/deck.pptd
|
|
19
|
+
pptd png 1,2,3 deck/deck.pptd
|
|
20
|
+
pptd png collage deck/deck.pptd
|
|
21
|
+
pptd pdf deck/deck.pptd
|
|
22
|
+
pptd pdf 1,2,3 deck/deck.pptd
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`all` is the default. PNG/PDF export requires LibreOffice (`soffice`).
|
|
26
|
+
|
|
27
|
+
The converter verifies slide count, fade transitions, supported content, and ZIP integrity.
|
|
28
|
+
|
|
29
|
+
## Supported PPTD features
|
|
30
|
+
|
|
31
|
+
- Editable text, shapes, images, icons, tables, and charts
|
|
32
|
+
- Linear and radial gradients
|
|
33
|
+
- Fill, shape, image, icon, and per-gradient-stop opacity
|
|
34
|
+
- Borders, shadows, arrows, and dash styles
|
|
35
|
+
- Native PowerPoint connectors for ordinary two-point lines
|
|
36
|
+
- Custom SVG-path shapes
|
|
37
|
+
- Embedded custom fonts
|
|
38
|
+
- Fade slide transitions
|
|
39
|
+
- Optional on-slide animations
|
|
40
|
+
- PPTD-to-PPTX conversion without a browser
|
|
41
|
+
|
|
42
|
+
PPTD reference:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
skills/cowork-ppt/reference/pptd.md
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Toolkit documentation:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
pptd_utils/README.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Local development
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install
|
|
58
|
+
npm test
|
|
59
|
+
npm run sync:pptd
|
|
60
|
+
npm run pack:check
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`pptd_utils/` is the source copy. `skills/cowork-ppt/scripts/pptd_utils/` is the synchronized packaged copy.
|
|
64
|
+
|
|
65
|
+
## Project layout
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
project/
|
|
69
|
+
deck.pptd
|
|
70
|
+
pages/
|
|
71
|
+
media/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Scope
|
|
75
|
+
|
|
76
|
+
This project is not an official cowork, Kimi, or Moonshot AI SDK. PowerPoint, WPS, and Keynote may render unsupported or advanced OOXML features differently.
|