@efxlab/motion-canvas-2d 4.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 (455) hide show
  1. package/editor/index.css +40 -0
  2. package/editor/index.js +525 -0
  3. package/editor/index.js.map +1 -0
  4. package/lib/code/CodeCursor.d.ts +84 -0
  5. package/lib/code/CodeCursor.d.ts.map +1 -0
  6. package/lib/code/CodeCursor.js +315 -0
  7. package/lib/code/CodeDiffer.d.ts +28 -0
  8. package/lib/code/CodeDiffer.d.ts.map +1 -0
  9. package/lib/code/CodeDiffer.js +51 -0
  10. package/lib/code/CodeFragment.d.ts +42 -0
  11. package/lib/code/CodeFragment.d.ts.map +1 -0
  12. package/lib/code/CodeFragment.js +72 -0
  13. package/lib/code/CodeHighlighter.d.ts +69 -0
  14. package/lib/code/CodeHighlighter.d.ts.map +1 -0
  15. package/lib/code/CodeHighlighter.js +2 -0
  16. package/lib/code/CodeMetrics.d.ts +11 -0
  17. package/lib/code/CodeMetrics.d.ts.map +1 -0
  18. package/lib/code/CodeMetrics.js +29 -0
  19. package/lib/code/CodeRange.d.ts +43 -0
  20. package/lib/code/CodeRange.d.ts.map +1 -0
  21. package/lib/code/CodeRange.js +185 -0
  22. package/lib/code/CodeScope.d.ts +16 -0
  23. package/lib/code/CodeScope.d.ts.map +1 -0
  24. package/lib/code/CodeScope.js +72 -0
  25. package/lib/code/CodeSelection.d.ts +6 -0
  26. package/lib/code/CodeSelection.d.ts.map +1 -0
  27. package/lib/code/CodeSelection.js +13 -0
  28. package/lib/code/CodeSignal.d.ts +63 -0
  29. package/lib/code/CodeSignal.d.ts.map +1 -0
  30. package/lib/code/CodeSignal.js +206 -0
  31. package/lib/code/CodeTokenizer.d.ts +8 -0
  32. package/lib/code/CodeTokenizer.d.ts.map +1 -0
  33. package/lib/code/CodeTokenizer.js +50 -0
  34. package/lib/code/DefaultHighlightStyle.d.ts +3 -0
  35. package/lib/code/DefaultHighlightStyle.d.ts.map +1 -0
  36. package/lib/code/DefaultHighlightStyle.js +98 -0
  37. package/lib/code/LezerHighlighter.d.ts +22 -0
  38. package/lib/code/LezerHighlighter.d.ts.map +1 -0
  39. package/lib/code/LezerHighlighter.js +91 -0
  40. package/lib/code/diff.d.ts +31 -0
  41. package/lib/code/diff.d.ts.map +1 -0
  42. package/lib/code/diff.js +236 -0
  43. package/lib/code/extractRange.d.ts +17 -0
  44. package/lib/code/extractRange.d.ts.map +1 -0
  45. package/lib/code/extractRange.js +102 -0
  46. package/lib/code/index.d.ts +14 -0
  47. package/lib/code/index.d.ts.map +1 -0
  48. package/lib/code/index.js +14 -0
  49. package/lib/components/Bezier.d.ts +22 -0
  50. package/lib/components/Bezier.d.ts.map +1 -0
  51. package/lib/components/Bezier.js +80 -0
  52. package/lib/components/Camera.d.ts +172 -0
  53. package/lib/components/Camera.d.ts.map +1 -0
  54. package/lib/components/Camera.js +239 -0
  55. package/lib/components/Circle.d.ts +191 -0
  56. package/lib/components/Circle.d.ts.map +1 -0
  57. package/lib/components/Circle.js +178 -0
  58. package/lib/components/Code.d.ts +238 -0
  59. package/lib/components/Code.d.ts.map +1 -0
  60. package/lib/components/Code.js +331 -0
  61. package/lib/components/CodeBlock.d.ts +131 -0
  62. package/lib/components/CodeBlock.d.ts.map +1 -0
  63. package/lib/components/CodeBlock.js +462 -0
  64. package/lib/components/CubicBezier.d.ts +69 -0
  65. package/lib/components/CubicBezier.d.ts.map +1 -0
  66. package/lib/components/CubicBezier.js +81 -0
  67. package/lib/components/Curve.d.ts +202 -0
  68. package/lib/components/Curve.d.ts.map +1 -0
  69. package/lib/components/Curve.js +284 -0
  70. package/lib/components/Grid.d.ts +75 -0
  71. package/lib/components/Grid.d.ts.map +1 -0
  72. package/lib/components/Grid.js +91 -0
  73. package/lib/components/Icon.d.ts +58 -0
  74. package/lib/components/Icon.d.ts.map +1 -0
  75. package/lib/components/Icon.js +58 -0
  76. package/lib/components/Img.d.ts +116 -0
  77. package/lib/components/Img.d.ts.map +1 -0
  78. package/lib/components/Img.js +233 -0
  79. package/lib/components/Knot.d.ts +89 -0
  80. package/lib/components/Knot.d.ts.map +1 -0
  81. package/lib/components/Knot.js +68 -0
  82. package/lib/components/Latex.d.ts +49 -0
  83. package/lib/components/Latex.d.ts.map +1 -0
  84. package/lib/components/Latex.js +206 -0
  85. package/lib/components/Layout.d.ts +423 -0
  86. package/lib/components/Layout.d.ts.map +1 -0
  87. package/lib/components/Layout.js +699 -0
  88. package/lib/components/Line.d.ts +158 -0
  89. package/lib/components/Line.d.ts.map +1 -0
  90. package/lib/components/Line.js +315 -0
  91. package/lib/components/Node.d.ts +843 -0
  92. package/lib/components/Node.d.ts.map +1 -0
  93. package/lib/components/Node.js +1335 -0
  94. package/lib/components/Path.d.ts +18 -0
  95. package/lib/components/Path.d.ts.map +1 -0
  96. package/lib/components/Path.js +96 -0
  97. package/lib/components/Polygon.d.ts +157 -0
  98. package/lib/components/Polygon.d.ts.map +1 -0
  99. package/lib/components/Polygon.js +183 -0
  100. package/lib/components/QuadBezier.d.ts +61 -0
  101. package/lib/components/QuadBezier.d.ts.map +1 -0
  102. package/lib/components/QuadBezier.js +76 -0
  103. package/lib/components/Ray.d.ts +60 -0
  104. package/lib/components/Ray.d.ts.map +1 -0
  105. package/lib/components/Ray.js +95 -0
  106. package/lib/components/Rect.d.ts +112 -0
  107. package/lib/components/Rect.d.ts.map +1 -0
  108. package/lib/components/Rect.js +76 -0
  109. package/lib/components/SVG.d.ts +175 -0
  110. package/lib/components/SVG.d.ts.map +1 -0
  111. package/lib/components/SVG.js +582 -0
  112. package/lib/components/Shape.d.ts +39 -0
  113. package/lib/components/Shape.d.ts.map +1 -0
  114. package/lib/components/Shape.js +134 -0
  115. package/lib/components/Spline.d.ts +87 -0
  116. package/lib/components/Spline.d.ts.map +1 -0
  117. package/lib/components/Spline.js +230 -0
  118. package/lib/components/Txt.d.ts +51 -0
  119. package/lib/components/Txt.d.ts.map +1 -0
  120. package/lib/components/Txt.js +172 -0
  121. package/lib/components/TxtLeaf.d.ts +20 -0
  122. package/lib/components/TxtLeaf.d.ts.map +1 -0
  123. package/lib/components/TxtLeaf.js +185 -0
  124. package/lib/components/Video.d.ts +110 -0
  125. package/lib/components/Video.d.ts.map +1 -0
  126. package/lib/components/Video.js +267 -0
  127. package/lib/components/View2D.d.ts +25 -0
  128. package/lib/components/View2D.d.ts.map +1 -0
  129. package/lib/components/View2D.js +85 -0
  130. package/lib/components/index.d.ts +27 -0
  131. package/lib/components/index.d.ts.map +1 -0
  132. package/lib/components/index.js +27 -0
  133. package/lib/components/types.d.ts +17 -0
  134. package/lib/components/types.d.ts.map +1 -0
  135. package/lib/components/types.js +2 -0
  136. package/lib/curves/ArcSegment.d.ts +26 -0
  137. package/lib/curves/ArcSegment.d.ts.map +1 -0
  138. package/lib/curves/ArcSegment.js +116 -0
  139. package/lib/curves/CircleSegment.d.ts +18 -0
  140. package/lib/curves/CircleSegment.d.ts.map +1 -0
  141. package/lib/curves/CircleSegment.js +60 -0
  142. package/lib/curves/CubicBezierSegment.d.ts +18 -0
  143. package/lib/curves/CubicBezierSegment.d.ts.map +1 -0
  144. package/lib/curves/CubicBezierSegment.js +60 -0
  145. package/lib/curves/CurveDrawingInfo.d.ts +11 -0
  146. package/lib/curves/CurveDrawingInfo.d.ts.map +1 -0
  147. package/lib/curves/CurveDrawingInfo.js +2 -0
  148. package/lib/curves/CurvePoint.d.ts +15 -0
  149. package/lib/curves/CurvePoint.d.ts.map +1 -0
  150. package/lib/curves/CurvePoint.js +2 -0
  151. package/lib/curves/CurveProfile.d.ts +7 -0
  152. package/lib/curves/CurveProfile.d.ts.map +1 -0
  153. package/lib/curves/CurveProfile.js +2 -0
  154. package/lib/curves/KnotInfo.d.ts +12 -0
  155. package/lib/curves/KnotInfo.d.ts.map +1 -0
  156. package/lib/curves/KnotInfo.js +2 -0
  157. package/lib/curves/LineSegment.d.ts +16 -0
  158. package/lib/curves/LineSegment.d.ts.map +1 -0
  159. package/lib/curves/LineSegment.js +51 -0
  160. package/lib/curves/Polynomial.d.ts +118 -0
  161. package/lib/curves/Polynomial.d.ts.map +1 -0
  162. package/lib/curves/Polynomial.js +263 -0
  163. package/lib/curves/Polynomial2D.d.ts +22 -0
  164. package/lib/curves/Polynomial2D.d.ts.map +1 -0
  165. package/lib/curves/Polynomial2D.js +51 -0
  166. package/lib/curves/PolynomialSegment.d.ts +39 -0
  167. package/lib/curves/PolynomialSegment.d.ts.map +1 -0
  168. package/lib/curves/PolynomialSegment.js +88 -0
  169. package/lib/curves/QuadBezierSegment.d.ts +17 -0
  170. package/lib/curves/QuadBezierSegment.d.ts.map +1 -0
  171. package/lib/curves/QuadBezierSegment.js +53 -0
  172. package/lib/curves/Segment.d.ts +9 -0
  173. package/lib/curves/Segment.d.ts.map +1 -0
  174. package/lib/curves/Segment.js +3 -0
  175. package/lib/curves/UniformPolynomialCurveSampler.d.ts +43 -0
  176. package/lib/curves/UniformPolynomialCurveSampler.d.ts.map +1 -0
  177. package/lib/curves/UniformPolynomialCurveSampler.js +74 -0
  178. package/lib/curves/createCurveProfileLerp.d.ts +32 -0
  179. package/lib/curves/createCurveProfileLerp.d.ts.map +1 -0
  180. package/lib/curves/createCurveProfileLerp.js +351 -0
  181. package/lib/curves/getBezierSplineProfile.d.ts +12 -0
  182. package/lib/curves/getBezierSplineProfile.d.ts.map +1 -0
  183. package/lib/curves/getBezierSplineProfile.js +140 -0
  184. package/lib/curves/getCircleProfile.d.ts +4 -0
  185. package/lib/curves/getCircleProfile.d.ts.map +1 -0
  186. package/lib/curves/getCircleProfile.js +44 -0
  187. package/lib/curves/getPathProfile.d.ts +3 -0
  188. package/lib/curves/getPathProfile.d.ts.map +1 -0
  189. package/lib/curves/getPathProfile.js +128 -0
  190. package/lib/curves/getPointAtDistance.d.ts +4 -0
  191. package/lib/curves/getPointAtDistance.d.ts.map +1 -0
  192. package/lib/curves/getPointAtDistance.js +15 -0
  193. package/lib/curves/getPolylineProfile.d.ts +4 -0
  194. package/lib/curves/getPolylineProfile.d.ts.map +1 -0
  195. package/lib/curves/getPolylineProfile.js +58 -0
  196. package/lib/curves/getRectProfile.d.ts +4 -0
  197. package/lib/curves/getRectProfile.d.ts.map +1 -0
  198. package/lib/curves/getRectProfile.js +57 -0
  199. package/lib/curves/index.d.ts +17 -0
  200. package/lib/curves/index.d.ts.map +1 -0
  201. package/lib/curves/index.js +17 -0
  202. package/lib/decorators/canvasStyleSignal.d.ts +5 -0
  203. package/lib/decorators/canvasStyleSignal.d.ts.map +1 -0
  204. package/lib/decorators/canvasStyleSignal.js +12 -0
  205. package/lib/decorators/colorSignal.d.ts +2 -0
  206. package/lib/decorators/colorSignal.d.ts.map +1 -0
  207. package/lib/decorators/colorSignal.js +9 -0
  208. package/lib/decorators/compound.d.ts +27 -0
  209. package/lib/decorators/compound.d.ts.map +1 -0
  210. package/lib/decorators/compound.js +49 -0
  211. package/lib/decorators/computed.d.ts +9 -0
  212. package/lib/decorators/computed.d.ts.map +1 -0
  213. package/lib/decorators/computed.js +18 -0
  214. package/lib/decorators/defaultStyle.d.ts +2 -0
  215. package/lib/decorators/defaultStyle.d.ts.map +1 -0
  216. package/lib/decorators/defaultStyle.js +13 -0
  217. package/lib/decorators/filtersSignal.d.ts +11 -0
  218. package/lib/decorators/filtersSignal.d.ts.map +1 -0
  219. package/lib/decorators/filtersSignal.js +73 -0
  220. package/lib/decorators/index.d.ts +11 -0
  221. package/lib/decorators/index.d.ts.map +1 -0
  222. package/lib/decorators/index.js +11 -0
  223. package/lib/decorators/initializers.d.ts +4 -0
  224. package/lib/decorators/initializers.d.ts.map +1 -0
  225. package/lib/decorators/initializers.js +27 -0
  226. package/lib/decorators/nodeName.d.ts +9 -0
  227. package/lib/decorators/nodeName.d.ts.map +1 -0
  228. package/lib/decorators/nodeName.js +13 -0
  229. package/lib/decorators/signal.d.ts +183 -0
  230. package/lib/decorators/signal.d.ts.map +1 -0
  231. package/lib/decorators/signal.js +285 -0
  232. package/lib/decorators/spacingSignal.d.ts +2 -0
  233. package/lib/decorators/spacingSignal.d.ts.map +1 -0
  234. package/lib/decorators/spacingSignal.js +15 -0
  235. package/lib/decorators/vector2Signal.d.ts +8 -0
  236. package/lib/decorators/vector2Signal.d.ts.map +1 -0
  237. package/lib/decorators/vector2Signal.js +15 -0
  238. package/lib/index.d.ts +9 -0
  239. package/lib/index.d.ts.map +1 -0
  240. package/lib/index.js +9 -0
  241. package/lib/jsx-dev-runtime.d.ts +3 -0
  242. package/lib/jsx-dev-runtime.d.ts.map +1 -0
  243. package/lib/jsx-dev-runtime.js +3 -0
  244. package/lib/jsx-runtime.d.ts +12 -0
  245. package/lib/jsx-runtime.d.ts.map +1 -0
  246. package/lib/jsx-runtime.js +23 -0
  247. package/lib/partials/Filter.d.ts +82 -0
  248. package/lib/partials/Filter.d.ts.map +1 -0
  249. package/lib/partials/Filter.js +137 -0
  250. package/lib/partials/Gradient.d.ts +31 -0
  251. package/lib/partials/Gradient.d.ts.map +1 -0
  252. package/lib/partials/Gradient.js +63 -0
  253. package/lib/partials/Pattern.d.ts +13 -0
  254. package/lib/partials/Pattern.d.ts.map +1 -0
  255. package/lib/partials/Pattern.js +27 -0
  256. package/lib/partials/ShaderConfig.d.ts +81 -0
  257. package/lib/partials/ShaderConfig.d.ts.map +1 -0
  258. package/lib/partials/ShaderConfig.js +25 -0
  259. package/lib/partials/index.d.ts +5 -0
  260. package/lib/partials/index.d.ts.map +1 -0
  261. package/lib/partials/index.js +5 -0
  262. package/lib/partials/types.d.ts +35 -0
  263. package/lib/partials/types.d.ts.map +1 -0
  264. package/lib/partials/types.js +2 -0
  265. package/lib/scenes/Scene2D.d.ts +23 -0
  266. package/lib/scenes/Scene2D.d.ts.map +1 -0
  267. package/lib/scenes/Scene2D.js +152 -0
  268. package/lib/scenes/index.d.ts +4 -0
  269. package/lib/scenes/index.d.ts.map +1 -0
  270. package/lib/scenes/index.js +4 -0
  271. package/lib/scenes/makeScene2D.d.ts +5 -0
  272. package/lib/scenes/makeScene2D.d.ts.map +1 -0
  273. package/lib/scenes/makeScene2D.js +12 -0
  274. package/lib/scenes/useScene2D.d.ts +3 -0
  275. package/lib/scenes/useScene2D.d.ts.map +1 -0
  276. package/lib/scenes/useScene2D.js +5 -0
  277. package/lib/tsconfig.build.tsbuildinfo +1 -0
  278. package/lib/tsconfig.tsbuildinfo +1 -0
  279. package/lib/utils/CanvasUtils.d.ts +21 -0
  280. package/lib/utils/CanvasUtils.d.ts.map +1 -0
  281. package/lib/utils/CanvasUtils.js +138 -0
  282. package/lib/utils/diff.d.ts +31 -0
  283. package/lib/utils/diff.d.ts.map +1 -0
  284. package/lib/utils/diff.js +97 -0
  285. package/lib/utils/index.d.ts +4 -0
  286. package/lib/utils/index.d.ts.map +1 -0
  287. package/lib/utils/index.js +4 -0
  288. package/lib/utils/is.d.ts +8 -0
  289. package/lib/utils/is.d.ts.map +1 -0
  290. package/lib/utils/is.js +10 -0
  291. package/lib/utils/makeSignalExtensions.d.ts +4 -0
  292. package/lib/utils/makeSignalExtensions.d.ts.map +1 -0
  293. package/lib/utils/makeSignalExtensions.js +20 -0
  294. package/lib/utils/withDefaults.d.ts +20 -0
  295. package/lib/utils/withDefaults.d.ts.map +1 -0
  296. package/lib/utils/withDefaults.js +23 -0
  297. package/package.json +54 -0
  298. package/src/editor/NodeInspectorConfig.tsx +76 -0
  299. package/src/editor/PreviewOverlayConfig.tsx +65 -0
  300. package/src/editor/Provider.tsx +109 -0
  301. package/src/editor/SceneGraphTabConfig.tsx +87 -0
  302. package/src/editor/icons/CircleIcon.tsx +7 -0
  303. package/src/editor/icons/CodeBlockIcon.tsx +8 -0
  304. package/src/editor/icons/CurveIcon.tsx +7 -0
  305. package/src/editor/icons/GridIcon.tsx +7 -0
  306. package/src/editor/icons/IconMap.ts +35 -0
  307. package/src/editor/icons/ImgIcon.tsx +8 -0
  308. package/src/editor/icons/LayoutIcon.tsx +9 -0
  309. package/src/editor/icons/LineIcon.tsx +7 -0
  310. package/src/editor/icons/NodeIcon.tsx +7 -0
  311. package/src/editor/icons/RayIcon.tsx +7 -0
  312. package/src/editor/icons/RectIcon.tsx +7 -0
  313. package/src/editor/icons/ShapeIcon.tsx +7 -0
  314. package/src/editor/icons/TxtIcon.tsx +8 -0
  315. package/src/editor/icons/VideoIcon.tsx +7 -0
  316. package/src/editor/icons/View2DIcon.tsx +10 -0
  317. package/src/editor/index.css +0 -0
  318. package/src/editor/index.ts +19 -0
  319. package/src/editor/shortcuts.ts +27 -0
  320. package/src/editor/tree/DetachedRoot.tsx +27 -0
  321. package/src/editor/tree/NodeElement.tsx +72 -0
  322. package/src/editor/tree/TreeElement.tsx +70 -0
  323. package/src/editor/tree/TreeRoot.tsx +10 -0
  324. package/src/editor/tree/ViewRoot.tsx +20 -0
  325. package/src/editor/tree/index.module.scss +45 -0
  326. package/src/editor/tree/index.ts +4 -0
  327. package/src/editor/tree/navigation.ts +145 -0
  328. package/src/editor/tsconfig.build.json +5 -0
  329. package/src/editor/tsconfig.json +12 -0
  330. package/src/editor/tsdoc.json +4 -0
  331. package/src/editor/utils/SignalSet.ts +37 -0
  332. package/src/editor/utils/index.ts +1 -0
  333. package/src/editor/vite-env.d.ts +1 -0
  334. package/src/lib/code/CodeCursor.ts +468 -0
  335. package/src/lib/code/CodeDiffer.ts +77 -0
  336. package/src/lib/code/CodeFragment.ts +96 -0
  337. package/src/lib/code/CodeHighlighter.ts +73 -0
  338. package/src/lib/code/CodeMetrics.ts +47 -0
  339. package/src/lib/code/CodeRange.test.ts +113 -0
  340. package/src/lib/code/CodeRange.ts +222 -0
  341. package/src/lib/code/CodeScope.ts +100 -0
  342. package/src/lib/code/CodeSelection.ts +28 -0
  343. package/src/lib/code/CodeSignal.ts +348 -0
  344. package/src/lib/code/CodeTokenizer.ts +54 -0
  345. package/src/lib/code/DefaultHighlightStyle.ts +98 -0
  346. package/src/lib/code/LezerHighlighter.ts +113 -0
  347. package/src/lib/code/diff.test.ts +311 -0
  348. package/src/lib/code/diff.ts +319 -0
  349. package/src/lib/code/extractRange.ts +125 -0
  350. package/src/lib/code/index.ts +13 -0
  351. package/src/lib/components/Bezier.ts +103 -0
  352. package/src/lib/components/Camera.ts +359 -0
  353. package/src/lib/components/Circle.ts +269 -0
  354. package/src/lib/components/Code.ts +532 -0
  355. package/src/lib/components/CodeBlock.ts +581 -0
  356. package/src/lib/components/CubicBezier.ts +115 -0
  357. package/src/lib/components/Curve.ts +455 -0
  358. package/src/lib/components/Grid.ts +134 -0
  359. package/src/lib/components/Icon.ts +95 -0
  360. package/src/lib/components/Img.ts +305 -0
  361. package/src/lib/components/Knot.ts +156 -0
  362. package/src/lib/components/Latex.ts +249 -0
  363. package/src/lib/components/Layout.ts +1071 -0
  364. package/src/lib/components/Line.ts +394 -0
  365. package/src/lib/components/Node.ts +1949 -0
  366. package/src/lib/components/Path.ts +132 -0
  367. package/src/lib/components/Polygon.ts +238 -0
  368. package/src/lib/components/QuadBezier.ts +103 -0
  369. package/src/lib/components/Ray.ts +126 -0
  370. package/src/lib/components/Rect.ts +186 -0
  371. package/src/lib/components/SVG.ts +788 -0
  372. package/src/lib/components/Shape.ts +146 -0
  373. package/src/lib/components/Spline.ts +318 -0
  374. package/src/lib/components/Txt.test.tsx +81 -0
  375. package/src/lib/components/Txt.ts +204 -0
  376. package/src/lib/components/TxtLeaf.ts +210 -0
  377. package/src/lib/components/Video.ts +368 -0
  378. package/src/lib/components/View2D.ts +85 -0
  379. package/src/lib/components/__logs__/image-without-source.md +17 -0
  380. package/src/lib/components/__logs__/line-without-points.md +30 -0
  381. package/src/lib/components/__logs__/reactive-playback-rate.md +21 -0
  382. package/src/lib/components/__logs__/spline-with-insufficient-knots.md +24 -0
  383. package/src/lib/components/__tests__/children.test.tsx +142 -0
  384. package/src/lib/components/__tests__/clone.test.tsx +126 -0
  385. package/src/lib/components/__tests__/generatorTest.ts +27 -0
  386. package/src/lib/components/__tests__/mockScene2D.ts +50 -0
  387. package/src/lib/components/__tests__/query.test.tsx +122 -0
  388. package/src/lib/components/__tests__/state.test.tsx +60 -0
  389. package/src/lib/components/index.ts +26 -0
  390. package/src/lib/components/types.ts +35 -0
  391. package/src/lib/curves/ArcSegment.ts +155 -0
  392. package/src/lib/curves/CircleSegment.ts +77 -0
  393. package/src/lib/curves/CubicBezierSegment.ts +78 -0
  394. package/src/lib/curves/CurveDrawingInfo.ts +11 -0
  395. package/src/lib/curves/CurvePoint.ts +15 -0
  396. package/src/lib/curves/CurveProfile.ts +7 -0
  397. package/src/lib/curves/KnotInfo.ts +10 -0
  398. package/src/lib/curves/LineSegment.ts +62 -0
  399. package/src/lib/curves/Polynomial.ts +355 -0
  400. package/src/lib/curves/Polynomial2D.ts +62 -0
  401. package/src/lib/curves/PolynomialSegment.ts +124 -0
  402. package/src/lib/curves/QuadBezierSegment.ts +64 -0
  403. package/src/lib/curves/Segment.ts +17 -0
  404. package/src/lib/curves/UniformPolynomialCurveSampler.ts +93 -0
  405. package/src/lib/curves/createCurveProfileLerp.ts +471 -0
  406. package/src/lib/curves/getBezierSplineProfile.ts +227 -0
  407. package/src/lib/curves/getCircleProfile.ts +86 -0
  408. package/src/lib/curves/getPathProfile.ts +177 -0
  409. package/src/lib/curves/getPointAtDistance.ts +21 -0
  410. package/src/lib/curves/getPolylineProfile.test.ts +21 -0
  411. package/src/lib/curves/getPolylineProfile.ts +88 -0
  412. package/src/lib/curves/getRectProfile.ts +138 -0
  413. package/src/lib/curves/index.ts +16 -0
  414. package/src/lib/decorators/canvasStyleSignal.ts +15 -0
  415. package/src/lib/decorators/colorSignal.ts +9 -0
  416. package/src/lib/decorators/compound.ts +85 -0
  417. package/src/lib/decorators/computed.ts +18 -0
  418. package/src/lib/decorators/defaultStyle.ts +15 -0
  419. package/src/lib/decorators/filtersSignal.ts +133 -0
  420. package/src/lib/decorators/index.ts +10 -0
  421. package/src/lib/decorators/initializers.ts +34 -0
  422. package/src/lib/decorators/nodeName.ts +13 -0
  423. package/src/lib/decorators/signal.test.ts +89 -0
  424. package/src/lib/decorators/signal.ts +348 -0
  425. package/src/lib/decorators/spacingSignal.ts +15 -0
  426. package/src/lib/decorators/vector2Signal.ts +35 -0
  427. package/src/lib/globals.d.ts +3 -0
  428. package/src/lib/index.ts +8 -0
  429. package/src/lib/jsx-dev-runtime.ts +2 -0
  430. package/src/lib/jsx-runtime.ts +45 -0
  431. package/src/lib/parse-svg-path.d.ts +14 -0
  432. package/src/lib/partials/Filter.ts +185 -0
  433. package/src/lib/partials/Gradient.ts +103 -0
  434. package/src/lib/partials/Pattern.ts +35 -0
  435. package/src/lib/partials/ShaderConfig.ts +122 -0
  436. package/src/lib/partials/index.ts +4 -0
  437. package/src/lib/partials/types.ts +58 -0
  438. package/src/lib/scenes/Scene2D.ts +195 -0
  439. package/src/lib/scenes/index.ts +3 -0
  440. package/src/lib/scenes/makeScene2D.ts +19 -0
  441. package/src/lib/scenes/useScene2D.ts +6 -0
  442. package/src/lib/tsconfig.build.json +12 -0
  443. package/src/lib/tsconfig.json +14 -0
  444. package/src/lib/tsdoc.json +4 -0
  445. package/src/lib/utils/CanvasUtils.ts +306 -0
  446. package/src/lib/utils/diff.test.ts +453 -0
  447. package/src/lib/utils/diff.ts +148 -0
  448. package/src/lib/utils/index.ts +3 -0
  449. package/src/lib/utils/is.ts +11 -0
  450. package/src/lib/utils/makeSignalExtensions.ts +29 -0
  451. package/src/lib/utils/withDefaults.tsx +26 -0
  452. package/src/tsconfig.base.json +18 -0
  453. package/src/tsconfig.build.json +8 -0
  454. package/src/tsconfig.json +5 -0
  455. package/tsconfig.project.json +7 -0
