@sanity-labs/slides 0.0.0

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 (224) hide show
  1. package/README.md +241 -0
  2. package/SKILL.md +119 -0
  3. package/dist/cli.d.ts +38 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +386 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/components.d.ts +179 -0
  8. package/dist/core/components.d.ts.map +1 -0
  9. package/dist/core/components.js +40 -0
  10. package/dist/core/components.js.map +1 -0
  11. package/dist/core/fake-runtime.d.ts +138 -0
  12. package/dist/core/fake-runtime.d.ts.map +1 -0
  13. package/dist/core/fake-runtime.js +210 -0
  14. package/dist/core/fake-runtime.js.map +1 -0
  15. package/dist/core/font-resolver.d.ts +28 -0
  16. package/dist/core/font-resolver.d.ts.map +1 -0
  17. package/dist/core/font-resolver.js +30 -0
  18. package/dist/core/font-resolver.js.map +1 -0
  19. package/dist/core/geometry.d.ts +71 -0
  20. package/dist/core/geometry.d.ts.map +1 -0
  21. package/dist/core/geometry.js +44 -0
  22. package/dist/core/geometry.js.map +1 -0
  23. package/dist/core/index.d.ts +19 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +20 -0
  26. package/dist/core/index.js.map +1 -0
  27. package/dist/core/manifest.d.ts +123 -0
  28. package/dist/core/manifest.d.ts.map +1 -0
  29. package/dist/core/manifest.js +43 -0
  30. package/dist/core/manifest.js.map +1 -0
  31. package/dist/core/op-translator-pptx.d.ts +150 -0
  32. package/dist/core/op-translator-pptx.d.ts.map +1 -0
  33. package/dist/core/op-translator-pptx.js +245 -0
  34. package/dist/core/op-translator-pptx.js.map +1 -0
  35. package/dist/core/pptx-runtime.d.ts +103 -0
  36. package/dist/core/pptx-runtime.d.ts.map +1 -0
  37. package/dist/core/pptx-runtime.js +405 -0
  38. package/dist/core/pptx-runtime.js.map +1 -0
  39. package/dist/core/reconciler.d.ts +113 -0
  40. package/dist/core/reconciler.d.ts.map +1 -0
  41. package/dist/core/reconciler.js +453 -0
  42. package/dist/core/reconciler.js.map +1 -0
  43. package/dist/core/runtime.d.ts +161 -0
  44. package/dist/core/runtime.d.ts.map +1 -0
  45. package/dist/core/runtime.js +11 -0
  46. package/dist/core/runtime.js.map +1 -0
  47. package/dist/core/template.d.ts +32 -0
  48. package/dist/core/template.d.ts.map +1 -0
  49. package/dist/core/template.js +3 -0
  50. package/dist/core/template.js.map +1 -0
  51. package/dist/dev/auto-examples.d.ts +6 -0
  52. package/dist/dev/auto-examples.d.ts.map +1 -0
  53. package/dist/dev/auto-examples.js +79 -0
  54. package/dist/dev/auto-examples.js.map +1 -0
  55. package/dist/dev/bin/slides-dev.d.ts +3 -0
  56. package/dist/dev/bin/slides-dev.d.ts.map +1 -0
  57. package/dist/dev/bin/slides-dev.js +87 -0
  58. package/dist/dev/bin/slides-dev.js.map +1 -0
  59. package/dist/dev/bin/slides-dev.mjs +24 -0
  60. package/dist/dev/compose-deck.d.ts +18 -0
  61. package/dist/dev/compose-deck.d.ts.map +1 -0
  62. package/dist/dev/compose-deck.js +19 -0
  63. package/dist/dev/compose-deck.js.map +1 -0
  64. package/dist/dev/deck-viewer.d.ts +19 -0
  65. package/dist/dev/deck-viewer.d.ts.map +1 -0
  66. package/dist/dev/deck-viewer.js +237 -0
  67. package/dist/dev/deck-viewer.js.map +1 -0
  68. package/dist/dev/dev-server/client/entry.d.ts +2 -0
  69. package/dist/dev/dev-server/client/entry.d.ts.map +1 -0
  70. package/dist/dev/dev-server/client/entry.js +12 -0
  71. package/dist/dev/dev-server/client/entry.js.map +1 -0
  72. package/dist/dev/dev-server/output.d.ts +8 -0
  73. package/dist/dev/dev-server/output.d.ts.map +1 -0
  74. package/dist/dev/dev-server/output.js +32 -0
  75. package/dist/dev/dev-server/output.js.map +1 -0
  76. package/dist/dev/dev-server/server-only-stub.d.ts +7 -0
  77. package/dist/dev/dev-server/server-only-stub.d.ts.map +1 -0
  78. package/dist/dev/dev-server/server-only-stub.js +12 -0
  79. package/dist/dev/dev-server/server-only-stub.js.map +1 -0
  80. package/dist/dev/dev-server/start.d.ts +14 -0
  81. package/dist/dev/dev-server/start.d.ts.map +1 -0
  82. package/dist/dev/dev-server/start.js +135 -0
  83. package/dist/dev/dev-server/start.js.map +1 -0
  84. package/dist/dev/index.d.ts +5 -0
  85. package/dist/dev/index.d.ts.map +1 -0
  86. package/dist/dev/index.js +5 -0
  87. package/dist/dev/index.js.map +1 -0
  88. package/dist/dev/lib/cn.d.ts +3 -0
  89. package/dist/dev/lib/cn.d.ts.map +1 -0
  90. package/dist/dev/lib/cn.js +3 -0
  91. package/dist/dev/lib/cn.js.map +1 -0
  92. package/dist/dev/slide-canvas.d.ts +12 -0
  93. package/dist/dev/slide-canvas.d.ts.map +1 -0
  94. package/dist/dev/slide-canvas.js +123 -0
  95. package/dist/dev/slide-canvas.js.map +1 -0
  96. package/dist/dev/styles.css +37 -0
  97. package/dist/dev/ui/icon-button.d.ts +12 -0
  98. package/dist/dev/ui/icon-button.d.ts.map +1 -0
  99. package/dist/dev/ui/icon-button.js +6 -0
  100. package/dist/dev/ui/icon-button.js.map +1 -0
  101. package/dist/dev/ui/kbd.d.ts +6 -0
  102. package/dist/dev/ui/kbd.d.ts.map +1 -0
  103. package/dist/dev/ui/kbd.js +4 -0
  104. package/dist/dev/ui/kbd.js.map +1 -0
  105. package/dist/dev/ui/text-button.d.ts +10 -0
  106. package/dist/dev/ui/text-button.d.ts.map +1 -0
  107. package/dist/dev/ui/text-button.js +6 -0
  108. package/dist/dev/ui/text-button.js.map +1 -0
  109. package/dist/dev/url-state.d.ts +7 -0
  110. package/dist/dev/url-state.d.ts.map +1 -0
  111. package/dist/dev/url-state.js +13 -0
  112. package/dist/dev/url-state.js.map +1 -0
  113. package/dist/dev/use-keyboard-nav.d.ts +17 -0
  114. package/dist/dev/use-keyboard-nav.d.ts.map +1 -0
  115. package/dist/dev/use-keyboard-nav.js +53 -0
  116. package/dist/dev/use-keyboard-nav.js.map +1 -0
  117. package/dist/index.d.ts +17 -0
  118. package/dist/index.d.ts.map +1 -0
  119. package/dist/index.js +17 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/mcp/errors.d.ts +57 -0
  122. package/dist/mcp/errors.d.ts.map +1 -0
  123. package/dist/mcp/errors.js +44 -0
  124. package/dist/mcp/errors.js.map +1 -0
  125. package/dist/mcp/index.d.ts +29 -0
  126. package/dist/mcp/index.d.ts.map +1 -0
  127. package/dist/mcp/index.js +29 -0
  128. package/dist/mcp/index.js.map +1 -0
  129. package/dist/mcp/naming.d.ts +37 -0
  130. package/dist/mcp/naming.d.ts.map +1 -0
  131. package/dist/mcp/naming.js +43 -0
  132. package/dist/mcp/naming.js.map +1 -0
  133. package/dist/mcp/render.d.ts +45 -0
  134. package/dist/mcp/render.d.ts.map +1 -0
  135. package/dist/mcp/render.js +77 -0
  136. package/dist/mcp/render.js.map +1 -0
  137. package/dist/mcp/schema.d.ts +54 -0
  138. package/dist/mcp/schema.d.ts.map +1 -0
  139. package/dist/mcp/schema.js +55 -0
  140. package/dist/mcp/schema.js.map +1 -0
  141. package/dist/mcp/server.d.ts +63 -0
  142. package/dist/mcp/server.d.ts.map +1 -0
  143. package/dist/mcp/server.js +196 -0
  144. package/dist/mcp/server.js.map +1 -0
  145. package/dist/scaffold/index.d.ts +39 -0
  146. package/dist/scaffold/index.d.ts.map +1 -0
  147. package/dist/scaffold/index.js +84 -0
  148. package/dist/scaffold/index.js.map +1 -0
  149. package/dist/scaffold/template-base/README.md +134 -0
  150. package/dist/scaffold/template-base/_gitignore +4 -0
  151. package/dist/scaffold/template-base/package.json +35 -0
  152. package/dist/scaffold/template-base/src/components/Cover.tsx +30 -0
  153. package/dist/scaffold/template-base/src/index.ts +27 -0
  154. package/dist/scaffold/template-base/src/preview.tsx +9 -0
  155. package/dist/scaffold/template-base/tsconfig.build.json +10 -0
  156. package/dist/scaffold/template-base/tsconfig.json +18 -0
  157. package/package.json +164 -0
  158. package/src/__tests__/fixtures/test-template/index.tsx +77 -0
  159. package/src/__tests__/pptx-mcp.test.ts +85 -0
  160. package/src/__tests__/pptx-smoke.test.ts +45 -0
  161. package/src/__tests__/preview.test.ts +28 -0
  162. package/src/cli.ts +426 -0
  163. package/src/core/__snapshots__/reconciler.test.ts.snap +320 -0
  164. package/src/core/components.test.ts +57 -0
  165. package/src/core/components.ts +196 -0
  166. package/src/core/fake-runtime.test.ts +174 -0
  167. package/src/core/fake-runtime.ts +302 -0
  168. package/src/core/font-resolver.ts +46 -0
  169. package/src/core/geometry.test.ts +58 -0
  170. package/src/core/geometry.ts +91 -0
  171. package/src/core/index.ts +69 -0
  172. package/src/core/manifest.test.ts +33 -0
  173. package/src/core/manifest.ts +150 -0
  174. package/src/core/op-translator-pptx.test.ts +204 -0
  175. package/src/core/op-translator-pptx.ts +365 -0
  176. package/src/core/pptx-runtime.test.ts +137 -0
  177. package/src/core/pptx-runtime.ts +504 -0
  178. package/src/core/reconciler.test.ts +644 -0
  179. package/src/core/reconciler.ts +603 -0
  180. package/src/core/runtime.ts +150 -0
  181. package/src/core/template.test.ts +136 -0
  182. package/src/core/template.ts +37 -0
  183. package/src/dev/auto-examples.ts +89 -0
  184. package/src/dev/bin/slides-dev.mjs +24 -0
  185. package/src/dev/bin/slides-dev.ts +101 -0
  186. package/src/dev/compose-deck.test.ts +68 -0
  187. package/src/dev/compose-deck.ts +40 -0
  188. package/src/dev/deck-viewer.tsx +677 -0
  189. package/src/dev/dev-server/client/entry.tsx +15 -0
  190. package/src/dev/dev-server/client/index.html +24 -0
  191. package/src/dev/dev-server/output.ts +37 -0
  192. package/src/dev/dev-server/server-only-stub.ts +12 -0
  193. package/src/dev/dev-server/start.ts +155 -0
  194. package/src/dev/index.ts +4 -0
  195. package/src/dev/lib/cn.ts +3 -0
  196. package/src/dev/slide-canvas.test.tsx +66 -0
  197. package/src/dev/slide-canvas.tsx +170 -0
  198. package/src/dev/styles.css +37 -0
  199. package/src/dev/ui/icon-button.tsx +31 -0
  200. package/src/dev/ui/kbd.tsx +20 -0
  201. package/src/dev/ui/text-button.tsx +31 -0
  202. package/src/dev/url-state.test.ts +22 -0
  203. package/src/dev/url-state.ts +17 -0
  204. package/src/dev/use-keyboard-nav.ts +64 -0
  205. package/src/index.ts +17 -0
  206. package/src/mcp/errors.test.ts +51 -0
  207. package/src/mcp/errors.ts +76 -0
  208. package/src/mcp/index.ts +45 -0
  209. package/src/mcp/naming.test.ts +39 -0
  210. package/src/mcp/naming.ts +49 -0
  211. package/src/mcp/render.ts +110 -0
  212. package/src/mcp/schema.test.ts +86 -0
  213. package/src/mcp/schema.ts +93 -0
  214. package/src/mcp/server.test.ts +309 -0
  215. package/src/mcp/server.ts +276 -0
  216. package/src/scaffold/index.ts +102 -0
  217. package/src/scaffold/template-base/README.md +134 -0
  218. package/src/scaffold/template-base/_gitignore +4 -0
  219. package/src/scaffold/template-base/package.json +35 -0
  220. package/src/scaffold/template-base/src/components/Cover.tsx +30 -0
  221. package/src/scaffold/template-base/src/index.ts +27 -0
  222. package/src/scaffold/template-base/src/preview.tsx +9 -0
  223. package/src/scaffold/template-base/tsconfig.build.json +10 -0
  224. package/src/scaffold/template-base/tsconfig.json +18 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/mcp/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,eAAe,EAA0C,MAAM,oBAAoB,CAAC;AAI7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA2BhD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,aAAqB,EACrB,SAA4B,EAC5B,UAAmB,EACN,EAAE;IACf,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;IAC1C,MAAM,eAAe,GAAG,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC/E,OAAO;QACL,IAAI,EAAE,iBAAiB,CAAC,aAAa,EAAE,UAAU,CAAC;QAClD,WAAW,EAAE,SAAS,CAAC,WAAW;QAClC,UAAU;QACV,WAAW,EAAE,SAAS,CAAC,MAAM;QAC7B,eAAe;QACf,aAAa;KACd,CAAC;AACJ,CAAC,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAe,EAAE,UAAmB,EAAiB,EAAE,CAC1F,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,CACzD,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAC7C,CAAC;AAEJ;;;;;;;;GAQG;AACH,MAAM,mBAAmB,GAAoC;IAC3D,MAAM,EAAE,aAAa;IACrB,YAAY,EAAE,MAAM;CACrB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The template-agnostic MCP server framework.
