@twick/studio 0.15.19 → 0.15.20
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/README.md +25 -0
- package/dist/components/container/element-panel-container.d.ts +3 -2
- package/dist/components/container/generate-media-panel-container.d.ts +13 -0
- package/dist/components/properties/caption-prop.d.ts +6 -21
- package/dist/helpers/constant.d.ts +36 -0
- package/dist/hooks/use-generate-image.d.ts +10 -0
- package/dist/hooks/use-generate-video.d.ts +10 -0
- package/dist/index.js +682 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +685 -26
- package/dist/index.mjs.map +1 -1
- package/dist/types/generation.d.ts +44 -0
- package/dist/types/index.d.ts +5 -0
- package/package.json +13 -12
package/dist/index.js
CHANGED
|
@@ -560,7 +560,8 @@ const toolCategories = [
|
|
|
560
560
|
{ id: "text", name: "Text", icon: "Type", description: "Add text elements" },
|
|
561
561
|
{ id: "circle", name: "Circle", icon: "Circle", description: "Add a circle element" },
|
|
562
562
|
{ id: "rect", name: "Rect", icon: "Rect", description: "Add a rectangle element" },
|
|
563
|
-
{ id: "caption", name: "Caption", icon: "MessageSquare", description: "Manage captions" }
|
|
563
|
+
{ id: "caption", name: "Caption", icon: "MessageSquare", description: "Manage captions" },
|
|
564
|
+
{ id: "generate-media", name: "Generate", icon: "Wand2", description: "Generate image or video with AI" }
|
|
564
565
|
];
|
|
565
566
|
const getIcon = (iconName) => {
|
|
566
567
|
switch (iconName) {
|
|
@@ -584,6 +585,8 @@ const getIcon = (iconName) => {
|
|
|
584
585
|
return Square;
|
|
585
586
|
case "MessageSquare":
|
|
586
587
|
return MessageSquare;
|
|
588
|
+
case "Wand2":
|
|
589
|
+
return WandSparkles;
|
|
587
590
|
default:
|
|
588
591
|
return Plus;
|
|
589
592
|
}
|
|
@@ -2828,6 +2831,42 @@ const CAPTION_PROPS = {
|
|
|
2828
2831
|
shadowOffset: [-2, 2],
|
|
2829
2832
|
shadowColor: "#000000",
|
|
2830
2833
|
shadowBlur: 5
|
|
2834
|
+
},
|
|
2835
|
+
[timeline.CAPTION_STYLE.OUTLINE_ONLY]: {
|
|
2836
|
+
font: {
|
|
2837
|
+
size: 42,
|
|
2838
|
+
weight: 600,
|
|
2839
|
+
family: "Arial"
|
|
2840
|
+
},
|
|
2841
|
+
colors: {
|
|
2842
|
+
text: "#ffffff",
|
|
2843
|
+
highlight: "#ff4081",
|
|
2844
|
+
bgColor: "#000000"
|
|
2845
|
+
},
|
|
2846
|
+
lineWidth: 0.5,
|
|
2847
|
+
stroke: "#000000",
|
|
2848
|
+
fontWeight: 600,
|
|
2849
|
+
shadowOffset: [0, 0],
|
|
2850
|
+
shadowColor: "#000000",
|
|
2851
|
+
shadowBlur: 0
|
|
2852
|
+
},
|
|
2853
|
+
[timeline.CAPTION_STYLE.SOFT_BOX]: {
|
|
2854
|
+
font: {
|
|
2855
|
+
size: 40,
|
|
2856
|
+
weight: 600,
|
|
2857
|
+
family: "Montserrat"
|
|
2858
|
+
},
|
|
2859
|
+
colors: {
|
|
2860
|
+
text: "#ffffff",
|
|
2861
|
+
highlight: "#ff4081",
|
|
2862
|
+
bgColor: "#333333"
|
|
2863
|
+
},
|
|
2864
|
+
lineWidth: 0.2,
|
|
2865
|
+
stroke: "#000000",
|
|
2866
|
+
fontWeight: 600,
|
|
2867
|
+
shadowOffset: [-1, 1],
|
|
2868
|
+
shadowColor: "rgba(0,0,0,0.3)",
|
|
2869
|
+
shadowBlur: 3
|
|
2831
2870
|
}
|
|
2832
2871
|
};
|
|
2833
2872
|
const useCaptionsPanel = () => {
|
|
@@ -2917,13 +2956,324 @@ function CaptionsPanelContainer() {
|
|
|
2917
2956
|
const captionsPanelProps = useCaptionsPanel();
|
|
2918
2957
|
return /* @__PURE__ */ jsxRuntime.jsx(CaptionsPanel, { ...captionsPanelProps });
|
|
2919
2958
|
}
|
|
2959
|
+
const FAL_IMAGE_ENDPOINTS = [
|
|
2960
|
+
{
|
|
2961
|
+
provider: "fal",
|
|
2962
|
+
endpointId: "fal-ai/flux-pro/kontext",
|
|
2963
|
+
label: "FLUX.1 Kontext [pro]",
|
|
2964
|
+
description: "Professional image generation with context-aware editing",
|
|
2965
|
+
popularity: 5,
|
|
2966
|
+
category: "image",
|
|
2967
|
+
inputAsset: ["image"],
|
|
2968
|
+
availableDimensions: [
|
|
2969
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
2970
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
2971
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
2972
|
+
]
|
|
2973
|
+
},
|
|
2974
|
+
{
|
|
2975
|
+
provider: "fal",
|
|
2976
|
+
endpointId: "fal-ai/flux/dev",
|
|
2977
|
+
label: "FLUX.1 [dev]",
|
|
2978
|
+
description: "High-quality image generation",
|
|
2979
|
+
popularity: 5,
|
|
2980
|
+
category: "image",
|
|
2981
|
+
minSteps: 1,
|
|
2982
|
+
maxSteps: 50,
|
|
2983
|
+
defaultSteps: 28,
|
|
2984
|
+
minGuidanceScale: 1,
|
|
2985
|
+
maxGuidanceScale: 20,
|
|
2986
|
+
defaultGuidanceScale: 3.5,
|
|
2987
|
+
hasSeed: true
|
|
2988
|
+
},
|
|
2989
|
+
{
|
|
2990
|
+
provider: "fal",
|
|
2991
|
+
endpointId: "fal-ai/flux/schnell",
|
|
2992
|
+
label: "FLUX.1 [schnell]",
|
|
2993
|
+
description: "Ultra-fast image generation",
|
|
2994
|
+
popularity: 4,
|
|
2995
|
+
category: "image",
|
|
2996
|
+
defaultSteps: 4,
|
|
2997
|
+
availableDimensions: [
|
|
2998
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
2999
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3000
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
3001
|
+
]
|
|
3002
|
+
},
|
|
3003
|
+
{
|
|
3004
|
+
provider: "fal",
|
|
3005
|
+
endpointId: "fal-ai/gemini-25-flash-image",
|
|
3006
|
+
label: "Gemini 2.5 Flash Image",
|
|
3007
|
+
description: "Rapid text-to-image generation",
|
|
3008
|
+
popularity: 5,
|
|
3009
|
+
category: "image",
|
|
3010
|
+
availableDimensions: [
|
|
3011
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
3012
|
+
{ width: 1024, height: 768, label: "1024x768 (4:3)" },
|
|
3013
|
+
{ width: 768, height: 1024, label: "768x1024 (3:4)" },
|
|
3014
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3015
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
3016
|
+
]
|
|
3017
|
+
},
|
|
3018
|
+
{
|
|
3019
|
+
provider: "fal",
|
|
3020
|
+
endpointId: "fal-ai/ideogram/v3",
|
|
3021
|
+
label: "Ideogram V3",
|
|
3022
|
+
description: "Advanced text-to-image with superior text rendering",
|
|
3023
|
+
popularity: 5,
|
|
3024
|
+
category: "image",
|
|
3025
|
+
hasSeed: true,
|
|
3026
|
+
hasNegativePrompt: true
|
|
3027
|
+
}
|
|
3028
|
+
];
|
|
3029
|
+
const FAL_VIDEO_ENDPOINTS = [
|
|
3030
|
+
{
|
|
3031
|
+
provider: "fal",
|
|
3032
|
+
endpointId: "fal-ai/veo3",
|
|
3033
|
+
label: "Veo 3",
|
|
3034
|
+
description: "Google Veo 3 text-to-video",
|
|
3035
|
+
popularity: 5,
|
|
3036
|
+
category: "video",
|
|
3037
|
+
availableDurations: [4, 6, 8],
|
|
3038
|
+
defaultDuration: 8,
|
|
3039
|
+
availableDimensions: [
|
|
3040
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3041
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3042
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3043
|
+
]
|
|
3044
|
+
},
|
|
3045
|
+
{
|
|
3046
|
+
provider: "fal",
|
|
3047
|
+
endpointId: "fal-ai/veo3/fast",
|
|
3048
|
+
label: "Veo 3 Fast",
|
|
3049
|
+
description: "Accelerated Veo 3 text-to-video",
|
|
3050
|
+
popularity: 5,
|
|
3051
|
+
category: "video",
|
|
3052
|
+
availableDurations: [4, 6, 8],
|
|
3053
|
+
defaultDuration: 8,
|
|
3054
|
+
availableDimensions: [
|
|
3055
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3056
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3057
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3058
|
+
]
|
|
3059
|
+
},
|
|
3060
|
+
{
|
|
3061
|
+
provider: "fal",
|
|
3062
|
+
endpointId: "fal-ai/veo3/image-to-video",
|
|
3063
|
+
label: "Veo 3 Image-to-Video",
|
|
3064
|
+
description: "Animate images with Veo 3",
|
|
3065
|
+
popularity: 5,
|
|
3066
|
+
category: "video",
|
|
3067
|
+
inputAsset: ["image"],
|
|
3068
|
+
availableDurations: [8],
|
|
3069
|
+
defaultDuration: 8
|
|
3070
|
+
},
|
|
3071
|
+
{
|
|
3072
|
+
provider: "fal",
|
|
3073
|
+
endpointId: "fal-ai/kling-video/v2.5-turbo/pro/text-to-video",
|
|
3074
|
+
label: "Kling 2.5 Turbo Pro",
|
|
3075
|
+
description: "Text-to-video with fluid motion",
|
|
3076
|
+
popularity: 5,
|
|
3077
|
+
category: "video",
|
|
3078
|
+
availableDurations: [5, 10],
|
|
3079
|
+
defaultDuration: 5,
|
|
3080
|
+
availableDimensions: [
|
|
3081
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3082
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3083
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3084
|
+
]
|
|
3085
|
+
}
|
|
3086
|
+
];
|
|
3087
|
+
const DEFAULT_IMAGE_DURATION = 5;
|
|
3088
|
+
function GenerateMediaPanelContainer({
|
|
3089
|
+
videoResolution,
|
|
3090
|
+
addElement,
|
|
3091
|
+
studioConfig
|
|
3092
|
+
}) {
|
|
3093
|
+
var _a;
|
|
3094
|
+
const { getCurrentTime } = livePlayer.useLivePlayerContext();
|
|
3095
|
+
const [tab, setTab] = react.useState("image");
|
|
3096
|
+
const [prompt2, setPrompt] = react.useState("");
|
|
3097
|
+
const [selectedEndpointId, setSelectedEndpointId] = react.useState("");
|
|
3098
|
+
const [isGenerating, setIsGenerating] = react.useState(false);
|
|
3099
|
+
const [error, setError] = react.useState(null);
|
|
3100
|
+
const [status, setStatus] = react.useState(null);
|
|
3101
|
+
const imageService = studioConfig == null ? void 0 : studioConfig.imageGenerationService;
|
|
3102
|
+
const videoService = studioConfig == null ? void 0 : studioConfig.videoGenerationService;
|
|
3103
|
+
const hasAnyService = !!imageService || !!videoService;
|
|
3104
|
+
const endpoints = tab === "image" ? FAL_IMAGE_ENDPOINTS : FAL_VIDEO_ENDPOINTS;
|
|
3105
|
+
const defaultEndpointId = ((_a = endpoints[0]) == null ? void 0 : _a.endpointId) ?? "";
|
|
3106
|
+
react.useEffect(() => {
|
|
3107
|
+
if (!selectedEndpointId && defaultEndpointId) {
|
|
3108
|
+
setSelectedEndpointId(defaultEndpointId);
|
|
3109
|
+
}
|
|
3110
|
+
}, [tab, defaultEndpointId, selectedEndpointId]);
|
|
3111
|
+
const pollStatus = react.useCallback(
|
|
3112
|
+
async (requestId) => {
|
|
3113
|
+
const service = tab === "image" ? imageService : videoService;
|
|
3114
|
+
if (!service) return;
|
|
3115
|
+
const interval = setInterval(async () => {
|
|
3116
|
+
try {
|
|
3117
|
+
const result = await service.getRequestStatus(requestId);
|
|
3118
|
+
if (result.status === "completed" && result.url) {
|
|
3119
|
+
clearInterval(interval);
|
|
3120
|
+
setIsGenerating(false);
|
|
3121
|
+
setStatus(null);
|
|
3122
|
+
setError(null);
|
|
3123
|
+
const currentTime = getCurrentTime();
|
|
3124
|
+
const duration = result.duration ?? DEFAULT_IMAGE_DURATION;
|
|
3125
|
+
if (tab === "image") {
|
|
3126
|
+
const element = new timeline.ImageElement(result.url, videoResolution);
|
|
3127
|
+
element.setStart(currentTime);
|
|
3128
|
+
element.setEnd(currentTime + duration);
|
|
3129
|
+
addElement(element);
|
|
3130
|
+
} else {
|
|
3131
|
+
const element = new timeline.VideoElement(result.url, videoResolution);
|
|
3132
|
+
element.setStart(currentTime);
|
|
3133
|
+
element.setEnd(currentTime + duration);
|
|
3134
|
+
addElement(element);
|
|
3135
|
+
}
|
|
3136
|
+
} else if (result.status === "failed") {
|
|
3137
|
+
clearInterval(interval);
|
|
3138
|
+
setIsGenerating(false);
|
|
3139
|
+
setStatus(null);
|
|
3140
|
+
setError(result.error ?? "Generation failed");
|
|
3141
|
+
}
|
|
3142
|
+
} catch {
|
|
3143
|
+
}
|
|
3144
|
+
}, 3e3);
|
|
3145
|
+
return () => clearInterval(interval);
|
|
3146
|
+
},
|
|
3147
|
+
[tab, imageService, videoService, getCurrentTime, videoResolution, addElement]
|
|
3148
|
+
);
|
|
3149
|
+
const handleGenerate = react.useCallback(async () => {
|
|
3150
|
+
if (!prompt2.trim()) {
|
|
3151
|
+
setError("Enter a prompt");
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
if (tab === "image" && !imageService) {
|
|
3155
|
+
setError("Image generation not configured");
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
if (tab === "video" && !videoService) {
|
|
3159
|
+
setError("Video generation not configured");
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3162
|
+
setIsGenerating(true);
|
|
3163
|
+
setError(null);
|
|
3164
|
+
setStatus("Starting...");
|
|
3165
|
+
try {
|
|
3166
|
+
const endpointId = selectedEndpointId || defaultEndpointId;
|
|
3167
|
+
if (tab === "image" && imageService) {
|
|
3168
|
+
const requestId = await imageService.generateImage({
|
|
3169
|
+
provider: "fal",
|
|
3170
|
+
endpointId,
|
|
3171
|
+
prompt: prompt2.trim()
|
|
3172
|
+
});
|
|
3173
|
+
if (requestId) {
|
|
3174
|
+
setStatus("Generating image...");
|
|
3175
|
+
pollStatus(requestId);
|
|
3176
|
+
}
|
|
3177
|
+
} else if (tab === "video" && videoService) {
|
|
3178
|
+
const requestId = await videoService.generateVideo({
|
|
3179
|
+
provider: "fal",
|
|
3180
|
+
endpointId,
|
|
3181
|
+
prompt: prompt2.trim()
|
|
3182
|
+
});
|
|
3183
|
+
if (requestId) {
|
|
3184
|
+
setStatus("Generating video (this may take several minutes)...");
|
|
3185
|
+
pollStatus(requestId);
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
} catch (err) {
|
|
3189
|
+
const msg = err instanceof Error ? err.message : "Generation failed";
|
|
3190
|
+
setError(msg);
|
|
3191
|
+
setIsGenerating(false);
|
|
3192
|
+
setStatus(null);
|
|
3193
|
+
}
|
|
3194
|
+
}, [
|
|
3195
|
+
tab,
|
|
3196
|
+
prompt2,
|
|
3197
|
+
selectedEndpointId,
|
|
3198
|
+
defaultEndpointId,
|
|
3199
|
+
imageService,
|
|
3200
|
+
videoService,
|
|
3201
|
+
pollStatus
|
|
3202
|
+
]);
|
|
3203
|
+
if (!hasAnyService) {
|
|
3204
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Image and video generation require configuration. Add imageGenerationService and videoGenerationService to StudioConfig." }) });
|
|
3205
|
+
}
|
|
3206
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
|
|
3207
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 mb-2", children: [
|
|
3208
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3209
|
+
"button",
|
|
3210
|
+
{
|
|
3211
|
+
type: "button",
|
|
3212
|
+
className: `btn-ghost ${tab === "image" ? "active" : ""}`,
|
|
3213
|
+
onClick: () => setTab("image"),
|
|
3214
|
+
disabled: !imageService,
|
|
3215
|
+
children: "Image"
|
|
3216
|
+
}
|
|
3217
|
+
),
|
|
3218
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3219
|
+
"button",
|
|
3220
|
+
{
|
|
3221
|
+
type: "button",
|
|
3222
|
+
className: `btn-ghost ${tab === "video" ? "active" : ""}`,
|
|
3223
|
+
onClick: () => setTab("video"),
|
|
3224
|
+
disabled: !videoService,
|
|
3225
|
+
children: "Video"
|
|
3226
|
+
}
|
|
3227
|
+
)
|
|
3228
|
+
] }),
|
|
3229
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
|
|
3230
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm mb-1", children: "Model" }),
|
|
3231
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3232
|
+
"select",
|
|
3233
|
+
{
|
|
3234
|
+
className: "w-full p-2 border rounded",
|
|
3235
|
+
value: selectedEndpointId,
|
|
3236
|
+
onChange: (e) => setSelectedEndpointId(e.target.value),
|
|
3237
|
+
disabled: isGenerating,
|
|
3238
|
+
children: endpoints.map((ep) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: ep.endpointId, children: ep.label }, ep.endpointId))
|
|
3239
|
+
}
|
|
3240
|
+
)
|
|
3241
|
+
] }),
|
|
3242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
|
|
3243
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm mb-1", children: "Prompt" }),
|
|
3244
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3245
|
+
"textarea",
|
|
3246
|
+
{
|
|
3247
|
+
className: "w-full p-2 border rounded min-h-[80px]",
|
|
3248
|
+
value: prompt2,
|
|
3249
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
3250
|
+
placeholder: "Describe the image or video you want...",
|
|
3251
|
+
disabled: isGenerating
|
|
3252
|
+
}
|
|
3253
|
+
)
|
|
3254
|
+
] }),
|
|
3255
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-red-600 text-sm", children: error }),
|
|
3256
|
+
status && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-sm text-gray-600", children: status }),
|
|
3257
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3258
|
+
"button",
|
|
3259
|
+
{
|
|
3260
|
+
type: "button",
|
|
3261
|
+
className: "btn-primary w-full",
|
|
3262
|
+
onClick: handleGenerate,
|
|
3263
|
+
disabled: isGenerating || !prompt2.trim(),
|
|
3264
|
+
children: isGenerating ? "Generating..." : `Generate ${tab}`
|
|
3265
|
+
}
|
|
3266
|
+
)
|
|
3267
|
+
] }) });
|
|
3268
|
+
}
|
|
2920
3269
|
const ElementPanelContainer = ({
|
|
2921
3270
|
selectedTool,
|
|
2922
3271
|
videoResolution,
|
|
2923
3272
|
selectedElement,
|
|
2924
3273
|
addElement,
|
|
2925
3274
|
updateElement,
|
|
2926
|
-
uploadConfig
|
|
3275
|
+
uploadConfig,
|
|
3276
|
+
studioConfig
|
|
2927
3277
|
}) => {
|
|
2928
3278
|
const addNewElement = async (element) => {
|
|
2929
3279
|
await addElement(element);
|
|
@@ -2994,6 +3344,17 @@ const ElementPanelContainer = ({
|
|
|
2994
3344
|
);
|
|
2995
3345
|
case "caption":
|
|
2996
3346
|
return /* @__PURE__ */ jsxRuntime.jsx(CaptionsPanelContainer, {});
|
|
3347
|
+
case "generate-media":
|
|
3348
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3349
|
+
GenerateMediaPanelContainer,
|
|
3350
|
+
{
|
|
3351
|
+
videoResolution,
|
|
3352
|
+
selectedElement,
|
|
3353
|
+
addElement: addNewElement,
|
|
3354
|
+
updateElement,
|
|
3355
|
+
studioConfig
|
|
3356
|
+
}
|
|
3357
|
+
);
|
|
2997
3358
|
default:
|
|
2998
3359
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state-content", children: [
|
|
2999
3360
|
/* @__PURE__ */ jsxRuntime.jsx(WandSparkles, { className: "empty-state-icon" }),
|
|
@@ -3468,6 +3829,258 @@ function Animation({
|
|
|
3468
3829
|
})() })
|
|
3469
3830
|
] });
|
|
3470
3831
|
}
|
|
3832
|
+
const CAPTION_FONT = {
|
|
3833
|
+
size: 40,
|
|
3834
|
+
family: "Bangers"
|
|
3835
|
+
};
|
|
3836
|
+
const CAPTION_COLOR = {
|
|
3837
|
+
text: "#ffffff",
|
|
3838
|
+
highlight: "#ff4081",
|
|
3839
|
+
bgColor: "#8C52FF",
|
|
3840
|
+
outlineColor: "#000000"
|
|
3841
|
+
};
|
|
3842
|
+
function CaptionPropPanel({
|
|
3843
|
+
selectedElement,
|
|
3844
|
+
updateElement
|
|
3845
|
+
}) {
|
|
3846
|
+
const { editor, changeLog } = timeline.useTimelineContext();
|
|
3847
|
+
const captionRef = react.useRef(null);
|
|
3848
|
+
const [capStyle, setCapStyle] = react.useState(
|
|
3849
|
+
timeline.CAPTION_STYLE_OPTIONS[timeline.CAPTION_STYLE.WORD_BG_HIGHLIGHT]
|
|
3850
|
+
);
|
|
3851
|
+
const [fontSize, setFontSize] = react.useState(CAPTION_FONT.size);
|
|
3852
|
+
const [fontFamily, setFontFamily] = react.useState(CAPTION_FONT.family);
|
|
3853
|
+
const [colors, setColors] = react.useState({
|
|
3854
|
+
text: CAPTION_COLOR.text,
|
|
3855
|
+
highlight: CAPTION_COLOR.highlight,
|
|
3856
|
+
bgColor: CAPTION_COLOR.bgColor,
|
|
3857
|
+
outlineColor: CAPTION_COLOR.outlineColor
|
|
3858
|
+
});
|
|
3859
|
+
const track = selectedElement instanceof timeline.CaptionElement ? editor.getTrackById(selectedElement.getTrackId()) : null;
|
|
3860
|
+
const trackProps = (track == null ? void 0 : track.getProps()) ?? {};
|
|
3861
|
+
const applyToAll = (trackProps == null ? void 0 : trackProps.applyToAll) ?? false;
|
|
3862
|
+
const handleUpdateCaption = (updates) => {
|
|
3863
|
+
const captionElement = selectedElement;
|
|
3864
|
+
if (!captionElement) return;
|
|
3865
|
+
if (applyToAll && track) {
|
|
3866
|
+
const nextFont = {
|
|
3867
|
+
size: updates.fontSize ?? fontSize,
|
|
3868
|
+
family: updates.fontFamily ?? fontFamily
|
|
3869
|
+
};
|
|
3870
|
+
const nextColors = updates.colors ?? colors;
|
|
3871
|
+
const nextCapStyle = updates.style ?? (capStyle == null ? void 0 : capStyle.value);
|
|
3872
|
+
track.setProps({
|
|
3873
|
+
...trackProps,
|
|
3874
|
+
capStyle: nextCapStyle,
|
|
3875
|
+
font: { ...(trackProps == null ? void 0 : trackProps.font) ?? {}, ...nextFont },
|
|
3876
|
+
colors: nextColors
|
|
3877
|
+
});
|
|
3878
|
+
editor.refresh();
|
|
3879
|
+
} else {
|
|
3880
|
+
const elementProps = captionElement.getProps() ?? {};
|
|
3881
|
+
captionElement.setProps({
|
|
3882
|
+
...elementProps,
|
|
3883
|
+
capStyle: updates.style ?? (capStyle == null ? void 0 : capStyle.value),
|
|
3884
|
+
font: {
|
|
3885
|
+
size: updates.fontSize ?? fontSize,
|
|
3886
|
+
family: updates.fontFamily ?? fontFamily
|
|
3887
|
+
},
|
|
3888
|
+
colors: updates.colors ?? colors
|
|
3889
|
+
});
|
|
3890
|
+
updateElement == null ? void 0 : updateElement(captionElement);
|
|
3891
|
+
}
|
|
3892
|
+
};
|
|
3893
|
+
react.useEffect(() => {
|
|
3894
|
+
var _a, _b;
|
|
3895
|
+
const captionElement = selectedElement;
|
|
3896
|
+
if (captionElement) {
|
|
3897
|
+
if (captionRef.current) {
|
|
3898
|
+
captionRef.current.value = captionElement == null ? void 0 : captionElement.getText();
|
|
3899
|
+
}
|
|
3900
|
+
const props = applyToAll ? trackProps : captionElement.getProps() ?? {};
|
|
3901
|
+
const _capStyle = props == null ? void 0 : props.capStyle;
|
|
3902
|
+
if (_capStyle && _capStyle in timeline.CAPTION_STYLE_OPTIONS) {
|
|
3903
|
+
setCapStyle(timeline.CAPTION_STYLE_OPTIONS[_capStyle]);
|
|
3904
|
+
}
|
|
3905
|
+
setFontSize(((_a = props == null ? void 0 : props.font) == null ? void 0 : _a.size) ?? CAPTION_FONT.size);
|
|
3906
|
+
setFontFamily(((_b = props == null ? void 0 : props.font) == null ? void 0 : _b.family) ?? CAPTION_FONT.family);
|
|
3907
|
+
const c = props == null ? void 0 : props.colors;
|
|
3908
|
+
setColors({
|
|
3909
|
+
text: (c == null ? void 0 : c.text) ?? CAPTION_COLOR.text,
|
|
3910
|
+
highlight: (c == null ? void 0 : c.highlight) ?? CAPTION_COLOR.highlight,
|
|
3911
|
+
bgColor: (c == null ? void 0 : c.bgColor) ?? CAPTION_COLOR.bgColor,
|
|
3912
|
+
outlineColor: (c == null ? void 0 : c.outlineColor) ?? CAPTION_COLOR.outlineColor
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
}, [selectedElement, applyToAll, changeLog]);
|
|
3916
|
+
if (!(selectedElement instanceof timeline.CaptionElement)) {
|
|
3917
|
+
return null;
|
|
3918
|
+
}
|
|
3919
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-container", children: [
|
|
3920
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
|
|
3921
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", children: "Caption Style" }),
|
|
3922
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3923
|
+
"select",
|
|
3924
|
+
{
|
|
3925
|
+
value: capStyle.value,
|
|
3926
|
+
onChange: (e) => {
|
|
3927
|
+
const val = e.target.value;
|
|
3928
|
+
if (val in timeline.CAPTION_STYLE_OPTIONS) {
|
|
3929
|
+
setCapStyle(timeline.CAPTION_STYLE_OPTIONS[val]);
|
|
3930
|
+
}
|
|
3931
|
+
handleUpdateCaption({ style: e.target.value });
|
|
3932
|
+
},
|
|
3933
|
+
className: "select-dark w-full",
|
|
3934
|
+
children: Object.values(timeline.CAPTION_STYLE_OPTIONS).map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))
|
|
3935
|
+
}
|
|
3936
|
+
)
|
|
3937
|
+
] }),
|
|
3938
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
|
|
3939
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", children: "Font Size" }),
|
|
3940
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "slider-container", children: [
|
|
3941
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3942
|
+
"input",
|
|
3943
|
+
{
|
|
3944
|
+
type: "range",
|
|
3945
|
+
min: "8",
|
|
3946
|
+
max: "72",
|
|
3947
|
+
step: "1",
|
|
3948
|
+
value: fontSize,
|
|
3949
|
+
onChange: (e) => {
|
|
3950
|
+
const value = Number(e.target.value);
|
|
3951
|
+
setFontSize(value);
|
|
3952
|
+
handleUpdateCaption({ fontSize: value });
|
|
3953
|
+
},
|
|
3954
|
+
className: "slider-purple"
|
|
3955
|
+
}
|
|
3956
|
+
),
|
|
3957
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "slider-value", children: [
|
|
3958
|
+
fontSize,
|
|
3959
|
+
"px"
|
|
3960
|
+
] })
|
|
3961
|
+
] })
|
|
3962
|
+
] }),
|
|
3963
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
|
|
3964
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", children: "Font" }),
|
|
3965
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3966
|
+
"select",
|
|
3967
|
+
{
|
|
3968
|
+
value: fontFamily,
|
|
3969
|
+
onChange: (e) => {
|
|
3970
|
+
const value = e.target.value;
|
|
3971
|
+
setFontFamily(value);
|
|
3972
|
+
handleUpdateCaption({ fontFamily: value });
|
|
3973
|
+
},
|
|
3974
|
+
className: "select-dark w-full",
|
|
3975
|
+
children: [
|
|
3976
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "Bangers", children: "Bangers" }),
|
|
3977
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "Arial", children: "Arial" }),
|
|
3978
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "Helvetica", children: "Helvetica" }),
|
|
3979
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "Times New Roman", children: "Times New Roman" })
|
|
3980
|
+
]
|
|
3981
|
+
}
|
|
3982
|
+
)
|
|
3983
|
+
] }),
|
|
3984
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-section", children: [
|
|
3985
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", children: "Colors" }),
|
|
3986
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-section", children: [
|
|
3987
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-control", children: [
|
|
3988
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "Text Color" }),
|
|
3989
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-inputs", children: [
|
|
3990
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3991
|
+
"input",
|
|
3992
|
+
{
|
|
3993
|
+
type: "color",
|
|
3994
|
+
value: colors.text,
|
|
3995
|
+
onChange: (e) => {
|
|
3996
|
+
const newColors = { ...colors, text: e.target.value };
|
|
3997
|
+
setColors(newColors);
|
|
3998
|
+
handleUpdateCaption({ colors: newColors });
|
|
3999
|
+
},
|
|
4000
|
+
className: "color-picker"
|
|
4001
|
+
}
|
|
4002
|
+
),
|
|
4003
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4004
|
+
"input",
|
|
4005
|
+
{
|
|
4006
|
+
type: "text",
|
|
4007
|
+
value: colors.text,
|
|
4008
|
+
onChange: (e) => {
|
|
4009
|
+
const newColors = { ...colors, text: e.target.value };
|
|
4010
|
+
setColors(newColors);
|
|
4011
|
+
handleUpdateCaption({ colors: newColors });
|
|
4012
|
+
},
|
|
4013
|
+
className: "color-text"
|
|
4014
|
+
}
|
|
4015
|
+
)
|
|
4016
|
+
] })
|
|
4017
|
+
] }),
|
|
4018
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-control", children: [
|
|
4019
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "Background Color" }),
|
|
4020
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-inputs", children: [
|
|
4021
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4022
|
+
"input",
|
|
4023
|
+
{
|
|
4024
|
+
type: "color",
|
|
4025
|
+
value: colors.bgColor,
|
|
4026
|
+
onChange: (e) => {
|
|
4027
|
+
const newColors = { ...colors, bgColor: e.target.value };
|
|
4028
|
+
setColors(newColors);
|
|
4029
|
+
handleUpdateCaption({ colors: newColors });
|
|
4030
|
+
},
|
|
4031
|
+
className: "color-picker"
|
|
4032
|
+
}
|
|
4033
|
+
),
|
|
4034
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4035
|
+
"input",
|
|
4036
|
+
{
|
|
4037
|
+
type: "text",
|
|
4038
|
+
value: colors.bgColor,
|
|
4039
|
+
onChange: (e) => {
|
|
4040
|
+
const newColors = { ...colors, bgColor: e.target.value };
|
|
4041
|
+
setColors(newColors);
|
|
4042
|
+
handleUpdateCaption({ colors: newColors });
|
|
4043
|
+
},
|
|
4044
|
+
className: "color-text"
|
|
4045
|
+
}
|
|
4046
|
+
)
|
|
4047
|
+
] })
|
|
4048
|
+
] }),
|
|
4049
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-control", children: [
|
|
4050
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "Outline Color" }),
|
|
4051
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-inputs", children: [
|
|
4052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4053
|
+
"input",
|
|
4054
|
+
{
|
|
4055
|
+
type: "color",
|
|
4056
|
+
value: colors.outlineColor,
|
|
4057
|
+
onChange: (e) => {
|
|
4058
|
+
const newColors = { ...colors, outlineColor: e.target.value };
|
|
4059
|
+
setColors(newColors);
|
|
4060
|
+
handleUpdateCaption({ colors: newColors });
|
|
4061
|
+
},
|
|
4062
|
+
className: "color-picker"
|
|
4063
|
+
}
|
|
4064
|
+
),
|
|
4065
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4066
|
+
"input",
|
|
4067
|
+
{
|
|
4068
|
+
type: "text",
|
|
4069
|
+
value: colors.outlineColor,
|
|
4070
|
+
onChange: (e) => {
|
|
4071
|
+
const newColors = { ...colors, outlineColor: e.target.value };
|
|
4072
|
+
setColors(newColors);
|
|
4073
|
+
handleUpdateCaption({ colors: newColors });
|
|
4074
|
+
},
|
|
4075
|
+
className: "color-text"
|
|
4076
|
+
}
|
|
4077
|
+
)
|
|
4078
|
+
] })
|
|
4079
|
+
] })
|
|
4080
|
+
] })
|
|
4081
|
+
] })
|
|
4082
|
+
] });
|
|
4083
|
+
}
|
|
3471
4084
|
const MIN_DB = -60;
|
|
3472
4085
|
const MAX_DB = 6;
|
|
3473
4086
|
function linearToDb(linear) {
|
|
@@ -3915,6 +4528,7 @@ function TextPropsPanel({
|
|
|
3915
4528
|
)
|
|
3916
4529
|
] });
|
|
3917
4530
|
}
|
|
4531
|
+
const DEFAULT_CANVAS_BACKGROUND = "#000000";
|
|
3918
4532
|
function PropertiesPanelContainer({
|
|
3919
4533
|
selectedElement,
|
|
3920
4534
|
updateElement,
|
|
@@ -3924,26 +4538,66 @@ function PropertiesPanelContainer({
|
|
|
3924
4538
|
pollingIntervalMs,
|
|
3925
4539
|
videoResolution
|
|
3926
4540
|
}) {
|
|
4541
|
+
const { editor, present } = timeline.useTimelineContext();
|
|
4542
|
+
const backgroundColor = (present == null ? void 0 : present.backgroundColor) ?? editor.getBackgroundColor() ?? DEFAULT_CANVAS_BACKGROUND;
|
|
4543
|
+
const handleBackgroundColorChange = react.useCallback(
|
|
4544
|
+
(value) => {
|
|
4545
|
+
editor.setBackgroundColor(value);
|
|
4546
|
+
},
|
|
4547
|
+
[editor]
|
|
4548
|
+
);
|
|
3927
4549
|
const title = selectedElement instanceof timeline.TextElement ? selectedElement.getText() : (selectedElement == null ? void 0 : selectedElement.getName()) || (selectedElement == null ? void 0 : selectedElement.getType()) || "Element";
|
|
3928
4550
|
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "properties-panel", "aria-label": "Element properties inspector", children: [
|
|
3929
4551
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "properties-header", children: [
|
|
3930
4552
|
!selectedElement && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: "Composition" }),
|
|
3931
|
-
selectedElement && selectedElement.getType() === "caption" && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: "
|
|
4553
|
+
selectedElement && selectedElement.getType() === "caption" && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: "Caption" }),
|
|
3932
4554
|
selectedElement && selectedElement.getType() !== "caption" && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: title })
|
|
3933
4555
|
] }),
|
|
3934
4556
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "prop-content", children: [
|
|
3935
4557
|
!selectedElement && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-container", children: [
|
|
3936
4558
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-title", children: "Canvas & Render" }),
|
|
3937
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3938
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
4559
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "properties-group", children: [
|
|
4560
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "property-section", children: [
|
|
4561
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "property-label", children: "Size" }),
|
|
4562
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "properties-size-readonly", children: [
|
|
4563
|
+
videoResolution.width,
|
|
4564
|
+
" × ",
|
|
4565
|
+
videoResolution.height
|
|
4566
|
+
] })
|
|
4567
|
+
] }),
|
|
4568
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-control", children: [
|
|
4569
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "Background Color" }),
|
|
4570
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "color-inputs", children: [
|
|
4571
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4572
|
+
"input",
|
|
4573
|
+
{
|
|
4574
|
+
type: "color",
|
|
4575
|
+
value: backgroundColor,
|
|
4576
|
+
onChange: (e) => handleBackgroundColorChange(e.target.value),
|
|
4577
|
+
className: "color-picker"
|
|
4578
|
+
}
|
|
4579
|
+
),
|
|
4580
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4581
|
+
"input",
|
|
4582
|
+
{
|
|
4583
|
+
type: "text",
|
|
4584
|
+
value: backgroundColor,
|
|
4585
|
+
onChange: (e) => handleBackgroundColorChange(e.target.value),
|
|
4586
|
+
className: "color-text"
|
|
4587
|
+
}
|
|
4588
|
+
)
|
|
4589
|
+
] })
|
|
3943
4590
|
] })
|
|
3944
|
-
] })
|
|
4591
|
+
] })
|
|
3945
4592
|
] }),
|
|
3946
|
-
selectedElement
|
|
4593
|
+
selectedElement instanceof timeline.CaptionElement && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4594
|
+
CaptionPropPanel,
|
|
4595
|
+
{
|
|
4596
|
+
selectedElement,
|
|
4597
|
+
updateElement
|
|
4598
|
+
}
|
|
4599
|
+
) }),
|
|
4600
|
+
selectedElement && !(selectedElement instanceof timeline.CaptionElement) && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (() => {
|
|
3947
4601
|
const isText = selectedElement instanceof timeline.TextElement;
|
|
3948
4602
|
const isVideo = selectedElement instanceof timeline.VideoElement;
|
|
3949
4603
|
const isAudio = selectedElement instanceof timeline.AudioElement;
|
|
@@ -4105,7 +4759,7 @@ function TwickStudio({ studioConfig }) {
|
|
|
4105
4759
|
addElement,
|
|
4106
4760
|
updateElement
|
|
4107
4761
|
} = useStudioManager();
|
|
4108
|
-
const { videoResolution, setVideoResolution } = timeline.useTimelineContext();
|
|
4762
|
+
const { editor, present, videoResolution, setVideoResolution } = timeline.useTimelineContext();
|
|
4109
4763
|
const {
|
|
4110
4764
|
onNewProject,
|
|
4111
4765
|
onLoadProject,
|
|
@@ -4119,16 +4773,20 @@ function TwickStudio({ studioConfig }) {
|
|
|
4119
4773
|
pollingIntervalMs
|
|
4120
4774
|
} = useGenerateCaptions(studioConfig);
|
|
4121
4775
|
const twickStudiConfig = react.useMemo(
|
|
4122
|
-
() =>
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
...
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4776
|
+
() => {
|
|
4777
|
+
var _a2;
|
|
4778
|
+
return {
|
|
4779
|
+
canvasMode: true,
|
|
4780
|
+
...studioConfig || {},
|
|
4781
|
+
videoProps: {
|
|
4782
|
+
...(studioConfig == null ? void 0 : studioConfig.videoProps) || {},
|
|
4783
|
+
width: videoResolution.width,
|
|
4784
|
+
height: videoResolution.height,
|
|
4785
|
+
backgroundColor: (present == null ? void 0 : present.backgroundColor) ?? editor.getBackgroundColor() ?? ((_a2 = studioConfig == null ? void 0 : studioConfig.videoProps) == null ? void 0 : _a2.backgroundColor)
|
|
4786
|
+
}
|
|
4787
|
+
};
|
|
4788
|
+
},
|
|
4789
|
+
[videoResolution, studioConfig, present == null ? void 0 : present.backgroundColor, editor]
|
|
4132
4790
|
);
|
|
4133
4791
|
return /* @__PURE__ */ jsxRuntime.jsx(MediaProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "studio-container", children: [
|
|
4134
4792
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4158,7 +4816,8 @@ function TwickStudio({ studioConfig }) {
|
|
|
4158
4816
|
selectedElement,
|
|
4159
4817
|
addElement,
|
|
4160
4818
|
updateElement,
|
|
4161
|
-
uploadConfig: twickStudiConfig.uploadConfig
|
|
4819
|
+
uploadConfig: twickStudiConfig.uploadConfig,
|
|
4820
|
+
studioConfig: twickStudiConfig
|
|
4162
4821
|
}
|
|
4163
4822
|
) }),
|
|
4164
4823
|
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "main-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-wrapper", children: /* @__PURE__ */ jsxRuntime.jsx(
|