@taloswork/ose-shared 0.1.3 → 0.1.5

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 (138) hide show
  1. package/package.json +3 -3
  2. package/skills/document/SKILL.md +54 -47
  3. package/skills/document/assets/fonts/ChakraPetch-600.woff2 +0 -0
  4. package/skills/document/assets/fonts/DMSerifDisplay-400.woff2 +0 -0
  5. package/skills/document/assets/fonts/Lexend-500.woff2 +0 -0
  6. package/skills/document/assets/fonts/Nunito-700.woff2 +0 -0
  7. package/skills/document/assets/fonts/PlayfairDisplay-600.woff2 +0 -0
  8. package/skills/document/assets/fonts/Quicksand-600.woff2 +0 -0
  9. package/skills/document/assets/fonts/SpaceGrotesk-500.woff2 +0 -0
  10. package/skills/document/assets/fonts/Syne-700.woff2 +0 -0
  11. package/skills/document/assets/fonts/ZillaSlab-600.woff2 +0 -0
  12. package/skills/document/assets/fonts/fonts.json +314 -216
  13. package/skills/document/bin/html2pptx.cjs +7 -5
  14. package/skills/document/catalog.json +37 -19
  15. package/skills/document/layouts/README.md +1 -0
  16. package/skills/document/layouts/big-stat.tpl +1 -1
  17. package/skills/document/layouts/quote-aside.tpl +11 -0
  18. package/skills/document/layouts/slots.json +1 -1
  19. package/skills/document/motion/README.md +19 -1
  20. package/skills/document/motion/anthropic.json +29 -0
  21. package/skills/document/motion/apple.json +41 -0
  22. package/skills/document/motion/bistro-warm.json +16 -0
  23. package/skills/document/motion/black-gold.json +29 -0
  24. package/skills/document/motion/board-brief.json +14 -0
  25. package/skills/document/motion/bold-clash.json +16 -0
  26. package/skills/document/motion/branding.json +22 -0
  27. package/skills/document/motion/campus-teal.json +22 -0
  28. package/skills/document/motion/cinereel.json +23 -0
  29. package/skills/document/motion/clinic-care.json +22 -0
  30. package/skills/document/motion/cool.json +41 -0
  31. package/skills/document/motion/dark-glass.json +22 -0
  32. package/skills/document/motion/gov-brief.json +14 -0
  33. package/skills/document/motion/grid-tech.json +16 -0
  34. package/skills/document/motion/hand-drawn.json +23 -0
  35. package/skills/document/motion/ivory-gold.json +22 -0
  36. package/skills/document/motion/legal-slate.json +15 -0
  37. package/skills/document/motion/magazine-ink.json +29 -0
  38. package/skills/document/motion/mckinsey.json +28 -0
  39. package/skills/document/motion/memphis.json +16 -0
  40. package/skills/document/motion/mono.json +21 -0
  41. package/skills/document/motion/neon-cyber.json +42 -0
  42. package/skills/document/motion/olive-gold.json +22 -0
  43. package/skills/document/motion/organic-earth.json +15 -0
  44. package/skills/document/motion/pastel-saas.json +15 -0
  45. package/skills/document/motion/portfolio-noir.json +21 -0
  46. package/skills/document/motion/press-room.json +14 -0
  47. package/skills/document/motion/retro-press.json +15 -0
  48. package/skills/document/motion/sport-arena.json +16 -0
  49. package/skills/document/motion/swiss-grid.json +34 -0
  50. package/skills/document/motion/wedding-blush.json +15 -0
  51. package/skills/document/packs/README.md +20 -1
  52. package/skills/document/packs/board-brief/backdrop.html +4 -0
  53. package/skills/document/packs/board-brief/layouts/cover.tpl +12 -0
  54. package/skills/document/packs/board-brief/layouts/toc-agenda.tpl +20 -0
  55. package/skills/document/packs/board-brief/pack.css +27 -0
  56. package/skills/document/packs/press-room/backdrop.html +4 -0
  57. package/skills/document/packs/press-room/layouts/cover.tpl +12 -0
  58. package/skills/document/packs/press-room/layouts/section.tpl +13 -0
  59. package/skills/document/packs/press-room/pack.css +27 -0
  60. package/skills/document/styles/README.md +32 -4
  61. package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
  62. package/skills/document/styles/_samples/_groups/creative.webp +0 -0
  63. package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
  64. package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
  65. package/skills/document/styles/_samples/_groups/natural.webp +0 -0
  66. package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
  67. package/skills/document/styles/_samples/anthropic.webp +0 -0
  68. package/skills/document/styles/_samples/apple.webp +0 -0
  69. package/skills/document/styles/_samples/bistro-warm.webp +0 -0
  70. package/skills/document/styles/_samples/black-gold.webp +0 -0
  71. package/skills/document/styles/_samples/board-brief.webp +0 -0
  72. package/skills/document/styles/_samples/bold-clash.webp +0 -0
  73. package/skills/document/styles/_samples/campus-teal.webp +0 -0
  74. package/skills/document/styles/_samples/cinereel.webp +0 -0
  75. package/skills/document/styles/_samples/clinic-care.webp +0 -0
  76. package/skills/document/styles/_samples/cool.webp +0 -0
  77. package/skills/document/styles/_samples/dark-glass.webp +0 -0
  78. package/skills/document/styles/_samples/gov-brief.webp +0 -0
  79. package/skills/document/styles/_samples/grid-tech.webp +0 -0
  80. package/skills/document/styles/_samples/hand-drawn.webp +0 -0
  81. package/skills/document/styles/_samples/ivory-gold.webp +0 -0
  82. package/skills/document/styles/_samples/legal-slate.webp +0 -0
  83. package/skills/document/styles/_samples/magazine-ink.webp +0 -0
  84. package/skills/document/styles/_samples/memphis.webp +0 -0
  85. package/skills/document/styles/_samples/mono.webp +0 -0
  86. package/skills/document/styles/_samples/neon-cyber.webp +0 -0
  87. package/skills/document/styles/_samples/olive-gold.webp +0 -0
  88. package/skills/document/styles/_samples/organic-earth.webp +0 -0
  89. package/skills/document/styles/_samples/pastel-saas.webp +0 -0
  90. package/skills/document/styles/_samples/portfolio-noir.webp +0 -0
  91. package/skills/document/styles/_samples/press-room.webp +0 -0
  92. package/skills/document/styles/_samples/retro-press.webp +0 -0
  93. package/skills/document/styles/_samples/sport-arena.webp +0 -0
  94. package/skills/document/styles/_samples/wedding-blush.webp +0 -0
  95. package/skills/document/styles/anthropic/skin.css +1 -1
  96. package/skills/document/styles/bistro-warm/backdrop.html +4 -0
  97. package/skills/document/styles/bistro-warm/skin.css +27 -0
  98. package/skills/document/styles/black-gold/skin.css +1 -1
  99. package/skills/document/styles/bold-clash/backdrop.html +4 -0
  100. package/skills/document/styles/bold-clash/skin.css +27 -0
  101. package/skills/document/styles/branding/skin.css +1 -1
  102. package/skills/document/styles/campus-teal/backdrop.html +3 -0
  103. package/skills/document/styles/campus-teal/skin.css +27 -0
  104. package/skills/document/styles/cinereel/skin.css +2 -2
  105. package/skills/document/styles/clinic-care/backdrop.html +4 -0
  106. package/skills/document/styles/clinic-care/skin.css +27 -0
  107. package/skills/document/styles/dark-glass/backdrop.html +4 -0
  108. package/skills/document/styles/dark-glass/skin.css +27 -0
  109. package/skills/document/styles/gov-brief/backdrop.html +4 -0
  110. package/skills/document/styles/gov-brief/skin.css +27 -0
  111. package/skills/document/styles/grid-tech/backdrop.html +37 -0
  112. package/skills/document/styles/grid-tech/skin.css +27 -0
  113. package/skills/document/styles/hand-drawn/skin.css +2 -2
  114. package/skills/document/styles/ivory-gold/skin.css +2 -2
  115. package/skills/document/styles/legal-slate/backdrop.html +6 -0
  116. package/skills/document/styles/legal-slate/skin.css +27 -0
  117. package/skills/document/styles/magazine-ink/skin.css +1 -1
  118. package/skills/document/styles/memphis/backdrop.html +5 -0
  119. package/skills/document/styles/memphis/skin.css +27 -0
  120. package/skills/document/styles/mono/skin.css +1 -1
  121. package/skills/document/styles/neon-cyber/backdrop.html +4 -0
  122. package/skills/document/styles/neon-cyber/skin.css +27 -0
  123. package/skills/document/styles/olive-gold/skin.css +1 -1
  124. package/skills/document/styles/organic-earth/backdrop.html +4 -0
  125. package/skills/document/styles/organic-earth/skin.css +27 -0
  126. package/skills/document/styles/pastel-saas/backdrop.html +4 -0
  127. package/skills/document/styles/pastel-saas/skin.css +27 -0
  128. package/skills/document/styles/portfolio-noir/backdrop.html +4 -0
  129. package/skills/document/styles/portfolio-noir/skin.css +27 -0
  130. package/skills/document/styles/retro-press/backdrop.html +6 -0
  131. package/skills/document/styles/retro-press/skin.css +27 -0
  132. package/skills/document/styles/sport-arena/backdrop.html +4 -0
  133. package/skills/document/styles/sport-arena/skin.css +27 -0
  134. package/skills/document/styles/wedding-blush/backdrop.html +6 -0
  135. package/skills/document/styles/wedding-blush/skin.css +27 -0
  136. package/skills/image-compose/LICENSE.txt +30 -0
  137. package/skills/image-compose/SKILL.md +137 -0
  138. package/skills/image-compose/bin/html2img.cjs +122 -0
