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.
Files changed (313) hide show
  1. pptd_utils-2026.10.2.dev3/.agents/reference/2026-09-19-implementation_plan.md +140 -0
  2. pptd_utils-2026.10.2.dev3/.agents/reference/2026-09-22-canvas_editor_rewrite_plan.md +122 -0
  3. pptd_utils-2026.10.2.dev3/.github/workflows/publish-pypi.yml +66 -0
  4. pptd_utils-2026.10.2.dev3/.gitignore +24 -0
  5. pptd_utils-2026.10.2.dev3/.ignore +5 -0
  6. pptd_utils-2026.10.2.dev3/.npmignore +15 -0
  7. pptd_utils-2026.10.2.dev3/AGENTS.md +41 -0
  8. pptd_utils-2026.10.2.dev3/PKG-INFO +120 -0
  9. pptd_utils-2026.10.2.dev3/README.md +76 -0
  10. pptd_utils-2026.10.2.dev3/app/.agents/skills/react-grab/SKILL.md +82 -0
  11. pptd_utils-2026.10.2.dev3/app/.gitignore +2 -0
  12. pptd_utils-2026.10.2.dev3/app/.oxlintrc.json +8 -0
  13. pptd_utils-2026.10.2.dev3/app/README.md +131 -0
  14. pptd_utils-2026.10.2.dev3/app/bun.lock +349 -0
  15. pptd_utils-2026.10.2.dev3/app/index.html +13 -0
  16. pptd_utils-2026.10.2.dev3/app/mockup.html +348 -0
  17. pptd_utils-2026.10.2.dev3/app/package-lock.json +1822 -0
  18. pptd_utils-2026.10.2.dev3/app/package.json +34 -0
  19. pptd_utils-2026.10.2.dev3/app/public/favicon.svg +1 -0
  20. pptd_utils-2026.10.2.dev3/app/public/icons.svg +24 -0
  21. pptd_utils-2026.10.2.dev3/app/src/Deck/Canvas.tsx +40 -0
  22. pptd_utils-2026.10.2.dev3/app/src/Deck/EditorOverlay.tsx +535 -0
  23. pptd_utils-2026.10.2.dev3/app/src/Deck/PropertyPanel.tsx +275 -0
  24. pptd_utils-2026.10.2.dev3/app/src/Deck/Root.tsx +84 -0
  25. pptd_utils-2026.10.2.dev3/app/src/Deck/SlideList.tsx +76 -0
  26. pptd_utils-2026.10.2.dev3/app/src/Deck/Stage.tsx +94 -0
  27. pptd_utils-2026.10.2.dev3/app/src/Deck/TextEditor.tsx +66 -0
  28. pptd_utils-2026.10.2.dev3/app/src/Deck/Tool.tsx +295 -0
  29. pptd_utils-2026.10.2.dev3/app/src/Deck/commands.ts +185 -0
  30. pptd_utils-2026.10.2.dev3/app/src/Deck/context.tsx +70 -0
  31. pptd_utils-2026.10.2.dev3/app/src/Deck/editorState.ts +55 -0
  32. pptd_utils-2026.10.2.dev3/app/src/Deck/helpers.ts +174 -0
  33. pptd_utils-2026.10.2.dev3/app/src/Deck/index.ts +9 -0
  34. pptd_utils-2026.10.2.dev3/app/src/Deck/pickers.tsx +136 -0
  35. pptd_utils-2026.10.2.dev3/app/src/Deck/textEdit.ts +73 -0
  36. pptd_utils-2026.10.2.dev3/app/src/FileExplorer.tsx +121 -0
  37. pptd_utils-2026.10.2.dev3/app/src/FilePreviewer.tsx +39 -0
  38. pptd_utils-2026.10.2.dev3/app/src/Pptd.tsx +69 -0
  39. pptd_utils-2026.10.2.dev3/app/src/Previewer/Content.tsx +70 -0
  40. pptd_utils-2026.10.2.dev3/app/src/Previewer/Layout.tsx +82 -0
  41. pptd_utils-2026.10.2.dev3/app/src/Previewer/Root.tsx +45 -0
  42. pptd_utils-2026.10.2.dev3/app/src/Previewer/context.tsx +26 -0
  43. pptd_utils-2026.10.2.dev3/app/src/Previewer/helpers.ts +58 -0
  44. pptd_utils-2026.10.2.dev3/app/src/Previewer/index.ts +8 -0
  45. pptd_utils-2026.10.2.dev3/app/src/Renderer.tsx +85 -0
  46. pptd_utils-2026.10.2.dev3/app/src/SelectPopover.tsx +35 -0
  47. pptd_utils-2026.10.2.dev3/app/src/Shell.tsx +174 -0
  48. pptd_utils-2026.10.2.dev3/app/src/Viewer.tsx +28 -0
  49. pptd_utils-2026.10.2.dev3/app/src/anim.ts +134 -0
  50. pptd_utils-2026.10.2.dev3/app/src/index.css +106 -0
  51. pptd_utils-2026.10.2.dev3/app/src/index.ts +12 -0
  52. pptd_utils-2026.10.2.dev3/app/src/load.ts +136 -0
  53. pptd_utils-2026.10.2.dev3/app/src/main.tsx +14 -0
  54. pptd_utils-2026.10.2.dev3/app/src/render/Fill.tsx +71 -0
  55. pptd_utils-2026.10.2.dev3/app/src/render/RichText.tsx +174 -0
  56. pptd_utils-2026.10.2.dev3/app/src/render/charts/map.ts +567 -0
  57. pptd_utils-2026.10.2.dev3/app/src/render/elements/Chart.tsx +61 -0
  58. pptd_utils-2026.10.2.dev3/app/src/render/elements/Icon.tsx +55 -0
  59. pptd_utils-2026.10.2.dev3/app/src/render/elements/Image.tsx +54 -0
  60. pptd_utils-2026.10.2.dev3/app/src/render/elements/Line.tsx +84 -0
  61. pptd_utils-2026.10.2.dev3/app/src/render/elements/Shape.tsx +80 -0
  62. pptd_utils-2026.10.2.dev3/app/src/render/elements/Table.tsx +270 -0
  63. pptd_utils-2026.10.2.dev3/app/src/render/elements/Text.tsx +45 -0
  64. pptd_utils-2026.10.2.dev3/app/src/render/elements/fx.ts +16 -0
  65. pptd_utils-2026.10.2.dev3/app/src/render/elements/geometry.ts +143 -0
  66. pptd_utils-2026.10.2.dev3/app/src/select.ts +14 -0
  67. pptd_utils-2026.10.2.dev3/app/src/theme.ts +98 -0
  68. pptd_utils-2026.10.2.dev3/app/src/types.ts +263 -0
  69. pptd_utils-2026.10.2.dev3/app/src/useDragResize.ts +27 -0
  70. pptd_utils-2026.10.2.dev3/app/test/Deck.test.ts +33 -0
  71. pptd_utils-2026.10.2.dev3/app/test/FilePreviewer.test.ts +31 -0
  72. pptd_utils-2026.10.2.dev3/app/test/anim.test.ts +24 -0
  73. pptd_utils-2026.10.2.dev3/app/test/charts.test.ts +57 -0
  74. pptd_utils-2026.10.2.dev3/app/test/editor.test.ts +166 -0
  75. pptd_utils-2026.10.2.dev3/app/test/elements.test.ts +160 -0
  76. pptd_utils-2026.10.2.dev3/app/test/primitives.test.ts +159 -0
  77. pptd_utils-2026.10.2.dev3/app/test/resize.test.ts +177 -0
  78. pptd_utils-2026.10.2.dev3/app/test/smoke.test.ts +73 -0
  79. pptd_utils-2026.10.2.dev3/app/test/textEdit.test.ts +70 -0
  80. pptd_utils-2026.10.2.dev3/app/tsconfig.app.json +26 -0
  81. pptd_utils-2026.10.2.dev3/app/tsconfig.json +7 -0
  82. pptd_utils-2026.10.2.dev3/app/tsconfig.node.json +23 -0
  83. pptd_utils-2026.10.2.dev3/app/vite.config.ts +17 -0
  84. pptd_utils-2026.10.2.dev3/package.json +58 -0
  85. pptd_utils-2026.10.2.dev3/pptd_utils/README.md +95 -0
  86. pptd_utils-2026.10.2.dev3/pptd_utils/__init__.py +10 -0
  87. pptd_utils-2026.10.2.dev3/pptd_utils/__main__.py +5 -0
  88. pptd_utils-2026.10.2.dev3/pptd_utils/_shape_data.py +134 -0
  89. pptd_utils-2026.10.2.dev3/pptd_utils/anim.py +367 -0
  90. pptd_utils-2026.10.2.dev3/pptd_utils/charts_native.py +847 -0
  91. pptd_utils-2026.10.2.dev3/pptd_utils/charts_raster.py +1019 -0
  92. pptd_utils-2026.10.2.dev3/pptd_utils/fonts.py +130 -0
  93. pptd_utils-2026.10.2.dev3/pptd_utils/icons.py +135 -0
  94. pptd_utils-2026.10.2.dev3/pptd_utils/images.py +105 -0
  95. pptd_utils-2026.10.2.dev3/pptd_utils/lines.py +180 -0
  96. pptd_utils-2026.10.2.dev3/pptd_utils/main.py +285 -0
  97. pptd_utils-2026.10.2.dev3/pptd_utils/render_text.py +241 -0
  98. pptd_utils-2026.10.2.dev3/pptd_utils/rich.py +213 -0
  99. pptd_utils-2026.10.2.dev3/pptd_utils/shapes.py +334 -0
  100. pptd_utils-2026.10.2.dev3/pptd_utils/slides_image.py +128 -0
  101. pptd_utils-2026.10.2.dev3/pptd_utils/style.py +253 -0
  102. pptd_utils-2026.10.2.dev3/pptd_utils/tables.py +241 -0
  103. pptd_utils-2026.10.2.dev3/pptd_utils/xmlutil.py +109 -0
  104. pptd_utils-2026.10.2.dev3/pyproject.toml +37 -0
  105. pptd_utils-2026.10.2.dev3/scripts/gen_example_manifest.py +19 -0
  106. pptd_utils-2026.10.2.dev3/scripts/set_release_version.py +31 -0
  107. pptd_utils-2026.10.2.dev3/scripts/test_release_version.py +12 -0
  108. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/SKILL.md +183 -0
  109. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/dji-pocket4.pptd +53 -0
  110. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/manifest.json +42 -0
  111. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/accessories.jpg +0 -0
  112. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/activetrack.jpg +0 -0
  113. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/day_street.jpg +0 -0
  114. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/film_dancer.jpg +0 -0
  115. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/hero_sunset.jpg +0 -0
  116. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/horse_dusk.jpg +0 -0
  117. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/horse_dusk_bl.jpg +0 -0
  118. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/inhand.jpg +0 -0
  119. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/mic3.jpg +0 -0
  120. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/night_vlog.jpg +0 -0
  121. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/night_vlog_bl.jpg +0 -0
  122. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/osmoaudio.jpg +0 -0
  123. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/picnic.jpg +0 -0
  124. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/portrait.jpg +0 -0
  125. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/product_black.jpg +0 -0
  126. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/product_sq.jpg +0 -0
  127. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/slowmo_rollers.jpg +0 -0
  128. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/slowmo_skate.jpg +0 -0
  129. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/tripod_street.jpg +0 -0
  130. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/tripod_street_bl.jpg +0 -0
  131. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/media/vlog_dusk.jpg +0 -0
  132. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/01_cover.page +66 -0
  133. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/02_highlights.page +151 -0
  134. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/03_toc.page +172 -0
  135. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/04_chapter1.page +77 -0
  136. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/05_cmos.page +109 -0
  137. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/06_dlog.page +118 -0
  138. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/07_slowmo.page +123 -0
  139. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/08_zoom.page +109 -0
  140. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/09_chapter2.page +77 -0
  141. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/10_tracking.page +109 -0
  142. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/11_control.page +119 -0
  143. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/12_gimbal.page +109 -0
  144. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/13_chapter3.page +77 -0
  145. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/14_audio.page +114 -0
  146. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/15_battery.page +130 -0
  147. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/16_accessories.page +151 -0
  148. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/17_specs.page +114 -0
  149. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/dji-pocket4/pages/18_price.page +139 -0
  150. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/manifest.json +12 -0
  151. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/media/blocks.svg +1 -0
  152. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/01_shapes.page +18 -0
  153. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/02_lines.page +7 -0
  154. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/03_image_icon.page +10 -0
  155. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/04_table.page +50 -0
  156. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/05_chart_cartesian.page +108 -0
  157. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/06_chart_xy.page +99 -0
  158. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/07_chart_misc.page +75 -0
  159. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/pages/08_chart_radar_mix.page +73 -0
  160. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/torture/torture.pptd +16 -0
  161. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/manifest.json +32 -0
  162. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/cabin-detail.jpg +0 -0
  163. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/cabin.jpg +0 -0
  164. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/charging.jpg +0 -0
  165. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-detail.png +0 -0
  166. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-front.jpg +0 -0
  167. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/design-side.png +0 -0
  168. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/hero.jpg +0 -0
  169. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/performance.jpg +0 -0
  170. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/tech-detail.jpg +0 -0
  171. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/tech.jpg +0 -0
  172. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-2.png +0 -0
  173. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-3.png +0 -0
  174. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-4.png +0 -0
  175. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin-5.png +0 -0
  176. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-cabin.jpg +0 -0
  177. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-detail.jpg +0 -0
  178. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-exterior.jpg +0 -0
  179. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-hero.jpg +0 -0
  180. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-performance.jpg +0 -0
  181. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-tech-2.png +0 -0
  182. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/media/yu7-tech.jpg +0 -0
  183. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/01_cover.page +70 -0
  184. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/02_position.page +80 -0
  185. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/03_design.page +80 -0
  186. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/04_cabin.page +80 -0
  187. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/05_performance.page +72 -0
  188. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/06_range.page +71 -0
  189. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/07_intelligence.page +74 -0
  190. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/pages/08_summary.page +80 -0
  191. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/xiaomi-yu7-ppt-animation/xiaomi-yu7.pptd +30 -0
  192. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/manifest.json +19 -0
  193. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_cabin.png +0 -0
  194. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_cover.jpg +0 -0
  195. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_data.png +0 -0
  196. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_exterior.jpg +0 -0
  197. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_final.jpg +0 -0
  198. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_had.jpg +0 -0
  199. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_performance.jpg +0 -0
  200. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/media/bg_safety.jpg +0 -0
  201. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/1_cover.page +80 -0
  202. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/2_overview.page +195 -0
  203. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/3_exterior.page +110 -0
  204. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/4_performance.page +130 -0
  205. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/5_cabin.page +133 -0
  206. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/6_had.page +159 -0
  207. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/7_safety.page +164 -0
  208. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/pages/8_space_final.page +141 -0
  209. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/example/yu7-ppt/yu7.pptd +52 -0
  210. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/01/en/dusk-violet-consulting.md +177 -0
  211. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/02/en/indigo-due-diligence.md +208 -0
  212. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/03/en/pine-green-strategy.md +151 -0
  213. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/04/en/red-black-business.md +184 -0
  214. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/05/en/moss-green-transformation.md +163 -0
  215. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/01_strategy/06/en/map-strategy.md +125 -0
  216. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/01/en/honey-orange-memo.md +176 -0
  217. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/02/en/lake-blue-memo.md +124 -0
  218. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/03/en/xuan-paper-annual.md +179 -0
  219. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/04/en/lead-gray-quarterly.md +192 -0
  220. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/05/en/ink-green-market-trends.md +163 -0
  221. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/02_business/06/en/orange-tech.md +172 -0
  222. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/01/en/sky-blue-wayfinding.md +128 -0
  223. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/02/en/mist-blue-travelogue.md +187 -0
  224. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/03/en/warm-jade-annual-report.md +170 -0
  225. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/04/en/color-stripes-documentary.md +167 -0
  226. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/05/en/moon-white-imagery.md +157 -0
  227. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/03_work/06/en/red-white-business.md +186 -0
  228. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/01/en/cream-collage.md +127 -0
  229. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/02/en/silk-yellow-magazine.md +161 -0
  230. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/03/en/pine-soot-pictorial.md +171 -0
  231. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/04/en/gold-orange-type-journal.md +152 -0
  232. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/05/en/silver-gray-luxury-magazine.md +253 -0
  233. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/04_promotion/06/en/fresh-brand.md +152 -0
  234. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/01/en/pink-purple-diagnosis.md +146 -0
  235. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/02/en/teal-green-academic-defense.md +147 -0
  236. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/03/en/pastel-derivation.md +115 -0
  237. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/04/en/paper-white-courseware.md +112 -0
  238. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/05/en/blue-line-courseware.md +113 -0
  239. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/05_academic/06/en/dark-themed-data.md +163 -0
  240. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/blue-line-courseware/design.md +81 -0
  241. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/deep-blue-atlas/design.md +97 -0
  242. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/paper-white-courseware/design.md +66 -0
  243. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/pastel-derivation/design.md +68 -0
  244. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/teal-green-academic-defense/design.md +90 -0
  245. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/academic/wine-red-data/design.md +62 -0
  246. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/apricot-white-brief/design.md +84 -0
  247. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/indigo-due-diligence/design.md +67 -0
  248. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/marine-blue-research/design.md +75 -0
  249. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/moss-green-transformation/design.md +69 -0
  250. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/pine-green-strategy/design.md +73 -0
  251. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/consulting/red-black-growth/design.md +73 -0
  252. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/black-gold-ledger/design.md +94 -0
  253. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/ebony-ledger/design.md +72 -0
  254. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/honey-orange-memo/design.md +74 -0
  255. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/lake-blue-memo/design.md +75 -0
  256. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/prospect-annual/design.md +68 -0
  257. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/finance/rice-paper-annual/design.md +62 -0
  258. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/aqua-charity-report/design.md +73 -0
  259. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/cream-collage/design.md +78 -0
  260. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/pine-soot-pictorial/design.md +65 -0
  261. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/silk-yellow-magazine/design.md +75 -0
  262. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/silver-gray-luxury-magazine/design.md +68 -0
  263. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/promotion/travel-green-handbook/design.md +75 -0
  264. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/blue-flame-brand/design.md +104 -0
  265. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/electric-violet-business/design.md +77 -0
  266. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/moon-white-imagery/design.md +62 -0
  267. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/sky-blue-wayfinding/design.md +84 -0
  268. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/warm-clay-works/design.md +111 -0
  269. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/design_system/work/warm-jade-annual-report/design.md +77 -0
  270. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/fonts.md +53 -0
  271. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/general-poster.md +241 -0
  272. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/pptd.md +2024 -0
  273. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/shapes.md +258 -0
  274. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/academic-research.md +136 -0
  275. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/analysis-decision.md +36 -0
  276. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/brand-creative.md +203 -0
  277. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/business-plan.md +50 -0
  278. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/education-training.md +256 -0
  279. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/management-report.md +38 -0
  280. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories/tech-engineering.md +205 -0
  281. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/reference/slides_categories.md +34 -0
  282. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/README.md +95 -0
  283. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/__init__.py +10 -0
  284. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/__main__.py +5 -0
  285. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/_shape_data.py +134 -0
  286. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/anim.py +367 -0
  287. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/charts_native.py +847 -0
  288. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/charts_raster.py +1019 -0
  289. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/fonts.py +130 -0
  290. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/icons.py +135 -0
  291. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/images.py +105 -0
  292. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/lines.py +180 -0
  293. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/main.py +285 -0
  294. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/render_text.py +241 -0
  295. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/rich.py +213 -0
  296. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/shapes.py +334 -0
  297. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/slides_image.py +128 -0
  298. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/style.py +253 -0
  299. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/tables.py +241 -0
  300. pptd_utils-2026.10.2.dev3/skills/cowork-ppt/scripts/pptd_utils/xmlutil.py +109 -0
  301. pptd_utils-2026.10.2.dev3/tests/fixtures/full/full.pptd +38 -0
  302. pptd_utils-2026.10.2.dev3/tests/fixtures/full/manifest.json +1 -0
  303. pptd_utils-2026.10.2.dev3/tests/fixtures/full/media/avatar.png +0 -0
  304. pptd_utils-2026.10.2.dev3/tests/fixtures/full/media/cover.jpg +0 -0
  305. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/1_rich.page +78 -0
  306. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/2_shapes_lines.page +91 -0
  307. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/3_table.page +84 -0
  308. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/4_chart_native.page +119 -0
  309. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/5_chart_native2.page +85 -0
  310. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/6_chart_raster.page +110 -0
  311. pptd_utils-2026.10.2.dev3/tests/fixtures/full/pages/7_media_anim.page +111 -0
  312. pptd_utils-2026.10.2.dev3/tests/run.py +55 -0
  313. 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,5 @@
1
+ # graft's cards are gitignored but should stay greppable: ripgrep reads
2
+ # .ignore before .gitignore, so this re-admits the tree to search only.
3
+ !graft/
4
+ graft/.cache/
5
+ graft/.graph/
@@ -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.