@remotion/effects 4.0.483 → 4.0.484
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/corner-pin/corner-pin-shaders.d.ts +1 -1
- package/dist/esm/corner-pin.mjs +38 -35
- package/dist/esm/index.mjs +642 -57
- package/dist/esm/linear-gradient-tint.mjs +426 -0
- package/dist/esm/linear-gradient.mjs +372 -0
- package/dist/index.d.ts +2 -0
- package/dist/linear-gradient-tint.d.ts +26 -0
- package/dist/linear-gradient.d.ts +22 -0
- package/package.json +19 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -2309,11 +2309,591 @@ var zigzag = createEffect5({
|
|
|
2309
2309
|
schema: zigzagSchema,
|
|
2310
2310
|
validateParams: validateZigzagParams
|
|
2311
2311
|
});
|
|
2312
|
-
|
|
2312
|
+
|
|
2313
|
+
// src/linear-gradient.ts
|
|
2314
|
+
import { Internals as Internals6 } from "remotion";
|
|
2315
|
+
var { createEffect: createEffect6, createWebGL2ContextError: createWebGL2ContextError6 } = Internals6;
|
|
2316
|
+
var DEFAULT_START = [0, 0.5];
|
|
2317
|
+
var DEFAULT_END = [1, 0.5];
|
|
2318
|
+
var DEFAULT_START_COLOR = "#000000";
|
|
2319
|
+
var DEFAULT_END_COLOR = "#ffffff";
|
|
2320
|
+
var linearGradientSchema = {
|
|
2321
|
+
start: {
|
|
2322
|
+
type: "uv-coordinate",
|
|
2323
|
+
min: -1,
|
|
2324
|
+
max: 2,
|
|
2325
|
+
step: 0.01,
|
|
2326
|
+
default: DEFAULT_START,
|
|
2327
|
+
description: "Start",
|
|
2328
|
+
visual: {
|
|
2329
|
+
type: "line",
|
|
2330
|
+
to: "end"
|
|
2331
|
+
}
|
|
2332
|
+
},
|
|
2333
|
+
end: {
|
|
2334
|
+
type: "uv-coordinate",
|
|
2335
|
+
min: -1,
|
|
2336
|
+
max: 2,
|
|
2337
|
+
step: 0.01,
|
|
2338
|
+
default: DEFAULT_END,
|
|
2339
|
+
description: "End"
|
|
2340
|
+
},
|
|
2341
|
+
startColor: {
|
|
2342
|
+
type: "color",
|
|
2343
|
+
default: DEFAULT_START_COLOR,
|
|
2344
|
+
description: "Start color"
|
|
2345
|
+
},
|
|
2346
|
+
endColor: {
|
|
2347
|
+
type: "color",
|
|
2348
|
+
default: DEFAULT_END_COLOR,
|
|
2349
|
+
description: "End color"
|
|
2350
|
+
}
|
|
2351
|
+
};
|
|
2352
|
+
var resolve6 = (p) => ({
|
|
2353
|
+
start: [...p.start ?? DEFAULT_START],
|
|
2354
|
+
end: [...p.end ?? DEFAULT_END],
|
|
2355
|
+
startColor: p.startColor ?? DEFAULT_START_COLOR,
|
|
2356
|
+
endColor: p.endColor ?? DEFAULT_END_COLOR
|
|
2357
|
+
});
|
|
2358
|
+
var assertOptionalUvCoordinate2 = (value, name) => {
|
|
2359
|
+
if (value === undefined) {
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
if (!Array.isArray(value) || value.length !== 2 || value.some((item) => typeof item !== "number" || !Number.isFinite(item))) {
|
|
2363
|
+
throw new TypeError(`"${name}" must be a [number, number] tuple`);
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
var validateLinearGradientParams = (params) => {
|
|
2367
|
+
assertEffectParamsObject(params, "Linear gradient");
|
|
2368
|
+
assertOptionalUvCoordinate2(params.start, "start");
|
|
2369
|
+
assertOptionalUvCoordinate2(params.end, "end");
|
|
2370
|
+
assertOptionalColor(params.startColor, "startColor");
|
|
2371
|
+
assertOptionalColor(params.endColor, "endColor");
|
|
2372
|
+
};
|
|
2373
|
+
var VERTEX_SHADER = `#version 300 es
|
|
2374
|
+
in vec2 aPos;
|
|
2375
|
+
in vec2 aUv;
|
|
2376
|
+
out vec2 vUv;
|
|
2377
|
+
|
|
2378
|
+
void main() {
|
|
2379
|
+
vUv = aUv;
|
|
2380
|
+
gl_Position = vec4(aPos, 0.0, 1.0);
|
|
2381
|
+
}
|
|
2382
|
+
`;
|
|
2383
|
+
var FRAGMENT_SHADER = `#version 300 es
|
|
2384
|
+
precision highp float;
|
|
2385
|
+
|
|
2386
|
+
in vec2 vUv;
|
|
2387
|
+
out vec4 fragColor;
|
|
2388
|
+
|
|
2389
|
+
uniform vec2 uStart;
|
|
2390
|
+
uniform vec2 uEnd;
|
|
2391
|
+
uniform vec4 uStartColor;
|
|
2392
|
+
uniform vec4 uEndColor;
|
|
2393
|
+
|
|
2394
|
+
float gradientProgress(vec2 uv) {
|
|
2395
|
+
vec2 gradient = uEnd - uStart;
|
|
2396
|
+
float gradientLengthSq = dot(gradient, gradient);
|
|
2397
|
+
if (gradientLengthSq <= 0.0000001) {
|
|
2398
|
+
return 0.0;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
return clamp(dot(uv - uStart, gradient) / gradientLengthSq, 0.0, 1.0);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
void main() {
|
|
2405
|
+
vec2 publicUv = vec2(vUv.x, 1.0 - vUv.y);
|
|
2406
|
+
vec4 color = mix(uStartColor, uEndColor, gradientProgress(publicUv));
|
|
2407
|
+
fragColor = vec4(color.rgb * color.a, color.a);
|
|
2408
|
+
}
|
|
2409
|
+
`;
|
|
2410
|
+
var compileShader6 = (gl, type, source) => {
|
|
2411
|
+
const shader = gl.createShader(type);
|
|
2412
|
+
if (!shader) {
|
|
2413
|
+
throw new Error("Failed to create WebGL shader");
|
|
2414
|
+
}
|
|
2415
|
+
gl.shaderSource(shader, source);
|
|
2416
|
+
gl.compileShader(shader);
|
|
2417
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
2418
|
+
const log = gl.getShaderInfoLog(shader);
|
|
2419
|
+
gl.deleteShader(shader);
|
|
2420
|
+
throw new Error(`Linear gradient shader compile failed: ${log ?? "(no log)"}`);
|
|
2421
|
+
}
|
|
2422
|
+
return shader;
|
|
2423
|
+
};
|
|
2424
|
+
var createProgram4 = (gl) => {
|
|
2425
|
+
const vs = compileShader6(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
2426
|
+
const fs = compileShader6(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
2427
|
+
const program = gl.createProgram();
|
|
2428
|
+
if (!program) {
|
|
2429
|
+
throw new Error("Failed to create WebGL program");
|
|
2430
|
+
}
|
|
2431
|
+
gl.attachShader(program, vs);
|
|
2432
|
+
gl.attachShader(program, fs);
|
|
2433
|
+
gl.linkProgram(program);
|
|
2434
|
+
gl.deleteShader(vs);
|
|
2435
|
+
gl.deleteShader(fs);
|
|
2436
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
2437
|
+
const log = gl.getProgramInfoLog(program);
|
|
2438
|
+
gl.deleteProgram(program);
|
|
2439
|
+
throw new Error(`Linear gradient program link failed: ${log ?? "(no log)"}`);
|
|
2440
|
+
}
|
|
2441
|
+
return program;
|
|
2442
|
+
};
|
|
2443
|
+
var setupLinearGradient = (target) => {
|
|
2444
|
+
const gl = target.getContext("webgl2", {
|
|
2445
|
+
premultipliedAlpha: true,
|
|
2446
|
+
alpha: true,
|
|
2447
|
+
preserveDrawingBuffer: true
|
|
2448
|
+
});
|
|
2449
|
+
if (!gl) {
|
|
2450
|
+
throw createWebGL2ContextError6("linear gradient effect");
|
|
2451
|
+
}
|
|
2452
|
+
const program = createProgram4(gl);
|
|
2453
|
+
const vao = gl.createVertexArray();
|
|
2454
|
+
if (!vao) {
|
|
2455
|
+
throw new Error("Failed to create WebGL vertex array");
|
|
2456
|
+
}
|
|
2457
|
+
gl.bindVertexArray(vao);
|
|
2458
|
+
const data = new Float32Array([
|
|
2459
|
+
-1,
|
|
2460
|
+
-1,
|
|
2461
|
+
0,
|
|
2462
|
+
0,
|
|
2463
|
+
1,
|
|
2464
|
+
-1,
|
|
2465
|
+
1,
|
|
2466
|
+
0,
|
|
2467
|
+
-1,
|
|
2468
|
+
1,
|
|
2469
|
+
0,
|
|
2470
|
+
1,
|
|
2471
|
+
1,
|
|
2472
|
+
1,
|
|
2473
|
+
1,
|
|
2474
|
+
1
|
|
2475
|
+
]);
|
|
2476
|
+
const vbo = gl.createBuffer();
|
|
2477
|
+
if (!vbo) {
|
|
2478
|
+
throw new Error("Failed to create WebGL buffer");
|
|
2479
|
+
}
|
|
2480
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
2481
|
+
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
|
|
2482
|
+
const aPos = gl.getAttribLocation(program, "aPos");
|
|
2483
|
+
const aUv = gl.getAttribLocation(program, "aUv");
|
|
2484
|
+
gl.enableVertexAttribArray(aPos);
|
|
2485
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
2486
|
+
gl.enableVertexAttribArray(aUv);
|
|
2487
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
2488
|
+
gl.bindVertexArray(null);
|
|
2489
|
+
const colorCanvas = document.createElement("canvas");
|
|
2490
|
+
colorCanvas.width = 1;
|
|
2491
|
+
colorCanvas.height = 1;
|
|
2492
|
+
const colorCtx = colorCanvas.getContext("2d", { willReadFrequently: true });
|
|
2493
|
+
if (!colorCtx) {
|
|
2494
|
+
throw new Error("Failed to acquire 2D context for color parsing");
|
|
2495
|
+
}
|
|
2496
|
+
return {
|
|
2497
|
+
gl,
|
|
2498
|
+
program,
|
|
2499
|
+
vao,
|
|
2500
|
+
vbo,
|
|
2501
|
+
uniforms: {
|
|
2502
|
+
uStart: gl.getUniformLocation(program, "uStart"),
|
|
2503
|
+
uEnd: gl.getUniformLocation(program, "uEnd"),
|
|
2504
|
+
uStartColor: gl.getUniformLocation(program, "uStartColor"),
|
|
2505
|
+
uEndColor: gl.getUniformLocation(program, "uEndColor")
|
|
2506
|
+
},
|
|
2507
|
+
colorCtx,
|
|
2508
|
+
cachedStartColor: "",
|
|
2509
|
+
cachedStartColorRgba: [0, 0, 0, 255],
|
|
2510
|
+
cachedEndColor: "",
|
|
2511
|
+
cachedEndColorRgba: [255, 255, 255, 255]
|
|
2512
|
+
};
|
|
2513
|
+
};
|
|
2514
|
+
var normalizedRgba = (color) => {
|
|
2515
|
+
return [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
|
|
2516
|
+
};
|
|
2517
|
+
var getParsedColors = (state, resolved) => {
|
|
2518
|
+
if (state.cachedStartColor !== resolved.startColor) {
|
|
2519
|
+
state.cachedStartColor = resolved.startColor;
|
|
2520
|
+
state.cachedStartColorRgba = parseColorRgba(state.colorCtx, resolved.startColor);
|
|
2521
|
+
}
|
|
2522
|
+
if (state.cachedEndColor !== resolved.endColor) {
|
|
2523
|
+
state.cachedEndColor = resolved.endColor;
|
|
2524
|
+
state.cachedEndColorRgba = parseColorRgba(state.colorCtx, resolved.endColor);
|
|
2525
|
+
}
|
|
2526
|
+
return {
|
|
2527
|
+
start: state.cachedStartColorRgba,
|
|
2528
|
+
end: state.cachedEndColorRgba
|
|
2529
|
+
};
|
|
2530
|
+
};
|
|
2531
|
+
var linearGradient = createEffect6({
|
|
2532
|
+
type: "dev.remotion.effects.linearGradient",
|
|
2533
|
+
label: "linearGradient()",
|
|
2534
|
+
documentationLink: "https://www.remotion.dev/docs/effects/linear-gradient",
|
|
2535
|
+
backend: "webgl2",
|
|
2536
|
+
calculateKey: (params) => {
|
|
2537
|
+
const r = resolve6(params);
|
|
2538
|
+
return `linear-gradient-${r.start.join(":")}-${r.end.join(":")}-${r.startColor}-${r.endColor}`;
|
|
2539
|
+
},
|
|
2540
|
+
setup: (target) => setupLinearGradient(target),
|
|
2541
|
+
apply: ({ width, height, params, state }) => {
|
|
2542
|
+
const r = resolve6(params);
|
|
2543
|
+
const { start, end } = getParsedColors(state, r);
|
|
2544
|
+
const [sr, sg, sb, sa] = normalizedRgba(start);
|
|
2545
|
+
const [er, eg, eb, ea] = normalizedRgba(end);
|
|
2546
|
+
const { gl, program, uniforms, vao } = state;
|
|
2547
|
+
gl.viewport(0, 0, width, height);
|
|
2548
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
2549
|
+
gl.clearColor(0, 0, 0, 0);
|
|
2550
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
2551
|
+
gl.useProgram(program);
|
|
2552
|
+
if (uniforms.uStart)
|
|
2553
|
+
gl.uniform2f(uniforms.uStart, r.start[0], r.start[1]);
|
|
2554
|
+
if (uniforms.uEnd)
|
|
2555
|
+
gl.uniform2f(uniforms.uEnd, r.end[0], r.end[1]);
|
|
2556
|
+
if (uniforms.uStartColor) {
|
|
2557
|
+
gl.uniform4f(uniforms.uStartColor, sr, sg, sb, sa);
|
|
2558
|
+
}
|
|
2559
|
+
if (uniforms.uEndColor) {
|
|
2560
|
+
gl.uniform4f(uniforms.uEndColor, er, eg, eb, ea);
|
|
2561
|
+
}
|
|
2562
|
+
gl.bindVertexArray(vao);
|
|
2563
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
2564
|
+
gl.bindVertexArray(null);
|
|
2565
|
+
gl.useProgram(null);
|
|
2566
|
+
},
|
|
2567
|
+
cleanup: ({ gl, program, vao, vbo }) => {
|
|
2568
|
+
gl.deleteBuffer(vbo);
|
|
2569
|
+
gl.deleteProgram(program);
|
|
2570
|
+
gl.deleteVertexArray(vao);
|
|
2571
|
+
},
|
|
2572
|
+
schema: linearGradientSchema,
|
|
2573
|
+
validateParams: validateLinearGradientParams
|
|
2574
|
+
});
|
|
2575
|
+
|
|
2576
|
+
// src/linear-gradient-tint.ts
|
|
2313
2577
|
import { Internals as Internals7 } from "remotion";
|
|
2578
|
+
var { createEffect: createEffect7, createWebGL2ContextError: createWebGL2ContextError7 } = Internals7;
|
|
2579
|
+
var DEFAULT_START2 = [0, 0.5];
|
|
2580
|
+
var DEFAULT_END2 = [1, 0.5];
|
|
2581
|
+
var DEFAULT_START_COLOR2 = "#000000";
|
|
2582
|
+
var DEFAULT_END_COLOR2 = "#ffffff";
|
|
2583
|
+
var DEFAULT_AMOUNT2 = 0.5;
|
|
2584
|
+
var linearGradientTintSchema = {
|
|
2585
|
+
start: {
|
|
2586
|
+
type: "uv-coordinate",
|
|
2587
|
+
min: -1,
|
|
2588
|
+
max: 2,
|
|
2589
|
+
step: 0.01,
|
|
2590
|
+
default: DEFAULT_START2,
|
|
2591
|
+
description: "Start",
|
|
2592
|
+
visual: {
|
|
2593
|
+
type: "line",
|
|
2594
|
+
to: "end"
|
|
2595
|
+
}
|
|
2596
|
+
},
|
|
2597
|
+
end: {
|
|
2598
|
+
type: "uv-coordinate",
|
|
2599
|
+
min: -1,
|
|
2600
|
+
max: 2,
|
|
2601
|
+
step: 0.01,
|
|
2602
|
+
default: DEFAULT_END2,
|
|
2603
|
+
description: "End"
|
|
2604
|
+
},
|
|
2605
|
+
startColor: {
|
|
2606
|
+
type: "color",
|
|
2607
|
+
default: DEFAULT_START_COLOR2,
|
|
2608
|
+
description: "Start color"
|
|
2609
|
+
},
|
|
2610
|
+
endColor: {
|
|
2611
|
+
type: "color",
|
|
2612
|
+
default: DEFAULT_END_COLOR2,
|
|
2613
|
+
description: "End color"
|
|
2614
|
+
},
|
|
2615
|
+
amount: {
|
|
2616
|
+
type: "number",
|
|
2617
|
+
min: 0,
|
|
2618
|
+
max: 1,
|
|
2619
|
+
step: 0.01,
|
|
2620
|
+
default: DEFAULT_AMOUNT2,
|
|
2621
|
+
description: "Amount",
|
|
2622
|
+
hiddenFromList: false
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
var resolve7 = (p) => ({
|
|
2626
|
+
start: [...p.start ?? DEFAULT_START2],
|
|
2627
|
+
end: [...p.end ?? DEFAULT_END2],
|
|
2628
|
+
startColor: p.startColor ?? DEFAULT_START_COLOR2,
|
|
2629
|
+
endColor: p.endColor ?? DEFAULT_END_COLOR2,
|
|
2630
|
+
amount: p.amount ?? DEFAULT_AMOUNT2
|
|
2631
|
+
});
|
|
2632
|
+
var assertOptionalUvCoordinate3 = (value, name) => {
|
|
2633
|
+
if (value === undefined) {
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
if (!Array.isArray(value) || value.length !== 2 || value.some((item) => typeof item !== "number" || !Number.isFinite(item))) {
|
|
2637
|
+
throw new TypeError(`"${name}" must be a [number, number] tuple`);
|
|
2638
|
+
}
|
|
2639
|
+
};
|
|
2640
|
+
var validateLinearGradientTintParams = (params) => {
|
|
2641
|
+
assertEffectParamsObject(params, "Linear gradient tint");
|
|
2642
|
+
assertOptionalUvCoordinate3(params.start, "start");
|
|
2643
|
+
assertOptionalUvCoordinate3(params.end, "end");
|
|
2644
|
+
assertOptionalColor(params.startColor, "startColor");
|
|
2645
|
+
assertOptionalColor(params.endColor, "endColor");
|
|
2646
|
+
assertOptionalFiniteNumber(params.amount, "amount");
|
|
2647
|
+
validateUnitInterval(resolve7(params).amount, "amount");
|
|
2648
|
+
};
|
|
2649
|
+
var VERTEX_SHADER2 = `#version 300 es
|
|
2650
|
+
in vec2 aPos;
|
|
2651
|
+
in vec2 aUv;
|
|
2652
|
+
out vec2 vUv;
|
|
2653
|
+
|
|
2654
|
+
void main() {
|
|
2655
|
+
vUv = aUv;
|
|
2656
|
+
gl_Position = vec4(aPos, 0.0, 1.0);
|
|
2657
|
+
}
|
|
2658
|
+
`;
|
|
2659
|
+
var FRAGMENT_SHADER2 = `#version 300 es
|
|
2660
|
+
precision highp float;
|
|
2661
|
+
|
|
2662
|
+
in vec2 vUv;
|
|
2663
|
+
out vec4 fragColor;
|
|
2664
|
+
|
|
2665
|
+
uniform sampler2D uSource;
|
|
2666
|
+
uniform vec2 uStart;
|
|
2667
|
+
uniform vec2 uEnd;
|
|
2668
|
+
uniform vec4 uStartColor;
|
|
2669
|
+
uniform vec4 uEndColor;
|
|
2670
|
+
uniform float uAmount;
|
|
2671
|
+
|
|
2672
|
+
float gradientProgress(vec2 uv) {
|
|
2673
|
+
vec2 gradient = uEnd - uStart;
|
|
2674
|
+
float gradientLengthSq = dot(gradient, gradient);
|
|
2675
|
+
if (gradientLengthSq <= 0.0000001) {
|
|
2676
|
+
return 0.0;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
return clamp(dot(uv - uStart, gradient) / gradientLengthSq, 0.0, 1.0);
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
void main() {
|
|
2683
|
+
vec4 texColor = texture(uSource, vUv);
|
|
2684
|
+
float alpha = texColor.a;
|
|
2685
|
+
|
|
2686
|
+
if (alpha <= 0.001) {
|
|
2687
|
+
fragColor = vec4(0.0);
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
vec2 publicUv = vec2(vUv.x, 1.0 - vUv.y);
|
|
2692
|
+
vec4 tintColor = mix(uStartColor, uEndColor, gradientProgress(publicUv));
|
|
2693
|
+
vec3 sourceRgb = texColor.rgb / alpha;
|
|
2694
|
+
vec3 blended = mix(sourceRgb, tintColor.rgb, uAmount * tintColor.a);
|
|
2695
|
+
|
|
2696
|
+
fragColor = vec4(blended * alpha, alpha);
|
|
2697
|
+
}
|
|
2698
|
+
`;
|
|
2699
|
+
var compileShader7 = (gl, type, source) => {
|
|
2700
|
+
const shader = gl.createShader(type);
|
|
2701
|
+
if (!shader) {
|
|
2702
|
+
throw new Error("Failed to create WebGL shader");
|
|
2703
|
+
}
|
|
2704
|
+
gl.shaderSource(shader, source);
|
|
2705
|
+
gl.compileShader(shader);
|
|
2706
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
2707
|
+
const log = gl.getShaderInfoLog(shader);
|
|
2708
|
+
gl.deleteShader(shader);
|
|
2709
|
+
throw new Error(`Linear gradient tint shader compile failed: ${log ?? "(no log)"}`);
|
|
2710
|
+
}
|
|
2711
|
+
return shader;
|
|
2712
|
+
};
|
|
2713
|
+
var createProgram5 = (gl) => {
|
|
2714
|
+
const vs = compileShader7(gl, gl.VERTEX_SHADER, VERTEX_SHADER2);
|
|
2715
|
+
const fs = compileShader7(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER2);
|
|
2716
|
+
const program = gl.createProgram();
|
|
2717
|
+
if (!program) {
|
|
2718
|
+
throw new Error("Failed to create WebGL program");
|
|
2719
|
+
}
|
|
2720
|
+
gl.attachShader(program, vs);
|
|
2721
|
+
gl.attachShader(program, fs);
|
|
2722
|
+
gl.linkProgram(program);
|
|
2723
|
+
gl.deleteShader(vs);
|
|
2724
|
+
gl.deleteShader(fs);
|
|
2725
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
2726
|
+
const log = gl.getProgramInfoLog(program);
|
|
2727
|
+
gl.deleteProgram(program);
|
|
2728
|
+
throw new Error(`Linear gradient tint program link failed: ${log ?? "(no log)"}`);
|
|
2729
|
+
}
|
|
2730
|
+
return program;
|
|
2731
|
+
};
|
|
2732
|
+
var createRgbaTexture = (gl) => {
|
|
2733
|
+
const texture = gl.createTexture();
|
|
2734
|
+
if (!texture) {
|
|
2735
|
+
throw new Error("Failed to create WebGL texture");
|
|
2736
|
+
}
|
|
2737
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
2738
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
2739
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
2740
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
2741
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
2742
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2743
|
+
return texture;
|
|
2744
|
+
};
|
|
2745
|
+
var setupLinearGradientTint = (target) => {
|
|
2746
|
+
const gl = target.getContext("webgl2", {
|
|
2747
|
+
premultipliedAlpha: true,
|
|
2748
|
+
alpha: true,
|
|
2749
|
+
preserveDrawingBuffer: true
|
|
2750
|
+
});
|
|
2751
|
+
if (!gl) {
|
|
2752
|
+
throw createWebGL2ContextError7("linear gradient tint effect");
|
|
2753
|
+
}
|
|
2754
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
2755
|
+
const program = createProgram5(gl);
|
|
2756
|
+
const vao = gl.createVertexArray();
|
|
2757
|
+
if (!vao) {
|
|
2758
|
+
throw new Error("Failed to create WebGL vertex array");
|
|
2759
|
+
}
|
|
2760
|
+
gl.bindVertexArray(vao);
|
|
2761
|
+
const data = new Float32Array([
|
|
2762
|
+
-1,
|
|
2763
|
+
-1,
|
|
2764
|
+
0,
|
|
2765
|
+
0,
|
|
2766
|
+
1,
|
|
2767
|
+
-1,
|
|
2768
|
+
1,
|
|
2769
|
+
0,
|
|
2770
|
+
-1,
|
|
2771
|
+
1,
|
|
2772
|
+
0,
|
|
2773
|
+
1,
|
|
2774
|
+
1,
|
|
2775
|
+
1,
|
|
2776
|
+
1,
|
|
2777
|
+
1
|
|
2778
|
+
]);
|
|
2779
|
+
const vbo = gl.createBuffer();
|
|
2780
|
+
if (!vbo) {
|
|
2781
|
+
throw new Error("Failed to create WebGL buffer");
|
|
2782
|
+
}
|
|
2783
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
2784
|
+
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
|
|
2785
|
+
const aPos = gl.getAttribLocation(program, "aPos");
|
|
2786
|
+
const aUv = gl.getAttribLocation(program, "aUv");
|
|
2787
|
+
gl.enableVertexAttribArray(aPos);
|
|
2788
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
2789
|
+
gl.enableVertexAttribArray(aUv);
|
|
2790
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
2791
|
+
gl.bindVertexArray(null);
|
|
2792
|
+
const textureSource = createRgbaTexture(gl);
|
|
2793
|
+
const colorCanvas = document.createElement("canvas");
|
|
2794
|
+
colorCanvas.width = 1;
|
|
2795
|
+
colorCanvas.height = 1;
|
|
2796
|
+
const colorCtx = colorCanvas.getContext("2d", { willReadFrequently: true });
|
|
2797
|
+
if (!colorCtx) {
|
|
2798
|
+
throw new Error("Failed to acquire 2D context for color parsing");
|
|
2799
|
+
}
|
|
2800
|
+
return {
|
|
2801
|
+
gl,
|
|
2802
|
+
program,
|
|
2803
|
+
vao,
|
|
2804
|
+
vbo,
|
|
2805
|
+
textureSource,
|
|
2806
|
+
uniforms: {
|
|
2807
|
+
uSource: gl.getUniformLocation(program, "uSource"),
|
|
2808
|
+
uStart: gl.getUniformLocation(program, "uStart"),
|
|
2809
|
+
uEnd: gl.getUniformLocation(program, "uEnd"),
|
|
2810
|
+
uStartColor: gl.getUniformLocation(program, "uStartColor"),
|
|
2811
|
+
uEndColor: gl.getUniformLocation(program, "uEndColor"),
|
|
2812
|
+
uAmount: gl.getUniformLocation(program, "uAmount")
|
|
2813
|
+
},
|
|
2814
|
+
colorCtx,
|
|
2815
|
+
cachedStartColor: "",
|
|
2816
|
+
cachedStartColorRgba: [0, 0, 0, 255],
|
|
2817
|
+
cachedEndColor: "",
|
|
2818
|
+
cachedEndColorRgba: [255, 255, 255, 255]
|
|
2819
|
+
};
|
|
2820
|
+
};
|
|
2821
|
+
var normalizedRgba2 = (color) => {
|
|
2822
|
+
return [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
|
|
2823
|
+
};
|
|
2824
|
+
var getParsedColors2 = (state, resolved) => {
|
|
2825
|
+
if (state.cachedStartColor !== resolved.startColor) {
|
|
2826
|
+
state.cachedStartColor = resolved.startColor;
|
|
2827
|
+
state.cachedStartColorRgba = parseColorRgba(state.colorCtx, resolved.startColor);
|
|
2828
|
+
}
|
|
2829
|
+
if (state.cachedEndColor !== resolved.endColor) {
|
|
2830
|
+
state.cachedEndColor = resolved.endColor;
|
|
2831
|
+
state.cachedEndColorRgba = parseColorRgba(state.colorCtx, resolved.endColor);
|
|
2832
|
+
}
|
|
2833
|
+
return {
|
|
2834
|
+
start: state.cachedStartColorRgba,
|
|
2835
|
+
end: state.cachedEndColorRgba
|
|
2836
|
+
};
|
|
2837
|
+
};
|
|
2838
|
+
var linearGradientTint = createEffect7({
|
|
2839
|
+
type: "dev.remotion.effects.linearGradientTint",
|
|
2840
|
+
label: "linearGradientTint()",
|
|
2841
|
+
documentationLink: "https://www.remotion.dev/docs/effects/linear-gradient-tint",
|
|
2842
|
+
backend: "webgl2",
|
|
2843
|
+
calculateKey: (params) => {
|
|
2844
|
+
const r = resolve7(params);
|
|
2845
|
+
return `linear-gradient-tint-${r.start.join(":")}-${r.end.join(":")}-${r.startColor}-${r.endColor}-${r.amount}`;
|
|
2846
|
+
},
|
|
2847
|
+
setup: (target) => setupLinearGradientTint(target),
|
|
2848
|
+
apply: ({ source, width, height, params, state, flipSourceY }) => {
|
|
2849
|
+
const r = resolve7(params);
|
|
2850
|
+
const { start, end } = getParsedColors2(state, r);
|
|
2851
|
+
const [sr, sg, sb, sa] = normalizedRgba2(start);
|
|
2852
|
+
const [er, eg, eb, ea] = normalizedRgba2(end);
|
|
2853
|
+
const { gl, program, textureSource, uniforms, vao } = state;
|
|
2854
|
+
gl.viewport(0, 0, width, height);
|
|
2855
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
2856
|
+
gl.clearColor(0, 0, 0, 0);
|
|
2857
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
2858
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
2859
|
+
gl.bindTexture(gl.TEXTURE_2D, textureSource);
|
|
2860
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
|
|
2861
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
2862
|
+
gl.useProgram(program);
|
|
2863
|
+
if (uniforms.uSource)
|
|
2864
|
+
gl.uniform1i(uniforms.uSource, 0);
|
|
2865
|
+
if (uniforms.uStart)
|
|
2866
|
+
gl.uniform2f(uniforms.uStart, r.start[0], r.start[1]);
|
|
2867
|
+
if (uniforms.uEnd)
|
|
2868
|
+
gl.uniform2f(uniforms.uEnd, r.end[0], r.end[1]);
|
|
2869
|
+
if (uniforms.uStartColor) {
|
|
2870
|
+
gl.uniform4f(uniforms.uStartColor, sr, sg, sb, sa);
|
|
2871
|
+
}
|
|
2872
|
+
if (uniforms.uEndColor) {
|
|
2873
|
+
gl.uniform4f(uniforms.uEndColor, er, eg, eb, ea);
|
|
2874
|
+
}
|
|
2875
|
+
if (uniforms.uAmount)
|
|
2876
|
+
gl.uniform1f(uniforms.uAmount, r.amount);
|
|
2877
|
+
gl.bindVertexArray(vao);
|
|
2878
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
2879
|
+
gl.bindVertexArray(null);
|
|
2880
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2881
|
+
gl.useProgram(null);
|
|
2882
|
+
},
|
|
2883
|
+
cleanup: ({ gl, program, vao, vbo, textureSource }) => {
|
|
2884
|
+
gl.deleteTexture(textureSource);
|
|
2885
|
+
gl.deleteBuffer(vbo);
|
|
2886
|
+
gl.deleteProgram(program);
|
|
2887
|
+
gl.deleteVertexArray(vao);
|
|
2888
|
+
},
|
|
2889
|
+
schema: linearGradientTintSchema,
|
|
2890
|
+
validateParams: validateLinearGradientTintParams
|
|
2891
|
+
});
|
|
2892
|
+
// src/corner-pin/index.ts
|
|
2893
|
+
import { Internals as Internals9 } from "remotion";
|
|
2314
2894
|
|
|
2315
2895
|
// src/corner-pin/corner-pin-runtime.ts
|
|
2316
|
-
import { Internals as
|
|
2896
|
+
import { Internals as Internals8 } from "remotion";
|
|
2317
2897
|
|
|
2318
2898
|
// src/corner-pin/corner-pin-shaders.ts
|
|
2319
2899
|
var CORNER_PIN_VS = `#version 300 es
|
|
@@ -2338,57 +2918,60 @@ uniform vec2 uTopRight;
|
|
|
2338
2918
|
uniform vec2 uBottomRight;
|
|
2339
2919
|
uniform vec2 uBottomLeft;
|
|
2340
2920
|
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2921
|
+
bool solveProjectiveInverse(vec2 p, out vec2 uv) {
|
|
2922
|
+
vec2 p0 = uBottomLeft;
|
|
2923
|
+
vec2 p1 = uBottomRight;
|
|
2924
|
+
vec2 p2 = uTopRight;
|
|
2925
|
+
vec2 p3 = uTopLeft;
|
|
2926
|
+
|
|
2927
|
+
vec2 dx1 = p1 - p2;
|
|
2928
|
+
vec2 dx2 = p3 - p2;
|
|
2929
|
+
vec2 dx3 = p0 - p1 + p2 - p3;
|
|
2344
2930
|
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
vec2 b = uBottomRight - uBottomLeft;
|
|
2348
|
-
vec2 c = uTopLeft - uBottomLeft;
|
|
2349
|
-
vec2 d = uBottomLeft - uBottomRight + uTopRight - uTopLeft;
|
|
2350
|
-
vec2 q = p - a;
|
|
2931
|
+
float g = 0.0;
|
|
2932
|
+
float h = 0.0;
|
|
2351
2933
|
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
if (abs(
|
|
2934
|
+
if (abs(dx3.x) > 0.000001 || abs(dx3.y) > 0.000001) {
|
|
2935
|
+
float denominator = dx1.x * dx2.y - dx2.x * dx1.y;
|
|
2936
|
+
if (abs(denominator) < 0.000001) {
|
|
2355
2937
|
return false;
|
|
2356
2938
|
}
|
|
2357
2939
|
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
return true;
|
|
2940
|
+
g = (dx3.x * dx2.y - dx2.x * dx3.y) / denominator;
|
|
2941
|
+
h = (dx1.x * dx3.y - dx3.x * dx1.y) / denominator;
|
|
2361
2942
|
}
|
|
2362
2943
|
|
|
2363
|
-
float
|
|
2364
|
-
float
|
|
2365
|
-
float
|
|
2366
|
-
float
|
|
2367
|
-
|
|
2368
|
-
|
|
2944
|
+
float a = p1.x - p0.x + g * p1.x;
|
|
2945
|
+
float b = p3.x - p0.x + h * p3.x;
|
|
2946
|
+
float c = p0.x;
|
|
2947
|
+
float d = p1.y - p0.y + g * p1.y;
|
|
2948
|
+
float e = p3.y - p0.y + h * p3.y;
|
|
2949
|
+
float f = p0.y;
|
|
2950
|
+
|
|
2951
|
+
float inverseX =
|
|
2952
|
+
(e - f * h) * p.x +
|
|
2953
|
+
(c * h - b) * p.y +
|
|
2954
|
+
(b * f - c * e);
|
|
2955
|
+
float inverseY =
|
|
2956
|
+
(f * g - d) * p.x +
|
|
2957
|
+
(a - c * g) * p.y +
|
|
2958
|
+
(c * d - a * f);
|
|
2959
|
+
float inverseW =
|
|
2960
|
+
(d * h - e * g) * p.x +
|
|
2961
|
+
(b * g - a * h) * p.y +
|
|
2962
|
+
(a * e - b * d);
|
|
2963
|
+
|
|
2964
|
+
if (abs(inverseW) < 0.000001) {
|
|
2369
2965
|
return false;
|
|
2370
2966
|
}
|
|
2371
2967
|
|
|
2372
|
-
|
|
2373
|
-
float u1 = (-qb + sqrtDiscriminant) / (2.0 * qa);
|
|
2374
|
-
float u2 = (-qb - sqrtDiscriminant) / (2.0 * qa);
|
|
2375
|
-
float u = u1;
|
|
2376
|
-
if (u1 < -0.001 || u1 > 1.001) {
|
|
2377
|
-
u = u2;
|
|
2378
|
-
}
|
|
2379
|
-
|
|
2380
|
-
vec2 denominator = c + d * u;
|
|
2381
|
-
float v = abs(denominator.x) > abs(denominator.y)
|
|
2382
|
-
? (q.x - b.x * u) / denominator.x
|
|
2383
|
-
: (q.y - b.y * u) / denominator.y;
|
|
2384
|
-
|
|
2385
|
-
uv = vec2(u, v);
|
|
2968
|
+
uv = vec2(inverseX / inverseW, inverseY / inverseW);
|
|
2386
2969
|
return true;
|
|
2387
2970
|
}
|
|
2388
2971
|
|
|
2389
2972
|
void main() {
|
|
2390
2973
|
vec2 sourceUv;
|
|
2391
|
-
if (!
|
|
2974
|
+
if (!solveProjectiveInverse(vUv, sourceUv)) {
|
|
2392
2975
|
fragColor = vec4(0.0);
|
|
2393
2976
|
return;
|
|
2394
2977
|
}
|
|
@@ -2408,8 +2991,8 @@ void main() {
|
|
|
2408
2991
|
`;
|
|
2409
2992
|
|
|
2410
2993
|
// src/corner-pin/corner-pin-runtime.ts
|
|
2411
|
-
var { createWebGL2ContextError:
|
|
2412
|
-
var
|
|
2994
|
+
var { createWebGL2ContextError: createWebGL2ContextError8 } = Internals8;
|
|
2995
|
+
var compileShader8 = (gl, type, source) => {
|
|
2413
2996
|
const shader = gl.createShader(type);
|
|
2414
2997
|
if (!shader) {
|
|
2415
2998
|
throw new Error("Failed to create WebGL shader");
|
|
@@ -2438,15 +3021,15 @@ var linkProgram6 = (gl, vs, fs) => {
|
|
|
2438
3021
|
}
|
|
2439
3022
|
return program;
|
|
2440
3023
|
};
|
|
2441
|
-
var
|
|
2442
|
-
const vs =
|
|
2443
|
-
const fs =
|
|
3024
|
+
var createProgram6 = (gl, vertexSource, fragmentSource) => {
|
|
3025
|
+
const vs = compileShader8(gl, gl.VERTEX_SHADER, vertexSource);
|
|
3026
|
+
const fs = compileShader8(gl, gl.FRAGMENT_SHADER, fragmentSource);
|
|
2444
3027
|
const program = linkProgram6(gl, vs, fs);
|
|
2445
3028
|
gl.deleteShader(vs);
|
|
2446
3029
|
gl.deleteShader(fs);
|
|
2447
3030
|
return program;
|
|
2448
3031
|
};
|
|
2449
|
-
var
|
|
3032
|
+
var createRgbaTexture2 = (gl) => {
|
|
2450
3033
|
const texture = gl.createTexture();
|
|
2451
3034
|
if (!texture) {
|
|
2452
3035
|
throw new Error("Failed to create WebGL texture");
|
|
@@ -2466,10 +3049,10 @@ var setupCornerPin = (target) => {
|
|
|
2466
3049
|
preserveDrawingBuffer: true
|
|
2467
3050
|
});
|
|
2468
3051
|
if (!gl) {
|
|
2469
|
-
throw
|
|
3052
|
+
throw createWebGL2ContextError8("corner pin effect");
|
|
2470
3053
|
}
|
|
2471
3054
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
2472
|
-
const program =
|
|
3055
|
+
const program = createProgram6(gl, CORNER_PIN_VS, CORNER_PIN_FS);
|
|
2473
3056
|
const vao = gl.createVertexArray();
|
|
2474
3057
|
if (!vao) {
|
|
2475
3058
|
throw new Error("Failed to create WebGL vertex array");
|
|
@@ -2504,7 +3087,7 @@ var setupCornerPin = (target) => {
|
|
|
2504
3087
|
gl.enableVertexAttribArray(1);
|
|
2505
3088
|
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 16, 8);
|
|
2506
3089
|
gl.bindVertexArray(null);
|
|
2507
|
-
const textureSource =
|
|
3090
|
+
const textureSource = createRgbaTexture2(gl);
|
|
2508
3091
|
return {
|
|
2509
3092
|
gl,
|
|
2510
3093
|
program,
|
|
@@ -2575,7 +3158,7 @@ var applyCornerPin = ({
|
|
|
2575
3158
|
};
|
|
2576
3159
|
|
|
2577
3160
|
// src/corner-pin/index.ts
|
|
2578
|
-
var { createEffect:
|
|
3161
|
+
var { createEffect: createEffect8 } = Internals9;
|
|
2579
3162
|
var DEFAULT_TOP_LEFT = [0, 0];
|
|
2580
3163
|
var DEFAULT_TOP_RIGHT = [1, 0];
|
|
2581
3164
|
var DEFAULT_BOTTOM_RIGHT = [1, 1];
|
|
@@ -2606,7 +3189,7 @@ var cornerPinSchema = {
|
|
|
2606
3189
|
description: "Bottom left"
|
|
2607
3190
|
}
|
|
2608
3191
|
};
|
|
2609
|
-
var
|
|
3192
|
+
var resolve8 = (p) => ({
|
|
2610
3193
|
topLeft: [...p.topLeft ?? DEFAULT_TOP_LEFT],
|
|
2611
3194
|
topRight: [...p.topRight ?? DEFAULT_TOP_RIGHT],
|
|
2612
3195
|
bottomRight: [
|
|
@@ -2616,7 +3199,7 @@ var resolve6 = (p) => ({
|
|
|
2616
3199
|
...p.bottomLeft ?? DEFAULT_BOTTOM_LEFT
|
|
2617
3200
|
]
|
|
2618
3201
|
});
|
|
2619
|
-
var
|
|
3202
|
+
var assertOptionalUvCoordinate4 = (value, name) => {
|
|
2620
3203
|
if (value === undefined) {
|
|
2621
3204
|
return;
|
|
2622
3205
|
}
|
|
@@ -2626,23 +3209,23 @@ var assertOptionalUvCoordinate2 = (value, name) => {
|
|
|
2626
3209
|
};
|
|
2627
3210
|
var validateCornerPinParams = (params) => {
|
|
2628
3211
|
assertEffectParamsObject(params, "Corner pin");
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
3212
|
+
assertOptionalUvCoordinate4(params.topLeft, "topLeft");
|
|
3213
|
+
assertOptionalUvCoordinate4(params.topRight, "topRight");
|
|
3214
|
+
assertOptionalUvCoordinate4(params.bottomRight, "bottomRight");
|
|
3215
|
+
assertOptionalUvCoordinate4(params.bottomLeft, "bottomLeft");
|
|
2633
3216
|
};
|
|
2634
|
-
var cornerPin =
|
|
3217
|
+
var cornerPin = createEffect8({
|
|
2635
3218
|
type: "dev.remotion.effects.cornerPin",
|
|
2636
3219
|
label: "cornerPin()",
|
|
2637
3220
|
documentationLink: "https://www.remotion.dev/docs/effects/corner-pin",
|
|
2638
3221
|
backend: "webgl2",
|
|
2639
3222
|
calculateKey: (params) => {
|
|
2640
|
-
const r =
|
|
3223
|
+
const r = resolve8(params);
|
|
2641
3224
|
return `corner-pin-${r.topLeft.join(":")}-${r.topRight.join(":")}-${r.bottomRight.join(":")}-${r.bottomLeft.join(":")}`;
|
|
2642
3225
|
},
|
|
2643
3226
|
setup: (target) => setupCornerPin(target),
|
|
2644
3227
|
apply: ({ source, width, height, params, state, flipSourceY }) => {
|
|
2645
|
-
const r =
|
|
3228
|
+
const r = resolve8(params);
|
|
2646
3229
|
applyCornerPin({
|
|
2647
3230
|
state,
|
|
2648
3231
|
source,
|
|
@@ -2663,6 +3246,8 @@ export {
|
|
|
2663
3246
|
zigzag,
|
|
2664
3247
|
rings,
|
|
2665
3248
|
pattern,
|
|
3249
|
+
linearGradientTint,
|
|
3250
|
+
linearGradient,
|
|
2666
3251
|
gridlines,
|
|
2667
3252
|
cornerPin,
|
|
2668
3253
|
checkerboard
|