@clypra/engine 1.3.0 → 1.3.1

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/index.js CHANGED
@@ -1,3 +1,171 @@
1
+ // src/validation.ts
2
+ import { z } from "zod";
3
+ var GradientStopSchema = z.object({
4
+ color: z.string(),
5
+ offset: z.number().min(0).max(100)
6
+ });
7
+ var EffectFillSchema = z.object({
8
+ type: z.enum(["solid", "linear", "radial", "pattern", "none"]),
9
+ color: z.string().optional(),
10
+ gradient: z.object({
11
+ angle: z.number(),
12
+ stops: z.array(GradientStopSchema)
13
+ }).optional(),
14
+ patternType: z.string().optional(),
15
+ perCharFillEnabled: z.boolean().optional(),
16
+ charFillColors: z.array(z.string()).optional()
17
+ });
18
+ var EffectStrokeSchema = z.object({
19
+ color: z.string(),
20
+ width: z.number().min(0),
21
+ position: z.enum(["outside", "center", "inside"]).optional(),
22
+ opacity: z.number().min(0).max(100).optional(),
23
+ lineJoin: z.enum(["round", "miter", "bevel"]).optional(),
24
+ blur: z.number().min(0).optional(),
25
+ type: z.enum(["solid", "gradient"]).optional(),
26
+ colorSecondary: z.string().optional(),
27
+ widthSecondary: z.number().min(0).optional(),
28
+ fadeRange: z.tuple([z.number(), z.number()]).optional()
29
+ });
30
+ var EffectShadowSchema = z.object({
31
+ type: z.enum(["drop", "inner"]).optional(),
32
+ color: z.string(),
33
+ blur: z.number().min(0),
34
+ offset: z.object({
35
+ x: z.number(),
36
+ y: z.number()
37
+ }).optional(),
38
+ offsetX: z.number().optional(),
39
+ // Legacy flat format
40
+ offsetY: z.number().optional(),
41
+ // Legacy flat format
42
+ opacity: z.number().min(0).max(100).optional()
43
+ }).refine((data) => data.offset !== void 0 || data.offsetX !== void 0 && data.offsetY !== void 0, { message: "Shadow must have either nested 'offset' or flat 'offsetX/offsetY'" });
44
+ var EffectBevelSchema = z.object({
45
+ depth: z.number().min(0),
46
+ highlight: z.string().optional(),
47
+ // Current Studio output
48
+ highlightColor: z.string().optional(),
49
+ // Legacy format
50
+ shadow: z.string().optional(),
51
+ // Current Studio output
52
+ shadowColor: z.string().optional(),
53
+ // Legacy format
54
+ direction: z.enum(["bottom-right", "bottom", "right"]).optional(),
55
+ coreColor: z.string().optional(),
56
+ edgeColor: z.string().optional(),
57
+ edgeWidth: z.number().min(0).optional(),
58
+ blur: z.number().min(0).optional(),
59
+ blurColor: z.string().optional(),
60
+ perspectiveEnabled: z.boolean().optional(),
61
+ vanishingPointX: z.number().optional(),
62
+ vanishingPointY: z.number().optional(),
63
+ focalLength: z.number().optional()
64
+ }).refine((data) => data.highlight !== void 0 || data.highlightColor !== void 0, { message: "Bevel must have either 'highlight' or 'highlightColor'" }).refine((data) => data.shadow !== void 0 || data.shadowColor !== void 0, { message: "Bevel must have either 'shadow' or 'shadowColor'" });
65
+ var EffectGlowSchema = z.object({
66
+ color: z.string(),
67
+ blur: z.number().min(0),
68
+ opacity: z.number().min(0).max(100),
69
+ type: z.enum(["outer", "inner"]).optional(),
70
+ strength: z.number().min(0).optional(),
71
+ spread: z.number().min(0).optional()
72
+ });
73
+ var EffectPanelSchema = z.object({
74
+ color: z.string(),
75
+ opacity: z.number().min(0).max(100),
76
+ radius: z.number().min(0),
77
+ padding: z.object({
78
+ x: z.number().min(0),
79
+ y: z.number().min(0)
80
+ }).optional(),
81
+ paddingX: z.number().min(0).optional(),
82
+ // Legacy flat format
83
+ paddingY: z.number().min(0).optional(),
84
+ // Legacy flat format
85
+ stroke: z.object({
86
+ color: z.string(),
87
+ width: z.number().min(0)
88
+ }).nullable().optional()
89
+ }).refine((data) => data.padding !== void 0 || data.paddingX !== void 0 && data.paddingY !== void 0, { message: "Panel must have either nested 'padding' or flat 'paddingX/paddingY'" });
90
+ var EffectStackSchema = z.object({
91
+ count: z.number().int().min(1).max(100),
92
+ offsetX: z.number(),
93
+ offsetY: z.number(),
94
+ opacityDecay: z.number().min(0).max(1),
95
+ color1: z.string().optional(),
96
+ color2: z.string().optional(),
97
+ color3: z.string().optional(),
98
+ color4: z.string().optional()
99
+ });
100
+ var FontSchema = z.object({
101
+ family: z.string().min(1),
102
+ weight: z.number().int().min(100).max(900),
103
+ style: z.enum(["normal", "italic"]),
104
+ letterSpacing: z.number(),
105
+ lineHeight: z.number().positive()
106
+ });
107
+ var AnimationSchema = z.object({
108
+ type: z.enum(["none", "typewriter", "wave", "fade", "glitch"]),
109
+ speed: z.number().positive().optional(),
110
+ amplitude: z.number().optional(),
111
+ frequency: z.number().positive().optional()
112
+ });
113
+ var EffectIndexItemSchema = z.object({
114
+ id: z.string().min(1),
115
+ name: z.string().min(1),
116
+ category: z.string().min(1),
117
+ description: z.string().optional(),
118
+ tags: z.array(z.string()).optional(),
119
+ isPremium: z.boolean().optional(),
120
+ previewType: z.enum(["static", "video", "lottie"]).optional(),
121
+ thumbnailUrl: z.string().url().optional(),
122
+ thumbnail: z.string().optional(),
123
+ previewUrl: z.string().url().optional(),
124
+ durationMs: z.number().positive().optional()
125
+ });
126
+ var EffectFullDefinitionSchema = EffectIndexItemSchema.extend({
127
+ version: z.string().optional(),
128
+ description: z.string(),
129
+ tags: z.array(z.string()),
130
+ font: FontSchema,
131
+ fills: z.array(EffectFillSchema),
132
+ strokes: z.array(EffectStrokeSchema),
133
+ shadows: z.array(EffectShadowSchema),
134
+ bevel: EffectBevelSchema.optional(),
135
+ glow: EffectGlowSchema.optional(),
136
+ // Legacy single glow
137
+ glows: z.array(EffectGlowSchema).optional(),
138
+ // Current multi-layer glows
139
+ panel: EffectPanelSchema.optional(),
140
+ glitch: z.any().optional(),
141
+ // TODO: Define proper schema when glitch effects are implemented
142
+ animation: AnimationSchema.optional(),
143
+ background: z.any().optional(),
144
+ // DEPRECATED: kept for backward compatibility
145
+ stack: EffectStackSchema.optional()
146
+ });
147
+ var TextEffectDefinitionSchema = EffectFullDefinitionSchema.extend({
148
+ text: z.string().optional()
149
+ });
150
+ function validateEffectDefinition(data) {
151
+ return EffectFullDefinitionSchema.safeParse(data);
152
+ }
153
+ function validateEffectDefinitionStrict(data) {
154
+ return EffectFullDefinitionSchema.parse(data);
155
+ }
156
+ function validateTextEffectDefinition(data) {
157
+ return TextEffectDefinitionSchema.safeParse(data);
158
+ }
159
+ function validateTextEffectDefinitionStrict(data) {
160
+ return TextEffectDefinitionSchema.parse(data);
161
+ }
162
+ function formatValidationErrors(error) {
163
+ return error.issues.map((err) => {
164
+ const path = err.path.join(".");
165
+ return `${path ? `${path}: ` : ""}${err.message}`;
166
+ });
167
+ }
168
+
1
169
  // src/engine/schema.ts
