@twick/visualizer 0.15.20 → 0.15.21
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/dist/project.js +121 -55
- package/package.json +11 -10
- package/src/controllers/element.controller.ts +4 -0
- package/src/elements/arrow.element.tsx +75 -0
- package/src/elements/index.ts +2 -0
- package/src/elements/line.element.tsx +17 -0
- package/src/elements/text.element.tsx +4 -0
- package/src/helpers/constants.ts +1 -0
- package/src/project.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twick/visualizer",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.21",
|
|
4
4
|
"license": "https://github.com/ncounterspecialist/twick/blob/main/LICENSE.md",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "twick editor --projectFile ./src/live.tsx",
|
|
@@ -22,18 +22,19 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@preact/signals": "^1.2.1",
|
|
25
|
-
"@twick/2d": "^0.15.
|
|
26
|
-
"@twick/core": "^0.15.
|
|
27
|
-
"@twick/
|
|
28
|
-
"@twick/
|
|
29
|
-
"
|
|
30
|
-
"
|
|
25
|
+
"@twick/2d": "^0.15.21",
|
|
26
|
+
"@twick/core": "^0.15.21",
|
|
27
|
+
"@twick/effects": "0.15.21",
|
|
28
|
+
"@twick/media-utils": "0.15.21",
|
|
29
|
+
"@twick/renderer": "^0.15.21",
|
|
30
|
+
"@twick/vite-plugin": "^0.15.21",
|
|
31
31
|
"crelt": "^1.0.6",
|
|
32
|
-
"
|
|
32
|
+
"date-fns": "^4.1.0",
|
|
33
|
+
"preact": "^10.19.2"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
|
-
"@twick/cli": "^0.15.
|
|
36
|
-
"@twick/ui": "^0.15.
|
|
36
|
+
"@twick/cli": "^0.15.21",
|
|
37
|
+
"@twick/ui": "^0.15.21",
|
|
37
38
|
"typescript": "5.4.2",
|
|
38
39
|
"typedoc": "^0.25.8",
|
|
39
40
|
"typedoc-plugin-markdown": "^3.17.1",
|
|
@@ -3,6 +3,8 @@ import { CaptionElement } from "../elements/caption.element";
|
|
|
3
3
|
import { CircleElement } from "../elements/circle.element";
|
|
4
4
|
import { ImageElement } from "../elements/image.element";
|
|
5
5
|
import { RectElement } from "../elements/rect.element";
|
|
6
|
+
import { ArrowElement } from "../elements/arrow.element";
|
|
7
|
+
import { LineElement } from "../elements/line.element";
|
|
6
8
|
import { SceneElement } from "../elements/scene.element";
|
|
7
9
|
import { TextElement } from "../elements/text.element";
|
|
8
10
|
import { VideoElement } from "../elements/video.element";
|
|
@@ -33,6 +35,8 @@ export class ElementController {
|
|
|
33
35
|
elementController.register(AudioElement);
|
|
34
36
|
elementController.register(CircleElement);
|
|
35
37
|
elementController.register(RectElement);
|
|
38
|
+
elementController.register(ArrowElement);
|
|
39
|
+
elementController.register(LineElement);
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
const elementController = new ElementController();
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ElementParams } from "../helpers/types";
|
|
2
|
+
import { all, createRef, waitFor } from "@twick/core";
|
|
3
|
+
import { Layout, Polygon, Rect } from "@twick/2d";
|
|
4
|
+
import { addAnimation } from "../helpers/element.utils";
|
|
5
|
+
import { logger } from "../helpers/log.utils";
|
|
6
|
+
|
|
7
|
+
const HEAD_OFFSET = 2;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Arrow element: bar + triangle (callout) for the visualizer.
|
|
11
|
+
* Matches canvas arrow layout: bar from left, triangle overlapping at the tip.
|
|
12
|
+
*/
|
|
13
|
+
export const ArrowElement = {
|
|
14
|
+
name: "arrow",
|
|
15
|
+
|
|
16
|
+
*create({ containerRef, element, view }: ElementParams) {
|
|
17
|
+
const elementRef = createRef<any>();
|
|
18
|
+
yield* waitFor(element?.s ?? 0);
|
|
19
|
+
logger(`ArrowElement: ${element?.id}`);
|
|
20
|
+
|
|
21
|
+
const w = element?.props?.width ?? 220;
|
|
22
|
+
const h = element?.props?.height ?? 14;
|
|
23
|
+
const fill = element?.props?.fill ?? "#f59e0b";
|
|
24
|
+
const radius = element?.props?.radius ?? 4;
|
|
25
|
+
const rotation = element?.props?.rotation ?? 0;
|
|
26
|
+
const opacity = element?.props?.opacity ?? 1;
|
|
27
|
+
const cx = element?.props?.x ?? 0;
|
|
28
|
+
const cy = element?.props?.y ?? 0;
|
|
29
|
+
|
|
30
|
+
// Match canvas triangle size: Polygon is inscribed in its size box so appears
|
|
31
|
+
// smaller than Fabric’s Triangle (which fills its box). Scale up ~1.3×.
|
|
32
|
+
const HEAD_SIZE_MULT = 1.8 * 1.3;
|
|
33
|
+
const headSize = h * HEAD_SIZE_MULT;
|
|
34
|
+
const barLength = w - headSize * 0.5 + HEAD_OFFSET;
|
|
35
|
+
const barWidth = w;
|
|
36
|
+
|
|
37
|
+
// Single group so one ref for animations
|
|
38
|
+
const arrowGroup = (
|
|
39
|
+
<Layout
|
|
40
|
+
ref={elementRef}
|
|
41
|
+
key={element?.id}
|
|
42
|
+
x={cx}
|
|
43
|
+
y={cy}
|
|
44
|
+
rotation={rotation}
|
|
45
|
+
opacity={opacity}
|
|
46
|
+
>
|
|
47
|
+
<Rect
|
|
48
|
+
x={-barWidth / 2 + barLength / 2}
|
|
49
|
+
y={0}
|
|
50
|
+
width={barLength}
|
|
51
|
+
height={h}
|
|
52
|
+
fill={fill}
|
|
53
|
+
radius={radius}
|
|
54
|
+
/>
|
|
55
|
+
<Polygon
|
|
56
|
+
x={barWidth / 2 - headSize * 0.25}
|
|
57
|
+
y={0}
|
|
58
|
+
width={headSize}
|
|
59
|
+
height={headSize}
|
|
60
|
+
sides={3}
|
|
61
|
+
fill={fill}
|
|
62
|
+
rotation={90}
|
|
63
|
+
/>
|
|
64
|
+
</Layout>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
yield containerRef().add(arrowGroup);
|
|
68
|
+
|
|
69
|
+
yield* all(
|
|
70
|
+
addAnimation({ elementRef, element: element!, view }),
|
|
71
|
+
waitFor(Math.max(0, (element?.e ?? 0) - (element?.s ?? 0)))
|
|
72
|
+
);
|
|
73
|
+
yield elementRef().remove();
|
|
74
|
+
},
|
|
75
|
+
};
|
package/src/elements/index.ts
CHANGED
|
@@ -9,5 +9,7 @@ export { AudioElement } from './audio.element';
|
|
|
9
9
|
export { TextElement } from './text.element';
|
|
10
10
|
export { CaptionElement } from './caption.element';
|
|
11
11
|
export { RectElement } from './rect.element';
|
|
12
|
+
export { ArrowElement } from './arrow.element';
|
|
13
|
+
export { LineElement } from './line.element';
|
|
12
14
|
export { CircleElement } from './circle.element';
|
|
13
15
|
export { SceneElement } from './scene.element';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ElementParams } from "../helpers/types";
|
|
2
|
+
import { RectElement } from "./rect.element";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* LineElement: visualizer representation for line/segment shapes.
|
|
6
|
+
* Uses the same renderer as RectElement so width/height/fill/rotation
|
|
7
|
+
* map directly to the exported video.
|
|
8
|
+
*/
|
|
9
|
+
export const LineElement = {
|
|
10
|
+
name: "line",
|
|
11
|
+
|
|
12
|
+
*create(params: ElementParams) {
|
|
13
|
+
// Delegate to RectElement to reuse rendering and animation behavior.
|
|
14
|
+
yield* RectElement.create(params);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
@@ -122,6 +122,10 @@ export const TextElement = {
|
|
|
122
122
|
alignItems={"center"}
|
|
123
123
|
justifyContent={"center"}
|
|
124
124
|
layout
|
|
125
|
+
x={element.props?.x}
|
|
126
|
+
y={element.props?.y}
|
|
127
|
+
rotation={element.props?.rotation}
|
|
128
|
+
opacity={element.props?.opacity}
|
|
125
129
|
>
|
|
126
130
|
<Txt
|
|
127
131
|
ref={innerTextRef}
|
package/src/helpers/constants.ts
CHANGED
package/src/project.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { makeProject } from "@twick/core";
|
|
2
|
+
import { getActiveEffectsForFrame } from "@twick/effects";
|
|
2
3
|
import { scene } from "./visualizer";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const project = makeProject({
|
|
5
6
|
scenes: [scene],
|
|
6
7
|
});
|
|
8
|
+
(project as import("@twick/core").Project).getActiveEffectsForFrame =
|
|
9
|
+
getActiveEffectsForFrame;
|
|
10
|
+
export default project;
|