visualfries 0.1.902 → 0.1.1095

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.
@@ -0,0 +1,148 @@
1
+ {
2
+ "id": "animated-shapes-example",
3
+ "version": "2.0",
4
+ "name": "Animated Shapes",
5
+ "settings": {
6
+ "width": 1080,
7
+ "height": 1920,
8
+ "duration": 3,
9
+ "fps": 30,
10
+ "backgroundColor": "#0a0a0a"
11
+ },
12
+ "assets": [],
13
+ "layers": [
14
+ {
15
+ "id": "layer-main",
16
+ "name": "Main Layer",
17
+ "order": 0,
18
+ "visible": true,
19
+ "muted": false,
20
+ "components": [
21
+ {
22
+ "id": "bg",
23
+ "name": "Background",
24
+ "type": "SHAPE",
25
+ "timeline": { "startAt": 0, "endAt": 3 },
26
+ "visible": true,
27
+ "order": 0,
28
+ "shape": { "type": "rectangle" },
29
+ "appearance": {
30
+ "x": 0,
31
+ "y": 0,
32
+ "width": 1080,
33
+ "height": 1920,
34
+ "opacity": 1,
35
+ "rotation": 0,
36
+ "scaleX": 1,
37
+ "scaleY": 1,
38
+ "color": "#0a0a0a"
39
+ },
40
+ "animations": { "enabled": true, "list": [] },
41
+ "effects": { "enabled": true, "map": {} }
42
+ },
43
+ {
44
+ "id": "circle-1",
45
+ "name": "Circle",
46
+ "type": "SHAPE",
47
+ "timeline": { "startAt": 0, "endAt": 3 },
48
+ "visible": true,
49
+ "order": 1,
50
+ "shape": { "type": "circle" },
51
+ "appearance": {
52
+ "x": 290,
53
+ "y": 710,
54
+ "width": 500,
55
+ "height": 500,
56
+ "opacity": 1,
57
+ "rotation": 0,
58
+ "scaleX": 1,
59
+ "scaleY": 1,
60
+ "background": {
61
+ "colors": ["#f472b6", "#a855f7"],
62
+ "angle": 45
63
+ }
64
+ },
65
+ "animations": {
66
+ "enabled": true,
67
+ "list": [
68
+ {
69
+ "id": "circle-scale",
70
+ "name": "Pulse",
71
+ "animation": {
72
+ "id": "pulse",
73
+ "timeline": [
74
+ {
75
+ "tweens": [
76
+ {
77
+ "method": "from",
78
+ "vars": { "duration": 0.5, "scale": 0 }
79
+ },
80
+ {
81
+ "method": "to",
82
+ "vars": { "duration": 0.5, "scale": 1.1 }
83
+ },
84
+ {
85
+ "method": "to",
86
+ "vars": { "duration": 0.3, "scale": 1 }
87
+ }
88
+ ]
89
+ }
90
+ ]
91
+ }
92
+ }
93
+ ]
94
+ },
95
+ "effects": { "enabled": true, "map": {} }
96
+ },
97
+ {
98
+ "id": "star-1",
99
+ "name": "Star",
100
+ "type": "SHAPE",
101
+ "timeline": { "startAt": 0.5, "endAt": 3 },
102
+ "visible": true,
103
+ "order": 2,
104
+ "shape": { "type": "star" },
105
+ "appearance": {
106
+ "x": 640,
107
+ "y": 300,
108
+ "width": 300,
109
+ "height": 300,
110
+ "opacity": 1,
111
+ "rotation": 0,
112
+ "scaleX": 1,
113
+ "scaleY": 1,
114
+ "background": {
115
+ "colors": ["#fbbf24", "#f59e0b"],
116
+ "angle": 90
117
+ }
118
+ },
119
+ "animations": {
120
+ "enabled": true,
121
+ "list": [
122
+ {
123
+ "id": "star-spin",
124
+ "name": "Spin",
125
+ "animation": {
126
+ "id": "spin",
127
+ "timeline": [
128
+ {
129
+ "tweens": [
130
+ {
131
+ "method": "from",
132
+ "vars": { "duration": 0.6, "rotation": 180, "scale": 0 }
133
+ }
134
+ ]
135
+ }
136
+ ]
137
+ }
138
+ }
139
+ ]
140
+ },
141
+ "effects": { "enabled": true, "map": {} }
142
+ }
143
+ ]
144
+ }
145
+ ],
146
+ "transitions": [],
147
+ "audioTracks": []
148
+ }
@@ -0,0 +1,105 @@
1
+ {
2
+ "id": "gradient-background-example",
3
+ "version": "2.0",
4
+ "name": "Gradient Background",
5
+ "settings": {
6
+ "width": 1080,
7
+ "height": 1920,
8
+ "duration": 5,
9
+ "fps": 30,
10
+ "backgroundColor": "#000000"
11
+ },
12
+ "assets": [],
13
+ "layers": [
14
+ {
15
+ "id": "layer-main",
16
+ "name": "Main Layer",
17
+ "order": 0,
18
+ "visible": true,
19
+ "muted": false,
20
+ "components": [
21
+ {
22
+ "id": "bg-gradient",
23
+ "name": "Background Gradient",
24
+ "type": "SHAPE",
25
+ "timeline": { "startAt": 0, "endAt": 5 },
26
+ "visible": true,
27
+ "order": 0,
28
+ "shape": { "type": "rectangle" },
29
+ "appearance": {
30
+ "x": 0,
31
+ "y": 0,
32
+ "width": 1080,
33
+ "height": 1920,
34
+ "opacity": 1,
35
+ "rotation": 0,
36
+ "scaleX": 1,
37
+ "scaleY": 1,
38
+ "background": {
39
+ "colors": ["#667eea", "#764ba2"],
40
+ "angle": 135
41
+ }
42
+ },
43
+ "animations": { "enabled": true, "list": [] },
44
+ "effects": { "enabled": true, "map": {} }
45
+ },
46
+ {
47
+ "id": "title-text",
48
+ "name": "Title",
49
+ "type": "TEXT",
50
+ "text": "Hello World",
51
+ "timeline": { "startAt": 0, "endAt": 5 },
52
+ "visible": true,
53
+ "order": 1,
54
+ "appearance": {
55
+ "x": 0,
56
+ "y": 800,
57
+ "width": 1080,
58
+ "height": 300,
59
+ "opacity": 1,
60
+ "rotation": 0,
61
+ "scaleX": 1,
62
+ "scaleY": 1,
63
+ "horizontalAlign": "center",
64
+ "verticalAlign": "center",
65
+ "text": {
66
+ "fontFamily": "Inter",
67
+ "fontSize": 120,
68
+ "fontWeight": "900",
69
+ "lineHeight": { "value": 1.1, "unit": "em" },
70
+ "letterSpacing": { "value": -0.02, "unit": "em" },
71
+ "color": "#ffffff",
72
+ "textAlign": "center",
73
+ "textTransform": "uppercase"
74
+ }
75
+ },
76
+ "animations": {
77
+ "enabled": true,
78
+ "list": [
79
+ {
80
+ "id": "title-scale",
81
+ "name": "Scale In",
82
+ "animation": {
83
+ "id": "scale-in",
84
+ "timeline": [
85
+ {
86
+ "tweens": [
87
+ {
88
+ "method": "from",
89
+ "vars": { "duration": 0.6, "scale": 0.5, "opacity": 0 }
90
+ }
91
+ ]
92
+ }
93
+ ]
94
+ }
95
+ }
96
+ ]
97
+ },
98
+ "effects": { "enabled": true, "map": {} }
99
+ }
100
+ ]
101
+ }
102
+ ],
103
+ "transitions": [],
104
+ "audioTracks": []
105
+ }
@@ -0,0 +1,97 @@
1
+ {
2
+ "id": "karaoke-subtitles-example",
3
+ "version": "2.0",
4
+ "name": "Karaoke Subtitles",
5
+ "settings": {
6
+ "width": 1080,
7
+ "height": 1920,
8
+ "duration": 4,
9
+ "fps": 30,
10
+ "backgroundColor": "#1a1a2e"
11
+ },
12
+ "assets": [],
13
+ "layers": [
14
+ {
15
+ "id": "layer-main",
16
+ "name": "Main Layer",
17
+ "order": 0,
18
+ "visible": true,
19
+ "muted": false,
20
+ "components": [
21
+ {
22
+ "id": "bg",
23
+ "name": "Background",
24
+ "type": "SHAPE",
25
+ "timeline": { "startAt": 0, "endAt": 4 },
26
+ "visible": true,
27
+ "order": 0,
28
+ "shape": { "type": "rectangle" },
29
+ "appearance": {
30
+ "x": 0,
31
+ "y": 0,
32
+ "width": 1080,
33
+ "height": 1920,
34
+ "opacity": 1,
35
+ "rotation": 0,
36
+ "scaleX": 1,
37
+ "scaleY": 1,
38
+ "background": {
39
+ "colors": ["#0f0f23", "#1a1a3e"],
40
+ "angle": 180
41
+ }
42
+ },
43
+ "animations": { "enabled": true, "list": [] },
44
+ "effects": { "enabled": true, "map": {} }
45
+ },
46
+ {
47
+ "id": "subtitle-karaoke",
48
+ "name": "Karaoke Text",
49
+ "type": "TEXT",
50
+ "text": "Create stunning videos",
51
+ "timeline": { "startAt": 0, "endAt": 4 },
52
+ "visible": true,
53
+ "order": 1,
54
+ "appearance": {
55
+ "x": 0,
56
+ "y": 850,
57
+ "width": 1080,
58
+ "height": 200,
59
+ "opacity": 1,
60
+ "rotation": 0,
61
+ "scaleX": 1,
62
+ "scaleY": 1,
63
+ "horizontalAlign": "center",
64
+ "verticalAlign": "center",
65
+ "text": {
66
+ "fontFamily": "Montserrat",
67
+ "fontSize": 90,
68
+ "fontWeight": "900",
69
+ "lineHeight": { "value": 1.2, "unit": "em" },
70
+ "color": "rgba(255,255,255,0.4)",
71
+ "textAlign": "center",
72
+ "textTransform": "uppercase",
73
+ "activeWord": {
74
+ "enabled": true,
75
+ "color": "#ffd700",
76
+ "scale": 1.3
77
+ }
78
+ }
79
+ },
80
+ "animations": {
81
+ "enabled": true,
82
+ "list": [
83
+ {
84
+ "id": "words-anim",
85
+ "name": "Words Highlight",
86
+ "animation": "cf-words-highlight"
87
+ }
88
+ ]
89
+ },
90
+ "effects": { "enabled": true, "map": {} }
91
+ }
92
+ ]
93
+ }
94
+ ],
95
+ "transitions": [],
96
+ "audioTracks": []
97
+ }
@@ -208,7 +208,9 @@ function buildSubtitlesManager(timeManager, eventManager, sceneData, subtitles)
208
208
  for (const [lang, langIndex] of Object.entries(assetIndex)) {
209
209
  for (const [subtitleId, subtitle] of Object.entries(langIndex)) {
210
210
  const text = subtitle.text;
211
- const characters = text.split('');
211
+ // Use Array.from to properly handle multi-codepoint characters (emojis, etc.)
212
+ // This prevents splitting emojis into unpaired surrogates that cause encodeURIComponent to fail
213
+ const characters = Array.from(text);
212
214
  if (characters && characters.length > 0) {
213
215
  for (const char of characters) {
214
216
  if (!charactersList.includes(char)) {
@@ -37,6 +37,13 @@ export interface LayerEvents {
37
37
  export interface ComponentEvents {
38
38
  componentschange: void;
39
39
  componentchange: ComponentData;
40
+ hookerror: {
41
+ hookName: string;
42
+ hookType: string;
43
+ error: Error;
44
+ componentId: string;
45
+ timestamp: number;
46
+ };
40
47
  }
41
48
  export interface SubtitlesEvents {
42
49
  subtitleschange: void;
@@ -19,6 +19,19 @@ export function changeIdDeep(obj) {
19
19
  }
20
20
  return obj;
21
21
  }
22
+ /**
23
+ * Checks if a character is an emoji.
24
+ * Preserves all legitimate Unicode letters and numbers (Chinese, Japanese, Korean, Arabic, etc.).
25
+ */
26
+ function isEmoji(char) {
27
+ // If it's a legitimate Unicode letter or number, it's NOT an emoji
28
+ // This includes Chinese, Japanese, Korean, Arabic, and all other writing systems
29
+ if (/\p{L}|\p{N}/u.test(char)) {
30
+ return false;
31
+ }
32
+ // Use Unicode emoji property - automatically maintained by the Unicode standard
33
+ return /\p{Emoji}/u.test(char);
34
+ }
22
35
  export const buildCharactersListFromComponentsAndSubtitles = function (layers, subtitlesCharactersList) {
23
36
  const characters = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-,;:!$?\'"';
24
37
  const charactestList = characters.split('');
@@ -28,11 +41,16 @@ export const buildCharactersListFromComponentsAndSubtitles = function (layers, s
28
41
  const c = component;
29
42
  const text = c.text;
30
43
  if (text) {
31
- const textList = text.split('');
44
+ // Use Array.from to properly handle multi-codepoint characters (emojis, etc.)
45
+ // This prevents splitting emojis into unpaired surrogates
46
+ const textList = Array.from(text);
32
47
  const missingChars = textList.filter((char) => {
33
48
  // Check if the character is not whitespace, not in the characters list,
34
- // and is a Unicode letter or number
35
- return !/\s/.test(char) && !characters.includes(char) && /\p{L}|\p{N}/u.test(char);
49
+ // is a Unicode letter or number, and is NOT an emoji
50
+ return (!/\s/.test(char) &&
51
+ !characters.includes(char) &&
52
+ /\p{L}|\p{N}/u.test(char) &&
53
+ !isEmoji(char));
36
54
  });
37
55
  // Add both uppercase and lowercase variants of missing chars
38
56
  const variantChars = missingChars.flatMap((char) => [
@@ -44,7 +62,7 @@ export const buildCharactersListFromComponentsAndSubtitles = function (layers, s
44
62
  }
45
63
  if (subtitlesCharactersList.length > 0) {
46
64
  for (const char of subtitlesCharactersList) {
47
- if (!characters.includes(char)) {
65
+ if (!characters.includes(char) && !isEmoji(char)) {
48
66
  // Add both uppercase and lowercase variants of missing chars
49
67
  charactestList.push(char.toLowerCase(), char.toUpperCase());
50
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "visualfries",
3
- "version": "0.1.902",
3
+ "version": "0.1.1095",
4
4
  "license": "MIT",
5
5
  "author": "ContentFries",
6
6
  "repository": {