semiotic 3.8.3 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/CLAUDE.md +13 -10
  2. package/README.md +52 -45
  3. package/ai/componentMetadata.cjs +1 -1
  4. package/ai/dist/mcp-server.js +4 -2
  5. package/ai/examples.md +168 -1
  6. package/ai/schema.json +3756 -327
  7. package/ai/surface-manifest.json +6 -4
  8. package/ai/system-prompt.md +1 -1
  9. package/dist/chunk-chartContainerDataAudit-74TLKIP6.module.min.js +2 -0
  10. package/dist/chunk-chunk-2JGJ5GUG.module.min.js +0 -1
  11. package/dist/chunk-chunk-4AANPFOX.module.min.js +2 -0
  12. package/dist/{chunk-chunk-JNCHKRIR.module.min.js → chunk-chunk-5I3UZV4Q.module.min.js} +1 -1
  13. package/dist/chunk-chunk-74CCPVXB.module.min.js +1 -0
  14. package/dist/{chunk-chunk-VVCA3DB7.module.min.js → chunk-chunk-7ALTGHK6.module.min.js} +1 -1
  15. package/dist/chunk-chunk-ACLDBMRH.module.min.js +2 -0
  16. package/dist/chunk-chunk-AVBI6GDT.module.min.js +1 -0
  17. package/dist/{chunk-chunk-XQYVEKEJ.module.min.js → chunk-chunk-BANTPINB.module.min.js} +1 -1
  18. package/dist/chunk-chunk-C4YA6TDR.module.min.js +1 -0
  19. package/dist/chunk-chunk-C57LR3YG.module.min.js +1 -0
  20. package/dist/chunk-chunk-CKMD5NV3.module.min.js +2 -0
  21. package/dist/chunk-chunk-CO5KQMGH.module.min.js +1 -0
  22. package/dist/chunk-chunk-CWQ5YIHX.module.min.js +2 -0
  23. package/dist/chunk-chunk-E6TXX6MI.module.min.js +1 -0
  24. package/dist/{chunk-chunk-7FW6EGLP.module.min.js → chunk-chunk-I36PJ4OC.module.min.js} +1 -1
  25. package/dist/chunk-chunk-IY7RYD4S.module.min.js +1 -0
  26. package/dist/chunk-chunk-K3DMEW22.module.min.js +1 -0
  27. package/dist/chunk-chunk-KT2VAZMZ.module.min.js +1 -0
  28. package/dist/{chunk-chunk-AZJUDQRM.module.min.js → chunk-chunk-L6EA5V3G.module.min.js} +1 -1
  29. package/dist/{chunk-chunk-SANERMIZ.module.min.js → chunk-chunk-LJLS6DY7.module.min.js} +1 -1
  30. package/dist/chunk-chunk-LJPCLYSC.module.min.js +2 -0
  31. package/dist/chunk-chunk-LRIFN2HK.module.min.js +1 -0
  32. package/dist/chunk-chunk-N5DDKCCF.module.min.js +1 -0
  33. package/dist/chunk-chunk-NEVE562N.module.min.js +1 -0
  34. package/dist/chunk-chunk-NLO44TOS.module.min.js +2 -0
  35. package/dist/{chunk-chunk-FYY2ACNJ.module.min.js → chunk-chunk-PRDGLMJT.module.min.js} +1 -1
  36. package/dist/chunk-chunk-PZJ2SBLL.module.min.js +2 -0
  37. package/dist/chunk-chunk-QUJ6TTLY.module.min.js +1 -0
  38. package/dist/chunk-chunk-RBIDBUT4.module.min.js +2 -0
  39. package/dist/chunk-chunk-RFLAG356.module.min.js +1 -0
  40. package/dist/chunk-chunk-RPU4IZAV.module.min.js +2 -0
  41. package/dist/chunk-chunk-SKMBCFIL.module.min.js +2 -0
  42. package/dist/chunk-chunk-TAE7W424.module.min.js +2 -0
  43. package/dist/{chunk-chunk-OQTLSTGI.module.min.js → chunk-chunk-TMWIZL3K.module.min.js} +1 -1
  44. package/dist/chunk-chunk-TUBMTZMU.module.min.js +2 -0
  45. package/dist/chunk-chunk-UFFEXJQY.module.min.js +1 -0
  46. package/dist/chunk-chunk-XSCHTS4D.module.min.js +2 -0
  47. package/dist/chunk-chunk-XXWSHGPL.module.min.js +2 -0
  48. package/dist/chunk-chunk-ZOAQDIJO.module.min.js +1 -0
  49. package/dist/chunk-chunk-ZXIXAPRE.module.min.js +2 -0
  50. package/dist/chunk-minimapBrushOverlay-JU57U7NM.module.min.js +2 -0
  51. package/dist/chunk-scatterplotMatrixBrushOverlay-SDIZSN66.module.min.js +2 -0
  52. package/dist/chunk-statisticalOverlays-QGDLRUHX.module.min.js +1 -0
  53. package/dist/chunk-statisticalOverlays-T77OKLDY.module.min.js +1 -0
  54. package/dist/components/ChartContainer.d.ts +12 -2
  55. package/dist/components/ai/chartCapabilities.d.ts +2 -1
  56. package/dist/components/ai/chartCapabilityTypes.d.ts +19 -0
  57. package/dist/components/chartContainerDataAudit.d.ts +10 -0
  58. package/dist/components/charts/geo/ChoroplethMap.d.ts +2 -0
  59. package/dist/components/charts/geo/DistanceCartogram.d.ts +35 -5
  60. package/dist/components/charts/geo/FlowMap.d.ts +4 -0
  61. package/dist/components/charts/geo/ProportionalSymbolMap.d.ts +3 -1
  62. package/dist/components/charts/index.d.ts +1 -0
  63. package/dist/components/charts/network/ForceDirectedGraph.d.ts +36 -1
  64. package/dist/components/charts/physics/CollisionSwarmChart.d.ts +6 -1
  65. package/dist/components/charts/physics/CrucibleChart.capability.d.ts +8 -0
  66. package/dist/components/charts/physics/CrucibleChart.d.ts +63 -0
  67. package/dist/components/charts/physics/GaltonBoardChart.d.ts +6 -1
  68. package/dist/components/charts/physics/crucibleBodyRenderers.d.ts +27 -0
  69. package/dist/components/charts/physics/crucibleChartProps.d.ts +90 -0
  70. package/dist/components/charts/physics/crucibleChrome.d.ts +47 -0
  71. package/dist/components/charts/physics/crucibleController.d.ts +59 -0
  72. package/dist/components/charts/physics/crucibleEffects.d.ts +30 -0
  73. package/dist/components/charts/physics/cruciblePhysics.d.ts +54 -0
  74. package/dist/components/charts/physics/crucibleProgram.d.ts +38 -0
  75. package/dist/components/charts/physics/crucibleTypes.d.ts +415 -0
  76. package/dist/components/charts/physics/gauntletChartProps.d.ts +7 -1
  77. package/dist/components/charts/physics/gauntletChrome.d.ts +2 -1
  78. package/dist/components/charts/physics/gauntletPhysics.d.ts +19 -4
  79. package/dist/components/charts/physics/gauntletRuntime.d.ts +3 -0
  80. package/dist/components/charts/physics/physicsHocUtils.d.ts +12 -0
  81. package/dist/components/charts/shared/chartMode.d.ts +8 -0
  82. package/dist/components/charts/shared/chartSpecCore.d.ts +10 -2
  83. package/dist/components/charts/shared/crucibleWireSchema.d.ts +5 -0
  84. package/dist/components/charts/shared/diagnoseTypes.d.ts +10 -0
  85. package/dist/components/charts/shared/hatchPattern.d.ts +8 -3
  86. package/dist/components/charts/shared/knownChartComponents.d.ts +1 -1
  87. package/dist/components/charts/shared/lineSeriesSsr.d.ts +55 -0
  88. package/dist/components/charts/shared/types.d.ts +2 -2
  89. package/dist/components/charts/shared/validateProps.d.ts +1 -1
  90. package/dist/components/charts/xy/AreaChart.d.ts +10 -0
  91. package/dist/components/charts/xy/minimapBrushOverlay.d.ts +17 -0
  92. package/dist/components/charts/xy/minimapBrushOverlayLazy.d.ts +4 -0
  93. package/dist/components/charts/xy/scatterplotMatrixBrushOverlay.d.ts +8 -0
  94. package/dist/components/charts/xy/scatterplotMatrixBrushOverlayLazy.d.ts +3 -0
  95. package/dist/components/data/auditData.d.ts +51 -0
  96. package/dist/components/data/dataAuditPresentation.d.ts +18 -0
  97. package/dist/components/data/dataAuditSources.d.ts +9 -0
  98. package/dist/components/data/numericContracts.d.ts +59 -0
  99. package/dist/components/data/numericFieldProfiler.d.ts +23 -0
  100. package/dist/components/realtime/types.d.ts +5 -0
  101. package/dist/components/recipes/gridObservatory.d.ts +176 -0
  102. package/dist/components/recipes/netEnsembleLayout.d.ts +167 -0
  103. package/dist/components/recipes/netEnsembleOverlays.d.ts +20 -0
  104. package/dist/components/recipes/recipeChrome.d.ts +24 -0
  105. package/dist/components/recipes/sequenceLayout.d.ts +139 -0
  106. package/dist/components/recipes/wordTrails.d.ts +156 -0
  107. package/dist/components/recipes/wordTrailsProgressiveReveal.d.ts +42 -0
  108. package/dist/components/semiotic-ai-core.d.ts +3 -0
  109. package/dist/components/semiotic-ai-data-audit.d.ts +4 -0
  110. package/dist/components/semiotic-ai.d.ts +7 -5
  111. package/dist/components/semiotic-physics.d.ts +1 -0
  112. package/dist/components/semiotic-recipes-core.d.ts +10 -2
  113. package/dist/components/semiotic-utils-core.d.ts +3 -0
  114. package/dist/components/semiotic.d.ts +1 -1
  115. package/dist/components/server/renderEvidence.d.ts +27 -0
  116. package/dist/components/server/serverChartConfigs.d.ts +1 -0
  117. package/dist/components/server/serverChartConfigsPhysics.d.ts +9 -0
  118. package/dist/components/server/staticAnnotations.d.ts +15 -1
  119. package/dist/components/stream/GeoPipelineStore.d.ts +1 -0
  120. package/dist/components/stream/GeoSVGOverlay.d.ts +7 -0
  121. package/dist/components/stream/SceneToSVG.d.ts +6 -6
  122. package/dist/components/stream/SceneToSVGOrdinal.d.ts +12 -0
  123. package/dist/components/stream/geoCartogram.d.ts +7 -0
  124. package/dist/components/stream/geoTypes.d.ts +17 -2
  125. package/dist/components/stream/networkFrameHandleTypes.d.ts +4 -0
  126. package/dist/components/stream/networkFramePaint.d.ts +2 -0
  127. package/dist/components/stream/physics/PhysicsPipelineStore.d.ts +18 -2
  128. package/dist/components/stream/physics/PhysicsSettledSVG.d.ts +8 -0
  129. package/dist/components/stream/physics/physicsBodyCanvas.d.ts +7 -0
  130. package/dist/components/stream/physics/physicsPipelineEviction.d.ts +15 -0
  131. package/dist/components/stream/physics/physicsPipelineObservations.d.ts +1 -1
  132. package/dist/components/stream/physics/physicsPipelineQuiescence.d.ts +20 -0
  133. package/dist/components/stream/sceneToSVGShared.d.ts +30 -1
  134. package/dist/components/stream/types.d.ts +4 -0
  135. package/dist/components/stream/useHydration.d.ts +7 -1
  136. package/dist/components/stream/xySceneBuilders/candlestickScene.d.ts +1 -1
  137. package/dist/components/useChartContainerDataAudit.d.ts +7 -0
  138. package/dist/forceLayoutWorker.js +1 -1
  139. package/dist/geo.min.js +1 -1
  140. package/dist/geo.module.min.js +1 -1
  141. package/dist/network.min.js +1 -1
  142. package/dist/network.module.min.js +1 -1
  143. package/dist/ordinal.min.js +1 -1
  144. package/dist/ordinal.module.min.js +1 -1
  145. package/dist/physics.min.js +1 -1
  146. package/dist/physics.module.min.js +1 -1
  147. package/dist/physicsWorker.js +1 -1
  148. package/dist/realtime.min.js +1 -1
  149. package/dist/realtime.module.min.js +1 -1
  150. package/dist/rough.min.js +1 -1
  151. package/dist/rough.module.min.js +1 -1
  152. package/dist/semiotic-ai-core.d.ts +3 -0
  153. package/dist/semiotic-ai-core.min.js +1 -1
  154. package/dist/semiotic-ai-core.module.min.js +1 -1
  155. package/dist/semiotic-ai.d.ts +7 -5
  156. package/dist/semiotic-ai.min.js +1 -1
  157. package/dist/semiotic-ai.module.min.js +1 -1
  158. package/dist/semiotic-experimental.min.js +1 -1
  159. package/dist/semiotic-experimental.module.min.js +1 -1
  160. package/dist/semiotic-physics.d.ts +1 -0
  161. package/dist/semiotic-realtime-core.min.js +1 -1
  162. package/dist/semiotic-realtime-core.module.min.js +1 -1
  163. package/dist/semiotic-recipes-core.d.ts +10 -2
  164. package/dist/semiotic-recipes-core.min.js +1 -1
  165. package/dist/semiotic-recipes-core.module.min.js +1 -1
  166. package/dist/semiotic-recipes.min.js +1 -1
  167. package/dist/semiotic-recipes.module.min.js +1 -1
  168. package/dist/semiotic-server-edge.min.js +1 -1
  169. package/dist/semiotic-server-edge.module.min.js +1 -1
  170. package/dist/semiotic-server-node.min.js +1 -1
  171. package/dist/semiotic-server-node.module.min.js +1 -1
  172. package/dist/semiotic-utils-core.d.ts +3 -0
  173. package/dist/semiotic-utils-core.min.js +1 -1
  174. package/dist/semiotic-utils-core.module.min.js +1 -1
  175. package/dist/semiotic-utils.min.js +1 -1
  176. package/dist/semiotic-utils.module.min.js +1 -1
  177. package/dist/semiotic-value.module.min.js +1 -1
  178. package/dist/semiotic.d.ts +1 -1
  179. package/dist/semiotic.min.js +1 -1
  180. package/dist/semiotic.module.min.js +1 -1
  181. package/dist/server.min.js +1 -1
  182. package/dist/server.module.min.js +1 -1
  183. package/dist/xy.min.js +1 -1
  184. package/dist/xy.module.min.js +1 -1
  185. package/package.json +4 -3
  186. package/dist/chunk-chunk-255KDHW5.module.min.js +0 -1
  187. package/dist/chunk-chunk-2CCFBTQC.module.min.js +0 -2
  188. package/dist/chunk-chunk-2RXP3FS3.module.min.js +0 -1
  189. package/dist/chunk-chunk-2WVCH4PL.module.min.js +0 -1
  190. package/dist/chunk-chunk-4TMZXLCR.module.min.js +0 -1
  191. package/dist/chunk-chunk-5APBQXZA.module.min.js +0 -1
  192. package/dist/chunk-chunk-6HSGDMTA.module.min.js +0 -2
  193. package/dist/chunk-chunk-7OEOSCBP.module.min.js +0 -1
  194. package/dist/chunk-chunk-A63CTACR.module.min.js +0 -2
  195. package/dist/chunk-chunk-B6V35LMY.module.min.js +0 -2
  196. package/dist/chunk-chunk-BOSVL645.module.min.js +0 -2
  197. package/dist/chunk-chunk-CP3EN6KZ.module.min.js +0 -1
  198. package/dist/chunk-chunk-F25UA5HT.module.min.js +0 -1
  199. package/dist/chunk-chunk-FRIO6MCV.module.min.js +0 -1
  200. package/dist/chunk-chunk-GWSWSPXN.module.min.js +0 -1
  201. package/dist/chunk-chunk-I6C3KR5H.module.min.js +0 -2
  202. package/dist/chunk-chunk-IP2UE74X.module.min.js +0 -1
  203. package/dist/chunk-chunk-J3ELI22J.module.min.js +0 -1
  204. package/dist/chunk-chunk-J5RL6GXU.module.min.js +0 -2
  205. package/dist/chunk-chunk-L3H6DQCR.module.min.js +0 -2
  206. package/dist/chunk-chunk-M337NY6L.module.min.js +0 -1
  207. package/dist/chunk-chunk-M7VYYHCE.module.min.js +0 -2
  208. package/dist/chunk-chunk-MC35ILYP.module.min.js +0 -2
  209. package/dist/chunk-chunk-N72SWNBV.module.min.js +0 -1
  210. package/dist/chunk-chunk-OBQRFTIL.module.min.js +0 -2
  211. package/dist/chunk-chunk-QRIBHZYW.module.min.js +0 -1
  212. package/dist/chunk-chunk-SA3D43RA.module.min.js +0 -2
  213. package/dist/chunk-chunk-UHSZEB74.module.min.js +0 -1
  214. package/dist/chunk-chunk-Y6AXCRVO.module.min.js +0 -1
  215. package/dist/chunk-chunk-ZCNBUZPL.module.min.js +0 -2