2
170
  var SCENE_VERSION = 1;
3
171
  var DEFAULT_CANVAS_WIDTH = 800;
@@ -3029,16 +3197,20 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3029
3197
  if (shadow) {
3030
3198
  if (shadow.color !== void 0) config.shadowColor = shadow.color;
3031
3199
  if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
3032
- if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3033
- if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3200
+ if (shadow.offset?.x !== void 0) config.shadowOffsetX = shadow.offset.x * ratio;
3201
+ else if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3202
+ if (shadow.offset?.y !== void 0) config.shadowOffsetY = shadow.offset.y * ratio;
3203
+ else if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3034
3204
  if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
3035
3205
  if (shadow.type !== void 0) config.shadowType = shadow.type;
3036
3206
  }
3037
3207
  config.bevelEnabled = !!bevel;
3038
3208
  if (bevel) {
3039
3209
  if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
3040
- if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3041
- if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3210
+ if (bevel.highlight !== void 0) config.bevelHighlight = bevel.highlight;
3211
+ else if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3212
+ if (bevel.shadow !== void 0) config.bevelShadow = bevel.shadow;
3213
+ else if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3042
3214
  if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
3043
3215
  if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
3044
3216
  if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
@@ -3066,8 +3238,10 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3066
3238
  if (panel.color !== void 0) config.panelColor = panel.color;
3067
3239
  if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
3068
3240
  if (panel.radius !== void 0) config.panelRadius = panel.radius;
3069
- if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3070
- if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3241
+ if (panel.padding?.x !== void 0) config.panelPaddingX = panel.padding.x * ratio;
3242
+ else if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3243
+ if (panel.padding?.y !== void 0) config.panelPaddingY = panel.padding.y * ratio;
3244
+ else if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3071
3245
  if (panel.stroke !== void 0) {
3072
3246
  config.panelStrokeEnabled = !!panel.stroke;
3073
3247
  if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
@@ -3088,23 +3262,7 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3088
3262
  return mappedGlow;
3089
3263
  });
