pptx-react-viewer 3.21.0 → 4.1.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 (188) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/{AiChatPanel-UD756KAU.mjs → AiChatPanel-C3ACRWOY.mjs} +4 -4
  3. package/dist/AiChatPanel-C3ACRWOY.mjs.br +0 -0
  4. package/dist/AiChatPanel-C3ACRWOY.mjs.gz +0 -0
  5. package/dist/{AiChatPanel-B3QM7MIC.js → AiChatPanel-GQNSKMP6.js} +25 -25
  6. package/dist/AiChatPanel-GQNSKMP6.js.br +0 -0
  7. package/dist/AiChatPanel-GQNSKMP6.js.gz +0 -0
  8. package/dist/{Area3DChartScene-435BFPLY.js → Area3DChartScene-3I6KB2DN.js} +2 -2
  9. package/dist/{Area3DChartScene-435BFPLY.js.br → Area3DChartScene-3I6KB2DN.js.br} +0 -0
  10. package/dist/Area3DChartScene-3I6KB2DN.js.gz +0 -0
  11. package/dist/{Area3DChartScene-MQKUWVMS.mjs → Area3DChartScene-4TPNRYXS.mjs} +1 -1
  12. package/dist/Area3DChartScene-4TPNRYXS.mjs.br +0 -0
  13. package/dist/Area3DChartScene-4TPNRYXS.mjs.gz +0 -0
  14. package/dist/{Bar3DChartScene-D4GMQGPN.mjs → Bar3DChartScene-V45IUIT7.mjs} +1 -1
  15. package/dist/Bar3DChartScene-V45IUIT7.mjs.br +0 -0
  16. package/dist/Bar3DChartScene-V45IUIT7.mjs.gz +0 -0
  17. package/dist/{Bar3DChartScene-KEYLVYJA.js → Bar3DChartScene-ZSCATOYF.js} +2 -2
  18. package/dist/Bar3DChartScene-ZSCATOYF.js.br +0 -0
  19. package/dist/Bar3DChartScene-ZSCATOYF.js.gz +0 -0
  20. package/dist/{Line3DChartScene-B3AWFXE4.mjs → Line3DChartScene-DCQJEZK6.mjs} +1 -1
  21. package/dist/Line3DChartScene-DCQJEZK6.mjs.br +0 -0
  22. package/dist/Line3DChartScene-DCQJEZK6.mjs.gz +0 -0
  23. package/dist/{Line3DChartScene-JYGXLE56.js → Line3DChartScene-DK55LQ2D.js} +2 -2
  24. package/dist/{Line3DChartScene-JYGXLE56.js.br → Line3DChartScene-DK55LQ2D.js.br} +0 -0
  25. package/dist/Line3DChartScene-DK55LQ2D.js.gz +0 -0
  26. package/dist/{Model3DScene-JF5J6N6W.js → Model3DScene-2WNP4XBP.js} +2 -2
  27. package/dist/Model3DScene-2WNP4XBP.js.br +0 -0
  28. package/dist/Model3DScene-2WNP4XBP.js.gz +0 -0
  29. package/dist/{Model3DScene-4TG4YRVM.mjs → Model3DScene-SA5XMR2D.mjs} +1 -1
  30. package/dist/Model3DScene-SA5XMR2D.mjs.br +0 -0
  31. package/dist/Model3DScene-SA5XMR2D.mjs.gz +0 -0
  32. package/dist/{PieChart3DScene-4BQ6PR7P.mjs → PieChart3DScene-HC2ZWL42.mjs} +1 -1
  33. package/dist/PieChart3DScene-HC2ZWL42.mjs.br +0 -0
  34. package/dist/PieChart3DScene-HC2ZWL42.mjs.gz +0 -0
  35. package/dist/{PieChart3DScene-CCQWSH3W.js → PieChart3DScene-Q75D66HS.js} +2 -2
  36. package/dist/{PieChart3DScene-CCQWSH3W.js.br → PieChart3DScene-Q75D66HS.js.br} +0 -0
  37. package/dist/PieChart3DScene-Q75D66HS.js.gz +0 -0
  38. package/dist/{SmartArt3DScene-QZGIABOK.mjs → SmartArt3DScene-D4VNNPHS.mjs} +124 -19
  39. package/dist/SmartArt3DScene-D4VNNPHS.mjs.br +0 -0
  40. package/dist/SmartArt3DScene-D4VNNPHS.mjs.gz +0 -0
  41. package/dist/{SmartArt3DScene-T236GYUT.js → SmartArt3DScene-NHD7CZJ5.js} +123 -18
  42. package/dist/SmartArt3DScene-NHD7CZJ5.js.br +0 -0
  43. package/dist/SmartArt3DScene-NHD7CZJ5.js.gz +0 -0
  44. package/dist/{SurfaceChart3DScene-FRQC5HBG.mjs → SurfaceChart3DScene-JRMX4PN5.mjs} +1 -1
  45. package/dist/SurfaceChart3DScene-JRMX4PN5.mjs.br +0 -0
  46. package/dist/SurfaceChart3DScene-JRMX4PN5.mjs.gz +0 -0
  47. package/dist/{SurfaceChart3DScene-UVZPT6OD.js → SurfaceChart3DScene-ODS5E6ZG.js} +2 -2
  48. package/dist/{SurfaceChart3DScene-UVZPT6OD.js.br → SurfaceChart3DScene-ODS5E6ZG.js.br} +0 -0
  49. package/dist/SurfaceChart3DScene-ODS5E6ZG.js.gz +0 -0
  50. package/dist/{chunk-EJMDD4VV.mjs → chunk-25CABWCR.mjs} +131 -329
  51. package/dist/chunk-25CABWCR.mjs.br +0 -0
  52. package/dist/chunk-25CABWCR.mjs.gz +0 -0
  53. package/dist/{chunk-BXMPXKV5.mjs → chunk-3B6YIH4K.mjs} +626 -133
  54. package/dist/chunk-3B6YIH4K.mjs.br +0 -0
  55. package/dist/chunk-3B6YIH4K.mjs.gz +0 -0
  56. package/dist/{chunk-BFPIMU6Q.js → chunk-A6JKOHSV.js} +2143 -1644
  57. package/dist/chunk-A6JKOHSV.js.br +0 -0
  58. package/dist/chunk-A6JKOHSV.js.gz +0 -0
  59. package/dist/{chunk-TOOKJUPG.mjs → chunk-GRAARMUW.mjs} +1 -1
  60. package/dist/chunk-GRAARMUW.mjs.br +0 -0
  61. package/dist/chunk-GRAARMUW.mjs.gz +0 -0
  62. package/dist/{chunk-H7QPQ4OR.js → chunk-MQHMMB6V.js} +5 -5
  63. package/dist/chunk-MQHMMB6V.js.br +0 -0
  64. package/dist/chunk-MQHMMB6V.js.gz +0 -0
  65. package/dist/{chunk-M6QJKPU2.js → chunk-NR4MQJM5.js} +1961 -2161
  66. package/dist/chunk-NR4MQJM5.js.br +0 -0
  67. package/dist/chunk-NR4MQJM5.js.gz +0 -0
  68. package/dist/{chunk-M24DEOP6.js → chunk-NXGUR2DO.js} +2 -0
  69. package/dist/chunk-NXGUR2DO.js.br +0 -0
  70. package/dist/chunk-NXGUR2DO.js.gz +0 -0
  71. package/dist/{chunk-R664EPDC.mjs → chunk-PC7H3C5W.mjs} +2 -0
  72. package/dist/chunk-PC7H3C5W.mjs.br +0 -0
  73. package/dist/chunk-PC7H3C5W.mjs.gz +0 -0
  74. package/dist/{chunk-SUZIFHXI.js → chunk-PUALTXTU.js} +182 -182
  75. package/dist/chunk-PUALTXTU.js.br +0 -0
  76. package/dist/chunk-PUALTXTU.js.gz +0 -0
  77. package/dist/{chunk-TMTQJAGK.mjs → chunk-Q6QJOD56.mjs} +2307 -552
  78. package/dist/chunk-Q6QJOD56.mjs.br +0 -0
  79. package/dist/chunk-Q6QJOD56.mjs.gz +0 -0
  80. package/dist/{chunk-T6V342NP.js → chunk-SK2CZQ6P.js} +2313 -551
  81. package/dist/chunk-SK2CZQ6P.js.br +0 -0
  82. package/dist/chunk-SK2CZQ6P.js.gz +0 -0
  83. package/dist/{chunk-HZEOZUUH.mjs → chunk-WLWAYLL6.mjs} +2 -2
  84. package/dist/chunk-WLWAYLL6.mjs.br +0 -0
  85. package/dist/chunk-WLWAYLL6.mjs.gz +0 -0
  86. package/dist/i18n/de.cjs +2 -0
  87. package/dist/i18n/de.cjs.br +0 -0
  88. package/dist/i18n/de.cjs.gz +0 -0
  89. package/dist/i18n/de.mjs +2 -0
  90. package/dist/i18n/de.mjs.br +0 -0
  91. package/dist/i18n/de.mjs.gz +0 -0
  92. package/dist/i18n/es.cjs +2 -0
  93. package/dist/i18n/es.cjs.br +0 -0
  94. package/dist/i18n/es.cjs.gz +0 -0
  95. package/dist/i18n/es.mjs +2 -0
  96. package/dist/i18n/es.mjs.br +0 -0
  97. package/dist/i18n/es.mjs.gz +0 -0
  98. package/dist/i18n/fr.cjs +2 -0
  99. package/dist/i18n/fr.cjs.br +0 -0
  100. package/dist/i18n/fr.cjs.gz +0 -0
  101. package/dist/i18n/fr.mjs +2 -0
  102. package/dist/i18n/fr.mjs.br +0 -0
  103. package/dist/i18n/fr.mjs.gz +0 -0
  104. package/dist/i18n/zh-CN.cjs +2 -0
  105. package/dist/i18n/zh-CN.cjs.br +0 -0
  106. package/dist/i18n/zh-CN.cjs.gz +0 -0
  107. package/dist/i18n/zh-CN.mjs +2 -0
  108. package/dist/i18n/zh-CN.mjs.br +0 -0
  109. package/dist/i18n/zh-CN.mjs.gz +0 -0
  110. package/dist/i18n.js +4 -4
  111. package/dist/i18n.js.br +0 -0
  112. package/dist/i18n.js.gz +0 -0
  113. package/dist/i18n.mjs +1 -1
  114. package/dist/i18n.mjs.br +0 -0
  115. package/dist/i18n.mjs.gz +0 -0
  116. package/dist/index.d.ts +586 -7
  117. package/dist/index.js +52 -48
  118. package/dist/index.js.br +0 -0
  119. package/dist/index.js.gz +0 -0
  120. package/dist/index.mjs +6 -6
  121. package/dist/index.mjs.br +0 -0
  122. package/dist/index.mjs.gz +0 -0
  123. package/dist/internals.d.ts +447 -13
  124. package/dist/internals.js +105 -105
  125. package/dist/internals.js.br +0 -0
  126. package/dist/internals.js.gz +0 -0
  127. package/dist/internals.mjs +4 -4
  128. package/dist/internals.mjs.br +0 -0
  129. package/dist/internals.mjs.gz +0 -0
  130. package/dist/viewer/index.js +32 -32
  131. package/dist/viewer/index.js.br +0 -0
  132. package/dist/viewer/index.js.gz +0 -0
  133. package/dist/viewer/index.mjs +6 -6
  134. package/dist/viewer/index.mjs.br +0 -0
  135. package/dist/viewer/index.mjs.gz +0 -0
  136. package/package.json +2 -2
  137. package/dist/AiChatPanel-B3QM7MIC.js.br +0 -0
  138. package/dist/AiChatPanel-B3QM7MIC.js.gz +0 -0
  139. package/dist/AiChatPanel-UD756KAU.mjs.br +0 -0
  140. package/dist/AiChatPanel-UD756KAU.mjs.gz +0 -0
  141. package/dist/Area3DChartScene-435BFPLY.js.gz +0 -0
  142. package/dist/Area3DChartScene-MQKUWVMS.mjs.br +0 -0
  143. package/dist/Area3DChartScene-MQKUWVMS.mjs.gz +0 -0
  144. package/dist/Bar3DChartScene-D4GMQGPN.mjs.br +0 -0
  145. package/dist/Bar3DChartScene-D4GMQGPN.mjs.gz +0 -0
  146. package/dist/Bar3DChartScene-KEYLVYJA.js.br +0 -0
  147. package/dist/Bar3DChartScene-KEYLVYJA.js.gz +0 -0
  148. package/dist/Line3DChartScene-B3AWFXE4.mjs.br +0 -0
  149. package/dist/Line3DChartScene-B3AWFXE4.mjs.gz +0 -0
  150. package/dist/Line3DChartScene-JYGXLE56.js.gz +0 -0
  151. package/dist/Model3DScene-4TG4YRVM.mjs.br +0 -0
  152. package/dist/Model3DScene-4TG4YRVM.mjs.gz +0 -0
  153. package/dist/Model3DScene-JF5J6N6W.js.br +0 -0
  154. package/dist/Model3DScene-JF5J6N6W.js.gz +0 -0
  155. package/dist/PieChart3DScene-4BQ6PR7P.mjs.br +0 -0
  156. package/dist/PieChart3DScene-4BQ6PR7P.mjs.gz +0 -0
  157. package/dist/PieChart3DScene-CCQWSH3W.js.gz +0 -0
  158. package/dist/SmartArt3DScene-QZGIABOK.mjs.br +0 -0
  159. package/dist/SmartArt3DScene-QZGIABOK.mjs.gz +0 -0
  160. package/dist/SmartArt3DScene-T236GYUT.js.br +0 -0
  161. package/dist/SmartArt3DScene-T236GYUT.js.gz +0 -0
  162. package/dist/SurfaceChart3DScene-FRQC5HBG.mjs.br +0 -0
  163. package/dist/SurfaceChart3DScene-FRQC5HBG.mjs.gz +0 -0
  164. package/dist/SurfaceChart3DScene-UVZPT6OD.js.gz +0 -0
  165. package/dist/chunk-BFPIMU6Q.js.br +0 -0
  166. package/dist/chunk-BFPIMU6Q.js.gz +0 -0
  167. package/dist/chunk-BXMPXKV5.mjs.br +0 -0
  168. package/dist/chunk-BXMPXKV5.mjs.gz +0 -0
  169. package/dist/chunk-EJMDD4VV.mjs.br +0 -0
  170. package/dist/chunk-EJMDD4VV.mjs.gz +0 -0
  171. package/dist/chunk-H7QPQ4OR.js.br +0 -0
  172. package/dist/chunk-H7QPQ4OR.js.gz +0 -0
  173. package/dist/chunk-HZEOZUUH.mjs.br +0 -0
  174. package/dist/chunk-HZEOZUUH.mjs.gz +0 -0
  175. package/dist/chunk-M24DEOP6.js.br +0 -0
  176. package/dist/chunk-M24DEOP6.js.gz +0 -0
  177. package/dist/chunk-M6QJKPU2.js.br +0 -0
  178. package/dist/chunk-M6QJKPU2.js.gz +0 -0
  179. package/dist/chunk-R664EPDC.mjs.br +0 -0
  180. package/dist/chunk-R664EPDC.mjs.gz +0 -0
  181. package/dist/chunk-SUZIFHXI.js.br +0 -0
  182. package/dist/chunk-SUZIFHXI.js.gz +0 -0
  183. package/dist/chunk-T6V342NP.js.br +0 -0
  184. package/dist/chunk-T6V342NP.js.gz +0 -0
  185. package/dist/chunk-TMTQJAGK.mjs.br +0 -0
  186. package/dist/chunk-TMTQJAGK.mjs.gz +0 -0
  187. package/dist/chunk-TOOKJUPG.mjs.br +0 -0
  188. package/dist/chunk-TOOKJUPG.mjs.gz +0 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ A release listed with no entries carried no Conventional Commit in this package'