@@ -0,0 +1,4 @@
1
+ <!-- generated by scripts/ppt-tpl/gen-skin.mjs — signature: footer-slab -->
2
+ <div style="position:absolute;inset:0;background:#1F1F1F"></div>
3
+ <div style="position:absolute;left:0;right:0;bottom:0;height:14px;background:var(--accent);opacity:.9;pointer-events:none"></div>
4
+ <div style="position:absolute;left:0;right:0;bottom:14px;height:2px;background:var(--hair);pointer-events:none"></div>
@@ -0,0 +1,27 @@
1
+ /* styles/portfolio-noir — generated by scripts/ppt-tpl/gen-skin.mjs from ppt-tpl/families/portfolio-noir/family.json.
2
+ 手改会在下次生成时丢失:要改就改 family.json。 */
3
+ :root{
4
+ --space-scale:1.12; --type-scale:1;
5
+ --accent:#FC8B79; --c1:#FC8B79; --c2:#BFAB4D; --c3:#51BF83; --c4:#24BCD0; --chart-1:#FC8B79;
6
+ --title:#F6F6F6; --body:#BBBBBB; --muted:#868686; --foot:#868686;
7
+ --hair:#424242; --card-radius:4px;
8
+ --font-head:'Archivo','Noto Sans SC',sans-serif;
9
+ --font-body:'Space Grotesk','Noto Sans SC',sans-serif;
10
+ --title-color:#F6F6F6; --body-color:#BBBBBB; --slide-bg:#1F1F1F; --font-heading:var(--font-head);
11
+ }
12
+ .slide{background:#1F1F1F;color:var(--body);font-family:var(--font-body)}
13
+ .slide-backdrop{position:absolute;inset:0;background:#1F1F1F}
14
+ .deck-header,.deck-footer,.deck-pageno{color:var(--muted)}
15
+ .rule,.rule-foot{background:var(--hair)}
16
+ .eyebrow{color:var(--accent);letter-spacing:.22em;font-weight:700}
17
+ .accent-bar{background:var(--accent)}
18
+ .deck-title,.cover-title,.section-title,.ending-title{color:var(--title);font-family:var(--font-head);font-weight:700}
19
+ .cover-sub,.ending-sub,.section-desc{color:var(--muted)}
20
+ .card{border-radius:var(--card-radius);background:transparent;border:1px solid var(--hair)}
21
+ .card-idx{color:var(--muted)} .card-body{color:var(--body)} .card-title{color:var(--title)}
22
+ .card-grid .card:nth-child(4n+1) .card-rail,.card-grid .card:nth-child(4n+1) .card-dot{background:var(--c1)}
23
+ .card-grid .card:nth-child(4n+2) .card-rail,.card-grid .card:nth-child(4n+2) .card-dot{background:var(--c2)}
24
+ .card-grid .card:nth-child(4n+3) .card-rail,.card-grid .card:nth-child(4n+3) .card-dot{background:var(--c3)}
25
+ .card-grid .card:nth-child(4n+4) .card-rail,.card-grid .card:nth-child(4n+4) .card-dot{background:var(--c4)}
26
+ .kpi-num,.stat-num{color:var(--title);font-family:var(--font-head)}
27
+ .kpi-label,.stat-unit{color:var(--muted)} .stat-lead{color:var(--title)} .stat-note{color:var(--body)}
@@ -0,0 +1,6 @@
1
+ <!-- generated by scripts/ppt-tpl/gen-skin.mjs — signature: crop-marks -->
2
+ <div style="position:absolute;inset:0;background:#FDEBD8"></div>
3
+ <div style="position:absolute;left:44px;top:44px;border-left:1px solid var(--hair);border-top:1px solid var(--hair);width:26px;height:26px;pointer-events:none"></div>
4
+ <div style="position:absolute;right:44px;top:44px;border-right:1px solid var(--hair);border-top:1px solid var(--hair);width:26px;height:26px;pointer-events:none"></div>
5
+ <div style="position:absolute;left:44px;bottom:44px;border-left:1px solid var(--hair);border-bottom:1px solid var(--hair);width:26px;height:26px;pointer-events:none"></div>
6
+ <div style="position:absolute;right:44px;bottom:44px;border-right:1px solid var(--hair);border-bottom:1px solid var(--hair);width:26px;height:26px;pointer-events:none"></div>
@@ -0,0 +1,27 @@
1
+ /* styles/retro-press — generated by scripts/ppt-tpl/gen-skin.mjs from ppt-tpl/families/retro-press/family.json.
2
+ 手改会在下次生成时丢失:要改就改 family.json。 */
3
+ :root{
4
+ --space-scale:1.04; --type-scale:1.04;
5
+ --accent:#BE433C; --c1:#BE433C; --c2:#926400; --c3:#4B790C; --c4:#107B62; --chart-1:#BE433C;
6
+ --title:#3C2721; --body:#62514D; --muted:#8A7873; --foot:#8A7873;
7
+ --hair:#E3C6BE; --card-radius:4px;
8
+ --font-head:'DM Serif Display','Songti SC',sans-serif;
9
+ --font-body:'Lora','Noto Serif SC',sans-serif;
10
+ --title-color:#3C2721; --body-color:#62514D; --slide-bg:#FDEBD8; --font-heading:var(--font-head);
11
+ }
12
+ .slide{background:#FDEBD8;color:var(--body);font-family:var(--font-body)}
13
+ .slide-backdrop{position:absolute;inset:0;background:#FDEBD8}
14
+ .deck-header,.deck-footer,.deck-pageno{color:var(--muted)}
15
+ .rule,.rule-foot{background:var(--hair)}
16
+ .eyebrow{color:var(--accent);letter-spacing:.22em;font-weight:700}
17
+ .accent-bar{background:var(--accent)}
18
+ .deck-title,.cover-title,.section-title,.ending-title{color:var(--title);font-family:var(--font-head);font-weight:700;--talos-bake:1}
19
+ .cover-sub,.ending-sub,.section-desc{color:var(--muted)}
20
+ .card{border-radius:var(--card-radius);background:transparent;border:1px solid var(--hair)}
21
+ .card-idx{color:var(--muted)} .card-body{color:var(--body)} .card-title{color:var(--title)}
22
+ .card-grid .card:nth-child(4n+1) .card-rail,.card-grid .card:nth-child(4n+1) .card-dot{background:var(--c1)}
23
+ .card-grid .card:nth-child(4n+2) .card-rail,.card-grid .card:nth-child(4n+2) .card-dot{background:var(--c2)}
24
+ .card-grid .card:nth-child(4n+3) .card-rail,.card-grid .card:nth-child(4n+3) .card-dot{background:var(--c3)}
25
+ .card-grid .card:nth-child(4n+4) .card-rail,.card-grid .card:nth-child(4n+4) .card-dot{background:var(--c4)}
26
+ .kpi-num,.stat-num{color:var(--title);font-family:var(--font-head);--talos-bake:1}
27
+ .kpi-label,.stat-unit{color:var(--muted)} .stat-lead{color:var(--title)} .stat-note{color:var(--body)}
@@ -0,0 +1,4 @@
1
+ <!-- generated by scripts/ppt-tpl/gen-skin.mjs — signature: diagonal-band -->
2
+ <div style="position:absolute;inset:0;background:#12242E"></div>
3
+ <div style="position:absolute;right:-60px;top:-40px;width:260px;height:820px;background:var(--accent);opacity:.14;transform:rotate(18deg);pointer-events:none"></div>
4
+ <div style="position:absolute;right:96px;top:-40px;width:2px;height:820px;background:var(--accent);opacity:.5;transform:rotate(18deg);pointer-events:none"></div>
@@ -0,0 +1,27 @@
1
+ /* styles/sport-arena — generated by scripts/ppt-tpl/gen-skin.mjs from ppt-tpl/families/sport-arena/family.json.
2
+ 手改会在下次生成时丢失:要改就改 family.json。 */
3
+ :root{
4
+ --space-scale:0.92; --type-scale:1.08;
5
+ --accent:#FB845C; --c1:#FB845C; --c2:#AFAA01; --c3:#1ABD7A; --c4:#1FB6C8; --chart-1:#FB845C;
6
+ --title:#F2F7FC; --body:#B5BCC2; --muted:#7E858A; --foot:#7E858A;
7
+ --hair:#37444D; --card-radius:4px;
8
+ --font-head:'Big Shoulders Display','Noto Sans SC',sans-serif;
9
+ --font-body:'Public Sans','Noto Sans SC',sans-serif;
10
+ --title-color:#F2F7FC; --body-color:#B5BCC2; --slide-bg:#12242E; --font-heading:var(--font-head);
11
+ }
12
+ .slide{background:#12242E;color:var(--body);font-family:var(--font-body)}
13
+ .slide-backdrop{position:absolute;inset:0;background:#12242E}
14
+ .deck-header,.deck-footer,.deck-pageno{color:var(--muted)}
15
+ .rule,.rule-foot{background:var(--hair)}
16
+ .eyebrow{color:var(--accent);letter-spacing:.22em;font-weight:700}
17
+ .accent-bar{background:var(--accent)}
18
+ .deck-title,.cover-title,.section-title,.ending-title{color:var(--title);font-family:var(--font-head);font-weight:700;--talos-bake:1}
19
+ .cover-sub,.ending-sub,.section-desc{color:var(--muted)}
20
+ .card{border-radius:var(--card-radius);background:transparent;border:1px solid var(--hair)}
21
+ .card-idx{color:var(--muted)} .card-body{color:var(--body)} .card-title{color:var(--title)}
22
+ .card-grid .card:nth-child(4n+1) .card-rail,.card-grid .card:nth-child(4n+1) .card-dot{background:var(--c1)}
23
+ .card-grid .card:nth-child(4n+2) .card-rail,.card-grid .card:nth-child(4n+2) .card-dot{background:var(--c2)}
24
+ .card-grid .card:nth-child(4n+3) .card-rail,.card-grid .card:nth-child(4n+3) .card-dot{background:var(--c3)}
25
+ .card-grid .card:nth-child(4n+4) .card-rail,.card-grid .card:nth-child(4n+4) .card-dot{background:var(--c4)}
26
+ .kpi-num,.stat-num{color:var(--title);font-family:var(--font-head);--talos-bake:1}
27
+ .kpi-label,.stat-unit{color:var(--muted)} .stat-lead{color:var(--title)} .stat-note{color:var(--body)}
@@ -0,0 +1,6 @@
1
+ <!-- generated by scripts/ppt-tpl/gen-skin.mjs — signature: arc-rise -->
2
+ <div style="position:absolute;inset:0;background:#FFF0EF"></div>
3
+ <svg style="position:absolute;inset:0;pointer-events:none" width="1280" height="720" viewBox="0 0 1280 720" fill="none" preserveAspectRatio="none">
4
+ <path d="M-40 660 C 420 706, 900 560, 1320 150" stroke="var(--accent)" stroke-opacity=".55" stroke-width="2" fill="none"/>
5
+ <path d="M-40 660 C 420 706, 900 560, 1320 150 L1320 720 L-40 720 Z" fill="var(--accent)" fill-opacity=".08"/>
6
+ </svg>
@@ -0,0 +1,27 @@
1
+ /* styles/wedding-blush — generated by scripts/ppt-tpl/gen-skin.mjs from ppt-tpl/families/wedding-blush/family.json.
2
+ 手改会在下次生成时丢失:要改就改 family.json。 */
3
+ :root{
4
+ --space-scale:1.1; --type-scale:1.06;
5
+ --accent:#A55B78; --c1:#A55B78; --c2:#A2614B; --c3:#7F7237; --c4:#497E50; --chart-1:#A55B78;
6
+ --title:#3C2C2C; --body:#625453; --muted:#8D7E7D; --foot:#8D7E7D;
7
+ --hair:#EFD4D2; --card-radius:4px;
8
+ --font-head:'Playfair Display','Songti SC',sans-serif;
9
+ --font-body:'Cormorant Garamond','Noto Serif SC',sans-serif;
10
+ --title-color:#3C2C2C; --body-color:#625453; --slide-bg:#FFF0EF; --font-heading:var(--font-head);
11
+ }
12
+ .slide{background:#FFF0EF;color:var(--body);font-family:var(--font-body)}
13
+ .slide-backdrop{position:absolute;inset:0;background:#FFF0EF}
14
+ .deck-header,.deck-footer,.deck-pageno{color:var(--muted)}
15
+ .rule,.rule-foot{background:var(--hair)}
16
+ .eyebrow{color:var(--accent);letter-spacing:.22em;font-weight:700}
17
+ .accent-bar{background:var(--accent)}
18
+ .deck-title,.cover-title,.section-title,.ending-title{color:var(--title);font-family:var(--font-head);font-weight:700;--talos-bake:1}
19
+ .cover-sub,.ending-sub,.section-desc{color:var(--muted)}
20
+ .card{border-radius:var(--card-radius);background:transparent;border:1px solid var(--hair)}
21
+ .card-idx{color:var(--muted)} .card-body{color:var(--body)} .card-title{color:var(--title)}
22
+ .card-grid .card:nth-child(4n+1) .card-rail,.card-grid .card:nth-child(4n+1) .card-dot{background:var(--c1)}
23
+ .card-grid .card:nth-child(4n+2) .card-rail,.card-grid .card:nth-child(4n+2) .card-dot{background:var(--c2)}
24
+ .card-grid .card:nth-child(4n+3) .card-rail,.card-grid .card:nth-child(4n+3) .card-dot{background:var(--c3)}
25
+ .card-grid .card:nth-child(4n+4) .card-rail,.card-grid .card:nth-child(4n+4) .card-dot{background:var(--c4)}
26
+ .kpi-num,.stat-num{color:var(--title);font-family:var(--font-head);--talos-bake:1}
27
+ .kpi-label,.stat-unit{color:var(--muted)} .stat-lead{color:var(--title)} .stat-note{color:var(--body)}
@@ -0,0 +1,30 @@
1
+ © 2025 Anthropic, PBC. All rights reserved.
2
+
3
+ LICENSE: Use of these materials (including all code, prompts, assets, files,
4
+ and other components of this Skill) is governed by your agreement with
5
+ Anthropic regarding use of Anthropic's services. If no separate agreement
6
+ exists, use is governed by Anthropic's Consumer Terms of Service or
7
+ Commercial Terms of Service, as applicable:
8
+ https://www.anthropic.com/legal/consumer-terms
9
+ https://www.anthropic.com/legal/commercial-terms
10
+ Your applicable agreement is referred to as the "Agreement." "Services" are
11
+ as defined in the Agreement.
12
+
13
+ ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
14
+ contrary, users may not:
15
+
16
+ - Extract these materials from the Services or retain copies of these
17
+ materials outside the Services
18
+ - Reproduce or copy these materials, except for temporary copies created
19
+ automatically during authorized use of the Services
20
+ - Create derivative works based on these materials
21
+ - Distribute, sublicense, or transfer these materials to any third party
22
+ - Make, offer to sell, sell, or import any inventions embodied in these
23
+ materials
24
+ - Reverse engineer, decompile, or disassemble these materials
25
+
26
+ The receipt, viewing, or possession of these materials does not convey or
27
+ imply any license or right beyond those expressly granted above.
28
+
29
+ Anthropic retains all right, title, and interest in these materials,
30
+ including all copyrights, patents, and other intellectual property rights.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: image-compose
3
+ description: "Use this skill whenever the user wants EXISTING images combined or altered as pixels — 拼图 / 拼接 / 拼一张 / 宫格 / 九宫格 / 长图 / 对比图 / 前后对比 / 加水印 / 加标签 / 加边框 / 裁剪 / 圆角 / 缩放, or stitch / combine / merge images / collage / contact sheet / side-by-side / before-after / watermark / label / crop / round corners / resize. Examples: 'combine these four into one picture', '把生成的几张图拼成九宫格', 'add a caption under each'. Method: HTML+CSS rendered by this skill's bin/html2img.cjs. The mechanical test: if the images do not exist as files yet, this is NOT the skill. Do NOT trigger for: generating NEW images, INCLUDING when the request names a layout word — '生成一张九宫格的图' asks for ONE generated picture whose COMPOSITION is a grid, not for tiling existing files; documents / PDF / PowerPoint (document skill); Xiaohongshu cards (talos-xhs-ops); or upscaling / background removal / content-aware fill, which need a model, not CSS."
4
+ license: Proprietary. LICENSE.txt has complete terms
5
+ ---
6
+
7
+ # Image composition
8
+
9
+ Combining or restyling images that **already exist** — as files on disk. You
10
+ write a layout in HTML+CSS; Chromium renders it to one PNG.
11
+
12
+ **Check first: do the image files exist?** If they do not, stop — the request is
13
+ for generation, not composition, and this skill cannot make imagery. A layout
14
+ word in the request does not change that: "生成一张九宫格的图" asks for ONE
15
+ generated picture whose composition happens to be a grid, the same way "three
16
+ cats" describes a scene rather than an output count. Compose only files you can
17
+ name a path for.
18
+
19
+ There is no ImageMagick / sharp / PIL / ffmpeg to call here, and no `npm i`.
20
+ Do not go looking for one, and do not ask a generation model to "draw a 2×2
21
+ grid" — it redraws the subjects instead of tiling the images you have.
22
+
23
+ ## The one command
24
+
25
+ ```
26
+ bin/html2img.cjs <in.html> <out.png> [--width N] [--max-height N]
27
+ ```
28
+
29
+ - `--width` (default 1280) is the canvas width in CSS pixels. **You declare it**;
30
+ it must equal the sum of your columns plus gaps and padding.
31
+ - The **height is measured** from the rendered page — never compute it. Captions
32
+ of any length, wrapped titles, variable rows all just work.
33
+ - Local images referenced by `<img src>` and CSS `url()` are collected
34
+ automatically and allowlisted; relative paths resolve against the HTML file's
35
+ own directory, and any filename works, spaces and `~ % [ ]` included.
36
+ **Remote URLs are blocked**, and any image that fails to decode fails the whole
37
+ render — you never get a "finished" sheet with a blank cell in it.
38
+ - Needs the Talos app (Chromium loopback). Headless it exits 69 with a clear
39
+ message; do not try to work around that.
40
+ - Bounds: width 160–4096, rendered height ≤ `--max-height` (default 8192, refused
41
+ not cropped), ≤64 local images per render.
42
+ - Output is always PNG.
43
+
44
+ Then deliver the result with `present_file` — one call, the composed image.
45
+
46
+ ## Rules that keep the output right
47
+
48
+ - **Give every cell an explicit pixel size.** The canvas width is arithmetic, and
49
+ arithmetic needs numbers: `cols × cell + (cols−1) × gap + 2 × padding`.
50
+ - **CJK text must lead its font stack with `TalosCJK`**, e.g.
51
+ `font-family: TalosCJK, system-ui, sans-serif`. The renderer injects that face
52
+ when the HTML contains CJK; without it Chinese labels come out blank.
53
+ - **Set an explicit `background`** on `body`. An unstyled page captures as white,
54
+ which is rarely what a dark sheet wants.
55
+ - Write the HTML **next to the images**, or reference them by absolute path.
56
+ - Source images keep their own resolution — a 1024px image in a 512px cell is
57
+ downscaled by the browser. Size cells for the output you want.
58
+
59
+ ## Recipes
60
+
61
+ Each is a starting point; the layout is ordinary CSS, so change it freely.
62
+
63
+ ### Contact sheet / 宫格
64
+
65
+ `cols × cell + (cols−1) × gap + 2 × pad`. Below: 2 × 512 + 20 + 48 = **1092**.
66
+
67
+ ```html
68
+ <!doctype html><html><head><meta charset="utf-8"><style>
69
+ html,body{margin:0;background:#0d0d10}
70
+ body{font-family:TalosCJK,system-ui,-apple-system,sans-serif;color:#e8e8ea}
71
+ h1{margin:0;padding:24px 24px 8px;font-size:34px}
72
+ .sheet{display:grid;grid-template-columns:repeat(2,512px);gap:20px;padding:0 24px 24px}
73
+ figure{margin:0;position:relative}
74
+ figure img{width:512px;height:512px;object-fit:cover;display:block;border-radius:14px}
75
+ .tag{position:absolute;top:14px;left:14px;padding:6px 14px;border-radius:999px;
76
+ background:rgba(0,0,0,.55);font-size:20px;font-weight:600}
77
+ figcaption{padding-top:10px;font-size:20px;color:#c9c9d1;text-align:center}
78
+ </style></head><body>
79
+ <h1>四个方案对比</h1>
80
+ <div class="sheet">
81
+ <figure><img src="a.png"><span class="tag">1</span><figcaption>方案 A</figcaption></figure>
82
+ <figure><img src="b.png"><span class="tag">2</span><figcaption>方案 B</figcaption></figure>
83
+ </div>
84
+ </body></html>
85
+ ```
86
+
87
+ ### Long strip / 长图
88
+
89
+ One column; the height takes care of itself.
90
+
91
+ ```css
92
+ .strip{display:grid;grid-template-columns:1080px;gap:0;padding:0}
93
+ .strip img{width:1080px;height:auto;display:block}
94
+ ```
95
+
96
+ ### Before / after
97
+
98
+ Two cells with labels, or one cell with the "after" clipped to half:
99
+
100
+ ```css
101
+ .pair{display:grid;grid-template-columns:repeat(2,640px);gap:2px}
102
+ /* single-frame variant */
103
+ .overlay{position:relative;width:1280px;height:720px}
104
+ .overlay img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
105
+ .overlay .after{clip-path:inset(0 0 0 50%)}
106
+ .overlay .seam{position:absolute;left:50%;top:0;bottom:0;width:2px;background:#fff}
107
+ ```
108
+
109
+ ### Watermark / label / border
110
+
111
+ ```css
112
+ .mark{position:absolute;right:20px;bottom:20px;font-size:22px;opacity:.75}
113
+ .framed{border:8px solid #fff;box-shadow:0 8px 30px rgba(0,0,0,.35)}
114
+ ```
115
+
116
+ ### Crop, scale, round, filter
117
+
118
+ Cropping and scaling are `object-fit` on a sized box; there is no separate crop
119
+ tool.
120
+
121
+ ```css
122
+ .crop{width:512px;height:512px;object-fit:cover;object-position:center} /* fill + centre-crop */
123
+ .fit {width:512px;height:512px;object-fit:contain;background:#111} /* letterbox, no crop */
124
+ .round{border-radius:24px}
125
+ .grey{filter:grayscale(1) contrast(1.05)}
126
+ ```
127
+
128
+ ## When this is the wrong skill
129
+
130
+ - **Generating a new image** → the media-generation tools. This skill never
131
+ creates imagery, it only arranges what exists.
132
+ - **A PDF / Word / PowerPoint deliverable** → the document skill (`doc-gen`,
133
+ `html2pptx`). Do not build a "poster" here and call it a document.
134
+ - **Xiaohongshu campaign cards** → `talos-xhs-ops` (`render-cards`), which owns
135
+ the 1080×1440 card format and its QA.
136
+ - **Pixel-level algorithms** — background removal, super-resolution,
137
+ content-aware fill. CSS cannot do these; they need a model.
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // apps/admin/data/skills.lib/image-compose/bin-src/html2img.mjs
5
+ var import_promises = require("node:fs/promises");
6
+ var import_node_path2 = require("node:path");
7
+
8
+ // packages/core/dist/document/html-local-assets.js
9
+ var import_node_fs = require("node:fs");
10
+ var import_node_path = require("node:path");
11
+ var import_node_url = require("node:url");
12
+ var IMG_SRC = /(<img\b[^>]*?\bsrc\s*=\s*)(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
13
+ var CSS_URL = /(url\(\s*)(?:"([^"]*)"|'([^']*)'|([^)\s]+))(\s*\))/gi;
14
+ function isNonLocal(ref) {
15
+ return ref.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(ref) && !ref.toLowerCase().startsWith("file:");
16
+ }
17
+ function resolveLocalAssets(html, baseDir) {
18
+ const found = /* @__PURE__ */ new Set();
19
+ const rewrite = (ref) => {
20
+ const url = ref === void 0 ? void 0 : localFileUrl(ref.trim(), baseDir);
21
+ if (url)
22
+ found.add(url);
23
+ return url;
24
+ };
25
+ const withCss = html.replace(CSS_URL, (match, prefix, dq, sq, bare, suffix) => {
26
+ const url = rewrite(dq ?? sq ?? bare);
27
+ return url ? `${prefix}"${url}"${suffix}` : match;
28
+ });
29
+ const rewritten = withCss.replace(IMG_SRC, (match, prefix, dq, sq, bare) => {
30
+ const url = rewrite(dq ?? sq ?? bare);
31
+ return url ? `${prefix}"${url}"` : match;
32
+ });
33
+ return { html: rewritten, assetFileUrls: [...found] };
34
+ }
35
+ function localFileUrl(ref, baseDir) {
36
+ if (!ref)
37
+ return void 0;
38
+ let path;
39
+ if (ref.toLowerCase().startsWith("file:")) {
40
+ try {
41
+ path = (0, import_node_url.fileURLToPath)(ref);
42
+ } catch {
43
+ return void 0;
44
+ }
45
+ } else if (isNonLocal(ref)) {
46
+ return void 0;
47
+ } else {
48
+ const bare = ref.split(/[?#]/)[0];
49
+ if (!bare)
50
+ return void 0;
51
+ path = (0, import_node_path.isAbsolute)(bare) ? bare : (0, import_node_path.resolve)(baseDir, bare);
52
+ }
53
+ return (0, import_node_fs.existsSync)(path) ? (0, import_node_url.pathToFileURL)(path).href : void 0;
54
+ }
55
+
56
+ // apps/admin/data/skills.lib/image-compose/bin-src/html2img.mjs
57
+ function die(msg, code = 1) {
58
+ process.stderr.write(`html2img: ${msg}
59
+ `);
60
+ process.exit(code);
61
+ }
62
+ function intArg(flag, fallback) {
63
+ const i = process.argv.indexOf(flag);
64
+ if (i < 0) return fallback;
65
+ const value = Number(process.argv[i + 1]);
66
+ if (!Number.isInteger(value)) die(`${flag} needs an integer`, 64);
67
+ return value;
68
+ }
69
+ async function main() {
70
+ const input = process.argv[2];
71
+ const output = process.argv[3];
72
+ if (!input || !output || input.startsWith("--") || output.startsWith("--")) {
73
+ die("usage: html2img <in.html> <out.png> [--width N] [--max-height N]", 64);
74
+ }
75
+ const width = intArg("--width", 1280);
76
+ const maxHeight = intArg("--max-height", void 0);
77
+ const url = process.env.TALOS_PDF_URL;
78
+ if (!url) {
79
+ die("rendering needs the Talos app's Chromium service (TALOS_PDF_URL is not set). Run inside the Talos app.", 69);
80
+ }
81
+ let source;
82
+ try {
83
+ source = await (0, import_promises.readFile)(input, "utf8");
84
+ } catch (e) {
85
+ die(`cannot read ${input}: ${e.message}`, 66);
86
+ }
87
+ const { html, assetFileUrls } = resolveLocalAssets(source, (0, import_node_path2.dirname)((0, import_node_path2.resolve)(input)));
88
+ let res;
89
+ try {
90
+ res = await fetch(url.replace(/\/pdf$/, "/img"), {
91
+ method: "POST",
92
+ headers: {
93
+ "content-type": "application/json",
94
+ ...process.env.TALOS_PDF_TOKEN ? { authorization: `Bearer ${process.env.TALOS_PDF_TOKEN}` } : {}
95
+ },
96
+ body: JSON.stringify({ html, width, ...maxHeight === void 0 ? {} : { maxHeight }, assetFileUrls })
97
+ });
98
+ } catch (e) {
99
+ die(`render request failed: ${e.message}`, 69);
100
+ }
101
+ const text = await res.text();
102
+ if (!res.ok) {
103
+ let detail = text;
104
+ try {
105
+ detail = JSON.parse(text).error ?? text;
106
+ } catch {
107
+ }
108
+ die(`render failed (${res.status}): ${detail}`);
109
+ }
110
+ let image;
111
+ try {
112
+ image = JSON.parse(text).image;
113
+ } catch {
114
+ die("render returned malformed JSON");
115
+ }
116
+ if (typeof image !== "string" || !image) die("render returned no image");
117
+ const dest = (0, import_node_path2.resolve)(output);
118
+ await (0, import_promises.writeFile)(dest, Buffer.from(image, "base64"));
119
+ process.stdout.write(`${JSON.stringify({ path: dest, width, assets: assetFileUrls.length })}
120
+ `);
121
+ }
122
+ main().catch((e) => die(e?.message ?? String(e)));