@@ -52,6 +52,7 @@ export declare class GeoPipelineStore implements UpdateResultStore {
52
52
  cy: number;
53
53
  maxCost: number;
54
54
  availableRadius: number;
55
+ layout?: "radial" | "strip";
55
56
  } | null;
56
57
  private areas;
57
58
  private pointData;
@@ -3,6 +3,7 @@ import type { OnObservationCallback } from "../store/ObservationStore";
3
3
  import { type OnAnnotationActivateCallback } from "../charts/shared/annotationActivation";
4
4
  import * as React from "react";
5
5
  import type { ReactNode } from "react";
6
+ import type { AnnotationContext } from "../realtime/types";
6
7
  import type { GradientLegendConfig, LegendGroup, LegendLayout } from "../types/legendTypes";
7
8
  import { type AutoPlaceAnnotations } from "../recipes/annotationLayout";
8
9
  interface GeoSVGOverlayProps {
@@ -45,6 +46,12 @@ interface GeoSVGOverlayProps {
45
46
  chartId?: string;
46
47
  chartType?: string;
47
48
  autoPlaceAnnotations?: AutoPlaceAnnotations;
49
+ /**
50
+ * Custom SVG annotation renderer. Same contract as XY/ordinal
51
+ * `svgAnnotationRules`. Runs after geographic `coordinates` are projected
52
+ * to pixel `x`/`y`, so rules can use the shared pixel-scale context.
53
+ */
54
+ svgAnnotationRules?: (annotation: Datum, index: number, context: AnnotationContext) => ReactNode;
48
55
  pointNodes?: {
49
56
  pointId?: string;
50
57
  x: number;
@@ -4,19 +4,19 @@
4
4
  * Shared module used by Stream Frames for SSR rendering and
5
5
  * by semiotic/server for static SVG export.
6
6
  *
7
- * Network and geo serializers live in sibling modules
8
- * (SceneToSVGNetwork.tsx / SceneToSVGGeo.tsx) and are re-exported below to
9
- * keep this file under the file-size ratchet ceiling; low-level helpers
10
- * shared across all three (svgFill, safeSvgId, glyphNodeToSVG, ARC_NOOP)
7
+ * Network, geo, and ordinal serializers live in sibling modules
8
+ * (SceneToSVGNetwork.tsx / SceneToSVGGeo.tsx / SceneToSVGOrdinal.tsx) and are
9
+ * re-exported below to keep this file under the file-size ratchet ceiling;
10
+ * low-level helpers shared across them (svgFill, safeSvgId, glyphNodeToSVG,
11
+ * buildRectSVGGradient, perCornerSvgPath, symbolSceneNodeToSVG, ARC_NOOP)
11
12
  * live in sceneToSVGShared.tsx.
12
13
  */
13
14
  import * as React from "react";
14
15
  import type { SceneNode } from "./types";
15
- import type { OrdinalSceneNode } from "./ordinalTypes";
16
16
  export { networkSceneNodeToSVG, networkSceneEdgeToSVG, networkLabelToSVG } from "./SceneToSVGNetwork";
17
17
  export { geoSceneNodeToSVG } from "./SceneToSVGGeo";
18
+ export { ordinalSceneNodeToSVG } from "./SceneToSVGOrdinal";
18
19
  export declare function xySceneNodeToSVG(node: SceneNode, i: number, idPrefix?: string): React.ReactNode;
19
- export declare function ordinalSceneNodeToSVG(node: OrdinalSceneNode, i: number, idPrefix?: string): React.ReactNode;
20
20
  /**
21
21
  * Returns true when running in a true server/Node.js context where
22
22
  * window and document are not available.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Ordinal scene graph → SVG element converter.
3
+ *
4
+ * Split out of SceneToSVG.tsx (which re-exports `ordinalSceneNodeToSVG`) to
5
+ * keep that file under the file-size ratchet ceiling. Shared helpers
6
+ * (svgFill, safeSvgId, glyphNodeToSVG, buildRectSVGGradient,
7
+ * perCornerSvgPath, symbolSceneNodeToSVG, ARC_NOOP) live in
8
+ * sceneToSVGShared.tsx so the XY and ordinal serializers agree on geometry.
9
+ */
10
+ import * as React from "react";
11
+ import type { OrdinalSceneNode } from "./ordinalTypes";
12
+ export declare function ordinalSceneNodeToSVG(node: OrdinalSceneNode, i: number, idPrefix?: string): React.ReactNode;
@@ -1,6 +1,11 @@
1
1
  /**
2
2
  * Distance-cartogram projection of geo point scene nodes.
3
3
  * Mutates point/line positions in place; returns layout metadata for overlays.
4
+ *
5
+ * Two encodings:
6
+ * - `radial` (default): pixel distance from center ∝ cost; bearing from geography
7
+ * - `strip`: 1D Langren-style cost axis — x ∝ cost, y collapsed to a baseline
8
+ * (sparkline-friendly; no map chrome)
4
9
  */
5
10
  import type { DistanceCartogramConfig, GeoSceneNode } from "./geoTypes";
6
11
  import type { StreamLayout } from "./types";
@@ -9,6 +14,8 @@ export type GeoCartogramLayout = {
9
14
  cy: number;
10
15
  maxCost: number;
11
16
  availableRadius: number;
17
+ /** Active layout encoding — overlays branch on this. */
18
+ layout: "radial" | "strip";
12
19
  };
13
20
  /**
14
21
  * Apply a distance cartogram transform to the scene.
@@ -3,7 +3,7 @@ import type { GeoProjection, GeoPath, GeoPermissibleObjects } from "d3-geo";
3
3
  import type { GradientLegendConfig, LegendGroup, LegendLayout } from "../types/legendTypes";
4
4
  import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, SceneDatum, PointSceneNode, GlyphSceneNode, ThemeSemanticColors, SceneAccessibilityMetadata, SceneRenderMode } from "./types";
5
5
  import type { AnimateProp } from "./pipelineTransitionUtils";
6
- import type { HoverAnnotationConfig, HoverData } from "../realtime/types";
6
+ import type { AnnotationContext, HoverAnnotationConfig, HoverData } from "../realtime/types";
7
7
  import type { GeoParticleStyle } from "./GeoParticlePool";
8
8
  import type { Datum } from "../charts/shared/datumTypes";
9
9
  import type { AutoPlaceAnnotations } from "../recipes/annotationLayout";
@@ -35,6 +35,12 @@ export interface DistanceCartogramConfig {
35
35
  costAccessor: string | ((d: Datum) => number);
36
36
  strength?: number;
37
37
  lineMode?: "straight" | "fractional";
38
+ /**
39
+ * Layout encoding for cost-from-center:
40
+ * - `"radial"` (default): polar cartogram — distance ∝ cost, bearing from geography
41
+ * - `"strip"`: 1D Langren-style number line — x ∝ cost, y collapsed (sparkline)
42
+ */
43
+ layout?: "radial" | "strip";
38
44
  }
39
45
  export interface GeoAreaSceneNode {
40
46
  type: "geoarea";
@@ -239,6 +245,14 @@ export interface StreamGeoFrameProps<T = Datum> {
239
245
  /** Observe activation of widget annotations without replacing widget behavior. */
240
246
  onAnnotationActivate?: OnAnnotationActivateCallback;
241
247
  autoPlaceAnnotations?: AutoPlaceAnnotations;
248
+ /**
249
+ * Custom SVG annotation renderer — same contract as XY/ordinal
250
+ * `svgAnnotationRules`. Called before the built-in geo annotation rules;
251
+ * return `null`/`undefined` to fall through. Geo pre-projects
252
+ * `coordinates: [lon, lat]` to pixel `x`/`y` before this runs so a single
253
+ * rule body works on canvas CSR and `renderChart` SSR.
254
+ */
255
+ svgAnnotationRules?: (annotation: Datum, index: number, context: AnnotationContext) => ReactNode;
242
256
  decay?: DecayConfig;
243
257
  pulse?: PulseConfig;
244
258
  transition?: TransitionConfig;
@@ -305,12 +319,13 @@ export interface StreamGeoFrameHandle {
305
319
  clear(): void;
306
320
  getProjection(): GeoProjection | null;
307
321
  getGeoPath(): GeoPath<void, GeoPermissibleObjects> | null;
308
- /** Get cartogram layout info (center position, max cost, radius) */
322
+ /** Get cartogram layout info (center position, max cost, radius / strip length) */
309
323
  getCartogramLayout(): {
310
324
  cx: number;
311
325
  cy: number;
312
326
  maxCost: number;
313
327
  availableRadius: number;
328
+ layout?: "radial" | "strip";
314
329
  } | null;
315
330
  /** Get current zoom level (1 = default) */
316
331
  getZoom(): number;
@@ -4,7 +4,11 @@ import type { CustomLayoutFailureDiagnostic } from "./customLayoutFailure";
4
4
  import type { NetworkLayoutResult } from "./networkCustomLayout";
5
5
  /** Imperative API exposed by `StreamNetworkFrame` refs. */
6
6
  export interface StreamNetworkFrameHandle {
7
+ /** Ingest one edge immediately and coalesce its expensive layout with other
8
+ * pushes at the next animation frame. Geometry getters commit first. */
7
9
  push(edge: EdgePush): void;
10
+ /** Ingest and lay out an explicit edge batch synchronously, absorbing any
11
+ * layout pending from prior single-edge pushes. */
8
12
  pushMany(edges: EdgePush[]): void;
9
13
  /** Remove a node by ID. Also removes connected edges. */
10
14
  removeNode(id: string): boolean;
@@ -44,6 +44,8 @@ export interface NetworkFramePaintContext {
44
44
  };
45
45
  setAnnotationFrame: (updater: (f: number) => number) => void;
46
46
  scheduleNextFrame: () => void;
47
+ /** Resync color caches from scene fills after an invalidating rebuild. */
48
+ syncColorMap?: () => void;
47
49
  }
48
50
  /**
49
51
  * Run one paint tick. Returns whether another rAF should be scheduled
@@ -28,6 +28,7 @@ export declare class PhysicsPipelineStore {
28
28
  private simulationState;
29
29
  private visible;
30
30
  private world;
31
+ private quiescence;
31
32
  constructor(config?: PhysicsPipelineConfig);
32
33
  updateConfig(config: PhysicsPipelineConfig): void;
33
34
  /** Additive explicit-result form of {@link updateConfig}. */
@@ -37,6 +38,15 @@ export declare class PhysicsPipelineStore {
37
38
  /** Additive explicit-result form of {@link enqueue}. */
38
39
  enqueueWithResult(spawn: PhysicsQueuedSpawn | PhysicsQueuedSpawn[], pacing?: PhysicsSpawnPacingOptions): UpdateResult;
39
40
  spawnNow(spawn: PhysicsQueuedSpawn): void;
41
+ /**
42
+ * Materialize already-due queued spawns without advancing simulation time.
43
+ *
44
+ * Unlike {@link tick} / {@link settleWithObservations}, this runs while
45
+ * paused or hidden so seed bodies (`initialSpawns` with `spawnAt <= elapsed`)
46
+ * appear on the first paint of a paused snapshot frame. Future-paced queue
47
+ * items stay queued. Does not step the kernel.
48
+ */
49
+ materializeDueSpawns(): string[];
40
50
  clear(): void;
41
51
  tick(deltaSeconds: number): PhysicsPipelineTickResult;
42
52
  settle(maxSteps?: number): number;
@@ -49,6 +59,14 @@ export declare class PhysicsPipelineStore {
49
59
  hitTest(x: number, y: number, radius?: number): PhysicsBodyState | null;
50
60
  events(): PhysicsKernelEvent[];
51
61
  allSleeping(): boolean;
62
+ /**
63
+ * True when the world is done moving — either every body has formally slept,
64
+ * or the whole system has stayed quiescent long enough that never-sleeping
65
+ * stragglers (mutually-leaning bodies, force-equilibrium tethers) should still
66
+ * count as settled. This is the gate for `shouldContinue` and the "settled"
67
+ * simulation state, so it decides when `rerunMS` re-arms.
68
+ */
69
+ atRest(): boolean;
52
70
  hasPendingWork(): boolean;
53
71
  queueSize(): number;
54
72
  liveBodyCount(): number;
@@ -81,6 +99,4 @@ export declare class PhysicsPipelineStore {
81
99
  private observeBodyBudget;
82
100
  private syncSimulationState;
83
101
  private evictOverflow;
84
- private absorbSediment;
85
- private sleepingFirstEvictionOrder;
86
102
  }
@@ -1,3 +1,7 @@
1
+ import * as React from "react";
2
+ import type { Style } from "../types";
3
+ import type { FrameGraphicsProp, FrameMargin } from "../useFrame";
4
+ import type { PhysicsBodyState } from "./PhysicsKernel";
1
5
  import type { PhysicsSettledEvidence } from "./PhysicsEvidence";
2
6
  import type { PhysicsPipelineStore } from "./PhysicsPipelineStore";
3
7
  import { type PhysicsSettledScene, type PhysicsSettledSceneOptions } from "./PhysicsSettledScene";
@@ -7,8 +11,12 @@ export interface PhysicsSettledSVGOptions extends PhysicsSettledSceneOptions {
7
11
  title?: string;
8
12
  description?: string;
9
13
  background?: string;
14
+ backgroundGraphics?: FrameGraphicsProp;
10
15
  className?: string;
16
+ foregroundGraphics?: FrameGraphicsProp;
11
17
  idPrefix?: string;
18
+ margin?: Partial<FrameMargin>;
19
+ renderBodySVG?: (body: PhysicsBodyState, style: Style, index: number, idPrefix: string) => React.ReactNode | undefined;
12
20
  }
13
21
  export interface PhysicsSettledSVGRender {
14
22
  svg: string;
@@ -13,12 +13,19 @@ export interface StreamPhysicsPopOptions {
13
13
  color?: string;
14
14
  durationMs?: number;
15
15
  radius?: number;
16
+ /**
17
+ * Uniform multiplier on the whole burst geometry (ring + sparks). Defaults to
18
+ * 1. Shrink it for small charts — a sparkline can't hold a context-scale
19
+ * burst — without changing the removed body's `radius`.
20
+ */
21
+ scale?: number;
16
22
  }
17
23
  export interface StreamPhysicsPopAnimation {
18
24
  body: PhysicsBodyState;
19
25
  color: string;
20
26
  durationMs: number;
21
27
  radius: number;
28
+ scale: number;
22
29
  startedAt: number;
23
30
  }
24
31
  export declare function resolveBodyMark(body: PhysicsBodyState, style: Style): PhysicsBodyMark;
@@ -0,0 +1,15 @@
1
+ import type { PhysicsEngineAdapter } from "./PhysicsEngineAdapter";
2
+ import type { PhysicsSedimentAccumulator } from "./PhysicsSediment";
3
+ import type { PhysicsPipelineConfig } from "./PhysicsPipelineTypes";
4
+ import type { PhysicsPipelineEvictionResult } from "./physicsPipelineHelpers";
5
+ import type { PhysicsObservationContext } from "./physicsPipelineObservations";
6
+ export declare function selectEvictionCandidates(world: PhysicsEngineAdapter, eviction: PhysicsPipelineConfig["eviction"], liveBodyOrder: string[]): string[];
7
+ export declare function absorbPhysicsSediment(world: PhysicsEngineAdapter, sediment: PhysicsSedimentAccumulator, ids: string[], context: PhysicsObservationContext): string[];
8
+ /**
9
+ * Selects and removes overflow bodies past `bodyLimit`, absorbing them into
10
+ * sediment where applicable. Returns the surviving `liveBodyOrder` alongside
11
+ * the eviction result so the caller can commit both atomically.
12
+ */
13
+ export declare function evictPhysicsOverflow(world: PhysicsEngineAdapter, sediment: PhysicsSedimentAccumulator, eviction: PhysicsPipelineConfig["eviction"], bodyLimit: number, liveBodyOrder: string[], context: PhysicsObservationContext): PhysicsPipelineEvictionResult & {
14
+ liveBodyOrder: string[];
15
+ };
@@ -10,5 +10,5 @@ export interface PhysicsObservationContext {
10
10
  export declare function observePhysicsKernelEvents(world: PhysicsEngineAdapter, events: PhysicsKernelEvent[], context: PhysicsObservationContext): void;
11
11
  export declare function observePhysicsSensorTransitions(world: PhysicsEngineAdapter, previousPairs: ReadonlySet<string>, context: PhysicsObservationContext): Set<string>;
12
12
  export declare function removePhysicsSensorPairsForBodies(pairs: Set<string>, bodyIds: ReadonlySet<string>): void;
13
- export declare function resolvePhysicsSimulationState(paused: boolean, visible: boolean, hasQueuedBodies: boolean, allSleeping: boolean): PhysicsSimulationState;
13
+ export declare function resolvePhysicsSimulationState(paused: boolean, visible: boolean, hasQueuedBodies: boolean, atRest: boolean): PhysicsSimulationState;
14
14
  export declare function emitPhysicsSimulationStateTransition(previous: PhysicsSimulationState, next: PhysicsSimulationState, context: PhysicsObservationContext): void;
@@ -0,0 +1,20 @@
1
+ import type { PhysicsKernelOptions } from "./PhysicsKernel";
2
+ import type { PhysicsEngineAdapter } from "./PhysicsEngineAdapter";
3
+ /**
4
+ * Tracks sustained-quiescence as an "at rest" fallback for bodies that never
5
+ * formally sleep (see {@link QUIESCENT_AFTER_SECONDS}).
6
+ */
7
+ export declare class PhysicsQuiescenceTracker {
8
+ private seconds;
9
+ private speed;
10
+ private scratch;
11
+ setKernelOptions(kernel: PhysicsKernelOptions | undefined): void;
12
+ reset(): void;
13
+ isAtRest(): boolean;
14
+ /**
15
+ * Advance (or reset) the sustained-quiescence timer from the bodies' current
16
+ * speeds. A fresh spawn or any body moving faster than the quiescent speed
17
+ * resets it; otherwise it accrues the simulated delta.
18
+ */
19
+ refresh(world: PhysicsEngineAdapter, deltaSeconds: number, spawnedCount: number): void;
20
+ }
@@ -8,7 +8,7 @@ import * as React from "react";
8
8
  import type { DefaultArcObject } from "d3-shape";
9
9
  import { type HatchFill } from "../charts/shared/hatchFill";
10
10
  import type { GlyphDef } from "./glyphDef";
11
- import type { Style } from "./types";
11
+ import type { RectSceneNode, Style, SymbolSceneNode } from "./types";
12
12
  /**
13
13
  * Sentinel arg for d3-shape arc generators that have all four
14
14
  * accessors set to constants. The generator's call signature requires
@@ -49,3 +49,32 @@ export declare function glyphNodeToSVG(g: {
49
49
  pointId?: string;
50
50
  _decayOpacity?: number;
51
51
  }, x: number, y: number, key: string): React.ReactNode;
52
+ export declare function colorStopElements(colorStops: Array<{
53
+ offset: number;
54
+ color: string;
55
+ }>): React.ReactElement[] | null;
56
+ /**
57
+ * Build `<defs><linearGradient>` for a bar's fillGradient, mirroring the
58
+ * tip→base direction the canvas renderer uses (inferred from roundedEdge).
59
+ * Returns null when the config can't resolve (e.g. colorStops < 2), so the
60
+ * caller falls back to a solid fill — same parity with the canvas path.
61
+ *
62
+ * Using `gradientUnits="userSpaceOnUse"` with absolute coords keeps each bar's
63
+ * gradient aligned to its own rect independent of the parent viewBox.
64
+ */
65
+ export declare function buildRectSVGGradient(n: RectSceneNode, id: string): React.ReactElement | null;
66
+ /**
67
+ * Emit an SVG path string for a rect with per-corner radii. Same trace
68
+ * order as the canvas helper (CCW from top-left); shared shape utilities
69
+ * (`hasAnyCornerRadius`, `clampCornerRadii`) live in
70
+ * `./renderers/cornerRadii.ts` so both paint paths agree on geometry.
71
+ */
72
+ export declare function perCornerSvgPath(n: RectSceneNode): string;
73
+ /**
74
+ * Shared SVG serializer for the XY/ordinal `SymbolSceneNode` (x/y-based) — the
75
+ * sibling of the network symbol case in `networkSceneNodeToSVG` (cx/cy). Both
76
+ * delegate glyph-path generation to `symbolPathString`, matching the canvas
77
+ * renderer exactly (fill only when a fill is set, so stroke-only glyphs stay
78
+ * unfilled in SSR too).
79
+ */
80
+ export declare function symbolSceneNodeToSVG(n: SymbolSceneNode, i: number, idPrefix?: string): React.ReactNode;
@@ -457,6 +457,10 @@ export interface CandlestickSceneNode {
457
457
  isUp: boolean;
458
458
  /** Range/dumbbell mode — no body, endpoint dots instead */
459
459
  isRange?: boolean;
460
+ /** Endpoint dot radius for range/dumbbell mode. Computed in the scene
461
+ * builder (which owns the layout height) so the canvas and SVG renderers
462
+ * paint identical bulbs. */
463
+ dotRadius?: number;
460
464
  datum: SceneDatum;
461
465
  accessibleDatum?: SceneAccessibilityMetadata["accessibleDatum"];
462
466
  accessibility?: SceneAccessibilityMetadata["accessibility"];
@@ -60,10 +60,16 @@ export interface HydrationLifecycleOptions {
60
60
  * `cancelIntroAnimation()`; the hook calls it when the SVG → canvas
61
61
  * swap fires after SSR rehydration. (Currently every shipped store
62
62
  * implements the method, but the optional shape lets a custom store
63
- * opt out.)
63
+ * opt out.) `sceneNodes` + `markStylePaintPending()` let the hook
64
+ * repaint an already-built scene instead of forcing a rebuild (see the
65
+ * effect body); both are optional so a minimal custom store still works.
64
66
  */
65
67
  storeRef: RefObject<{
66
68
  cancelIntroAnimation?: () => void;
69
+ sceneNodes?: {
70
+ length: number;
71
+ };
72
+ markStylePaintPending?: () => void;
67
73
  } | null>;
68
74
  /**
69
75
  * Mutable dirty flag the renderer reads on its next paint. The hook
@@ -8,4 +8,4 @@ import type { Datum } from "../../charts/shared/datumTypes";
8
8
  */
9
9
  import type { CandlestickSceneNode, StreamLayout } from "../types";
10
10
  import type { XYSceneContext } from "./types";
11
- export declare function buildCandlestickScene(ctx: XYSceneContext, data: Datum[], _layout: StreamLayout): CandlestickSceneNode[];
11
+ export declare function buildCandlestickScene(ctx: XYSceneContext, data: Datum[], layout: StreamLayout): CandlestickSceneNode[];
@@ -0,0 +1,7 @@
1
+ import type { ChartNotification } from "./ChartContainer";
2
+ import type { ChartConfig } from "./export/chartConfig";
3
+ import type { ChartContainerDataAudit } from "./chartContainerDataAudit";
4
+ type AuditableChartConfig = Pick<ChartConfig, "component" | "props">;
5
+ /** Load the opt-in numeric evaluator only when a container asks for it. */
6
+ export declare function useChartContainerDataAudit(chartConfig: AuditableChartConfig | undefined, dataAudit: ChartContainerDataAudit | undefined): ChartNotification[];
7
+ export {};
@@ -1 +1 @@
1
- import{forceCenter as e,forceCollide as t,forceLink as o,forceManyBody as n,forceSimulation as r,forceX as a,forceY as f}from"d3-force";function c(c,s,i={}){const d=i.seed??1,u=i.iterations??260,l=i.repulsion??5200,g=i.linkDistance??165,h=i.linkStrength??.045,b=i.centerStrength??.018,y=i.damping??.84,p=i.nodeRadius??12,m=i.nodePadding??3,M=i.inset??.06,x=function(e){let t=e>>>0;return function(){t=t+1831565813|0;let e=Math.imul(t^t>>>15,1|t);return e=e+Math.imul(e^e>>>7,61|e)^e,((e^e>>>14)>>>0)/4294967296}}(d),S=new Map;for(const e of c)S.set(e.id,0);for(const e of s)S.set(e.source,(S.get(e.source)??0)+1),S.set(e.target,(S.get(e.target)??0)+1);const k=500,w=c.map(e=>({id:e.id,data:e,x:200+600*x(),y:200+600*x()})),q=new Set(c.map(e=>e.id)),v=s.filter(e=>q.has(e.source)&&q.has(e.target)).map(e=>({source:e.source,target:e.target}));if(u>0){const c=r(w).randomSource(x).alphaDecay(1-Math.pow(.001,1/u)).velocityDecay(Math.max(0,Math.min(1,1-y))).force("charge",n().strength(e=>{const t=S.get(e.id)??0;return 2.5*-Math.sqrt(l)*Math.sqrt(t+1)})).force("collide",t(e=>(e=>"function"==typeof p?p(e.data):p)(e)+m).strength(.9).iterations(2)).force("center",e(k,k).strength(.8)).force("x",a(k).strength(b)).force("y",f(k).strength(b));v.length>0&&c.force("link",o(v).id(e=>e.id).distance(g).strength(e=>{const t="string"==typeof e.source?e.source:e.source.id,o="string"==typeof e.target?e.target:e.target.id,n=Math.max(1,Math.min(S.get(t)??1,S.get(o)??1));return h/.045/n})),c.stop();for(let e=0;e<u;e+=1)c.tick()}let I=1/0,R=1/0,z=-1/0,$=-1/0;for(const e of w){const t=e.x??k,o=e.y??k;t<I&&(I=t),o<R&&(R=o),t>z&&(z=t),o>$&&($=o)}const E=z-I,_=$-R,C={};for(const e of w)C[e.id]={x:0===E?.5:M+((e.x??k)-I)/E*(1-2*M),y:0===_?.5:M+((e.y??k)-R)/_*(1-2*M)};return C}import{forceSimulation as s,forceCenter as i,forceX as d,forceY as u,forceLink as l,forceManyBody as g,forceCollide as h}from"d3-force";import{scaleLinear as b}from"d3-scale";function y(e){return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function p(e,t,o){const n=e=>e.toString(16).padStart(2,"0");return`#${n(e)}${n(t)}${n(o)}`}function m(e){const t=e.map(y),o=t.length-1;return e=>{if(e<=0){const[e,o,n]=t[0];return p(e,o,n)}if(e>=1){const[e,n,r]=t[o];return p(e,n,r)}const n=e*o,r=Math.floor(n),a=n-r,[f,c,s]=t[r],[i,d,u]=t[r+1];return p(Math.round(f+(i-f)*a),Math.round(c+(d-c)*a),Math.round(s+(u-s)*a))}}var M=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];m(["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"]),m(["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"]),m(["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"]),m(["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"]),m(["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"]),m(["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"]),m(["#440154","#482878","#3e4989","#31688e","#26828e","#1f9e89","#35b779","#6ece58","#b5de2b","#fde725"]),m(["#0d0887","#41049d","#6a00a8","#8f0da4","#b12a90","#cb4679","#e16462","#f1844b","#fca636","#fcce25","#f0f921"]),m(["#000004","#160b39","#420a68","#6a176e","#932667","#bc3754","#dd513a","#f3771a","#fca50a","#f6d746","#fcffa4"]),m(["#000004","#140e36","#3b0f70","#641a80","#8c2981","#b73779","#de4968","#f7705c","#fe9f6d","#fecf92","#fcfdbf"]),m(["#00224e","#123570","#3b496c","#575d6d","#707173","#8a8678","#a59c74","#c3b369","#e1cc55","#fee838","#ffea46"]),m(["#23171b","#4a58dd","#3f9ee9","#46c7af","#7eed5a","#cdf134","#fbb91f","#f56918","#c52f06","#7a0403"]),m(["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"]),m(["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"]),m(["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"]),m(["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"]),m(["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"]),m(["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"]),m(["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"]);var x=new Set,S=new WeakMap;function k(e,t){if(!e||!e.data||"object"!=typeof e.data)return e;let o=S.get(e);if(o){const e=o.get(t);if(e)return e}else o=new Map,S.set(e,o);const n=new Proxy(e,{get(e,o,n){if("string"==typeof o&&!(o in e)&&e.data&&o in e.data){const e=`${t}:${o}`;x.has(e)||(x.add(e),console.warn(`[Semiotic] "${t}" callback accessed "${o}" on the wrapper object, but it only exists on ".data". Use d.data.${o} (or d.data?.${o}) instead. Frame callbacks receive RealtimeNode/RealtimeEdge wrappers, not your raw data.`))}return Reflect.get(e,o,n)}});return o.set(t,n),n}var w={supportsStreaming:!0,hierarchical:!1,computeLayout(e,t,o,n){if(0===e.length)return;const r=o.forceStrength??.1,a=n[0]/2,f=n[1]/2,c=o.__previousPositions;let b=0;const y=[];for(const t of e){const e=null!=t.x&&null!=t.y&&(0!==t.x||0!==t.y),o=c?.get(t.id);e?b++:o?(t.x=o.x,t.y=o.y,b++):y.push(t)}const p=e.length>0?y.length/e.length:1,m=b>0&&p<=.3;if(m){const o=new Map;for(const t of e)o.set(t.id,t);for(const e of y){const n=q(e.id,t,o);if(n.length>0){let t=0,o=0;for(const e of n)t+=e.x,o+=e.y;const r=v(e.id),a=r%360*(Math.PI/180),f=10+r%20;e.x=t/n.length+f*Math.cos(a),e.y=o/n.length+f*Math.sin(a)}else{const t=v(e.id),o=t%360*(Math.PI/180),n=15+t%30;e.x=a+n*Math.cos(o),e.y=f+n*Math.sin(o)}}}else{const t=Math.PI*(3-Math.sqrt(5));for(let o=0;o<e.length;o++){const n=e[o];if(null==n.x||null==n.y||0===n.x&&0===n.y){const e=10*Math.sqrt(o+.5),r=o*t;n.x=a+e*Math.cos(r),n.y=f+e*Math.sin(r)}}}const M=e.length,x=o.iterations??Math.max(50,Math.min(300,Math.floor(300-2*(M-30)))),S=o.__skipForceSimulation||0===o.iterations?0:m?40:x,k=I(o.nodeSize,o.nodeSizeRange,e),w=e=>k(e);if(S>0){const n=new Map,c=new Map;for(const t of e)n.set(t.id,0),c.set(t.id,t);for(const e of t){const t="string"==typeof e.source?e.source:e.source.id,o="string"==typeof e.target?e.target:e.target.id;n.set(t,(n.get(t)??0)+1),n.set(o,(n.get(o)??0)+1)}const b=l().strength(e=>{const t=e.weight,o="string"==typeof e.source?e.source:e.source.id,a="string"==typeof e.target?e.target:e.target.id,f=Math.max(1,Math.min(n.get(o)??1,n.get(a)??1)),c=t&&t>0?Math.sqrt(t):1;return Math.min(2.5,c*r/(.1*f))}).distance(e=>{const t="string"==typeof e.source?c.get(e.source):e.source,o="string"==typeof e.target?c.get(e.target):e.target,n=(t?w(t):0)+(o?w(o):0)+12;return Math.max(40,n)}).id(e=>e.id),y=s();if(void 0===o.random&&void 0===o.seed||y.randomSource(o.random??function(e){let t=e>>>0;return()=>{t+=1831565813;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(o.seed)),y.force("charge",g().strength(e=>{const t=n.get(e.id)??0;return-15*w(e)*Math.sqrt(t+1)})).force("collide",h(e=>w(e)+3).strength(.9).iterations(2)).force("center",i(a,f).strength(.8)).force("x",d(a).strength(.06)).force("y",u(f).strength(.06)),y.nodes(e),t.length>0){const e=t.map(e=>({...e,source:"string"==typeof e.source?e.source:e.source.id,target:"string"==typeof e.target?e.target:e.target.id}));b.links(e),y.force("link",b)}m?y.alpha(.3):y.alpha()<.1&&y.alpha(1),y.stop();for(let e=0;e<S;++e)y.tick()}for(const t of e){if(null==t.x||null==t.y)continue;const e=w(t);t.x=Math.max(e,Math.min(n[0]-e,t.x)),t.y=Math.max(e,Math.min(n[1]-e,t.y)),t.x0=0,t.x1=0,t.y0=0,t.y1=0}const R=new Map;for(const t of e)R.set(t.id,t);for(const e of t){if("string"==typeof e.source){const t=R.get(e.source);t&&(e.source=t)}if("string"==typeof e.target){const t=R.get(e.target);t&&(e.target=t)}}},buildScene(e,t,o,n){const r=o.nodeStyle,a=o.edgeStyle,f=I(o.nodeSize,o.nodeSizeRange,e),c=Array.isArray(o.colorScheme)?o.colorScheme:o.themeCategorical&&o.themeCategorical.length>0?o.themeCategorical:M,s=new Map;e.forEach((e,t)=>{s.set(e.id,c[t%c.length])});const i=[],d=[],u=[];for(const t of e){if(null==t.x||null==t.y)continue;const e=f(k(t,"nodeSize")),n=r?r(k(t,"nodeStyle")):{},a={fill:n.fill||s.get(t.id)||o.themeSemantic?.primary||"#007bff",stroke:n.stroke||o.themeSemantic?.surface||"#fff",strokeWidth:n.strokeWidth??2,opacity:n.opacity};i.push({type:"circle",cx:t.x,cy:t.y,r:e,style:a,datum:t,id:t.id,label:t.id})}const l=new Map;for(const t of e)l.set(t.id,t);for(const e of t){const t="object"==typeof e.source?e.source:l.get(e.source),n="object"==typeof e.target?e.target:l.get(e.target);if(!t||!n)continue;if(null==t.x||null==t.y)continue;if(null==n.x||null==n.y)continue;const r=a?a(k(e,"edgeStyle")):{},f={stroke:r.stroke||o.themeSemantic?.border||o.themeSemantic?.secondary||"#999",strokeWidth:r.strokeWidth??1,opacity:r.opacity??.6};d.push({type:"line",x1:t.x,y1:t.y,x2:n.x,y2:n.y,style:f,datum:e})}if(!1!==o.showLabels){const t=(g=o.nodeLabel)?"function"==typeof g?g:e=>e[g]||e.id:null;for(const o of e){if(null==o.x||null==o.y)continue;const e=t?t(o):o.id;if(!e)continue;const n=f(k(o,"nodeSize"));u.push({x:o.x,y:o.y-n-4,text:String(e),anchor:"middle",baseline:"auto",fontSize:11})}}var g;return{sceneNodes:i,sceneEdges:d,labels:u}}};function q(e,t,o){const n=[];for(const r of t){const t="string"==typeof r.source?r.source:r.source.id,a="string"==typeof r.target?r.target:r.target.id;let f=null;if(t===e?f=a:a===e&&(f=t),f){const e=o.get(f);!e||0===e.x&&0===e.y||n.push({x:e.x,y:e.y})}}return n}function v(e){let t=0;for(let o=0;o<e.length;o++)t=(t<<5)-t+e.charCodeAt(o)|0;return Math.abs(t)}function I(e,t,o){if(o.some(e=>null!=e.__forceRadius))return e=>e.__forceRadius??8;if(null==e)return()=>8;if("number"==typeof e)return()=>e;if("function"==typeof e)return t=>e(t)||8;const n=t||[5,20],r=[];for(const t of o){const o=t.data?.[e];"number"==typeof o&&r.push(o)}if(0===r.length)return()=>n[0];const[a,f]=function(e){let t=1/0,o=-1/0;for(const n of e)n<t&&(t=n),n>o&&(o=n);return[t,o]}(r);if(a===f)return()=>(n[0]+n[1])/2;const c=b().domain([a,f]).range(n).clamp(!0);return t=>{const o=t.data?.[e];return null==o||"number"!=typeof o?n[0]:c(o)}}self.onmessage=e=>{const t=e.data,o=t?.requestId,n=t?.request??t;try{if("normalized"===n.kind){const e=n.nodeRadii,t=e?{...n.options,nodeRadius:t=>e[t.id]??12}:n.options;return void self.postMessage({requestId:o,positions:c(n.nodes,n.edges,t)})}const e=n.nodes,t=n.edges;w.computeLayout(e,t,n.config,n.size),self.postMessage({requestId:o,positions:Object.fromEntries(e.map(e=>[e.id,{x:e.x,y:e.y}]))})}catch(e){self.postMessage({requestId:o,error:{message:e instanceof Error?e.message:String(e),name:e instanceof Error?e.name:"Error",stack:e instanceof Error?e.stack:void 0}})}};
1
+ import{forceCenter as e,forceCollide as t,forceLink as o,forceManyBody as n,forceSimulation as r,forceX as a,forceY as f}from"d3-force";function c(c,s,i={}){const d=i.seed??1,u=i.iterations??260,l=i.repulsion??5200,g=i.linkDistance??165,h=i.linkStrength??.045,y=i.centerStrength??.018,b=i.damping??.84,m=i.nodeRadius??12,p=i.nodePadding??3,M=i.inset??.06,x=function(e){let t=e>>>0;return function(){t=t+1831565813|0;let e=Math.imul(t^t>>>15,1|t);return e=e+Math.imul(e^e>>>7,61|e)^e,((e^e>>>14)>>>0)/4294967296}}(d),S=new Map;for(const e of c)S.set(e.id,0);for(const e of s)S.set(e.source,(S.get(e.source)??0)+1),S.set(e.target,(S.get(e.target)??0)+1);const k=500,w=c.map(e=>({id:e.id,data:e,x:200+600*x(),y:200+600*x()})),v=new Set(c.map(e=>e.id)),q=s.filter(e=>v.has(e.source)&&v.has(e.target)).map(e=>({source:e.source,target:e.target}));if(u>0){const c=r(w).randomSource(x).alphaDecay(1-Math.pow(.001,1/u)).velocityDecay(Math.max(0,Math.min(1,1-b))).force("charge",n().strength(e=>{const t=S.get(e.id)??0;return 2.5*-Math.sqrt(l)*Math.sqrt(t+1)})).force("collide",t(e=>(e=>"function"==typeof m?m(e.data):m)(e)+p).strength(.9).iterations(2)).force("center",e(k,k).strength(.8)).force("x",a(k).strength(y)).force("y",f(k).strength(y));q.length>0&&c.force("link",o(q).id(e=>e.id).distance(g).strength(e=>{const t="string"==typeof e.source?e.source:e.source.id,o="string"==typeof e.target?e.target:e.target.id,n=Math.max(1,Math.min(S.get(t)??1,S.get(o)??1));return h/.045/n})),c.stop();for(let e=0;e<u;e+=1)c.tick()}let z=1/0,I=1/0,R=-1/0,$=-1/0;for(const e of w){const t=e.x??k,o=e.y??k;t<z&&(z=t),o<I&&(I=o),t>R&&(R=t),o>$&&($=o)}const E=R-z,_=$-I,C={};for(const e of w)C[e.id]={x:0===E?.5:M+((e.x??k)-z)/E*(1-2*M),y:0===_?.5:M+((e.y??k)-I)/_*(1-2*M)};return C}import{forceSimulation as s,forceCenter as i,forceX as d,forceY as u,forceLink as l,forceManyBody as g,forceCollide as h}from"d3-force";import{scaleLinear as y}from"d3-scale";function b(e){return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function m(e,t,o){const n=e=>e.toString(16).padStart(2,"0");return`#${n(e)}${n(t)}${n(o)}`}function p(e){const t=e.map(b),o=t.length-1;return e=>{if(e<=0){const[e,o,n]=t[0];return m(e,o,n)}if(e>=1){const[e,n,r]=t[o];return m(e,n,r)}const n=e*o,r=Math.floor(n),a=n-r,[f,c,s]=t[r],[i,d,u]=t[r+1];return m(Math.round(f+(i-f)*a),Math.round(c+(d-c)*a),Math.round(s+(u-s)*a))}}var M=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];p(["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"]),p(["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"]),p(["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"]),p(["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"]),p(["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"]),p(["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"]),p(["#440154","#482878","#3e4989","#31688e","#26828e","#1f9e89","#35b779","#6ece58","#b5de2b","#fde725"]),p(["#0d0887","#41049d","#6a00a8","#8f0da4","#b12a90","#cb4679","#e16462","#f1844b","#fca636","#fcce25","#f0f921"]),p(["#000004","#160b39","#420a68","#6a176e","#932667","#bc3754","#dd513a","#f3771a","#fca50a","#f6d746","#fcffa4"]),p(["#000004","#140e36","#3b0f70","#641a80","#8c2981","#b73779","#de4968","#f7705c","#fe9f6d","#fecf92","#fcfdbf"]),p(["#00224e","#123570","#3b496c","#575d6d","#707173","#8a8678","#a59c74","#c3b369","#e1cc55","#fee838","#ffea46"]),p(["#23171b","#4a58dd","#3f9ee9","#46c7af","#7eed5a","#cdf134","#fbb91f","#f56918","#c52f06","#7a0403"]),p(["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"]),p(["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"]),p(["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"]),p(["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"]),p(["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"]),p(["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"]),p(["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"]);var x=new Set,S=new WeakMap;function k(e,t){if(!e||!e.data||"object"!=typeof e.data)return e;let o=S.get(e);if(o){const e=o.get(t);if(e)return e}else o=new Map,S.set(e,o);const n=new Proxy(e,{get(e,o,n){if("string"==typeof o&&!(o in e)&&e.data&&o in e.data){const e=`${t}:${o}`;x.has(e)||(x.add(e),console.warn(`[Semiotic] "${t}" callback accessed "${o}" on the wrapper object, but it only exists on ".data". Use d.data.${o} (or d.data?.${o}) instead. Frame callbacks receive RealtimeNode/RealtimeEdge wrappers, not your raw data.`))}return Reflect.get(e,o,n)}});return o.set(t,n),n}var w={supportsStreaming:!0,hierarchical:!1,computeLayout(e,t,o,n){if(0===e.length)return;const r=o.forceStrength??.1,a=n[0]/2,f=n[1]/2,c=Math.max(.1,Math.min(1,Math.min(n[0],n[1])/200)),y=Math.min(.5,.06+1.8*(1-c)),b=o.__previousPositions;let m=0;const p=[];for(const t of e){const e=null!=t.x&&null!=t.y&&(0!==t.x||0!==t.y),o=b?.get(t.id);e?m++:o?(t.x=o.x,t.y=o.y,m++):p.push(t)}const M=e.length>0?p.length/e.length:1,x=m>0&&M<=.3;if(x){const o=new Map;for(const t of e)o.set(t.id,t);for(const e of p){const n=v(e.id,t,o);if(n.length>0){let t=0,o=0;for(const e of n)t+=e.x,o+=e.y;const r=q(e.id),a=r%360*(Math.PI/180),f=(10+r%20)*c;e.x=t/n.length+f*Math.cos(a),e.y=o/n.length+f*Math.sin(a)}else{const t=q(e.id),o=t%360*(Math.PI/180),n=(15+t%30)*c;e.x=a+n*Math.cos(o),e.y=f+n*Math.sin(o)}}}else{const t=Math.PI*(3-Math.sqrt(5));for(let o=0;o<e.length;o++){const n=e[o];if(null==n.x||null==n.y||0===n.x&&0===n.y){const e=10*Math.sqrt(o+.5)*c,r=o*t;n.x=a+e*Math.cos(r),n.y=f+e*Math.sin(r)}}}const S=e.length,k=o.iterations??Math.max(50,Math.min(300,Math.floor(300-2*(S-30)))),w=o.__skipForceSimulation||0===o.iterations?0:x?40:k,I=z(o.nodeSize,o.nodeSizeRange,e),R=e=>I(e);if(w>0){const b=new Map,m=new Map;for(const t of e)b.set(t.id,0),m.set(t.id,t);for(const e of t){const t="string"==typeof e.source?e.source:e.source.id,o="string"==typeof e.target?e.target:e.target.id;b.set(t,(b.get(t)??0)+1),b.set(o,(b.get(o)??0)+1)}const p=l().strength(e=>{const t=e.weight,o="string"==typeof e.source?e.source:e.source.id,n="string"==typeof e.target?e.target:e.target.id,a=Math.max(1,Math.min(b.get(o)??1,b.get(n)??1)),f=t&&t>0?Math.sqrt(t):1;return Math.min(2.5,f*r/(.1*a))}).distance(e=>{const t="string"==typeof e.source?m.get(e.source):e.source,o="string"==typeof e.target?m.get(e.target):e.target,n=(t?R(t):0)+(o?R(o):0)+Math.max(6,12*c);return Math.max(16,40*c,n)}).id(e=>e.id),M=s();if(void 0===o.random&&void 0===o.seed||M.randomSource(o.random??function(e){let t=e>>>0;return()=>{t+=1831565813;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(o.seed)),M.force("charge",g().strength(e=>{const t=b.get(e.id)??0;return-15*c*R(e)*Math.sqrt(t+1)})).force("collide",h(e=>R(e)+3*c).strength(.9).iterations(2)).force("center",i(a,f).strength(.8)).force("x",d(a).strength(y)).force("y",u(f).strength(y)).force("bounds",function(e,t,o=2,n=.6){let r=[];const a=a=>{const f=n*Math.max(a,.2);for(const n of r){const r=n.x??e[0]/2,a=n.y??e[1]/2,c=n.vx??0,s=n.vy??0,i=t(n)+o,d=Math.min(e[0]/2,i),u=Math.max(e[0]/2,e[0]-i),l=Math.min(e[1]/2,i),g=Math.max(e[1]/2,e[1]-i),h=r+c,y=a+s;h<d?n.vx=c+(d-h)*f:h>u&&(n.vx=c+(u-h)*f),y<l?n.vy=s+(l-y)*f:y>g&&(n.vy=s+(g-y)*f)}};return a.initialize=e=>{r=e},a}(n,R)),M.nodes(e),t.length>0){const e=t.map(e=>({...e,source:"string"==typeof e.source?e.source:e.source.id,target:"string"==typeof e.target?e.target:e.target.id}));p.links(e),M.force("link",p)}x?M.alpha(.3):M.alpha()<.1&&M.alpha(1),M.stop();for(let e=0;e<w;++e)M.tick()}for(const t of e){if(null==t.x||null==t.y)continue;const e=R(t),o=w>0?2:0,r=Math.min(n[0]/2,e+o),a=Math.min(n[1]/2,e+o);t.x=Math.max(r,Math.min(n[0]-r,t.x)),t.y=Math.max(a,Math.min(n[1]-a,t.y)),t.x0=0,t.x1=0,t.y0=0,t.y1=0}const $=new Map;for(const t of e)$.set(t.id,t);for(const e of t){if("string"==typeof e.source){const t=$.get(e.source);t&&(e.source=t)}if("string"==typeof e.target){const t=$.get(e.target);t&&(e.target=t)}}},buildScene(e,t,o,n){const r=o.nodeStyle,a=o.edgeStyle,f=z(o.nodeSize,o.nodeSizeRange,e),c=Array.isArray(o.colorScheme)?o.colorScheme:o.themeCategorical&&o.themeCategorical.length>0?o.themeCategorical:M,s=new Map;e.forEach((e,t)=>{s.set(e.id,c[t%c.length])});const i=[],d=[],u=[];for(const t of e){if(null==t.x||null==t.y)continue;const e=f(k(t,"nodeSize")),n=r?r(k(t,"nodeStyle")):{},a={fill:n.fill||s.get(t.id)||o.themeSemantic?.primary||"#007bff",stroke:n.stroke||o.themeSemantic?.surface||"#fff",strokeWidth:n.strokeWidth??2,opacity:n.opacity};i.push({type:"circle",cx:t.x,cy:t.y,r:e,style:a,datum:t,id:t.id,label:t.id})}const l=new Map;for(const t of e)l.set(t.id,t);for(const e of t){const t="object"==typeof e.source?e.source:l.get(e.source),n="object"==typeof e.target?e.target:l.get(e.target);if(!t||!n)continue;if(null==t.x||null==t.y)continue;if(null==n.x||null==n.y)continue;const r=a?a(k(e,"edgeStyle")):{},f={stroke:r.stroke||o.themeSemantic?.border||o.themeSemantic?.secondary||"#999",strokeWidth:r.strokeWidth??1,opacity:r.opacity??.6};d.push({type:"line",x1:t.x,y1:t.y,x2:n.x,y2:n.y,style:f,datum:e})}if(!1!==o.showLabels){const t=(g=o.nodeLabel)?"function"==typeof g?g:e=>e[g]||e.id:null;for(const o of e){if(null==o.x||null==o.y)continue;const e=t?t(o):o.id;if(!e)continue;const n=f(k(o,"nodeSize"));u.push({x:o.x,y:o.y-n-4,text:String(e),anchor:"middle",baseline:"auto",fontSize:11})}}var g;return{sceneNodes:i,sceneEdges:d,labels:u}}};function v(e,t,o){const n=[];for(const r of t){const t="string"==typeof r.source?r.source:r.source.id,a="string"==typeof r.target?r.target:r.target.id;let f=null;if(t===e?f=a:a===e&&(f=t),f){const e=o.get(f);!e||0===e.x&&0===e.y||n.push({x:e.x,y:e.y})}}return n}function q(e){let t=0;for(let o=0;o<e.length;o++)t=(t<<5)-t+e.charCodeAt(o)|0;return Math.abs(t)}function z(e,t,o){if(o.some(e=>null!=e.__forceRadius))return e=>e.__forceRadius??8;if(null==e)return()=>8;if("number"==typeof e)return()=>e;if("function"==typeof e)return t=>e(t)||8;const n=t||[5,20],r=[];for(const t of o){const o=t.data?.[e];"number"==typeof o&&r.push(o)}if(0===r.length)return()=>n[0];const[a,f]=function(e){let t=1/0,o=-1/0;for(const n of e)n<t&&(t=n),n>o&&(o=n);return[t,o]}(r);if(a===f)return()=>(n[0]+n[1])/2;const c=y().domain([a,f]).range(n).clamp(!0);return t=>{const o=t.data?.[e];return null==o||"number"!=typeof o?n[0]:c(o)}}self.onmessage=e=>{const t=e.data,o=t?.requestId,n=t?.request??t;try{if("normalized"===n.kind){const e=n.nodeRadii,t=e?{...n.options,nodeRadius:t=>e[t.id]??12}:n.options;return void self.postMessage({requestId:o,positions:c(n.nodes,n.edges,t)})}const e=n.nodes,t=n.edges;w.computeLayout(e,t,n.config,n.size),self.postMessage({requestId:o,positions:Object.fromEntries(e.map(e=>[e.id,{x:e.x,y:e.y}]))})}catch(e){self.postMessage({requestId:o,error:{message:e instanceof Error?e.message:String(e),name:e instanceof Error?e.name:"Error",stack:e instanceof Error?e.stack:void 0}})}};