@remotion/starburst 4.0.435

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 ADDED
@@ -0,0 +1,18 @@
1
+ # @remotion/starburst
2
+
3
+ Starburst ray effect for Remotion
4
+
5
+ [![NPM Downloads](https://img.shields.io/npm/dm/@remotion/starburst.svg?style=flat&color=black&label=Downloads)](https://npmcharts.com/compare/@remotion/starburst?minimal=true)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @remotion/starburst --save-exact
11
+ ```
12
+
13
+ When installing a Remotion package, make sure to align the version of all `remotion` and `@remotion/*` packages to the same version.
14
+ Remove the `^` character from the version number to use the exact version.
15
+
16
+ ## Usage
17
+
18
+ See the [documentation](https://www.remotion.dev/docs/starburst) for more information.
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { type AbsoluteFillLayout, type LayoutAndStyle, type SequenceProps } from 'remotion';
3
+ export type StarburstProps = Omit<SequenceProps, 'children' | 'durationInFrames' | keyof LayoutAndStyle> & Omit<AbsoluteFillLayout, 'layout'> & {
4
+ readonly durationInFrames?: number;
5
+ readonly rays: number;
6
+ readonly colors: readonly string[];
7
+ readonly rotation?: number;
8
+ readonly smoothness?: number;
9
+ readonly vignette?: number;
10
+ readonly originOffsetX?: number;
11
+ readonly originOffsetY?: number;
12
+ };
13
+ export declare const Starburst: React.ComponentType<Omit<SequenceProps, "children" | "durationInFrames" | "layout"> & Omit<AbsoluteFillLayout, "layout"> & {
14
+ readonly durationInFrames?: number | undefined;
15
+ readonly rays: number;
16
+ readonly colors: readonly string[];
17
+ readonly rotation?: number | undefined;
18
+ readonly smoothness?: number | undefined;
19
+ readonly vignette?: number | undefined;
20
+ readonly originOffsetX?: number | undefined;
21
+ readonly originOffsetY?: number | undefined;
22
+ }>;
@@ -0,0 +1,346 @@
1
+ // src/Starburst.tsx
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import {
4
+ AbsoluteFill,
5
+ Internals,
6
+ Sequence,
7
+ useDelayRender,
8
+ useVideoConfig
9
+ } from "remotion";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var hexToRgb = (hex) => {
12
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
13
+ if (!result) {
14
+ throw new Error(`Invalid hex color: ${hex}`);
15
+ }
16
+ return [
17
+ parseInt(result[1], 16) / 255,
18
+ parseInt(result[2], 16) / 255,
19
+ parseInt(result[3], 16) / 255
20
+ ];
21
+ };
22
+ var VERTEX_SHADER = `
23
+ attribute vec2 position;
24
+ void main() {
25
+ gl_Position = vec4(position, 0.0, 1.0);
26
+ }
27
+ `;
28
+ var FRAGMENT_SHADER = `
29
+ #ifdef GL_ES
30
+ precision mediump float;
31
+ #endif
32
+
33
+ uniform float numRays;
34
+ uniform float rotationOffset;
35
+ uniform float smoothEdge;
36
+ uniform vec2 resolution;
37
+ uniform sampler2D colorPalette;
38
+ uniform float numColors;
39
+ uniform float vignetteAmount;
40
+ uniform vec2 originOffset;
41
+
42
+ const float Pi = 3.14159265359;
43
+
44
+ void main() {
45
+ vec2 uv = gl_FragCoord.xy / resolution;
46
+ vec2 center = uv - 0.5 - originOffset;
47
+ center.x *= resolution.x / resolution.y;
48
+
49
+ float angle = atan(center.y, center.x) + rotationOffset;
50
+ float normalizedAngle = (angle + Pi) / (2.0 * Pi);
51
+ float sector = normalizedAngle * numRays;
52
+ float rayIndex = mod(floor(sector), numRays);
53
+
54
+ float colorIndex = mod(rayIndex, numColors);
55
+ float texCoord = (colorIndex + 0.5) / numColors;
56
+ vec3 col = texture2D(colorPalette, vec2(texCoord, 0.5)).rgb;
57
+
58
+ float fractSector = fract(sector);
59
+ float edgeSmooth = smoothEdge * 0.5;
60
+ float nextColorIndex = mod(rayIndex + 1.0, numColors);
61
+ float nextTexCoord = (nextColorIndex + 0.5) / numColors;
62
+ vec3 nextCol = texture2D(colorPalette, vec2(nextTexCoord, 0.5)).rgb;
63
+
64
+ float blend = smoothstep(1.0 - edgeSmooth, 1.0, fractSector);
65
+ col = mix(col, nextCol, blend);
66
+ float blendStart = smoothstep(edgeSmooth, 0.0, fractSector);
67
+ float prevColorIndex = mod(rayIndex - 1.0 + numColors, numColors);
68
+ float prevTexCoord = (prevColorIndex + 0.5) / numColors;
69
+ vec3 prevCol = texture2D(colorPalette, vec2(prevTexCoord, 0.5)).rgb;
70
+ col = mix(col, prevCol, blendStart);
71
+
72
+ vec2 vignetteCenter = (uv - 0.5) * vec2(resolution.x / resolution.y, 1.0);
73
+ float dist = length(vignetteCenter);
74
+ float radius = vignetteAmount * 3.0;
75
+ float alpha = smoothstep(radius, radius * 0.5, dist);
76
+
77
+ gl_FragColor = vec4(col, alpha);
78
+ }
79
+ `;
80
+ var StarburstCanvas = ({
81
+ rays,
82
+ colors,
83
+ rotation,
84
+ smoothness,
85
+ vignette,
86
+ originOffsetX,
87
+ originOffsetY
88
+ }) => {
89
+ const { width, height } = useVideoConfig();
90
+ const canvasRef = useRef(null);
91
+ const glRef = useRef(null);
92
+ const { delayRender, continueRender, cancelRender } = useDelayRender();
93
+ const [handle] = useState(() => delayRender());
94
+ const initGl = useCallback((canvas) => {
95
+ const gl = canvas.getContext("webgl", {
96
+ premultipliedAlpha: false,
97
+ alpha: true
98
+ });
99
+ if (!gl) {
100
+ cancelRender(new Error("Failed to get WebGL context. Try rendering with --gl=angle to enable WebGL."));
101
+ return null;
102
+ }
103
+ gl.enable(gl.BLEND);
104
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
105
+ const compile = (type, src) => {
106
+ const s = gl.createShader(type);
107
+ gl.shaderSource(s, src);
108
+ gl.compileShader(s);
109
+ return s;
110
+ };
111
+ const program = gl.createProgram();
112
+ gl.attachShader(program, compile(gl.VERTEX_SHADER, VERTEX_SHADER));
113
+ gl.attachShader(program, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));
114
+ gl.linkProgram(program);
115
+ gl.useProgram(program);
116
+ const buf = gl.createBuffer();
117
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
118
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
119
+ const pos = gl.getAttribLocation(program, "position");
120
+ gl.enableVertexAttribArray(pos);
121
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
122
+ const colorTexture = gl.createTexture();
123
+ gl.activeTexture(gl.TEXTURE0);
124
+ gl.bindTexture(gl.TEXTURE_2D, colorTexture);
125
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
126
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
127
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
128
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
129
+ const paletteLoc = gl.getUniformLocation(program, "colorPalette");
130
+ gl.uniform1i(paletteLoc, 0);
131
+ continueRender(handle);
132
+ return {
133
+ gl,
134
+ resLoc: gl.getUniformLocation(program, "resolution"),
135
+ numRaysLoc: gl.getUniformLocation(program, "numRays"),
136
+ rotationOffsetLoc: gl.getUniformLocation(program, "rotationOffset"),
137
+ smoothEdgeLoc: gl.getUniformLocation(program, "smoothEdge"),
138
+ numColorsLoc: gl.getUniformLocation(program, "numColors"),
139
+ vignetteAmountLoc: gl.getUniformLocation(program, "vignetteAmount"),
140
+ originOffsetLoc: gl.getUniformLocation(program, "originOffset"),
141
+ colorTexture
142
+ };
143
+ }, [continueRender, handle, cancelRender]);
144
+ useEffect(() => {
145
+ const canvas = canvasRef.current;
146
+ if (!canvas || glRef.current)
147
+ return;
148
+ glRef.current = initGl(canvas);
149
+ }, [initGl]);
150
+ useEffect(() => {
151
+ const ctx = glRef.current;
152
+ if (!ctx)
153
+ return;
154
+ const {
155
+ gl,
156
+ resLoc,
157
+ numRaysLoc,
158
+ rotationOffsetLoc,
159
+ smoothEdgeLoc,
160
+ numColorsLoc,
161
+ vignetteAmountLoc,
162
+ originOffsetLoc,
163
+ colorTexture
164
+ } = ctx;
165
+ const rotationRad = rotation * Math.PI / 180;
166
+ const pixelData = new Uint8Array(colors.length * 4);
167
+ for (let i = 0;i < colors.length; i++) {
168
+ const rgb = hexToRgb(colors[i]);
169
+ pixelData[i * 4] = Math.round(rgb[0] * 255);
170
+ pixelData[i * 4 + 1] = Math.round(rgb[1] * 255);
171
+ pixelData[i * 4 + 2] = Math.round(rgb[2] * 255);
172
+ pixelData[i * 4 + 3] = 255;
173
+ }
174
+ gl.activeTexture(gl.TEXTURE0);
175
+ gl.bindTexture(gl.TEXTURE_2D, colorTexture);
176
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, colors.length, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
177
+ gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
178
+ gl.clearColor(0, 0, 0, 0);
179
+ gl.clear(gl.COLOR_BUFFER_BIT);
180
+ gl.uniform1f(numRaysLoc, rays);
181
+ gl.uniform1f(numColorsLoc, colors.length);
182
+ gl.uniform1f(rotationOffsetLoc, rotationRad);
183
+ gl.uniform1f(smoothEdgeLoc, smoothness);
184
+ gl.uniform1f(vignetteAmountLoc, vignette);
185
+ gl.uniform2f(originOffsetLoc, originOffsetX, originOffsetY);
186
+ gl.uniform2f(resLoc, gl.canvas.width, gl.canvas.height);
187
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
188
+ }, [
189
+ rays,
190
+ colors,
191
+ rotation,
192
+ smoothness,
193
+ vignette,
194
+ originOffsetX,
195
+ originOffsetY,
196
+ width,
197
+ height
198
+ ]);
199
+ return /* @__PURE__ */ jsx(AbsoluteFill, {
200
+ children: /* @__PURE__ */ jsx("canvas", {
201
+ ref: canvasRef,
202
+ width,
203
+ height
204
+ })
205
+ });
206
+ };
207
+ var starburstSchema = {
208
+ rays: {
209
+ type: "number",
210
+ min: 2,
211
+ max: 100,
212
+ step: 1,
213
+ default: 12,
214
+ description: "Number of Rays"
215
+ },
216
+ rotation: {
217
+ type: "number",
218
+ min: 0,
219
+ max: 360,
220
+ step: 1,
221
+ default: 0,
222
+ description: "Rotation"
223
+ },
224
+ smoothness: {
225
+ type: "number",
226
+ min: 0,
227
+ max: 1,
228
+ step: 0.01,
229
+ default: 0,
230
+ description: "Edge Smoothness"
231
+ },
232
+ vignette: {
233
+ type: "number",
234
+ min: 0,
235
+ max: 1,
236
+ step: 0.01,
237
+ default: 1,
238
+ description: "Vignette"
239
+ },
240
+ originOffsetX: {
241
+ type: "number",
242
+ min: -1,
243
+ max: 1,
244
+ step: 0.01,
245
+ default: 0,
246
+ description: "Origin Offset X"
247
+ },
248
+ originOffsetY: {
249
+ type: "number",
250
+ min: -1,
251
+ max: 1,
252
+ step: 0.01,
253
+ default: 0,
254
+ description: "Origin Offset Y"
255
+ },
256
+ "style.translate": {
257
+ type: "translate",
258
+ step: 1,
259
+ default: "0px 0px",
260
+ description: "Position"
261
+ },
262
+ "style.scale": {
263
+ type: "number",
264
+ min: 0.05,
265
+ max: 100,
266
+ step: 0.01,
267
+ default: 1,
268
+ description: "Scale"
269
+ },
270
+ "style.rotate": {
271
+ type: "rotation",
272
+ step: 1,
273
+ default: "0deg",
274
+ description: "Rotation"
275
+ },
276
+ "style.opacity": {
277
+ type: "number",
278
+ min: 0,
279
+ max: 1,
280
+ step: 0.01,
281
+ default: 1,
282
+ description: "Opacity"
283
+ }
284
+ };
285
+ var StarburstInner = ({
286
+ rays,
287
+ colors,
288
+ rotation = 0,
289
+ smoothness = 0,
290
+ vignette = 1,
291
+ originOffsetX = 0,
292
+ originOffsetY = 0,
293
+ durationInFrames,
294
+ style,
295
+ controls,
296
+ ...sequenceProps
297
+ }) => {
298
+ const { durationInFrames: videoDuration } = useVideoConfig();
299
+ const resolvedDuration = durationInFrames ?? videoDuration;
300
+ if (typeof rays !== "number" || !Number.isFinite(rays)) {
301
+ throw new TypeError(`"rays" must be a finite number, but got ${JSON.stringify(rays)}`);
302
+ }
303
+ if (rays < 2 || rays > 100) {
304
+ throw new RangeError(`"rays" must be between 2 and 100, but got ${rays}`);
305
+ }
306
+ if (!Array.isArray(colors) || colors.length < 2) {
307
+ throw new TypeError(`"colors" must be an array with at least 2 colors, but got ${JSON.stringify(colors)}`);
308
+ }
309
+ if (typeof rotation !== "number" || !Number.isFinite(rotation)) {
310
+ throw new TypeError(`"rotation" must be a finite number, but got ${JSON.stringify(rotation)}`);
311
+ }
312
+ if (typeof smoothness !== "number" || !Number.isFinite(smoothness)) {
313
+ throw new TypeError(`"smoothness" must be a finite number, but got ${JSON.stringify(smoothness)}`);
314
+ }
315
+ if (smoothness < 0 || smoothness > 1) {
316
+ throw new RangeError(`"smoothness" must be between 0 and 1, but got ${smoothness}`);
317
+ }
318
+ if (typeof vignette !== "number" || !Number.isFinite(vignette)) {
319
+ throw new TypeError(`"vignette" must be a finite number, but got ${JSON.stringify(vignette)}`);
320
+ }
321
+ if (vignette < 0 || vignette > 1) {
322
+ throw new RangeError(`"vignette" must be between 0 and 1, but got ${vignette}`);
323
+ }
324
+ return /* @__PURE__ */ jsx(Sequence, {
325
+ durationInFrames: resolvedDuration,
326
+ name: "<Starburst>",
327
+ controls,
328
+ ...sequenceProps,
329
+ style,
330
+ children: /* @__PURE__ */ jsx(StarburstCanvas, {
331
+ rays,
332
+ colors,
333
+ rotation,
334
+ smoothness,
335
+ vignette,
336
+ originOffsetX,
337
+ originOffsetY
338
+ })
339
+ });
340
+ };
341
+ var Starburst = Internals.wrapInSchema(StarburstInner, starburstSchema);
342
+ Starburst.displayName = "Starburst";
343
+ Internals.addSequenceStackTraces(Starburst);
344
+ export {
345
+ Starburst
346
+ };
@@ -0,0 +1,2 @@
1
+ export { Starburst } from './Starburst';
2
+ export type { StarburstProps } from './Starburst';
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@remotion/starburst",
3
+ "version": "4.0.435",
4
+ "description": "Starburst ray effect for Remotion",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/esm/index.mjs",
8
+ "repository": {
9
+ "url": "https://github.com/remotion-dev/remotion/tree/main/packages/starburst"
10
+ },
11
+ "sideEffects": false,
12
+ "type": "module",
13
+ "scripts": {
14
+ "formatting": "oxfmt src --check",
15
+ "format": "oxfmt src",
16
+ "lint": "eslint src",
17
+ "watch": "tsgo -w",
18
+ "make": "tsgo && bun --env-file=../.env.bundle bundle.ts"
19
+ },
20
+ "author": "Jonny Burger <jonny@remotion.dev>",
21
+ "contributors": [],
22
+ "license": "Remotion License",
23
+ "bugs": {
24
+ "url": "https://github.com/remotion-dev/remotion/issues"
25
+ },
26
+ "dependencies": {
27
+ "remotion": "4.0.435",
28
+ "zod": "4.3.6"
29
+ },
30
+ "peerDependencies": {
31
+ "react": ">=16.8.0",
32
+ "react-dom": ">=16.8.0"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "module": "./dist/esm/index.mjs",
38
+ "import": "./dist/esm/index.mjs"
39
+ },
40
+ "./package.json": "./package.json"
41
+ },
42
+ "devDependencies": {
43
+ "react": "19.2.3",
44
+ "react-dom": "19.2.3",
45
+ "@remotion/eslint-config-internal": "4.0.435",
46
+ "eslint": "9.19.0",
47
+ "@typescript/native-preview": "7.0.0-dev.20260217.1"
48
+ },
49
+ "keywords": [
50
+ "remotion",
51
+ "starburst"
52
+ ],
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "homepage": "https://www.remotion.dev/docs/starburst"
57
+ }