7
7
  scope: scripts/release-plan.mjs re-releases a package whenever any of its files
8
8
  change, not only on conventional ones.
9
9
 
10
+ ## [4.0.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-react-viewer@4.0.0) - 2026-09-18
11
+
12
+ ### Bug Fixes
13
+
14
+ - **core:** Switch to emf-converter's unified convertMetafileToDataUrl (by @ChristopherVR) ([70a2ea5](https://github.com/ChristopherVR/pptx-viewer/commit/70a2ea5059af31627dfa1f0a7ebe5e12219804bb))
15
+
16
+ ## [3.21.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-react-viewer@3.21.0) - 2026-09-17
17
+
18
+ ### Features
19
+
20
+ - **shared:** Support host-owned collaboration sessions (by @Sudhansh6) ([cd44eb3](https://github.com/ChristopherVR/pptx-viewer/commit/cd44eb3e79ff6d23e9b92d6f9b0a4eb4ea4f228e))
21
+ - **react:** Attach viewers to host collaboration sessions (by @Sudhansh6) ([ad55608](https://github.com/ChristopherVR/pptx-viewer/commit/ad556085dd83b7013fc5b92d7203b74bf4111f8a))
22
+
23
+ ### Bug Fixes
24
+
25
+ - **shared:** Preserve consecutive collaborative text breaks (by @Sudhansh6) ([10d1667](https://github.com/ChristopherVR/pptx-viewer/commit/10d1667b3b41cf650985324b2accf7b006bf53c1))
26
+ - **react:** Preserve the public provider awareness type (by @Sudhansh6) ([67d5120](https://github.com/ChristopherVR/pptx-viewer/commit/67d5120932665ee07a48256d92363fd8c8cb6688))
27
+ - **build:** Keep collaboration on the host Yjs runtime (by @Sudhansh6) ([1148601](https://github.com/ChristopherVR/pptx-viewer/commit/114860156b8a82967a85655464e7833bb0fd2644))
28
+ - **react:** Retain snapshots when host callbacks change (by @Sudhansh6) ([47e5751](https://github.com/ChristopherVR/pptx-viewer/commit/47e575159b7e7bfac84bcd7d0c514869e856173e))
29
+ - **react:** Honor external readiness before queued edits (by @Sudhansh6) ([dae37ed](https://github.com/ChristopherVR/pptx-viewer/commit/dae37ed9370d11f11f337e0192c15c7e26ded3cf))
30
+ - **shared:** Unify host session readiness and writeback (by @Sudhansh6) ([4635d01](https://github.com/ChristopherVR/pptx-viewer/commit/4635d01dd9f0d6cd48cfbd3f1ad9968acfd02906))
31
+ - **react:** Preserve accepted drafts when host readiness changes (by @Sudhansh6) ([b1c25cb](https://github.com/ChristopherVR/pptx-viewer/commit/b1c25cbc692f32f693e838ff0a21ca8c919655f4))
32
+
10
33
  ## [3.20.1](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-react-viewer@3.20.1) - 2026-09-17
11
34
 
12
35
  ### Bug Fixes
@@ -1,7 +1,7 @@
1
- import { deckIdFromBridge, isAiAvailable, createAiChatSession, toolCanvasTarget, createChatHistoryStore, focusTargetChips, isTwoTableFocus, mergeTablesDirective, humanizeDiffLine, buildDeckContext, describeToolActivity, summarizeToolArgs, toolLabel } from './chunk-TOOKJUPG.mjs';
2
- import { cn } from './chunk-HZEOZUUH.mjs';
3
- import './chunk-TMTQJAGK.mjs';
4
- import './chunk-R664EPDC.mjs';
1
+ import { deckIdFromBridge, isAiAvailable, createAiChatSession, toolCanvasTarget, createChatHistoryStore, focusTargetChips, isTwoTableFocus, mergeTablesDirective, humanizeDiffLine, buildDeckContext, describeToolActivity, summarizeToolArgs, toolLabel } from './chunk-GRAARMUW.mjs';
2
+ import { cn } from './chunk-WLWAYLL6.mjs';
3
+ import './chunk-Q6QJOD56.mjs';
4
+ import './chunk-PC7H3C5W.mjs';
5
5
  import './chunk-XGB3TDIC.mjs';
6
6
  import { useMemo, useRef, useState, useEffect, useReducer, useCallback } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
Binary file
Binary file
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkH7QPQ4OR_js = require('./chunk-H7QPQ4OR.js');
4
- var chunkSUZIFHXI_js = require('./chunk-SUZIFHXI.js');
5
- require('./chunk-T6V342NP.js');
6
- require('./chunk-M24DEOP6.js');
3
+ var chunkMQHMMB6V_js = require('./chunk-MQHMMB6V.js');
4
+ var chunkPUALTXTU_js = require('./chunk-PUALTXTU.js');
5
+ require('./chunk-SK2CZQ6P.js');
6
+ require('./chunk-NXGUR2DO.js');
7
7
  require('./chunk-4VNS5WPM.js');
8
8
  var react = require('react');
9
9
  var reactI18next = require('react-i18next');
@@ -23,7 +23,7 @@ function useAiChat(bridge, config) {
23
23
  setInitError(void 0);
24
24
  void (async () => {
25
25
  try {
26
- const available = await chunkH7QPQ4OR_js.isAiAvailable();
26
+ const available = await chunkMQHMMB6V_js.isAiAvailable();
27
27
  if (cancelled) {
28
28
  return;
29
29
  }
@@ -31,7 +31,7 @@ function useAiChat(bridge, config) {
31
31
  setState("unavailable");
32
32
  return;
33
33
  }
34
- const built = await chunkH7QPQ4OR_js.createAiChatSession(bridge, configRef.current);
34
+ const built = await chunkMQHMMB6V_js.createAiChatSession(bridge, configRef.current);
35
35
  if (cancelled) {
36
36
  return;
37
37
  }
@@ -137,7 +137,7 @@ function withDeckContext(inner, bridge, strategy) {
137
137
  }
138
138
  let context = "";
139
139
  try {
140
- context = await chunkH7QPQ4OR_js.buildDeckContext(bridge, { strategy, focus: {} });
140
+ context = await chunkMQHMMB6V_js.buildDeckContext(bridge, { strategy, focus: {} });
141
141
  } catch {
142
142
  context = "";
143
143
  }
@@ -200,7 +200,7 @@ function useAiConversation(useChat, session, config, bridge, options = {}) {
200
200
  continue;
201
201
  }
202
202
  seen.add(call.toolCallId);
203
- onToolTargetRef.current?.(chunkH7QPQ4OR_js.toolCanvasTarget(call.toolName, call.input));
203
+ onToolTargetRef.current?.(chunkMQHMMB6V_js.toolCanvasTarget(call.toolName, call.input));
204
204
  }
205
205
  }, [chat.messages]);
206
206
  const send = react.useCallback(
@@ -276,7 +276,7 @@ function deriveTitle(messages) {
276
276
  }
277
277
  function useAiHistory(input) {
278
278
  const { deckId, messages, setMessages } = input;
279
- const store = react.useMemo(() => input.store ?? chunkH7QPQ4OR_js.createChatHistoryStore(), [input.store]);
279
+ const store = react.useMemo(() => input.store ?? chunkMQHMMB6V_js.createChatHistoryStore(), [input.store]);
280
280
  const [activeChatId, setActiveChatId] = react.useState(newChatId);
281
281
  const [chats, setChats] = react.useState([]);
282
282
  const createdAtRef = react.useRef(Date.now());
@@ -419,7 +419,7 @@ function AiComposer({
419
419
  disabled: value.trim().length === 0,
420
420
  title: t("pptx.ai.send"),
421
421
  "aria-label": t("pptx.ai.send"),
422
- className: chunkSUZIFHXI_js.cn(
422
+ className: chunkPUALTXTU_js.cn(
423
423
  "shrink-0 rounded-sm p-1.5 transition-colors",
424
424
  value.trim().length === 0 ? "text-muted-foreground/50" : "bg-primary text-primary-foreground hover:bg-primary/90"
425
425
  ),
@@ -442,15 +442,15 @@ function AiFocusBar({
442
442
  onClearPicks
443
443
  }) {
444
444
  const { t } = reactI18next.useTranslation();
445
- const chips = chunkH7QPQ4OR_js.focusTargetChips(targets, slides);
446
- const twoTables = chunkH7QPQ4OR_js.isTwoTableFocus(targets, slides);
445
+ const chips = chunkMQHMMB6V_js.focusTargetChips(targets, slides);
446
+ const twoTables = chunkMQHMMB6V_js.isTwoTableFocus(targets, slides);
447
447
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border bg-secondary/30", children: [
448
448
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1 px-2.5 py-1.5", children: [
449
449
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("pptx.ai.focusScope") }),
450
450
  chips.map((chip) => /* @__PURE__ */ jsxRuntime.jsx(
451
451
  "span",
452
452
  {
453
- className: chunkSUZIFHXI_js.cn(
453
+ className: chunkPUALTXTU_js.cn(
454
454
  "inline-flex max-w-[10rem] items-center rounded-full px-2 py-0.5 text-[11px]",
455
455
  hasPicks || isPinned ? "bg-primary/15 text-primary" : "bg-muted text-muted-foreground"
456
456
  ),
@@ -466,7 +466,7 @@ function AiFocusBar({
466
466
  {
467
467
  type: "button",
468
468
  onClick: () => onSendDirective(
469
- chunkH7QPQ4OR_js.mergeTablesDirective(
469
+ chunkMQHMMB6V_js.mergeTablesDirective(
470
470
  twoTables.slideIndex,
471
471
  twoTables.elementIdA,
472
472
  twoTables.elementIdB
@@ -487,7 +487,7 @@ function AiFocusBar({
487
487
  title: t("pptx.ai.pickElement"),
488
488
  "aria-label": t("pptx.ai.pickAria"),
489
489
  "aria-pressed": pickMode,
490
- className: chunkSUZIFHXI_js.cn(
490
+ className: chunkPUALTXTU_js.cn(
491
491
  "rounded-sm p-1 max-md:min-w-[44px]! max-md:min-h-[44px]! flex items-center justify-center",
492
492
  pickMode ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent"
493
493
  ),
@@ -566,7 +566,7 @@ function AiHistoryList({ chats, activeChatId, onResume, onDelete }) {
566
566
  {
567
567
  type: "button",
568
568
  onClick: () => onResume(chat.id),
569
- className: chunkSUZIFHXI_js.cn(
569
+ className: chunkPUALTXTU_js.cn(
570
570
  "flex min-w-0 flex-1 items-start gap-2 rounded-sm px-2 py-1.5 text-left hover:bg-accent",
571
571
  chat.id === activeChatId && "bg-accent/60"
572
572
  ),
@@ -721,26 +721,26 @@ function AiToolCallCard({ part }) {
721
721
  const failed = part.state === "output-error";
722
722
  const done = part.state === "output-available";
723
723
  const running = !failed && !done;
724
- const activity = chunkH7QPQ4OR_js.describeToolActivity(part.toolName, part.input, running ? "present" : "past");
724
+ const activity = chunkMQHMMB6V_js.describeToolActivity(part.toolName, part.input, running ? "present" : "past");
725
725
  const Icon = ICONS[activity.icon] ?? lu.LuWrench;
726
- const rawSummary = chunkH7QPQ4OR_js.summarizeToolArgs(part.input);
726
+ const rawSummary = chunkMQHMMB6V_js.summarizeToolArgs(part.input);
727
727
  const statusLabel = failed ? t("pptx.ai.toolFailed") : done ? t("pptx.ai.toolDone") : t("pptx.ai.toolRunning");
728
728
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[12px]", children: [
729
729
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
730
730
  /* @__PURE__ */ jsxRuntime.jsx(
731
731
  Icon,
732
732
  {
733
- className: chunkSUZIFHXI_js.cn(
733
+ className: chunkPUALTXTU_js.cn(
734
734
  "w-3.5 h-3.5 shrink-0",
735
735
  failed ? "text-destructive" : "text-muted-foreground"
736
736
  )
737
737
  }
738
738
  ),
739
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkSUZIFHXI_js.cn("truncate", failed ? "text-destructive" : "text-foreground"), children: activity.label }),
739
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkPUALTXTU_js.cn("truncate", failed ? "text-destructive" : "text-foreground"), children: activity.label }),
740
740
  /* @__PURE__ */ jsxRuntime.jsxs(
741
741
  "span",
742
742
  {
743
- className: chunkSUZIFHXI_js.cn(
743
+ className: chunkPUALTXTU_js.cn(
744
744
  "ml-auto inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 text-[10px]",
745
745
  failed ? "bg-destructive/15 text-destructive" : done ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"
746
746
  ),
@@ -757,7 +757,7 @@ function AiToolCallCard({ part }) {
757
757
  rawSummary && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mt-0.5 pl-5", children: [
758
758
  /* @__PURE__ */ jsxRuntime.jsx("summary", { className: "cursor-pointer list-none text-[10px] text-muted-foreground/70 hover:text-muted-foreground", children: t("pptx.ai.toolDetails") }),
759
759
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 break-words font-mono text-[10px] text-muted-foreground/80", children: [
760
- chunkH7QPQ4OR_js.toolLabel(part.toolName),
760
+ chunkMQHMMB6V_js.toolLabel(part.toolName),
761
761
  ": ",
762
762
  rawSummary
763
763
  ] })
@@ -788,7 +788,7 @@ function AiMessageList({ messages, isStreaming, bridge }) {
788
788
  /* @__PURE__ */ jsxRuntime.jsx(
789
789
  "div",
790
790
  {
791
- className: chunkSUZIFHXI_js.cn(
791
+ className: chunkPUALTXTU_js.cn(
792
792
  "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
793
793
  isUser ? "bg-secondary text-muted-foreground" : "bg-primary/15 text-primary"
794
794
  ),
@@ -835,7 +835,7 @@ function AiMessageList({ messages, isStreaming, bridge }) {
835
835
  }
836
836
  function AiProposalCard({ proposal, onAccept, onReject }) {
837
837
  const { t } = reactI18next.useTranslation();
838
- const lines = proposal.summary.map(chunkH7QPQ4OR_js.humanizeDiffLine);
838
+ const lines = proposal.summary.map(chunkMQHMMB6V_js.humanizeDiffLine);
839
839
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-primary/40 bg-primary/5 p-2.5", children: [
840
840
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-primary", children: t("pptx.ai.proposedChange") }),
841
841
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[12px] font-medium text-foreground", children: proposal.label }),
@@ -1043,7 +1043,7 @@ function AiChatPanel({
1043
1043
  }) {
1044
1044
  const { t } = reactI18next.useTranslation();
1045
1045
  const { state, session, initError } = useAiChat(bridge, config);
1046
- const deckId = react.useMemo(() => chunkH7QPQ4OR_js.deckIdFromBridge(bridge), [bridge]);
1046
+ const deckId = react.useMemo(() => chunkMQHMMB6V_js.deckIdFromBridge(bridge), [bridge]);
1047
1047
  return /* @__PURE__ */ jsxRuntime.jsxs(
1048
1048
  "div",
1049
1049
  {
Binary file
Binary file
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkDNR6CH6I_js = require('./chunk-DNR6CH6I.js');
4
- var chunkT6V342NP_js = require('./chunk-T6V342NP.js');
4
+ var chunkSK2CZQ6P_js = require('./chunk-SK2CZQ6P.js');
5
5
  require('./chunk-4VNS5WPM.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -23,7 +23,7 @@ function Area3DChartScene({
23
23
  return;
24
24
  }
25
25
  let disposed = false;
26
- void chunkT6V342NP_js.mountAreaChart3D(container, options, stableInteraction).then((handle) => {
26
+ void chunkSK2CZQ6P_js.mountAreaChart3D(container, options, stableInteraction).then((handle) => {
27
27
  if (disposed) {
28
28
  handle.dispose();
29
29
  } else {
@@ -1,5 +1,5 @@
1
1
  import { useStableChart3DInteraction, useLatestRef } from './chunk-T6GFCLSM.mjs';
2
- import { mountAreaChart3D } from './chunk-TMTQJAGK.mjs';
2
+ import { mountAreaChart3D } from './chunk-Q6QJOD56.mjs';
3
3
  import './chunk-XGB3TDIC.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
1
  import { useStableChart3DInteraction, useLatestRef } from './chunk-T6GFCLSM.mjs';
2
- import { mountBarChart3D } from './chunk-TMTQJAGK.mjs';
2
+ import { mountBarChart3D } from './chunk-Q6QJOD56.mjs';
3
3
  import './chunk-XGB3TDIC.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkDNR6CH6I_js = require('./chunk-DNR6CH6I.js');
4
- var chunkT6V342NP_js = require('./chunk-T6V342NP.js');
4
+ var chunkSK2CZQ6P_js = require('./chunk-SK2CZQ6P.js');
5
5
  require('./chunk-4VNS5WPM.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -23,7 +23,7 @@ function Bar3DChartScene({
23
23
  return;
24
24
  }
25
25
  let disposed = false;
26
- void chunkT6V342NP_js.mountBarChart3D(container, options, stableInteraction).then((handle) => {
26
+ void chunkSK2CZQ6P_js.mountBarChart3D(container, options, stableInteraction).then((handle) => {
27
27
  if (disposed) {
28
28
  handle.dispose();
29
29
  } else {
@@ -1,5 +1,5 @@
1
1
  import { useStableChart3DInteraction, useLatestRef } from './chunk-T6GFCLSM.mjs';
2
- import { mountLineChart3D } from './chunk-TMTQJAGK.mjs';
2
+ import { mountLineChart3D } from './chunk-Q6QJOD56.mjs';
3
3
  import './chunk-XGB3TDIC.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkDNR6CH6I_js = require('./chunk-DNR6CH6I.js');
4
- var chunkT6V342NP_js = require('./chunk-T6V342NP.js');
4
+ var chunkSK2CZQ6P_js = require('./chunk-SK2CZQ6P.js');
5
5
  require('./chunk-4VNS5WPM.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -23,7 +23,7 @@ function Line3DChartScene({
23
23
  return;
24
24
  }
25
25
  let disposed = false;
26
- void chunkT6V342NP_js.mountLineChart3D(container, options, stableInteraction).then((handle) => {
26
+ void chunkSK2CZQ6P_js.mountLineChart3D(container, options, stableInteraction).then((handle) => {
27
27
  if (disposed) {
28
28
  handle.dispose();
29
29
  } else {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkT6V342NP_js = require('./chunk-T6V342NP.js');
3
+ var chunkSK2CZQ6P_js = require('./chunk-SK2CZQ6P.js');
4
4
  require('./chunk-4VNS5WPM.js');
5
5
  var react = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
@@ -14,7 +14,7 @@ function Model3DScene({ modelUrl, interactive, width, height }) {
14
14
  return;
15
15
  }
16
16
  let disposed = false;
17
- void chunkT6V342NP_js.mountModel3D(container, modelUrl, { width, height, interactive }).then((handle) => {
17
+ void chunkSK2CZQ6P_js.mountModel3D(container, modelUrl, { width, height, interactive }).then((handle) => {
18
18
  if (disposed) {
19
19
  handle.dispose();
20
20
  } else {
Binary file
Binary file
@@ -1,4 +1,4 @@
1
- import { mountModel3D } from './chunk-TMTQJAGK.mjs';
1
+ import { mountModel3D } from './chunk-Q6QJOD56.mjs';
2
2
  import './chunk-XGB3TDIC.mjs';
3
3
  import { useRef, useEffect } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
1
  import { useStableChart3DInteraction, useLatestRef } from './chunk-T6GFCLSM.mjs';
2
- import { mountPieChart3D } from './chunk-TMTQJAGK.mjs';
2
+ import { mountPieChart3D } from './chunk-Q6QJOD56.mjs';
3
3
  import './chunk-XGB3TDIC.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkDNR6CH6I_js = require('./chunk-DNR6CH6I.js');
4
- var chunkT6V342NP_js = require('./chunk-T6V342NP.js');
4
+ var chunkSK2CZQ6P_js = require('./chunk-SK2CZQ6P.js');
5
5
  require('./chunk-4VNS5WPM.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -21,7 +21,7 @@ function PieChart3DScene({
21
21
  return;
22
22
  }
23
23
  let disposed = false;
24
- void chunkT6V342NP_js.mountPieChart3D(container, options, stableInteraction).then((handle) => {
24
+ void chunkSK2CZQ6P_js.mountPieChart3D(container, options, stableInteraction).then((handle) => {
25
25
  if (disposed) {
26
26
  handle.dispose();
27
27
  } else {
@@ -1,6 +1,6 @@
1
1
  import { useLatestRef } from './chunk-T6GFCLSM.mjs';
2
2
  import { OrbitControls } from './chunk-MV2GCDBR.mjs';
3
- import { WebGLRenderer, Scene, Color, PerspectiveCamera, AmbientLight, DirectionalLight, Group, MeshStandardMaterial, Mesh, EdgesGeometry, LineBasicMaterial, LineSegments, PlaneGeometry, MeshBasicMaterial, Euler, Vector3, BufferGeometry, Line, Shape, ExtrudeGeometry, CanvasTexture, SRGBColorSpace, LinearFilter, RepeatWrapping } from './chunk-7TAWW5QQ.mjs';
3
+ import { WebGLRenderer, Scene, Color, PerspectiveCamera, AmbientLight, DirectionalLight, Group, MeshStandardMaterial, Mesh, EdgesGeometry, LineBasicMaterial, LineSegments, PlaneGeometry, MeshBasicMaterial, DoubleSide, Euler, Vector3, BufferGeometry, Line, Shape, ExtrudeGeometry, CanvasTexture, SRGBColorSpace, LinearFilter, RepeatWrapping } from './chunk-7TAWW5QQ.mjs';
4
4
  import './chunk-XGB3TDIC.mjs';
5
5
  import { useRef, useEffect } from 'react';
6
6
  import { jsx } from 'react/jsx-runtime';
@@ -159,9 +159,12 @@ function buildLabelPlane(m, textStyle) {
159
159
  const planeMaterial = new MeshBasicMaterial({
160
160
  map: tex.texture,
161
161
  transparent: true,
162
- depthWrite: false
162
+ depthWrite: false,
163
+ depthTest: false,
164
+ side: DoubleSide
163
165
  });
164
166
  const plane = new Mesh(planeGeo, planeMaterial);
167
+ plane.renderOrder = 1;
165
168
  const euler = new Euler(m.rotation.x, m.rotation.y, m.rotation.z);
166
169
  const offset = new Vector3(0, 0, m.depth + m.bevel + 0.4).applyEuler(euler);
167
170
  plane.position.set(m.position.x + offset.x, m.position.y + offset.y, m.position.z + offset.z);
@@ -218,6 +221,13 @@ function buildMeshGroup(model, textStyle) {
218
221
  }
219
222
  }
220
223
  },
224
+ forEachLabelPlane(fn) {
225
+ for (const entry of labelEntries) {
226
+ if (entry.plane) {
227
+ fn(entry.plane);
228
+ }
229
+ }
230
+ },
221
231
  dispose() {
222
232
  for (const d of blockDisposables) {
223
233
  d.dispose();
@@ -229,6 +239,17 @@ function buildMeshGroup(model, textStyle) {
229
239
  };
230
240
  }
231
241
  var FOV = 42;
242
+ function expandForMesh(expand, m) {
243
+ const hx = m.halfWidth + m.bevel;
244
+ const hy = m.halfHeight + m.bevel;
245
+ const hz = m.depth / 2 + m.bevel;
246
+ const midZ = m.position.z + m.depth / 2;
247
+ const cosY = Math.cos(m.rotation.y);
248
+ const sinY = Math.sin(m.rotation.y);
249
+ const worldHalfX = Math.abs(hx * cosY) + Math.abs(hz * sinY);
250
+ const worldHalfZ = Math.abs(hx * sinY) + Math.abs(hz * cosY);
251
+ expand(m.position.x, m.position.y, midZ, worldHalfX, hy, worldHalfZ);
252
+ }
232
253
  function contentSphere(model) {
233
254
  let minX = Infinity;
234
255
  let minY = Infinity;
@@ -236,32 +257,36 @@ function contentSphere(model) {
236
257
  let maxX = -Infinity;
237
258
  let maxY = -Infinity;
238
259
  let maxZ = -Infinity;
239
- const expand = (x, y, z, r) => {
240
- minX = Math.min(minX, x - r);
241
- minY = Math.min(minY, y - r);
242
- minZ = Math.min(minZ, z - r);
243
- maxX = Math.max(maxX, x + r);
244
- maxY = Math.max(maxY, y + r);
245
- maxZ = Math.max(maxZ, z + r);
260
+ const expand = (x, y, z, rx, ry, rz) => {
261
+ minX = Math.min(minX, x - rx);
262
+ minY = Math.min(minY, y - ry);
263
+ minZ = Math.min(minZ, z - rz);
264
+ maxX = Math.max(maxX, x + rx);
265
+ maxY = Math.max(maxY, y + ry);
266
+ maxZ = Math.max(maxZ, z + rz);
246
267
  };
247
268
  for (const m of model.meshes) {
248
- const r = Math.max(m.halfWidth, m.halfHeight) + m.depth + m.bevel;
249
- expand(m.position.x, m.position.y, m.position.z, r);
269
+ expandForMesh(expand, m);
250
270
  }
251
271
  for (const c of model.connectors) {
252
272
  for (const p of c.points) {
253
- expand(p.x, p.y, p.z, 1);
273
+ expand(p.x, p.y, p.z, 1, 1, 1);
254
274
  }
255
275
  }
256
276
  if (!Number.isFinite(minX)) {
257
- const fallback = Math.max(model.bounds.width, model.bounds.height) / 2 || 1;
258
- return { cx: 0, cy: 0, cz: 0, radius: fallback };
277
+ const halfW = model.bounds.width / 2 || 1;
278
+ const halfH = model.bounds.height / 2 || 1;
279
+ const fallback = Math.max(halfW, halfH);
280
+ return { cx: 0, cy: 0, cz: 0, radius: fallback, halfW, halfH, halfD: 1 };
259
281
  }
260
282
  return {
261
283
  cx: (minX + maxX) / 2,
262
284
  cy: (minY + maxY) / 2,
263
285
  cz: (minZ + maxZ) / 2,
264
- radius: 0.5 * Math.hypot(maxX - minX, maxY - minY, maxZ - minZ) || 1
286
+ radius: 0.5 * Math.hypot(maxX - minX, maxY - minY, maxZ - minZ) || 1,
287
+ halfW: (maxX - minX) / 2,
288
+ halfH: (maxY - minY) / 2,
289
+ halfD: (maxZ - minZ) / 2
265
290
  };
266
291
  }
267
292
  function frameDistance(radius, aspect) {
@@ -270,6 +295,83 @@ function frameDistance(radius, aspect) {
270
295
  const minFov = Math.min(vFov, hFov);
271
296
  return radius / Math.sin(minFov / 2) * 1.1;
272
297
  }
298
+ var FRAME_FILL = 0.92;
299
+ function placeCamera(bounds, family, dist) {
300
+ const { cx, cy, cz, radius } = bounds;
301
+ const elevation = cameraElevation(family, radius, dist);
302
+ return {
303
+ position: [cx + radius * 0.25, cy + elevation, cz + dist],
304
+ target: [cx, cy, cz],
305
+ dist
306
+ };
307
+ }
308
+ function projectedFill(bounds, placement, aspect) {
309
+ const vFov = FOV * Math.PI / 180;
310
+ const tanV = Math.tan(vFov / 2);
311
+ const tanH = tanV * aspect;
312
+ const [px, py, pz] = placement.position;
313
+ const [tx, ty, tz] = placement.target;
314
+ let fx = tx - px, fy = ty - py, fz = tz - pz;
315
+ const fl = Math.hypot(fx, fy, fz) || 1;
316
+ fx /= fl;
317
+ fy /= fl;
318
+ fz /= fl;
319
+ let rx = -fz, rz = fx;
320
+ const rl = Math.hypot(rx, rz) || 1;
321
+ rx /= rl;
322
+ rz /= rl;
323
+ const ux = -rz * fy, uy = rz * fx - rx * fz, uz = rx * fy;
324
+ let worst = 0;
325
+ for (const sx of [-1, 1]) {
326
+ for (const sy of [-1, 1]) {
327
+ for (const sz of [-1, 1]) {
328
+ const dx = bounds.cx + sx * bounds.halfW - px;
329
+ const dy = bounds.cy + sy * bounds.halfH - py;
330
+ const dz = bounds.cz + sz * bounds.halfD - pz;
331
+ const depth = dx * fx + dy * fy + dz * fz;
332
+ if (depth <= 1e-6) {
333
+ return Infinity;
334
+ }
335
+ const x = Math.abs(dx * rx + dz * rz) / (depth * tanH);
336
+ const y = Math.abs(dx * ux + dy * uy + dz * uz) / (depth * tanV);
337
+ worst = Math.max(worst, x, y);
338
+ }
339
+ }
340
+ }
341
+ return worst;
342
+ }
343
+ function fitCamera(bounds, family, aspect) {
344
+ let dist = frameDistance(bounds.radius, aspect);
345
+ let placement = placeCamera(bounds, family, dist);
346
+ for (let step = 0; step < 8; step++) {
347
+ const fill = projectedFill(bounds, placement, aspect);
348
+ if (!Number.isFinite(fill)) {
349
+ dist *= 2;
350
+ } else {
351
+ const ratio = fill / FRAME_FILL;
352
+ if (Math.abs(ratio - 1) < 0.01) {
353
+ break;
354
+ }
355
+ dist *= ratio;
356
+ }
357
+ placement = placeCamera(bounds, family, dist);
358
+ }
359
+ return placement;
360
+ }
361
+ var CAROUSEL_ELEVATION_DEG = 34;
362
+ function cameraElevation(family, radius, dist) {
363
+ if (family === "cycle" || family === "radial") {
364
+ return dist * Math.tan(CAROUSEL_ELEVATION_DEG * Math.PI / 180);
365
+ }
366
+ return radius * 0.3;
367
+ }
368
+ function billboardLabels(built, camera) {
369
+ built.forEachLabelPlane((plane) => {
370
+ const dx = camera.position.x - plane.position.x;
371
+ const dz = camera.position.z - plane.position.z;
372
+ plane.rotation.set(0, Math.atan2(dx, dz), 0);
373
+ });
374
+ }
273
375
  function mountSmartArt3D(canvas, model, width, height, options = {}) {
274
376
  const renderer = new WebGLRenderer({ canvas, antialias: true, alpha: !options.background });
275
377
  renderer.setPixelRatio(
@@ -283,12 +385,14 @@ function mountSmartArt3D(canvas, model, width, height, options = {}) {
283
385
  if (options.background) {
284
386
  scene.background = new Color(options.background);
285
387
  }
286
- const { cx, cy, cz, radius } = contentSphere(model);
388
+ const bounds = contentSphere(model);
389
+ const { cx, cy, cz, radius } = bounds;
287
390
  const aspect = width / Math.max(1, height);
288
- const dist = frameDistance(radius, aspect);
391
+ const placement = fitCamera(bounds, model.family, aspect);
392
+ const { dist } = placement;
289
393
  const camera = new PerspectiveCamera(FOV, aspect, 0.1, dist * 8 + radius * 4);
290
- camera.position.set(cx + radius * 0.25, cy + radius * 0.3, cz + dist);
291
- camera.lookAt(cx, cy, cz);
394
+ camera.position.set(...placement.position);
395
+ camera.lookAt(...placement.target);
292
396
  scene.add(new AmbientLight(16777215, 0.62));
293
397
  const key = new DirectionalLight(16777215, 0.95);
294
398
  key.position.set(cx + radius, cy + radius * 1.4, cz + dist);
@@ -324,6 +428,7 @@ function mountSmartArt3D(canvas, model, width, height, options = {}) {
324
428
  return;
325
429
  }
326
430
  frame = requestAnimationFrame(renderLoop);
431
+ billboardLabels(built, camera);
327
432
  controls?.update();
328
433
  renderer.render(scene, camera);
329
434
  };