3090
3264
  }
3091
- const standardKeys = /* @__PURE__ */ new Set([
3092
- "id",
3093
- "name",
3094
- "category",
3095
- "description",
3096
- "tags",
3097
- "font",
3098
- "fills",
3099
- "strokes",
3100
- "shadows",
3101
- "glows",
3102
- "bevel",
3103
- "panel",
3104
- "text",
3105
- "animation",
3106
- "stack"
3107
- ]);
3265
+ const standardKeys = /* @__PURE__ */ new Set(["id", "name", "category", "description", "tags", "font", "fills", "strokes", "shadows", "glows", "bevel", "panel", "text", "animation", "stack"]);
3108
3266
  for (const key of Object.keys(effect)) {
3109
3267
  if (!standardKeys.has(key)) {
3110
3268
  config[key] = effect[key];
@@ -4157,8 +4315,8 @@ function applyToLayerTransform(layer2, override) {
4157
4315
  ks.s.k = [override.scaleX, override.scaleY, 100];
4158
4316
  }
4159
4317
  if (override.posX !== void 0 && override.posY !== void 0 && ks.p?.a === 0) {
4160
- const z = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4161
- ks.p.k = [override.posX, override.posY, z];
4318
+ const z2 = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4319
+ ks.p.k = [override.posX, override.posY, z2];
4162
4320
  }
4163
4321
  }
4164
4322
  function mutateTextLayer(layer2, override) {
@@ -7258,6 +7416,7 @@ var TextEffectBuilder = class _TextEffectBuilder {
7258
7416
  }
7259
7417
  };
7260
7418
  export {
7419
+ AnimationSchema,
7261
7420
  COMPOSITION_PRESETS,
7262
7421
  CUSTOM_ENGINE_IDS,
7263
7422
  CanvasDevice,
@@ -7271,8 +7430,19 @@ export {
7271
7430
  ENGINE_ID_TO_LEGACY,
7272
7431
  ENTRANCE_PRESETS,
7273
7432
  EXIT_PRESETS,
7433
+ EffectBevelSchema,
7434
+ EffectFillSchema,
7435
+ EffectFullDefinitionSchema,
7436
+ EffectGlowSchema,
7437
+ EffectIndexItemSchema,
7438
+ EffectPanelSchema,
7439
+ EffectShadowSchema,
7440
+ EffectStackSchema,
7441
+ EffectStrokeSchema,
7274
7442
  FONT_WEIGHT_OPTIONS,
7275
7443
  FontLoader,
7444
+ FontSchema,
7445
+ GradientStopSchema,
7276
7446
  InkBrushEngine,
7277
7447
  LEGACY_RENDERER_MAP,
7278
7448
  LOOP_PRESETS,
@@ -7282,6 +7452,7 @@ export {
7282
7452
  SUPPORTED_FONT_FAMILIES,
7283
7453
  TEMPLATE_CATEGORIES,
7284
7454
  TextEffectBuilder,
7455
+ TextEffectDefinitionSchema,
7285
7456
  TextEffectRenderer,
7286
7457
  WEBM_EXPORT_MAX_FRAMES,
7287
7458
  WebGLCompositor,
@@ -7347,6 +7518,7 @@ export {
7347
7518
  evaluateConfig,
7348
7519
  evaluateScene,
7349
7520
  findTrackIndex,
7521
+ formatValidationErrors,
7350
7522
  getAnimPreset,
7351
7523
  getAnimatableParamDef,
7352
7524
  getAnimatableParamsForLayer,
@@ -7433,6 +7605,10 @@ export {
7433
7605
  updateTrack,
7434
7606
  updateTrackMatte,
7435
7607
  upsertKeyframe,
7608
+ validateEffectDefinition,
7609
+ validateEffectDefinitionStrict,
7610
+ validateTextEffectDefinition,
7611
+ validateTextEffectDefinitionStrict,
7436
7612
  waitForFontsReady,
7437
7613
  wrapTextToWidth
7438
7614
  };