@classytic/stage 0.2.0 → 0.3.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.
- package/LICENSE +1 -1
- package/README.md +5 -1
- package/dist/assets/index.mjs +0 -1
- package/dist/builder/Palette.mjs +50 -89
- package/dist/builder/SceneBuilder.mjs +15 -73
- package/dist/core/index.d.mts +2 -1
- package/dist/core/index.mjs +2 -1
- package/dist/core/math.d.mts +26 -0
- package/dist/core/math.mjs +37 -0
- package/dist/finance/bizsim.d.mts +93 -0
- package/dist/finance/bizsim.mjs +117 -0
- package/dist/finance/index.d.mts +118 -0
- package/dist/finance/index.mjs +203 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +4 -4
- package/dist/interaction/MovableDot.mjs +19 -0
- package/dist/interaction/useDraggable.mjs +24 -4
- package/dist/math/calculus.d.mts +22 -1
- package/dist/math/calculus.mjs +156 -2
- package/dist/math/index.d.mts +2 -2
- package/dist/math/index.mjs +2 -2
- package/dist/math/latex.mjs +8 -0
- package/dist/primitives/Dot.d.mts +2 -15
- package/dist/primitives/Dot.mjs +6 -4
- package/dist/primitives/Grid.d.mts +33 -17
- package/dist/primitives/Grid.mjs +89 -17
- package/dist/primitives/Label.d.mts +1 -14
- package/dist/primitives/Label.mjs +3 -2
- package/dist/primitives/Lines.d.mts +4 -32
- package/dist/primitives/Lines.mjs +10 -8
- package/dist/primitives/Shapes.d.mts +5 -43
- package/dist/primitives/Shapes.mjs +12 -10
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/primitives/props.mjs +31 -0
- package/dist/scene/Scene.d.mts +6 -1
- package/dist/scene/Scene.mjs +15 -40
- package/dist/view/Stage.mjs +4 -11
- package/package.json +30 -22
- package/styles.css +125 -8
- package/dist/assets/kit/index.mjs +0 -4
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { fmt } from "../core/coords.mjs";
|
|
4
4
|
import { useCoords } from "../core/context.mjs";
|
|
5
|
+
import { geomPropsEqual } from "./props.mjs";
|
|
6
|
+
import { memo } from "react";
|
|
5
7
|
import { jsx } from "react/jsx-runtime";
|
|
6
8
|
|
|
7
9
|
//#region src/primitives/Lines.tsx
|
|
@@ -14,7 +16,7 @@ const extend = (c, a, b, back) => {
|
|
|
14
16
|
const big = Math.hypot(c.width, c.height) * 2;
|
|
15
17
|
return [back ? [a[0] - ux * big, a[1] - uy * big] : a, [a[0] + ux * big, a[1] + uy * big]];
|
|
16
18
|
};
|
|
17
|
-
function Segment({ from, to, color = "var(--stage-fg)", weight = 2, opacity = 1, dashed }) {
|
|
19
|
+
const Segment = memo(function Segment({ from, to, color = "var(--stage-fg)", weight = 2, opacity = 1, dashed }) {
|
|
18
20
|
const c = useCoords();
|
|
19
21
|
const a = c.toPx(from.x, from.y);
|
|
20
22
|
const b = c.toPx(to.x, to.y);
|
|
@@ -29,8 +31,8 @@ function Segment({ from, to, color = "var(--stage-fg)", weight = 2, opacity = 1,
|
|
|
29
31
|
strokeLinecap: "round",
|
|
30
32
|
strokeDasharray: dashed ? "6 6" : void 0
|
|
31
33
|
});
|
|
32
|
-
}
|
|
33
|
-
function Line({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1, dashed }) {
|
|
34
|
+
}, geomPropsEqual);
|
|
35
|
+
const Line = memo(function Line({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1, dashed }) {
|
|
34
36
|
const c = useCoords();
|
|
35
37
|
const [p1, p2] = extend(c, c.toPx(from.x, from.y), c.toPx(to.x, to.y), true);
|
|
36
38
|
return /* @__PURE__ */ jsx("line", {
|
|
@@ -43,8 +45,8 @@ function Line({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1,
|
|
|
43
45
|
opacity,
|
|
44
46
|
strokeDasharray: dashed ? "6 6" : void 0
|
|
45
47
|
});
|
|
46
|
-
}
|
|
47
|
-
function Ray({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1, dashed }) {
|
|
48
|
+
}, geomPropsEqual);
|
|
49
|
+
const Ray = memo(function Ray({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1, dashed }) {
|
|
48
50
|
const c = useCoords();
|
|
49
51
|
const [p1, p2] = extend(c, c.toPx(from.x, from.y), c.toPx(to.x, to.y), false);
|
|
50
52
|
return /* @__PURE__ */ jsx("line", {
|
|
@@ -57,8 +59,8 @@ function Ray({ from, to, color = "var(--stage-axis)", weight = 2, opacity = 1, d
|
|
|
57
59
|
opacity,
|
|
58
60
|
strokeDasharray: dashed ? "6 6" : void 0
|
|
59
61
|
});
|
|
60
|
-
}
|
|
61
|
-
function Vector({ tail = {
|
|
62
|
+
}, geomPropsEqual);
|
|
63
|
+
const Vector = memo(function Vector({ tail = {
|
|
62
64
|
x: 0,
|
|
63
65
|
y: 0
|
|
64
66
|
}, tip, color = "var(--stage-accent-2)", weight = 2.5, opacity = 1 }) {
|
|
@@ -76,7 +78,7 @@ function Vector({ tail = {
|
|
|
76
78
|
strokeLinecap: "round",
|
|
77
79
|
markerEnd: "url(#stage-arrow)"
|
|
78
80
|
});
|
|
79
|
-
}
|
|
81
|
+
}, geomPropsEqual);
|
|
80
82
|
|
|
81
83
|
//#endregion
|
|
82
84
|
export { Line, Ray, Segment, Vector };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Vec2 } from "../core/vec.mjs";
|
|
2
2
|
import { StyleProps } from "./props.mjs";
|
|
3
|
-
import { ReactNode } from "react";
|
|
4
3
|
|
|
5
4
|
//#region src/primitives/Shapes.d.ts
|
|
6
5
|
interface CircleProps extends StyleProps {
|
|
@@ -9,15 +8,7 @@ interface CircleProps extends StyleProps {
|
|
|
9
8
|
fill?: string;
|
|
10
9
|
fillOpacity?: number;
|
|
11
10
|
}
|
|
12
|
-
declare
|
|
13
|
-
center,
|
|
14
|
-
r,
|
|
15
|
-
color,
|
|
16
|
-
fill,
|
|
17
|
-
fillOpacity,
|
|
18
|
-
weight,
|
|
19
|
-
opacity
|
|
20
|
-
}: CircleProps): ReactNode;
|
|
11
|
+
declare const Circle: import("react").NamedExoticComponent<CircleProps>;
|
|
21
12
|
interface EllipseProps extends StyleProps {
|
|
22
13
|
center: Vec2;
|
|
23
14
|
rx: number;
|
|
@@ -25,52 +16,23 @@ interface EllipseProps extends StyleProps {
|
|
|
25
16
|
fill?: string;
|
|
26
17
|
fillOpacity?: number;
|
|
27
18
|
}
|
|
28
|
-
declare
|
|
29
|
-
center,
|
|
30
|
-
rx,
|
|
31
|
-
ry,
|
|
32
|
-
color,
|
|
33
|
-
fill,
|
|
34
|
-
fillOpacity,
|
|
35
|
-
weight,
|
|
36
|
-
opacity
|
|
37
|
-
}: EllipseProps): ReactNode;
|
|
19
|
+
declare const Ellipse: import("react").NamedExoticComponent<EllipseProps>;
|
|
38
20
|
interface PolygonProps extends StyleProps {
|
|
39
21
|
points: Vec2[];
|
|
40
22
|
fill?: string;
|
|
41
23
|
fillOpacity?: number;
|
|
42
24
|
}
|
|
43
|
-
declare
|
|
44
|
-
points,
|
|
45
|
-
color,
|
|
46
|
-
fill,
|
|
47
|
-
fillOpacity,
|
|
48
|
-
weight,
|
|
49
|
-
opacity
|
|
50
|
-
}: PolygonProps): ReactNode;
|
|
25
|
+
declare const Polygon: import("react").NamedExoticComponent<PolygonProps>;
|
|
51
26
|
interface PolylineProps extends StyleProps {
|
|
52
27
|
points: Vec2[];
|
|
53
28
|
}
|
|
54
|
-
declare
|
|
55
|
-
points,
|
|
56
|
-
color,
|
|
57
|
-
weight,
|
|
58
|
-
opacity,
|
|
59
|
-
dashed
|
|
60
|
-
}: PolylineProps): ReactNode;
|
|
29
|
+
declare const Polyline: import("react").NamedExoticComponent<PolylineProps>;
|
|
61
30
|
/** Low-level pixel-space path (d is already in pixels). */
|
|
62
31
|
interface PathProps extends StyleProps {
|
|
63
32
|
d: string;
|
|
64
33
|
fill?: string;
|
|
65
34
|
fillOpacity?: number;
|
|
66
35
|
}
|
|
67
|
-
declare
|
|
68
|
-
d,
|
|
69
|
-
color,
|
|
70
|
-
fill,
|
|
71
|
-
fillOpacity,
|
|
72
|
-
weight,
|
|
73
|
-
opacity
|
|
74
|
-
}: PathProps): ReactNode;
|
|
36
|
+
declare const Path: import("react").NamedExoticComponent<PathProps>;
|
|
75
37
|
//#endregion
|
|
76
38
|
export { Circle, CircleProps, Ellipse, EllipseProps, Path, PathProps, Polygon, PolygonProps, Polyline, PolylineProps };
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { fmt } from "../core/coords.mjs";
|
|
4
4
|
import { useCoords } from "../core/context.mjs";
|
|
5
|
+
import { geomPropsEqual } from "./props.mjs";
|
|
6
|
+
import { memo } from "react";
|
|
5
7
|
import { jsx } from "react/jsx-runtime";
|
|
6
8
|
|
|
7
9
|
//#region src/primitives/Shapes.tsx
|
|
@@ -9,7 +11,7 @@ const toPoints = (c, points) => points.map((p) => {
|
|
|
9
11
|
const [x, y] = c.toPx(p.x, p.y);
|
|
10
12
|
return `${fmt(x)},${fmt(y)}`;
|
|
11
13
|
}).join(" ");
|
|
12
|
-
function Circle({ center, r, color = "var(--stage-accent)", fill = "none", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
14
|
+
const Circle = memo(function Circle({ center, r, color = "var(--stage-accent)", fill = "none", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
13
15
|
const c = useCoords();
|
|
14
16
|
const [cx, cy] = c.toPx(center.x, center.y);
|
|
15
17
|
return /* @__PURE__ */ jsx("ellipse", {
|
|
@@ -23,8 +25,8 @@ function Circle({ center, r, color = "var(--stage-accent)", fill = "none", fillO
|
|
|
23
25
|
fillOpacity: fill === "none" ? void 0 : fillOpacity,
|
|
24
26
|
opacity
|
|
25
27
|
});
|
|
26
|
-
}
|
|
27
|
-
function Ellipse({ center, rx, ry, color = "var(--stage-accent)", fill = "none", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
28
|
+
}, geomPropsEqual);
|
|
29
|
+
const Ellipse = memo(function Ellipse({ center, rx, ry, color = "var(--stage-accent)", fill = "none", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
28
30
|
const c = useCoords();
|
|
29
31
|
const [cx, cy] = c.toPx(center.x, center.y);
|
|
30
32
|
return /* @__PURE__ */ jsx("ellipse", {
|
|
@@ -38,8 +40,8 @@ function Ellipse({ center, rx, ry, color = "var(--stage-accent)", fill = "none",
|
|
|
38
40
|
fillOpacity: fill === "none" ? void 0 : fillOpacity,
|
|
39
41
|
opacity
|
|
40
42
|
});
|
|
41
|
-
}
|
|
42
|
-
function Polygon({ points, color = "var(--stage-accent)", fill = "var(--stage-accent)", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
43
|
+
}, geomPropsEqual);
|
|
44
|
+
const Polygon = memo(function Polygon({ points, color = "var(--stage-accent)", fill = "var(--stage-accent)", fillOpacity = .12, weight = 2, opacity = 1 }) {
|
|
43
45
|
return /* @__PURE__ */ jsx("polygon", {
|
|
44
46
|
points: toPoints(useCoords(), points),
|
|
45
47
|
stroke: color,
|
|
@@ -49,8 +51,8 @@ function Polygon({ points, color = "var(--stage-accent)", fill = "var(--stage-ac
|
|
|
49
51
|
opacity,
|
|
50
52
|
strokeLinejoin: "round"
|
|
51
53
|
});
|
|
52
|
-
}
|
|
53
|
-
function Polyline({ points, color = "var(--stage-fg)", weight = 2, opacity = 1, dashed }) {
|
|
54
|
+
}, geomPropsEqual);
|
|
55
|
+
const Polyline = memo(function Polyline({ points, color = "var(--stage-fg)", weight = 2, opacity = 1, dashed }) {
|
|
54
56
|
return /* @__PURE__ */ jsx("polyline", {
|
|
55
57
|
points: toPoints(useCoords(), points),
|
|
56
58
|
fill: "none",
|
|
@@ -61,8 +63,8 @@ function Polyline({ points, color = "var(--stage-fg)", weight = 2, opacity = 1,
|
|
|
61
63
|
strokeLinecap: "round",
|
|
62
64
|
strokeDasharray: dashed ? "6 6" : void 0
|
|
63
65
|
});
|
|
64
|
-
}
|
|
65
|
-
function Path({ d, color = "var(--stage-fg)", fill = "none", fillOpacity = 1, weight = 2, opacity = 1 }) {
|
|
66
|
+
}, geomPropsEqual);
|
|
67
|
+
const Path = memo(function Path({ d, color = "var(--stage-fg)", fill = "none", fillOpacity = 1, weight = 2, opacity = 1 }) {
|
|
66
68
|
return /* @__PURE__ */ jsx("path", {
|
|
67
69
|
d,
|
|
68
70
|
stroke: color,
|
|
@@ -73,7 +75,7 @@ function Path({ d, color = "var(--stage-fg)", fill = "none", fillOpacity = 1, we
|
|
|
73
75
|
strokeLinejoin: "round",
|
|
74
76
|
strokeLinecap: "round"
|
|
75
77
|
});
|
|
76
|
-
}
|
|
78
|
+
}, geomPropsEqual);
|
|
77
79
|
|
|
78
80
|
//#endregion
|
|
79
81
|
export { Circle, Ellipse, Path, Polygon, Polyline };
|
|
@@ -4,7 +4,7 @@ import { Line, LineProps, Ray, Segment, SegmentProps, Vector, VectorProps } from
|
|
|
4
4
|
import { Circle, CircleProps, Ellipse, EllipseProps, Path, PathProps, Polygon, PolygonProps, Polyline, PolylineProps } from "./Shapes.mjs";
|
|
5
5
|
import { Label, LabelProps } from "./Label.mjs";
|
|
6
6
|
import { Tex, TexProps } from "./Tex.mjs";
|
|
7
|
-
import { Axes, AxesProps, Grid, GridProps, niceStep } from "./Grid.mjs";
|
|
7
|
+
import { Axes, AxesProps, ClearZone, Grid, GridProps, clearOfLabel, niceStep } from "./Grid.mjs";
|
|
8
8
|
import { OfXProps, OfYProps, ParametricProps, Plot } from "./Plot.mjs";
|
|
9
9
|
import { CanvasLayer, CanvasLayerProps } from "./CanvasLayer.mjs";
|
|
10
|
-
export { type A11yProps, Axes, type AxesProps, CanvasLayer, type CanvasLayerProps, Circle, type CircleProps, Dot, type DotProps, Ellipse, type EllipseProps, Grid, type GridProps, Label, type LabelProps, Line, type LineProps, type OfXProps, type OfYProps, type ParametricProps, Path, type PathProps, Plot, Point, Polygon, type PolygonProps, Polyline, type PolylineProps, Ray, Segment, type SegmentProps, type StyleProps, Tex, type TexProps, Vector, type VectorProps, niceStep };
|
|
10
|
+
export { type A11yProps, Axes, type AxesProps, CanvasLayer, type CanvasLayerProps, Circle, type CircleProps, type ClearZone, Dot, type DotProps, Ellipse, type EllipseProps, Grid, type GridProps, Label, type LabelProps, Line, type LineProps, type OfXProps, type OfYProps, type ParametricProps, Path, type PathProps, Plot, Point, Polygon, type PolygonProps, Polyline, type PolylineProps, Ray, Segment, type SegmentProps, type StyleProps, Tex, type TexProps, Vector, type VectorProps, clearOfLabel, niceStep };
|
|
@@ -3,8 +3,8 @@ import { Line, Ray, Segment, Vector } from "./Lines.mjs";
|
|
|
3
3
|
import { Circle, Ellipse, Path, Polygon, Polyline } from "./Shapes.mjs";
|
|
4
4
|
import { Label } from "./Label.mjs";
|
|
5
5
|
import { Tex } from "./Tex.mjs";
|
|
6
|
-
import { Axes, Grid, niceStep } from "./Grid.mjs";
|
|
6
|
+
import { Axes, Grid, clearOfLabel, niceStep } from "./Grid.mjs";
|
|
7
7
|
import { Plot } from "./Plot.mjs";
|
|
8
8
|
import { CanvasLayer } from "./CanvasLayer.mjs";
|
|
9
9
|
|
|
10
|
-
export { Axes, CanvasLayer, Circle, Dot, Ellipse, Grid, Label, Line, Path, Plot, Point, Polygon, Polyline, Ray, Segment, Tex, Vector, niceStep };
|
|
10
|
+
export { Axes, CanvasLayer, Circle, Dot, Ellipse, Grid, Label, Line, Path, Plot, Point, Polygon, Polyline, Ray, Segment, Tex, Vector, clearOfLabel, niceStep };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/primitives/props.ts
|
|
2
|
+
const MAX_DEPTH = 4;
|
|
3
|
+
const valEq = (a, b, depth) => {
|
|
4
|
+
if (Object.is(a, b)) return true;
|
|
5
|
+
if (depth <= 0) return false;
|
|
6
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
7
|
+
if ("$$typeof" in a || "$$typeof" in b) return false;
|
|
8
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
9
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
10
|
+
for (let i = 0; i < a.length; i++) if (!valEq(a[i], b[i], depth - 1)) return false;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const ka = Object.keys(a);
|
|
14
|
+
if (ka.length !== Object.keys(b).length) return false;
|
|
15
|
+
for (const k of ka) {
|
|
16
|
+
if (!(k in b)) return false;
|
|
17
|
+
if (!valEq(a[k], b[k], depth - 1)) return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Value-based props comparator for `React.memo` on geometry primitives.
|
|
23
|
+
* Labs recreate `Vec2`/`points` objects every render (often 60×/s under a frame
|
|
24
|
+
* tick), so identity-based memo never hits; comparing coordinate VALUES lets
|
|
25
|
+
* static shapes skip reconciliation while anything that actually moved still
|
|
26
|
+
* re-renders. Functions and React elements compare by reference (safe fallback).
|
|
27
|
+
*/
|
|
28
|
+
const geomPropsEqual = (prev, next) => valEq(prev, next, MAX_DEPTH);
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { geomPropsEqual };
|
package/dist/scene/Scene.d.mts
CHANGED
|
@@ -15,6 +15,9 @@ interface SceneProps {
|
|
|
15
15
|
/** Author opt-in: start a sim running immediately (ambient motion) instead of
|
|
16
16
|
* the default "press Play". A SceneDoc with no `meta.sims` is always static. */
|
|
17
17
|
autoPlay?: boolean;
|
|
18
|
+
/** Optional controlled playback for hosts that provide their own transport. */
|
|
19
|
+
playing?: boolean;
|
|
20
|
+
onPlayingChange?: (playing: boolean) => void;
|
|
18
21
|
}
|
|
19
22
|
declare function Scene({
|
|
20
23
|
doc,
|
|
@@ -25,7 +28,9 @@ declare function Scene({
|
|
|
25
28
|
height,
|
|
26
29
|
view,
|
|
27
30
|
ariaLabel,
|
|
28
|
-
autoPlay
|
|
31
|
+
autoPlay,
|
|
32
|
+
playing: playingProp,
|
|
33
|
+
onPlayingChange
|
|
29
34
|
}: SceneProps): ReactNode;
|
|
30
35
|
//#endregion
|
|
31
36
|
export { Scene, SceneProps };
|
package/dist/scene/Scene.mjs
CHANGED
|
@@ -45,7 +45,7 @@ function autoView(resolved) {
|
|
|
45
45
|
yMax: Math.max(...ys) + pad
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes = true, height, view, ariaLabel = "Interactive figure", autoPlay = false }) {
|
|
48
|
+
function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes = true, height, view, ariaLabel = "Interactive figure", autoPlay = false, playing: playingProp, onPlayingChange }) {
|
|
49
49
|
const [overlay, setOverlay] = useState(/* @__PURE__ */ new Map());
|
|
50
50
|
const prevRef = useRef(void 0);
|
|
51
51
|
const sims = doc.meta?.sims;
|
|
@@ -55,14 +55,22 @@ function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes =
|
|
|
55
55
|
const [frame, setFrame] = useState(0);
|
|
56
56
|
const { ref: rootRef, inView } = useInView();
|
|
57
57
|
const [done, setDone] = useState(false);
|
|
58
|
-
const [
|
|
58
|
+
const [internalPlaying, setInternalPlaying] = useState(autoPlay);
|
|
59
|
+
const playing = playingProp ?? internalPlaying;
|
|
60
|
+
const setPlaying = (next) => {
|
|
61
|
+
if (playingProp === void 0) setInternalPlaying(next);
|
|
62
|
+
onPlayingChange?.(next);
|
|
63
|
+
};
|
|
59
64
|
useFrameLoop((f) => {
|
|
60
65
|
if (!sims?.length || !simStates.current) return;
|
|
61
66
|
const next = stepSims(sims, simStates.current, Math.min(.05, f.dtMs / 1e3));
|
|
62
67
|
simStates.current = next.states;
|
|
63
68
|
simScalars.current = next.scalars;
|
|
64
69
|
setFrame((n) => (n + 1) % 1e6);
|
|
65
|
-
if (next.done)
|
|
70
|
+
if (next.done) {
|
|
71
|
+
setDone(true);
|
|
72
|
+
setPlaying(false);
|
|
73
|
+
}
|
|
66
74
|
}, { running: !!sims?.length && inView && playing && !done });
|
|
67
75
|
const merged = useMemo(() => {
|
|
68
76
|
const scalars = simScalars.current;
|
|
@@ -95,7 +103,7 @@ function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes =
|
|
|
95
103
|
const hasSims = !!sims?.length;
|
|
96
104
|
return /* @__PURE__ */ jsxs("div", {
|
|
97
105
|
ref: rootRef,
|
|
98
|
-
|
|
106
|
+
className: "stage-scene",
|
|
99
107
|
children: [
|
|
100
108
|
/* @__PURE__ */ jsxs(Stage, {
|
|
101
109
|
view: v,
|
|
@@ -114,30 +122,9 @@ function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes =
|
|
|
114
122
|
type: "button",
|
|
115
123
|
onClick: () => setPlaying(true),
|
|
116
124
|
"aria-label": "Play simulation",
|
|
117
|
-
|
|
118
|
-
position: "absolute",
|
|
119
|
-
inset: 0,
|
|
120
|
-
display: "flex",
|
|
121
|
-
alignItems: "center",
|
|
122
|
-
justifyContent: "center",
|
|
123
|
-
background: "color-mix(in oklab, var(--stage-bg) 38%, transparent)",
|
|
124
|
-
border: "none",
|
|
125
|
-
borderRadius: 12,
|
|
126
|
-
cursor: "pointer"
|
|
127
|
-
},
|
|
125
|
+
className: "stage-scene__play-overlay",
|
|
128
126
|
children: /* @__PURE__ */ jsx("span", {
|
|
129
|
-
|
|
130
|
-
display: "inline-flex",
|
|
131
|
-
alignItems: "center",
|
|
132
|
-
gap: 8,
|
|
133
|
-
padding: "11px 26px",
|
|
134
|
-
borderRadius: 999,
|
|
135
|
-
background: "var(--stage-accent)",
|
|
136
|
-
color: "#fff",
|
|
137
|
-
fontWeight: 800,
|
|
138
|
-
fontSize: 16,
|
|
139
|
-
boxShadow: "0 6px 18px rgba(0,0,0,.28)"
|
|
140
|
-
},
|
|
127
|
+
className: "stage-scene__play-label",
|
|
141
128
|
children: "▶ Play"
|
|
142
129
|
})
|
|
143
130
|
}),
|
|
@@ -145,19 +132,7 @@ function Scene({ doc, onChange, interactive = true, showGrid = true, showAxes =
|
|
|
145
132
|
type: "button",
|
|
146
133
|
onClick: () => setPlaying(false),
|
|
147
134
|
"aria-label": "Pause simulation",
|
|
148
|
-
|
|
149
|
-
position: "absolute",
|
|
150
|
-
top: 10,
|
|
151
|
-
right: 10,
|
|
152
|
-
width: 34,
|
|
153
|
-
height: 34,
|
|
154
|
-
borderRadius: 999,
|
|
155
|
-
border: "1px solid var(--stage-grid)",
|
|
156
|
-
background: "color-mix(in oklab, var(--stage-bg) 80%, transparent)",
|
|
157
|
-
color: "var(--stage-fg)",
|
|
158
|
-
cursor: "pointer",
|
|
159
|
-
fontSize: 13
|
|
160
|
-
},
|
|
135
|
+
className: "stage-scene__pause",
|
|
161
136
|
children: "⏸"
|
|
162
137
|
})
|
|
163
138
|
]
|
package/dist/view/Stage.mjs
CHANGED
|
@@ -31,7 +31,7 @@ function Stage({ view = DEFAULT_VIEW, width, height, aspectRatio, pad = 12, pres
|
|
|
31
31
|
}), [
|
|
32
32
|
w,
|
|
33
33
|
h,
|
|
34
|
-
view
|
|
34
|
+
`${view.xMin} ${view.xMax} ${view.yMin} ${view.yMax}`,
|
|
35
35
|
pad,
|
|
36
36
|
preserveAspect
|
|
37
37
|
]);
|
|
@@ -43,8 +43,7 @@ function Stage({ view = DEFAULT_VIEW, width, height, aspectRatio, pad = 12, pres
|
|
|
43
43
|
} : void 0;
|
|
44
44
|
return /* @__PURE__ */ jsx("div", {
|
|
45
45
|
ref: wrapRef,
|
|
46
|
-
className,
|
|
47
|
-
style: { width: "100%" },
|
|
46
|
+
className: ["stage-root", className].filter(Boolean).join(" "),
|
|
48
47
|
children: /* @__PURE__ */ jsxs("svg", {
|
|
49
48
|
ref: svgRef,
|
|
50
49
|
width: w,
|
|
@@ -53,14 +52,8 @@ function Stage({ view = DEFAULT_VIEW, width, height, aspectRatio, pad = 12, pres
|
|
|
53
52
|
role: "group",
|
|
54
53
|
"aria-label": ariaLabel,
|
|
55
54
|
onPointerDown: handlePointer,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
background,
|
|
59
|
-
borderRadius: 12,
|
|
60
|
-
border: "1px solid var(--stage-grid)",
|
|
61
|
-
userSelect: "none",
|
|
62
|
-
touchAction: "none"
|
|
63
|
-
},
|
|
55
|
+
className: "stage-canvas",
|
|
56
|
+
style: { background },
|
|
64
57
|
children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", {
|
|
65
58
|
id: "stage-arrow",
|
|
66
59
|
viewBox: "0 0 10 10",
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/stage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Domain-neutral visual primitive engine for the web. Declarative SVG diagram/math primitives, draggable handles, a math↔pixel coordinate system, a motion core + energy effect defs, theming, pure sim cores, and a small kit of neutral glyph primitives. Reactive, web-native, agent-drivable. The render foundation under @classytic/labs (subject-matter glyphs live there); canvas + 3D subpaths later.",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"sideEffects": [
|
|
9
|
-
"**/*.css"
|
|
10
|
-
"**/assets/**"
|
|
9
|
+
"**/*.css"
|
|
11
10
|
],
|
|
12
11
|
"engines": {
|
|
13
12
|
"node": ">=22"
|
|
@@ -52,6 +51,10 @@
|
|
|
52
51
|
"types": "./dist/math/index.d.mts",
|
|
53
52
|
"default": "./dist/math/index.mjs"
|
|
54
53
|
},
|
|
54
|
+
"./logic": {
|
|
55
|
+
"types": "./dist/logic/index.d.mts",
|
|
56
|
+
"default": "./dist/logic/index.mjs"
|
|
57
|
+
},
|
|
55
58
|
"./sim": {
|
|
56
59
|
"types": "./dist/sim/index.d.mts",
|
|
57
60
|
"default": "./dist/sim/index.mjs"
|
|
@@ -72,6 +75,10 @@
|
|
|
72
75
|
"types": "./dist/chem/index.d.mts",
|
|
73
76
|
"default": "./dist/chem/index.mjs"
|
|
74
77
|
},
|
|
78
|
+
"./finance": {
|
|
79
|
+
"types": "./dist/finance/index.d.mts",
|
|
80
|
+
"default": "./dist/finance/index.mjs"
|
|
81
|
+
},
|
|
75
82
|
"./steps": {
|
|
76
83
|
"types": "./dist/steps/index.d.mts",
|
|
77
84
|
"default": "./dist/steps/index.mjs"
|
|
@@ -88,21 +95,6 @@
|
|
|
88
95
|
"LICENSE",
|
|
89
96
|
"README.md"
|
|
90
97
|
],
|
|
91
|
-
"scripts": {
|
|
92
|
-
"build": "tsdown",
|
|
93
|
-
"dev": "tsdown --watch",
|
|
94
|
-
"typecheck": "tsc --noEmit",
|
|
95
|
-
"sync": "node scripts/sync-stage.mjs",
|
|
96
|
-
"pretest": "npm run build",
|
|
97
|
-
"test": "vitest run",
|
|
98
|
-
"verify": "npm run typecheck && npm test",
|
|
99
|
-
"push": "classytic-push",
|
|
100
|
-
"changeset": "changeset",
|
|
101
|
-
"version-packages": "changeset version",
|
|
102
|
-
"release": "npm run build && changeset publish",
|
|
103
|
-
"prepublishOnly": "npm run typecheck && npm run build && npm test",
|
|
104
|
-
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
105
|
-
},
|
|
106
98
|
"peerDependencies": {
|
|
107
99
|
"katex": ">=0.16",
|
|
108
100
|
"react": ">=19",
|
|
@@ -117,12 +109,11 @@
|
|
|
117
109
|
"@changesets/cli": "^2.27.9",
|
|
118
110
|
"@classytic/dev-tools": "^0.2.0",
|
|
119
111
|
"@testing-library/react": "^16.3.2",
|
|
120
|
-
"@types/katex": "^0.16.7",
|
|
121
112
|
"@types/node": "^22.0.0",
|
|
122
113
|
"@types/react": "^19.2.0",
|
|
123
114
|
"@types/react-dom": "^19.2.0",
|
|
124
115
|
"happy-dom": "^20.0.0",
|
|
125
|
-
"katex": "^0.
|
|
116
|
+
"katex": "^0.18.7",
|
|
126
117
|
"react": "^19.2.0",
|
|
127
118
|
"react-dom": "^19.2.0",
|
|
128
119
|
"tsdown": "^0.22.0",
|
|
@@ -141,5 +132,22 @@
|
|
|
141
132
|
"math",
|
|
142
133
|
"engine",
|
|
143
134
|
"primitives"
|
|
144
|
-
]
|
|
145
|
-
|
|
135
|
+
],
|
|
136
|
+
"scripts": {
|
|
137
|
+
"build": "tsdown",
|
|
138
|
+
"dev": "tsdown --watch",
|
|
139
|
+
"typecheck": "tsc --noEmit",
|
|
140
|
+
"sync": "node scripts/sync-stage.mjs",
|
|
141
|
+
"pretest": "npm run build",
|
|
142
|
+
"test": "vitest run",
|
|
143
|
+
"verify": "npm run typecheck && npm test",
|
|
144
|
+
"package:check": "node scripts/package-check.mjs",
|
|
145
|
+
"package:consumer": "node scripts/packed-consumer-check.mjs",
|
|
146
|
+
"verify:release": "npm run typecheck && npm test && npm run package:check && npm run package:consumer",
|
|
147
|
+
"push": "classytic-push",
|
|
148
|
+
"changeset": "changeset",
|
|
149
|
+
"version-packages": "changeset version",
|
|
150
|
+
"release": "npm run build && changeset publish",
|
|
151
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
152
|
+
}
|
|
153
|
+
}
|