@@ -0,0 +1,368 @@
1
+ import {
2
+ BBox,
3
+ DependencyContext,
4
+ PlaybackState,
5
+ SerializedVector2,
6
+ SignalValue,
7
+ SimpleSignal,
8
+ clamp,
9
+ isReactive,
10
+ useLogger,
11
+ useThread,
12
+ } from '@efxlab/motion-canvas-core';
13
+ import {computed, initial, nodeName, signal} from '../decorators';
14
+ import {DesiredLength} from '../partials';
15
+ import {drawImage} from '../utils';
16
+ import {Rect, RectProps} from './Rect';
17
+ import reactivePlaybackRate from './__logs__/reactive-playback-rate.md';
18
+
19
+ export interface VideoProps extends RectProps {
20
+ /**
21
+ * {@inheritDoc Video.src}
22
+ */
23
+ src?: SignalValue<string>;
24
+ /**
25
+ * {@inheritDoc Video.alpha}
26
+ */
27
+ alpha?: SignalValue<number>;
28
+ /**
29
+ * {@inheritDoc Video.smoothing}
30
+ */
31
+ smoothing?: SignalValue<boolean>;
32
+ /**
33
+ * {@inheritDoc Video.loop}
34
+ */
35
+ loop?: SignalValue<boolean>;
36
+ /**
37
+ * {@inheritDoc Video.playbackRate}
38
+ */
39
+ playbackRate?: number;
40
+ /**
41
+ * The starting time for this video in seconds.
42
+ */
43
+ time?: SignalValue<number>;
44
+ play?: boolean;
45
+ }
46
+
47
+ @nodeName('Video')
48
+ export class Video extends Rect {
49
+ private static readonly pool: Record<string, HTMLVideoElement> = {};
50
+
51
+ /**
52
+ * The source of this video.
53
+ *
54
+ * @example
55
+ * Using a local video:
56
+ * ```tsx
57
+ * import video from './example.mp4';
58
+ * // ...
59
+ * view.add(<Video src={video} />)
60
+ * ```
61
+ * Loading an image from the internet:
62
+ * ```tsx
63
+ * view.add(<Video src="https://example.com/video.mp4" />)
64
+ * ```
65
+ */
66
+ @signal()
67
+ declare public readonly src: SimpleSignal<string, this>;
68
+
69
+ /**
70
+ * The alpha value of this video.
71
+ *
72
+ * @remarks
73
+ * Unlike opacity, the alpha value affects only the video itself, leaving the
74
+ * fill, stroke, and children intact.
75
+ */
76
+ @initial(1)
77
+ @signal()
78
+ declare public readonly alpha: SimpleSignal<number, this>;
79
+
80
+ /**
81
+ * Whether the video should be smoothed.
82
+ *
83
+ * @remarks
84
+ * When disabled, the video will be scaled using the nearest neighbor
85
+ * interpolation with no smoothing. The resulting video will appear pixelated.
86
+ *
87
+ * @defaultValue true
88
+ */
89
+ @initial(true)
90
+ @signal()
91
+ declare public readonly smoothing: SimpleSignal<boolean, this>;
92
+
93
+ /**
94
+ * Whether this video should loop upon reaching the end.
95
+ */
96
+ @initial(false)
97
+ @signal()
98
+ declare public readonly loop: SimpleSignal<boolean, this>;
99
+
100
+ /**
101
+ * The rate at which the video plays, as multiples of the normal speed.
102
+ *
103
+ * @defaultValue 1
104
+ */
105
+ @initial(1)
106
+ @signal()
107
+ declare public readonly playbackRate: SimpleSignal<number, this>;
108
+
109
+ @initial(0)
110
+ @signal()
111
+ declare protected readonly time: SimpleSignal<number, this>;
112
+
113
+ @initial(false)
114
+ @signal()
115
+ declare protected readonly playing: SimpleSignal<boolean, this>;
116
+
117
+ private lastTime = -1;
118
+
119
+ public constructor({play, ...props}: VideoProps) {
120
+ super(props);
121
+ if (play) {
122
+ this.play();
123
+ }
124
+ }
125
+
126
+ /**
127
+ * {@inheritDoc Curve.completion}
128
+ */
129
+ public curveCompletion(): number {
130
+ return super.completion();
131
+ }
132
+
133
+ public isPlaying(): boolean {
134
+ return this.playing();
135
+ }
136
+
137
+ public getCurrentTime(): number {
138
+ return this.clampTime(this.time());
139
+ }
140
+
141
+ public getDuration(): number {
142
+ return this.video().duration;
143
+ }
144
+
145
+ protected override desiredSize(): SerializedVector2<DesiredLength> {
146
+ const custom = super.desiredSize();
147
+ if (custom.x === null && custom.y === null) {
148
+ const image = this.video();
149
+ return {
150
+ x: image.videoWidth,
151
+ y: image.videoHeight,
152
+ };
153
+ }
154
+
155
+ return custom;
156
+ }
157
+
158
+ /**
159
+ * The completion of this video in the range from 0 to 1.
160
+ *
161
+ * @remarks
162
+ * To get the percentage of the stroke that's currently visible, use
163
+ * {@link Video.curveCompletion} instead.
164
+ */
165
+ @computed()
166
+ public override completion(): number {
167
+ return this.clampTime(this.time()) / this.video().duration;
168
+ }
169
+
170
+ @computed()
171
+ protected video(): HTMLVideoElement {
172
+ const src = this.src();
173
+ const key = `${this.key}/${src}`;
174
+ let video = Video.pool[key];
175
+ if (!video) {
176
+ video = document.createElement('video');
177
+ video.src = src;
178
+ Video.pool[key] = video;
179
+ }
180
+
181
+ if (video.readyState < 2) {
182
+ DependencyContext.collectPromise(
183
+ new Promise<void>(resolve => {
184
+ const listener = () => {
185
+ resolve();
186
+ video.removeEventListener('canplay', listener);
187
+ };
188
+ video.addEventListener('canplay', listener);
189
+ }),
190
+ );
191
+ }
192
+
193
+ return video;
194
+ }
195
+
196
+ @computed()
197
+ protected seekedVideo(): HTMLVideoElement {
198
+ const video = this.video();
199
+ const time = this.clampTime(this.time());
200
+
201
+ video.playbackRate = this.playbackRate();
202
+
203
+ if (!video.paused) {
204
+ video.pause();
205
+ }
206
+
207
+ if (this.lastTime === time) {
208
+ return video;
209
+ }
210
+
211
+ this.setCurrentTime(time);
212
+
213
+ return video;
214
+ }
215
+
216
+ @computed()
217
+ protected fastSeekedVideo(): HTMLVideoElement {
218
+ const video = this.video();
219
+ const time = this.clampTime(this.time());
220
+
221
+ video.playbackRate = this.playbackRate();
222
+
223
+ if (this.lastTime === time) {
224
+ return video;
225
+ }
226
+
227
+ const playing =
228
+ this.playing() && time < video.duration && video.playbackRate > 0;
229
+ if (playing) {
230
+ if (video.paused) {
231
+ DependencyContext.collectPromise(video.play());
232
+ }
233
+ } else {
234
+ if (!video.paused) {
235
+ video.pause();
236
+ }
237
+ }
238
+
239
+ if (Math.abs(video.currentTime - time) > 0.2) {
240
+ this.setCurrentTime(time);
241
+ } else if (!playing) {
242
+ video.currentTime = time;
243
+ }
244
+
245
+ return video;
246
+ }
247
+
248
+ protected override draw(context: CanvasRenderingContext2D) {
249
+ this.drawShape(context);
250
+ const alpha = this.alpha();
251
+ if (alpha > 0) {
252
+ const playbackState = this.view().playbackState();
253
+ const video =
254
+ playbackState === PlaybackState.Playing ||
255
+ playbackState === PlaybackState.Presenting
256
+ ? this.fastSeekedVideo()
257
+ : this.seekedVideo();
258
+
259
+ const box = BBox.fromSizeCentered(this.computedSize());
260
+ context.save();
261
+ context.clip(this.getPath());
262
+ if (alpha < 1) {
263
+ context.globalAlpha *= alpha;
264
+ }
265
+ context.imageSmoothingEnabled = this.smoothing();
266
+ drawImage(context, video, box);
267
+ context.restore();
268
+ }
269
+
270
+ if (this.clip()) {
271
+ context.clip(this.getPath());
272
+ }
273
+
274
+ this.drawChildren(context);
275
+ }
276
+
277
+ protected override applyFlex() {
278
+ super.applyFlex();
279
+ const video = this.video();
280
+ this.element.style.aspectRatio = (
281
+ this.ratio() ?? video.videoWidth / video.videoHeight
282
+ ).toString();
283
+ }
284
+
285
+ protected setCurrentTime(value: number) {
286
+ const video = this.video();
287
+ if (video.readyState < 2) return;
288
+
289
+ video.currentTime = value;
290
+ this.lastTime = value;
291
+ if (video.seeking) {
292
+ DependencyContext.collectPromise(
293
+ new Promise<void>(resolve => {
294
+ const listener = () => {
295
+ resolve();
296
+ video.removeEventListener('seeked', listener);
297
+ };
298
+ video.addEventListener('seeked', listener);
299
+ }),
300
+ );
301
+ }
302
+ }
303
+
304
+ protected setPlaybackRate(playbackRate: number) {
305
+ let value: number;
306
+ if (isReactive(playbackRate)) {
307
+ value = playbackRate();
308
+ useLogger().warn({
309
+ message: 'Invalid value set as the playback rate',
310
+ remarks: reactivePlaybackRate,
311
+ inspect: this.key,
312
+ stack: new Error().stack,
313
+ });
314
+ } else {
315
+ value = playbackRate;
316
+ }
317
+ this.playbackRate.context.setter(value);
318
+
319
+ if (this.playing()) {
320
+ if (value === 0) {
321
+ this.pause();
322
+ } else {
323
+ const time = useThread().time;
324
+ const start = time();
325
+ const offset = this.time();
326
+ this.time(() => this.clampTime(offset + (time() - start) * value));
327
+ }
328
+ }
329
+ }
330
+
331
+ public play() {
332
+ const time = useThread().time;
333
+ const start = time();
334
+ const offset = this.time();
335
+ const playbackRate = this.playbackRate();
336
+ this.playing(true);
337
+ this.time(() => this.clampTime(offset + (time() - start) * playbackRate));
338
+ }
339
+
340
+ public pause() {
341
+ this.playing(false);
342
+ this.time.save();
343
+ this.video().pause();
344
+ }
345
+
346
+ public seek(time: number) {
347
+ const playing = this.playing();
348
+ this.time(this.clampTime(time));
349
+ if (playing) {
350
+ this.play();
351
+ } else {
352
+ this.pause();
353
+ }
354
+ }
355
+
356
+ public clampTime(time: number): number {
357
+ const duration = this.video().duration;
358
+ if (this.loop()) {
359
+ time %= duration;
360
+ }
361
+ return clamp(0, duration, time);
362
+ }
363
+
364
+ protected override collectAsyncResources() {
365
+ super.collectAsyncResources();
366
+ this.seekedVideo();
367
+ }
368
+ }
@@ -0,0 +1,85 @@
1
+ import {PlaybackState, SimpleSignal, lazy} from '@efxlab/motion-canvas-core';
2
+ import {initial, signal} from '../decorators';
3
+ import {nodeName} from '../decorators/nodeName';
4
+ import {useScene2D} from '../scenes/useScene2D';
5
+ import type {Node} from './Node';
6
+ import {Rect, RectProps} from './Rect';
7
+
8
+ export interface View2DProps extends RectProps {
9
+ assetHash: string;
10
+ }
11
+
12
+ @nodeName('View2D')
13
+ export class View2D extends Rect {
14
+ @lazy(() => {
15
+ const frameID = 'motion-canvas-2d-frame';
16
+ let frame = document.querySelector<HTMLDivElement>(`#${frameID}`);
17
+ if (!frame) {
18
+ frame = document.createElement('div');
19
+ frame.id = frameID;
20
+ frame.style.position = 'absolute';
21
+ frame.style.pointerEvents = 'none';
22
+ frame.style.top = '0';
23
+ frame.style.left = '0';
24
+ frame.style.opacity = '0';
25
+ frame.style.overflow = 'hidden';
26
+ document.body.prepend(frame);
27
+ }
28
+ return frame.shadowRoot ?? frame.attachShadow({mode: 'open'});
29
+ })
30
+ public static shadowRoot: ShadowRoot;
31
+
32
+ @initial(PlaybackState.Paused)
33
+ @signal()
34
+ declare public readonly playbackState: SimpleSignal<PlaybackState, this>;
35
+
36
+ @initial(0)
37
+ @signal()
38
+ declare public readonly globalTime: SimpleSignal<number, this>;
39
+
40
+ @signal()
41
+ declare public readonly assetHash: SimpleSignal<string, this>;
42
+
43
+ public constructor(props: View2DProps) {
44
+ super({
45
+ composite: true,
46
+ ...props,
47
+ });
48
+ this.view2D = this;
49
+
50
+ View2D.shadowRoot.append(this.element);
51
+ this.applyFlex();
52
+ }
53
+
54
+ public override dispose() {
55
+ this.removeChildren();
56
+ super.dispose();
57
+ }
58
+
59
+ public override render(context: CanvasRenderingContext2D) {
60
+ this.computedSize();
61
+ this.computedPosition();
62
+ super.render(context);
63
+ }
64
+
65
+ /**
66
+ * Find a node by its key.
67
+ *
68
+ * @param key - The key of the node.
69
+ */
70
+ public findKey<T extends Node = Node>(key: string): T | null {
71
+ return (useScene2D().getNode(key) as T) ?? null;
72
+ }
73
+
74
+ protected override requestLayoutUpdate() {
75
+ this.updateLayout();
76
+ }
77
+
78
+ protected override requestFontUpdate() {
79
+ this.applyFont();
80
+ }
81
+
82
+ public override view(): View2D {
83
+ return this;
84
+ }
85
+ }
@@ -0,0 +1,17 @@
1
+ The image won't be visible unless you specify a source:
2
+
3
+ ```tsx
4
+ import myImage from './example.png';
5
+ // ...
6
+ <Img src={myImage} />;
7
+ ```
8
+
9
+ If you did this intentionally, and don't want to see this warning, set the `src`
10
+ property to `null`:
11
+
12
+ ```tsx
13
+ <Img src={null} />
14
+ ```
15
+
16
+ [Learn more](https://motioncanvas.io/docs/media#images) about working with
17
+ images.
@@ -0,0 +1,30 @@
1
+ The line won't be visible unless you specify at least two points:
2
+
3
+ ```tsx
4
+ <Line
5
+ stroke="#fff"
6
+ lineWidth={8}
7
+ points={[
8
+ [100, 0],
9
+ [0, 0],
10
+ [0, 100],
11
+ ]}
12
+ />
13
+ ```
14
+
15
+ Alternatively, you can define the points using the children:
16
+
17
+ ```tsx
18
+ <Line stroke="#fff" lineWidth={8}>
19
+ <Node x={100} />
20
+ <Node />
21
+ <Node y={100} />
22
+ </Line>
23
+ ```
24
+
25
+ If you did this intentionally, and want to disable this message, set the
26
+ `points` property to `null`:
27
+
28
+ ```tsx
29
+ <Line stroke="#fff" lineWidth={8} points={null} />
30
+ ```
@@ -0,0 +1,21 @@
1
+ The `playbackRate` of a `Video` cannot be reactive.
2
+
3
+ Make sure to use a concrete value and not a function:
4
+
5
+ ```ts wrong
6
+ video.playbackRate(() => 7);
7
+ ```
8
+
9
+ ```ts correct
10
+ video.playbackRate(7);
11
+ ```
12
+
13
+ If you're using a signal, extract its value before passing it to the property:
14
+
15
+ ```ts wrong
16
+ video.playbackRate(mySignal);
17
+ ```
18
+
19
+ ```ts correct
20
+ video.playbackRate(mySignal());
21
+ ```
@@ -0,0 +1,24 @@
1
+ The spline won't be visible unless you specify at least two knots:
2
+
3
+ ```tsx
4
+ <Spline
5
+ stroke="#fff"
6
+ lineWidth={8}
7
+ points={[
8
+ [100, 0],
9
+ [0, 0],
10
+ [0, 100],
11
+ ]}
12
+ />
13
+ ```
14
+
15
+ For more control over the knot handles, you can alternatively provide the knots
16
+ as children to the spline using the `Knot` component:
17
+
18
+ ```tsx
19
+ <Spline stroke="#fff" lineWidth={8}>
20
+ <Knot x={100} endHandle={[-50, 0]} />
21
+ <Knot />
22
+ <Knot y={100} startHandle={[-100, 50]} />
23
+ </Spline>
24
+ ```
@@ -0,0 +1,142 @@
1
+ import {createRef, createSignal, range} from '@efxlab/motion-canvas-core';
2
+ import {describe, expect, it} from 'vitest';
3
+ import {useScene2D} from '../../scenes';
4
+ import {Node} from '../Node';
5
+ import {mockScene2D} from './mockScene2D';
6
+
7
+ describe('children', () => {
8
+ mockScene2D();
9
+
10
+ it('Append children', () => {
11
+ const view = useScene2D().getView();
12
+ const parent = createRef<Node>();
13
+ const childA = createRef<Node>();
14
+ const childB = createRef<Node>();
15
+
16
+ view.add(
17
+ <Node ref={parent}>
18
+ <Node ref={childA} />
19
+ <Node ref={childB} />
20
+ </Node>,
21
+ );
22
+
23
+ expect(childA().parent()).toBe(parent());
24
+ expect(childB().parent()).toBe(parent());
25
+ expect(parent().children()).toEqual([childA(), childB()]);
26
+ });
27
+
28
+ it('Clear children', () => {
29
+ const view = useScene2D().getView();
30
+ const parent = createRef<Node>();
31
+ const childA = createRef<Node>();
32
+ const childB = createRef<Node>();
33
+
34
+ view.add(
35
+ <Node ref={parent}>
36
+ <Node ref={childA} />
37
+ <Node ref={childB} />
38
+ </Node>,
39
+ );
40
+
41
+ parent().removeChildren();
42
+
43
+ expect(childA().parent()).toBe(null);
44
+ expect(childB().parent()).toBe(null);
45
+ expect(parent().children()).toEqual([]);
46
+ });
47
+
48
+ it('Replace children', () => {
49
+ const view = useScene2D().getView();
50
+ const parent = createRef<Node>();
51
+ const childA = <Node />;
52
+ const childB = <Node />;
53
+
54
+ view.add(<Node ref={parent}>{childA}</Node>);
55
+
56
+ parent().children(childB);
57
+
58
+ expect(childA.parent()).toBe(null);
59
+ expect(childB.parent()).toBe(parent());
60
+ expect(parent().children()).toEqual([childB]);
61
+ });
62
+
63
+ it('Take a child from another node', () => {
64
+ const view = useScene2D().getView();
65
+ const parentA = createRef<Node>();
66
+ const parentB = createRef<Node>();
67
+ const child = createRef<Node>();
68
+
69
+ view.add(
70
+ <>
71
+ <Node ref={parentA}>
72
+ <Node ref={child} />
73
+ </Node>
74
+ <Node ref={parentB} />
75
+ </>,
76
+ );
77
+
78
+ expect(parentA().children()).toEqual([child()]);
79
+ expect(parentB().children()).toEqual([]);
80
+ expect(child().parent()).toBe(parentA());
81
+
82
+ parentB().children(child());
83
+
84
+ expect(parentA().children()).toEqual([]);
85
+ expect(parentB().children()).toEqual([child()]);
86
+ expect(child().parent()).toBe(parentB());
87
+ });
88
+
89
+ it('Append children conditionally', () => {
90
+ const view = useScene2D().getView();
91
+ const parent = createRef<Node>();
92
+ const childA = <Node />;
93
+ const childB = <Node />;
94
+ const predicate = createSignal(false);
95
+
96
+ view.add(<Node ref={parent}>{() => (predicate() ? childA : childB)}</Node>);
97
+
98
+ expect(parent().children()).toEqual([childB]);
99
+ expect(childA.parent()).toBe(null);
100
+ expect(childB.parent()).toBe(parent());
101
+
102
+ predicate(true);
103
+
104
+ expect(parent().children()).toEqual([childA]);
105
+ expect(childA.parent()).toBe(parent());
106
+ expect(childB.parent()).toBe(null);
107
+ });
108
+
109
+ it('Spawn reactive children', () => {
110
+ const view = useScene2D().getView();
111
+ const parent = createRef<Node>();
112
+ const count = createSignal(3);
113
+
114
+ view.add(
115
+ <Node ref={parent}>{() => range(count()).map(() => <Node />)}</Node>,
116
+ );
117
+
118
+ expect(parent().children().length).toBe(3);
119
+
120
+ count(5);
121
+
122
+ expect(parent().children().length).toBe(5);
123
+ });
124
+
125
+ it('Replace a spawner', () => {
126
+ const view = useScene2D().getView();
127
+ const parent = createRef<Node>();
128
+ const childA = <Node />;
129
+ const childB = <Node />;
130
+
131
+ view.add(<Node ref={parent}>{() => childA}</Node>);
132
+
133
+ expect(parent().children()).toEqual([childA]);
134
+ expect(childA.parent()).toBe(parent());
135
+
136
+ parent().children(childB);
137
+
138
+ expect(childA.parent()).toBe(null);
139
+ expect(childB.parent()).toBe(parent());
140
+ expect(parent().children()).toEqual([childB]);
141
+ });
142
+ });