3
+ *
4
+ * createSlideServer({ template, runtime }) builds an McpServer that exposes
5
+ * three kinds of tools:
6
+ *
7
+ * 1. **`slides_list`** — returns the list of slide types the loaded template
8
+ * supports, with descriptions. One round-trip to discover the surface.
9
+ *
10
+ * 2. **One tool per slide type**, named `<toolPrefix><snake_case>` (default
11
+ * prefix `slides_add_`). Validates user-supplied props against the
12
+ * component's Zod schema and echoes them back as a slide spec. Used
13
+ * iteratively by an LLM to assemble a deck before calling `slides_create`.
14
+ *
15
+ * 3. **`slides_create`** — full pipeline. Takes `{ title, slides }`, renders
16
+ * via the reconciler, applies through the PPTX runtime, writes the .pptx
17
+ * file to disk, and returns the path.
18
+ */
19
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
20
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
21
+ import type { SlidesRuntime, Template } from '../core/index.js';
22
+ import { type DerivedTool } from './schema.js';
23
+ /** Configuration accepted by createSlideServer. */
24
+ export interface SlideServerConfig {
25
+ /** The template (component vocabulary + tokens) the server exposes. */
26
+ readonly template: Template;
27
+ /** The PPTX runtime used to materialize presentations. */
28
+ readonly runtime: SlidesRuntime;
29
+ /**
30
+ * Override the server's reported name/version. Defaults to a name derived
31
+ * from the template and version `'0.1.0'`.
32
+ */
33
+ readonly serverInfo?: {
34
+ readonly name: string;
35
+ readonly version: string;
36
+ };
37
+ /**
38
+ * Override the per-slide-type tool-name prefix. Default: `'slides_add_'`.
39
+ * Use this when the server emits something other than slide decks (a
40
+ * report-builder might use `'report_add_'`, etc.).
41
+ */
42
+ readonly toolPrefix?: string;
43
+ }
44
+ /** Options accepted by server.start. */
45
+ export type StartOptions = {
46
+ readonly transport: 'stdio';
47
+ };
48
+ /** The handle returned by createSlideServer. */
49
+ export interface SlideServer {
50
+ /** The underlying MCP server. Exposed for advanced callers. */
51
+ readonly mcp: McpServer;
52
+ /** Tool definitions derived from the template. */
53
+ readonly tools: ReadonlyArray<DerivedTool>;
54
+ /** Connect to the given transport. Lower-level than start. */
55
+ connect(transport: Transport): Promise<void>;
56
+ /** Start serving over the configured transport. */
57
+ start(options: StartOptions): Promise<void>;
58
+ /** Close the server and disconnect any active transport. */
59
+ close(): Promise<void>;
60
+ }
61
+ /** Construct a template-locked MCP server. */
62
+ export declare const createSlideServer: (config: SlideServerConfig) => SlideServer;
63
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAG/E,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAErE,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wCAAwC;AACxC,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3D,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3C,8DAA8D;IAC9D,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,mDAAmD;IACnD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,4DAA4D;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,8CAA8C;AAC9C,eAAO,MAAM,iBAAiB,GAAI,QAAQ,iBAAiB,KAAG,WA4B7D,CAAC"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * The template-agnostic MCP server framework.
3
+ *
4
+ * createSlideServer({ template, runtime }) builds an McpServer that exposes
5
+ * three kinds of tools:
6
+ *
7
+ * 1. **`slides_list`** — returns the list of slide types the loaded template
8
+ * supports, with descriptions. One round-trip to discover the surface.
9
+ *
10
+ * 2. **One tool per slide type**, named `<toolPrefix><snake_case>` (default
11
+ * prefix `slides_add_`). Validates user-supplied props against the
12
+ * component's Zod schema and echoes them back as a slide spec. Used
13
+ * iteratively by an LLM to assemble a deck before calling `slides_create`.
14
+ *
15
+ * 3. **`slides_create`** — full pipeline. Takes `{ title, slides }`, renders
16
+ * via the reconciler, applies through the PPTX runtime, writes the .pptx
17
+ * file to disk, and returns the path.
18
+ */
19
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
20
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
21
+ import { z } from 'zod';
22
+ import { errorResult, zodErrorResult } from './errors.js';
23
+ import { renderSlides } from './render.js';
24
+ import { deriveComponentTools } from './schema.js';
25
+ /** Construct a template-locked MCP server. */
26
+ export const createSlideServer = (config) => {
27
+ const { template, runtime } = config;
28
+ const serverInfo = config.serverInfo ?? {
29
+ name: 'react-pptx-mcp:' + template.name,
30
+ version: '0.1.0',
31
+ };
32
+ const mcp = new McpServer(serverInfo);
33
+ const tools = deriveComponentTools(template, config.toolPrefix);
34
+ registerListTool(mcp, template, tools);
35
+ registerComponentTools(mcp, tools);
36
+ registerCreateTool(mcp, runtime, template);
37
+ return {
38
+ mcp,
39
+ tools,
40
+ connect: (transport) => mcp.connect(transport),
41
+ start: async (options) => {
42
+ switch (options.transport) {
43
+ case 'stdio': {
44
+ await mcp.connect(new StdioServerTransport());
45
+ return;
46
+ }
47
+ }
48
+ },
49
+ close: () => mcp.close(),
50
+ };
51
+ };
52
+ // ---------------------------------------------------------------------------
53
+ // slides_list
54
+ // ---------------------------------------------------------------------------
55
+ const LIST_OUTPUT_SHAPE = {
56
+ template: z.string().describe('The name of the loaded template.'),
57
+ slides: z
58
+ .array(z.object({
59
+ name: z.string().describe('Slide-type name, e.g. "Cover".'),
60
+ toolName: z.string().describe('MCP tool name for this slide type.'),
61
+ description: z.string().describe('When to use this slide type.'),
62
+ }))
63
+ .describe('Every slide type the template exposes.'),
64
+ };
65
+ const registerListTool = (mcp, template, tools) => {
66
+ mcp.registerTool('slides_list', {
67
+ description: 'List every slide type this template supports, with descriptions and the per-type tool names. ' +
68
+ 'Call once at the start of a deck-building session to learn the surface.',
69
+ outputSchema: LIST_OUTPUT_SHAPE,
70
+ annotations: {
71
+ readOnlyHint: true,
72
+ destructiveHint: false,
73
+ idempotentHint: true,
74
+ openWorldHint: false,
75
+ },
76
+ }, async () => {
77
+ const slides = tools.map((t) => ({
78
+ name: t.componentName,
79
+ toolName: t.name,
80
+ description: t.description,
81
+ }));
82
+ const lines = [
83
+ `Template: ${template.name}`,
84
+ '',
85
+ 'Available slide types:',
86
+ ...slides.map((s) => ` • ${s.name} (${s.toolName}) — ${s.description}`),
87
+ '',
88
+ 'Call slides_add_<type> to validate a single slide. ' +
89
+ 'Call slides_create with an array of slide specs to write a .pptx file.',
90
+ ].join('\n');
91
+ return {
92
+ content: [{ type: 'text', text: lines }],
93
+ structuredContent: { template: template.name, slides },
94
+ };
95
+ });
96
+ };
97
+ // ---------------------------------------------------------------------------
98
+ // slides_add_<component>
99
+ // ---------------------------------------------------------------------------
100
+ const COMPONENT_OUTPUT_SHAPE = {
101
+ slide: z
102
+ .object({
103
+ component: z.string(),
104
+ props: z.record(z.unknown()),
105
+ })
106
+ .describe('A single validated slide spec, ready to be passed to slides_create.'),
107
+ };
108
+ const registerComponentTools = (mcp, tools) => {
109
+ for (const tool of tools) {
110
+ mcp.registerTool(tool.name, {
111
+ description: tool.description,
112
+ inputSchema: tool.inputShape,
113
+ outputSchema: COMPONENT_OUTPUT_SHAPE,
114
+ annotations: {
115
+ readOnlyHint: true,
116
+ destructiveHint: false,
117
+ idempotentHint: true,
118
+ openWorldHint: false,
119
+ },
120
+ }, async (rawProps) => {
121
+ const parsed = tool.inputSchema.safeParse(rawProps);
122
+ if (!parsed.success) {
123
+ return zodErrorResult(`Validation error in ${tool.name} props:`, parsed.error, "Refer to this tool's input schema and retry.");
124
+ }
125
+ return {
126
+ content: [
127
+ {
128
+ type: 'text',
129
+ text: `Validated ${tool.componentName} props. ` +
130
+ `Pass { component: "${tool.componentName}", props: <these> } ` +
131
+ `as one entry of slides_create.slides.`,
132
+ },
133
+ ],
134
+ structuredContent: {
135
+ slide: { component: tool.componentName, props: parsed.data },
136
+ },
137
+ };
138
+ });
139
+ }
140
+ };
141
+ // ---------------------------------------------------------------------------
142
+ // slides_create
143
+ // ---------------------------------------------------------------------------
144
+ const SLIDE_SPEC_SCHEMA = z
145
+ .object({
146
+ component: z.string().min(1).describe('The slide-type name, e.g. "Cover".'),
147
+ props: z
148
+ .record(z.unknown())
149
+ .describe("Props matching that slide type's input schema (see slides_add_<type>)."),
150
+ })
151
+ .describe('One slide to add. Same shape as the structuredContent of slides_add_<type>.');
152
+ const CREATE_INPUT_SHAPE = {
153
+ title: z.string().min(1).describe('Deck title — used as the .pptx filename stem.'),
154
+ slides: z.array(SLIDE_SPEC_SCHEMA).min(1).describe('The slides to write, in order.'),
155
+ };
156
+ const CREATE_OUTPUT_SHAPE = {
157
+ filePath: z.string().describe('Absolute path to the generated .pptx file.'),
158
+ slideCount: z.number().int().nonnegative(),
159
+ };
160
+ const registerCreateTool = (mcp, runtime, template) => {
161
+ mcp.registerTool('slides_create', {
162
+ description: 'Generate a template-locked .pptx presentation from a sequence of slide specs and write it to disk. ' +
163
+ 'Returns the absolute file path. Each spec is { component, props } — ' +
164
+ 'use the per-type slides_add_<type> tools first to discover schemas and validate props.',
165
+ inputSchema: CREATE_INPUT_SHAPE,
166
+ outputSchema: CREATE_OUTPUT_SHAPE,
167
+ annotations: {
168
+ readOnlyHint: false,
169
+ destructiveHint: false,
170
+ idempotentHint: false,
171
+ openWorldHint: false,
172
+ },
173
+ }, async (input) => {
174
+ const result = await renderSlides({
175
+ template,
176
+ runtime,
177
+ title: input.title,
178
+ slides: input.slides,
179
+ });
180
+ if (result.ok) {
181
+ const slideWord = result.slideCount === 1 ? 'slide' : 'slides';
182
+ return {
183
+ content: [
184
+ {
185
+ type: 'text',
186
+ text: `Wrote ${result.slideCount} ${slideWord} to ${result.filePath}.`,
187
+ },
188
+ ],
189
+ structuredContent: { filePath: result.filePath, slideCount: result.slideCount },
190
+ };
191
+ }
192
+ const hint = result.code === 'validation_error' ? ' Fix the listed fields and retry slides_create.' : '';
193
+ return errorResult(result.code, result.message + hint, result.issues);
194
+ });
195
+ };
196
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Programmatic scaffolder. The `slidesctl scaffold <dir>` subcommand wraps
3
+ * this; the same API is exposed at `@sanity-labs/slides/scaffold` so it can
4
+ * be driven by other tooling.
5
+ *
6
+ * The scaffold stamps every file under `template-base/` into the target
7
+ * directory, applying `__NAME__` / `__IDENT__` substitutions and renaming
8
+ * the `_gitignore` placeholder back to `.gitignore`.
9
+ */
10
+ export type ScaffoldOptions = {
11
+ /** Target directory; created if missing. Must be empty if it exists. */
12
+ readonly target: string;
13
+ /** Template name (used as the package name + Template `name` field). */
14
+ readonly name: string;
15
+ };
16
+ export type ScaffoldResult = {
17
+ readonly targetPath: string;
18
+ readonly fileCount: number;
19
+ };
20
+ /**
21
+ * Stamp the template-base into `target`, applying the substitutions.
22
+ *
23
+ * Throws if `target` exists and is non-empty.
24
+ */
25
+ export declare const scaffoldTemplate: (options: ScaffoldOptions) => ScaffoldResult;
26
+ /**
27
+ * Convert a kebab-case template name into a camelCase JS identifier. Used
28
+ * as the `__IDENT__` substitution in stamped files (e.g. the exported
29
+ * `Template` const).
30
+ */
31
+ export declare const toIdentifier: (name: string) => string;
32
+ /**
33
+ * Validate a template name. Returns an error message string when invalid,
34
+ * `undefined` when ok. Used by interactive prompts.
35
+ */
36
+ export declare const validateName: (value: string) => string | undefined;
37
+ /** Infer a default template name from a target path. */
38
+ export declare const defaultName: (target: string) => string;
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,MAAM,eAAe,GAAG;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,eAAe,KAAG,cAU3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MACqB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,SAMrD,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,KAAG,MAG5C,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Programmatic scaffolder. The `slidesctl scaffold <dir>` subcommand wraps
3
+ * this; the same API is exposed at `@sanity-labs/slides/scaffold` so it can
4
+ * be driven by other tooling.
5
+ *
6
+ * The scaffold stamps every file under `template-base/` into the target
7
+ * directory, applying `__NAME__` / `__IDENT__` substitutions and renaming
8
+ * the `_gitignore` placeholder back to `.gitignore`.
9
+ */
10
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
11
+ import { dirname, join, resolve as resolvePath } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ const HERE = dirname(fileURLToPath(import.meta.url));
14
+ const TEMPLATE_BASE = resolvePath(HERE, 'template-base');
15
+ /**
16
+ * Stamp the template-base into `target`, applying the substitutions.
17
+ *
18
+ * Throws if `target` exists and is non-empty.
19
+ */
20
+ export const scaffoldTemplate = (options) => {
21
+ const targetPath = resolvePath(process.cwd(), options.target);
22
+ if (existsSync(targetPath) && readdirSync(targetPath).length > 0) {
23
+ throw new Error(`Target directory "${targetPath}" already exists and is not empty.`);
24
+ }
25
+ copyTemplate(TEMPLATE_BASE, targetPath, {
26
+ __NAME__: options.name,
27
+ __IDENT__: toIdentifier(options.name),
28
+ });
29
+ return { targetPath, fileCount: countFiles(targetPath) };
30
+ };
31
+ /**
32
+ * Convert a kebab-case template name into a camelCase JS identifier. Used
33
+ * as the `__IDENT__` substitution in stamped files (e.g. the exported
34
+ * `Template` const).
35
+ */
36
+ export const toIdentifier = (name) => name.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
37
+ /**
38
+ * Validate a template name. Returns an error message string when invalid,
39
+ * `undefined` when ok. Used by interactive prompts.
40
+ */
41
+ export const validateName = (value) => {
42
+ if (!value)
43
+ return 'Required';
44
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(value)) {
45
+ return 'Must start with a letter or digit and contain only [a-z0-9-].';
46
+ }
47
+ return undefined;
48
+ };
49
+ /** Infer a default template name from a target path. */
50
+ export const defaultName = (target) => {
51
+ const last = (target ?? './my-template').split('/').filter(Boolean).pop() ?? 'my-template';
52
+ return last.replace(/[^a-z0-9-]/gi, '-').toLowerCase();
53
+ };
54
+ const copyTemplate = (src, dst, replacements) => {
55
+ mkdirSync(dst, { recursive: true });
56
+ for (const entry of readdirSync(src)) {
57
+ const srcEntry = join(src, entry);
58
+ const dstEntry = join(dst, denormaliseFilename(entry));
59
+ if (statSync(srcEntry).isDirectory()) {
60
+ copyTemplate(srcEntry, dstEntry, replacements);
61
+ continue;
62
+ }
63
+ writeFileSync(dstEntry, applyReplacements(readFileSync(srcEntry, 'utf8'), replacements));
64
+ }
65
+ };
66
+ const denormaliseFilename = (name) => (name === '_gitignore' ? '.gitignore' : name);
67
+ const applyReplacements = (content, replacements) => {
68
+ let out = content;
69
+ for (const [from, to] of Object.entries(replacements))
70
+ out = out.split(from).join(to);
71
+ return out;
72
+ };
73
+ const countFiles = (dir) => {
74
+ let n = 0;
75
+ for (const entry of readdirSync(dir)) {
76
+ const full = join(dir, entry);
77
+ if (statSync(full).isDirectory())
78
+ n += countFiles(full);
79
+ else
80
+ n += 1;
81
+ }
82
+ return n;
83
+ };
84
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ # **NAME**
2
+
3
+ A react-pptx template. The brand lives in JSX; an LLM (Claude, anything that
4
+ speaks MCP) drives it through the generic `react-pptx-mcp` server without
5
+ ever touching fonts, colors, or layout.
6
+
7
+ ## Develop
8
+
9
+ ```bash
10
+ pnpm install
11
+ pnpm dev
12
+ ```
13
+
14
+ Opens the hot-reloading viewer at <http://localhost:5173>. Edit anything
15
+ under `src/` and the page updates.
16
+
17
+ ## Anatomy
18
+
19
+ ```
20
+ src/
21
+ ├── index.ts # Template value — tokens, fonts, components map
22
+ ├── preview.tsx # Canonical slide order shown in the viewer
23
+ └── components/ # Slide components, each one a Zod schema + JSX
24
+ ```
25
+
26
+ The Zod schema on every component is what Claude sees as the tool input
27
+ schema. Field descriptions become the LLM-facing documentation. Drop a
28
+ new component into `src/components/` and `defineTemplateComponent({...})`
29
+ in `src/index.ts` — that's the entire authoring loop.
30
+
31
+ ## Generate a deck from the CLI
32
+
33
+ After editing, build once and then invoke the generic CLI against your
34
+ template:
35
+
36
+ ```bash
37
+ pnpm build
38
+ echo '{
39
+ "title": "Q2 Review",
40
+ "slides": [{ "component": "Cover", "props": { "title": "Q2 Review" } }]
41
+ }' | pnpm generate --output ~/Desktop
42
+ # /Users/you/Desktop/Q2-Review.pptx
43
+ ```
44
+
45
+ `pnpm generate` is a thin wrapper around `react-pptx-mcp generate --template
46
+ ./dist/index.js`.
47
+
48
+ ## Plug this template into Claude Desktop
49
+
50
+ No global install. No per-template binary. Use `npx` so Claude pulls the
51
+ generic MCP server straight from npm.
52
+
53
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`
54
+ (or the equivalent on your OS):
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "__NAME__-slides": {
60
+ "command": "npx",
61
+ "args": [
62
+ "-y",
63
+ "react-pptx-mcp",
64
+ "serve",
65
+ "--template",
66
+ "/absolute/path/to/__NAME__/dist/index.js",
67
+ "--output",
68
+ "/Users/you/Desktop"
69
+ ]
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ Restart Claude. Three tools appear, auto-derived from this template:
76
+
77
+ | Tool | Purpose |
78
+ | ------------------- | ---------------------------------------------------------------- |
79
+ | `slides_list` | Lists every slide type, with descriptions. |
80
+ | `slides_add_<type>` | Validates a single slide's props against the Zod schema. |
81
+ | `slides_create` | Takes `{ title, slides }`, writes the `.pptx`, returns the path. |
82
+
83
+ Ask Claude:
84
+
85
+ > "Make me a 5-slide Q2 review deck with this template."
86
+
87
+ Whenever you edit the template, run `pnpm build` and Claude will pick up
88
+ the changes on its next request.
89
+
90
+ ### Want Claude to know the conventions up front?
91
+
92
+ Drop the bundled skill into your Claude project. Print it with:
93
+
94
+ ```bash
95
+ npx react-pptx-mcp skill
96
+ ```
97
+
98
+ …and paste into your Claude project's knowledge sources.
99
+
100
+ ## API in 30 seconds
101
+
102
+ ```ts
103
+ import { defineTemplate, defineTemplateComponent, CANVAS_16_9 } from 'react-pptx';
104
+ import { Cover, CoverSchema } from './components/Cover.js';
105
+ import { preview } from './preview.js';
106
+
107
+ export const __IDENT__ = defineTemplate({
108
+ name: '__NAME__',
109
+ canvas: CANVAS_16_9,
110
+ fonts: { display: ['Inter'], body: ['Inter'], mono: ['IBM Plex Mono'] },
111
+ colors: {},
112
+ typography: {},
113
+ spacing: {},
114
+ components: {
115
+ Cover: defineTemplateComponent({
116
+ component: Cover,
117
+ schema: CoverSchema,
118
+ description: 'Use as the first slide of a deck.',
119
+ }),
120
+ },
121
+ preview,
122
+ });
123
+ ```
124
+
125
+ Add a new component:
126
+
127
+ 1. Create `src/components/MySlide.tsx` exporting a Zod schema and a React
128
+ component. Keep all styling token-locked through your tokens map.
129
+ 2. Register it in `src/index.ts` under `components` with a clear
130
+ description (LLMs read it).
131
+ 3. Add a sample call in `src/preview.tsx` so the viewer shows it.
132
+
133
+ Run `pnpm build` and the new component appears as `slides_add_my_slide` the
134
+ next time Claude talks to your MCP server.
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ *.tsbuildinfo
4
+ .vite
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "__NAME__",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "A react-pptx template.",
6
+ "type": "module",
7
+ "main": "./src/index.ts",
8
+ "types": "./src/index.ts",
9
+ "files": [
10
+ "dist",
11
+ "src"
12
+ ],
13
+ "scripts": {
14
+ "dev": "slides-dev",
15
+ "build": "tsc -p tsconfig.build.json",
16
+ "typecheck": "tsc --noEmit -p tsconfig.json",
17
+ "serve": "react-pptx-mcp serve --template ./dist/index.js",
18
+ "generate": "react-pptx-mcp generate --template ./dist/index.js"
19
+ },
20
+ "peerDependencies": {
21
+ "react": "^19.0.0",
22
+ "react-pptx": "^0.0.0"
23
+ },
24
+ "dependencies": {
25
+ "zod": "^3.23.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/react": "^19.0.0",
29
+ "react": "19.2.5",
30
+ "react-pptx": "^0.0.0",
31
+ "react-pptx-dev": "^0.0.0",
32
+ "react-pptx-mcp": "^0.0.0",
33
+ "typescript": "^5.5.0"
34
+ }
35
+ }
@@ -0,0 +1,30 @@
1
+ import type { ReactElement } from 'react';
2
+ import { Slide, Box, Text } from '../../../../core/index.js';
3
+ import { z } from 'zod';
4
+
5
+ export const CoverSchema = z
6
+ .object({
7
+ title: z.string().min(1).describe('The deck title.'),
8
+ subtitle: z.string().optional().describe('Optional subtitle.'),
9
+ })
10
+ .strict();
11
+
12
+ type CoverProps = z.infer<typeof CoverSchema>;
13
+
14
+ export const Cover = ({ title, subtitle }: CoverProps): ReactElement => (
15
+ <Slide>
16
+ <Box rect={{ x: 0, y: 0, w: 960, h: 540 }} fill={{ kind: 'solid', color: '#0b0b0b' }} />
17
+ <Box rect={{ x: 60, y: 200, w: 800, h: 120 }}>
18
+ <Text textStyle={{ fontFamily: 'display', fontSize: 64, foregroundColor: '#ffffff' }}>
19
+ {title}
20
+ </Text>
21
+ </Box>
22
+ {subtitle ? (
23
+ <Box rect={{ x: 60, y: 320, w: 800, h: 40 }}>
24
+ <Text textStyle={{ fontFamily: 'body', fontSize: 20, foregroundColor: '#cccccc' }}>
25
+ {subtitle}
26
+ </Text>
27
+ </Box>
28
+ ) : null}
29
+ </Slide>
30
+ );
@@ -0,0 +1,27 @@
1
+ import { CANVAS_16_9, defineTemplate, defineTemplateComponent } from '../../../core/index.js';
2
+ import { Cover, CoverSchema } from './components/Cover.js';
3
+ import { preview } from './preview.js';
4
+
5
+ export const __IDENT__ = defineTemplate({
6
+ name: '__NAME__',
7
+ canvas: CANVAS_16_9,
8
+ fonts: {
9
+ display: ['Inter', 'Arial'],
10
+ body: ['Inter', 'Arial'],
11
+ mono: ['IBM Plex Mono', 'Courier New'],
12
+ },
13
+ colors: {
14
+ 'fg.base': '#0b0b0b',
15
+ 'bg.surface': '#ffffff',
16
+ },
17
+ typography: {},
18
+ spacing: { md: 12, lg: 24 },
19
+ components: {
20
+ Cover: defineTemplateComponent({
21
+ component: Cover,
22
+ schema: CoverSchema,
23
+ description: 'Use as the first slide of a deck. Sets the title.',
24
+ }),
25
+ },
26
+ preview,
27
+ });
@@ -0,0 +1,9 @@
1
+ import type { ReactElement } from 'react';
2
+ import { Cover } from './components/Cover.js';
3
+
4
+ export const preview = (): ReactElement => (
5
+ <>
6
+ <Cover title="Hello, __NAME__" subtitle="A react-pptx template." />
7
+ <Cover title="Edit me" subtitle="src/preview.tsx" />
8
+ </>
9
+ );