@pixerate/flair 0.21.1 → 0.23.0
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/CHANGELOG.md +12 -0
- package/README.md +27 -0
- package/dist/catalog/index.d.ts +91 -4
- package/dist/catalog/index.js +7 -1
- package/dist/{chunk-ECBG5K6E.js → chunk-4F4KL4KU.js} +88 -11
- package/dist/chunk-4F4KL4KU.js.map +1 -0
- package/dist/editor/index.d.ts +2 -2
- package/dist/editor/index.js +31 -11
- package/dist/editor/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/svelte/index.d.ts +2 -2
- package/dist/svelte/index.js +1 -1
- package/dist/{types-Cy5EihZ8.d.ts → types-DLkbOX8d.d.ts} +2 -2
- package/dist/vector/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-ECBG5K6E.js.map +0 -1
- package/dist/{svg-BEOJriIW.d.ts → svg-BhRboN9q.d.ts} +46 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @pixerate/flair
|
|
2
2
|
|
|
3
|
+
## 0.23.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 69cdb60: `effectInputs(effect)` says what an effect takes and how it answers the pointer: what it `accepts` (image, video, svg, text, mask, path), its image controls and whether each wants a picture, a mask or text, its text controls (copy, font, path, glyphs), its video use, its `interactions` (hover, press, click, trail, pointer) and whether it is a transparent overlay. It is worked out from the effect's controls, source and fields, so it never drifts. `findEffects` and the `catalog.search` command filter on `accepts`, `interaction` and `transparent`, and the search lists each effect's inputs. `silhouette-morph` now says `video: "none"` (it takes silhouettes, not photos), and the fireworks, explosion and bullet-time effects are tagged `interactive`.
|
|
8
|
+
|
|
9
|
+
## 0.22.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 4eb5f23: `image-duotone` is now only a duotone: it maps the picture onto two colours by brightness, still and without its built-in light sweep (the `uSweep` control is gone). For the glare, lay the `shine-sweep` overlay over it.
|
|
14
|
+
|
|
3
15
|
## 0.21.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -150,6 +150,33 @@ new SvgPlayer(host, motion, { loop: false });
|
|
|
150
150
|
|
|
151
151
|
Find effects with `findEffects({ text: "glow", category: "light", kind: "shader" })`. Each effect has an `id`, `name`, `description`, `category`, `tags` and optional `presets`. Image effects default to built-in sample pictures, so they look right before you set `uImage` to your own URL.
|
|
152
152
|
|
|
153
|
+
#### What an effect takes
|
|
154
|
+
|
|
155
|
+
`effectInputs(effect)` says what you can give an effect and how it answers the pointer, worked out from the effect itself:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { effectInputs, findEffects, getEffect, textImage } from "@pixerate/flair/catalog";
|
|
159
|
+
|
|
160
|
+
effectInputs(getEffect("image-duotone")!);
|
|
161
|
+
// { accepts: ["image", "video", "svg"], images: [{ name: "uImage", wants: "picture" }], video: "filter", interactions: [], transparent: false, … }
|
|
162
|
+
effectInputs(getEffect("typewriter")!);
|
|
163
|
+
// { accepts: ["text"], texts: [{ name: "text", holds: "copy" }, { name: "font", holds: "font" }], interactions: [], … }
|
|
164
|
+
effectInputs(getEffect("click-ripple")!).interactions; // ["click"]
|
|
165
|
+
|
|
166
|
+
findEffects({ accepts: ["video"] }); // effects that run on video
|
|
167
|
+
findEffects({ accepts: ["text"], kind: "vector" }); // animated titles and labels
|
|
168
|
+
findEffects({ accepts: ["image"], interaction: ["hover"] }); // pictures that react to hovering
|
|
169
|
+
findEffects({ transparent: true }); // overlays to lay over a page, picture or video
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- `accepts`: `image` (any picture URL), `video` (a live `<video>`, with `setLiveSource`), `svg` (an SVG URL, drawn with its transparency), `text` (words for a text control, or for a text mask through `textImage("…")`), `mask` (a shape with transparency whose silhouette the effect uses: an icon, a logo, a word), `path` (SVG path data for a shape control).
|
|
173
|
+
- `images`: each image control's name, and whether it `wants` a `picture`, a `mask` or `text`.
|
|
174
|
+
- `texts`: each text control's name, and whether it `holds` `copy`, a `font`, a `path` or `glyphs`.
|
|
175
|
+
- `interactions`: `hover`, `press`, `click`, `trail` (follows where the pointer has been) or `pointer` (follows where it is), from the pointer built-ins a shader reads or a vector effect's `trigger`.
|
|
176
|
+
- `transparent`, `video` and `trigger`, as on the effect.
|
|
177
|
+
|
|
178
|
+
`findEffects` filters on `accepts` (all of them), `interaction` (any of them; `[]` for effects that don't answer the pointer) and `transparent`, and the `catalog.search` command takes the same filters and lists each effect's `accepts` and `interactions`. The `interactive` tag is kept in step with `interactions`.
|
|
179
|
+
|
|
153
180
|
Effects that show a picture (image, transition, morph, time-warp and the like) take transparent pictures too, such as SVG icons (Lucide and similar sets draw black `currentColor` strokes on a clear background). They lay the picture over a backdrop: `uBackdrop` (white by default) shows through its clear parts. Set `uBackdropAlpha` to 0 to keep the picture's alpha instead, and render with `{ alpha: true }` to lay the result over the page. `SAMPLE_IMAGES.icon` is a Lucide-style sample icon. SVGs are rasterised at 2048 px on the long edge, so icons stay sharp.
|
|
154
181
|
|
|
155
182
|
#### Effects on video
|
package/dist/catalog/index.d.ts
CHANGED
|
@@ -1,7 +1,76 @@
|
|
|
1
1
|
import { a as ControlDef, C as ControlValue } from '../controls-Ec6P0Vpy.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { a as SvgTrigger } from '../svg-BhRboN9q.js';
|
|
3
|
+
import { a as VideoUse, E as EffectDefinition, b as EffectCategory, S as ShaderEffect } from '../types-DLkbOX8d.js';
|
|
4
|
+
export { C as CURRENT_COLOR, c as EFFECT_CATEGORIES, d as EffectPreset, e as VECTOR_CONTROL_TYPES, f as VIDEO_USES, g as VectorControl, V as VectorEffect, h as colorControl, i as isCurrentColor, n as numberControl, r as renderVectorEffect, v as vectorControlDef, j as vectorControlIssues, k as vectorControls, l as vectorEffectControls } from '../types-DLkbOX8d.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* What an effect takes and how it answers the pointer, worked out from the
|
|
8
|
+
* effect itself (its controls, its `video` use, the pointer built-ins its
|
|
9
|
+
* source reads, its `trigger`), so a consumer can pair a picture, a video,
|
|
10
|
+
* an SVG, a word or a path with effects that suit it.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Something you can give an effect:
|
|
15
|
+
* - `image`: a photo or picture (any URL or `data:` image) for an image control.
|
|
16
|
+
* - `video`: a live `<video>` (or canvas) for an image control, with `setLiveSource`.
|
|
17
|
+
* - `svg`: an SVG file or `data:` URL for an image control (drawn as a picture, keeping its transparency).
|
|
18
|
+
* - `text`: words, for a text control, or for a text mask through `textImage`.
|
|
19
|
+
* - `mask`: a shape with transparency (an icon, a logo, `textImage`) whose silhouette the effect uses.
|
|
20
|
+
* - `path`: SVG path data (`d`), for a shape control.
|
|
21
|
+
*/
|
|
22
|
+
type EffectInput = "image" | "video" | "svg" | "text" | "mask" | "path";
|
|
23
|
+
/** Every {@link EffectInput}. */
|
|
24
|
+
declare const EFFECT_INPUTS: readonly EffectInput[];
|
|
25
|
+
/**
|
|
26
|
+
* How an effect answers the pointer:
|
|
27
|
+
* - `hover`: changes while the pointer is over it.
|
|
28
|
+
* - `press`: changes while the pointer is held down (or dragged).
|
|
29
|
+
* - `click`: answers each click or tap.
|
|
30
|
+
* - `trail`: follows where the pointer has just been.
|
|
31
|
+
* - `pointer`: follows where the pointer is.
|
|
32
|
+
*/
|
|
33
|
+
type EffectInteraction = "hover" | "press" | "click" | "trail" | "pointer";
|
|
34
|
+
/** Every {@link EffectInteraction}. */
|
|
35
|
+
declare const EFFECT_INTERACTIONS: readonly EffectInteraction[];
|
|
36
|
+
/** A shader's image control and what it wants. */
|
|
37
|
+
interface ImageSlot {
|
|
38
|
+
/** The control's name (a `sampler2D` uniform): set it with `setValues` or `setLiveSource`. */
|
|
39
|
+
name: string;
|
|
40
|
+
label: string;
|
|
41
|
+
/**
|
|
42
|
+
* What it is for: `picture` (a photo, video or SVG shown as it is), `mask`
|
|
43
|
+
* (a shape whose transparency the effect uses: an icon, a logo, a
|
|
44
|
+
* silhouette), or `text` (a word drawn by `textImage`).
|
|
45
|
+
*/
|
|
46
|
+
wants: "picture" | "mask" | "text";
|
|
47
|
+
}
|
|
48
|
+
/** A vector effect's text control and what it holds. */
|
|
49
|
+
interface TextSlot {
|
|
50
|
+
/** The control's name: set it with `renderVectorEffect(effect, { [name]: … })`. */
|
|
51
|
+
name: string;
|
|
52
|
+
label: string;
|
|
53
|
+
/** `copy` (words shown), `font` (a CSS font family), `path` (SVG path data) or `glyphs` (characters to draw from). */
|
|
54
|
+
holds: "copy" | "font" | "path" | "glyphs";
|
|
55
|
+
default: string;
|
|
56
|
+
}
|
|
57
|
+
/** What an effect takes and how it answers the pointer (see {@link effectInputs}). */
|
|
58
|
+
interface EffectInputs {
|
|
59
|
+
/** Everything it can be given, from its image and text controls. Empty: it makes its picture from nothing. */
|
|
60
|
+
accepts: EffectInput[];
|
|
61
|
+
/** Its image controls (shader effects). */
|
|
62
|
+
images: ImageSlot[];
|
|
63
|
+
/** Its text controls (vector effects). */
|
|
64
|
+
texts: TextSlot[];
|
|
65
|
+
/** How it suits video, for shaders with an image control (see `VideoUse`). */
|
|
66
|
+
video?: VideoUse;
|
|
67
|
+
/** How it answers the pointer; empty when it does not. */
|
|
68
|
+
interactions: EffectInteraction[];
|
|
69
|
+
/** A vector effect's trigger: what makes it play. */
|
|
70
|
+
trigger?: SvgTrigger;
|
|
71
|
+
/** Draws over other content (render it with `alpha: true`, over a page or picture). */
|
|
72
|
+
transparent: boolean;
|
|
73
|
+
}
|
|
5
74
|
|
|
6
75
|
/**
|
|
7
76
|
* Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,
|
|
@@ -71,6 +140,7 @@ declare function glsl(...parts: string[]): string;
|
|
|
71
140
|
* - Video: shader effects with image controls say how they suit video
|
|
72
141
|
* (`video`, see `VideoUse`); `findEffects({ video: ["filter"] })` finds them.
|
|
73
142
|
* - Controls: `effectControls`, `effectDefaults`.
|
|
143
|
+
* - Inputs: `effectInputs` (what an effect takes, how it answers the pointer).
|
|
74
144
|
* - Vector effects: their pictures declare their controls (`vectorControls`),
|
|
75
145
|
* and `renderVectorEffect` fills them in.
|
|
76
146
|
*
|
|
@@ -83,6 +153,17 @@ declare const SHADER_EFFECTS: readonly ShaderEffect[];
|
|
|
83
153
|
declare const EFFECTS: readonly EffectDefinition[];
|
|
84
154
|
/** The effect with this id, or undefined. */
|
|
85
155
|
declare function getEffect(id: string): EffectDefinition | undefined;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* What an effect takes and how it answers the pointer: what you can give it
|
|
159
|
+
* (`accepts`: image, video, svg, text, mask, path), its image controls and
|
|
160
|
+
* whether each wants a picture, a mask or text, its text controls (copy,
|
|
161
|
+
* font, path, glyphs), how it suits video, how it answers the pointer
|
|
162
|
+
* (`interactions`: hover, press, click, trail, pointer) and whether it draws
|
|
163
|
+
* over other content. Worked out from the effect itself, so it always agrees
|
|
164
|
+
* with its controls and source.
|
|
165
|
+
*/
|
|
166
|
+
declare function effectInputs(effect: EffectDefinition): EffectInputs;
|
|
86
167
|
interface EffectQuery {
|
|
87
168
|
/** Words to look for in the name, description, tags and id (all must match). */
|
|
88
169
|
text?: string;
|
|
@@ -92,6 +173,12 @@ interface EffectQuery {
|
|
|
92
173
|
tags?: readonly string[];
|
|
93
174
|
/** Effects that suit video in one of these ways (shader effects with image controls only). */
|
|
94
175
|
video?: readonly VideoUse[];
|
|
176
|
+
/** Effects that can be given every one of these (see {@link effectInputs}): `["image"]`, `["text"]`, `["svg"]`… */
|
|
177
|
+
accepts?: readonly EffectInput[];
|
|
178
|
+
/** Effects that answer the pointer in at least one of these ways; `[]` for effects that don't answer it at all. */
|
|
179
|
+
interaction?: readonly EffectInteraction[];
|
|
180
|
+
/** Overlays (`true`), which draw over other content, or effects that fill their frame (`false`). */
|
|
181
|
+
transparent?: boolean;
|
|
95
182
|
}
|
|
96
183
|
/** Effects matching a query, in catalog order. */
|
|
97
184
|
declare function findEffects(query?: EffectQuery): EffectDefinition[];
|
|
@@ -103,4 +190,4 @@ declare function effectDefaults(effect: EffectDefinition, options?: {
|
|
|
103
190
|
values?: Record<string, ControlValue>;
|
|
104
191
|
}): Record<string, ControlValue>;
|
|
105
192
|
|
|
106
|
-
export { EFFECTS, EffectCategory, EffectDefinition, type EffectQuery, FBM, HASH, NOISE, OKLAB_MIX, PALETTE, ROTATE, SAMPLE_IMAGES, SHADER_EFFECTS, ShaderEffect, VideoUse, effectControls, effectDefaults, findEffects, getEffect, glsl, svgDataUrl, textImage };
|
|
193
|
+
export { EFFECTS, EFFECT_INPUTS, EFFECT_INTERACTIONS, EffectCategory, EffectDefinition, type EffectInput, type EffectInputs, type EffectInteraction, type EffectQuery, FBM, HASH, type ImageSlot, NOISE, OKLAB_MIX, PALETTE, ROTATE, SAMPLE_IMAGES, SHADER_EFFECTS, ShaderEffect, type TextSlot, VideoUse, effectControls, effectDefaults, effectInputs, findEffects, getEffect, glsl, svgDataUrl, textImage };
|
package/dist/catalog/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import {
|
|
|
2
2
|
CURRENT_COLOR,
|
|
3
3
|
EFFECTS,
|
|
4
4
|
EFFECT_CATEGORIES,
|
|
5
|
+
EFFECT_INPUTS,
|
|
6
|
+
EFFECT_INTERACTIONS,
|
|
5
7
|
FBM,
|
|
6
8
|
HASH,
|
|
7
9
|
NOISE,
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
colorControl,
|
|
16
18
|
effectControls,
|
|
17
19
|
effectDefaults,
|
|
20
|
+
effectInputs,
|
|
18
21
|
findEffects,
|
|
19
22
|
getEffect,
|
|
20
23
|
glsl,
|
|
@@ -27,7 +30,7 @@ import {
|
|
|
27
30
|
vectorControlIssues,
|
|
28
31
|
vectorControls,
|
|
29
32
|
vectorEffectControls
|
|
30
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-4F4KL4KU.js";
|
|
31
34
|
import "../chunk-OHW7UG6D.js";
|
|
32
35
|
import "../chunk-EHDJ3CPJ.js";
|
|
33
36
|
import "../chunk-VYOMXE6I.js";
|
|
@@ -35,6 +38,8 @@ export {
|
|
|
35
38
|
CURRENT_COLOR,
|
|
36
39
|
EFFECTS,
|
|
37
40
|
EFFECT_CATEGORIES,
|
|
41
|
+
EFFECT_INPUTS,
|
|
42
|
+
EFFECT_INTERACTIONS,
|
|
38
43
|
FBM,
|
|
39
44
|
HASH,
|
|
40
45
|
NOISE,
|
|
@@ -48,6 +53,7 @@ export {
|
|
|
48
53
|
colorControl,
|
|
49
54
|
effectControls,
|
|
50
55
|
effectDefaults,
|
|
56
|
+
effectInputs,
|
|
51
57
|
findEffects,
|
|
52
58
|
getEffect,
|
|
53
59
|
glsl,
|
|
@@ -14,6 +14,68 @@ import {
|
|
|
14
14
|
rgbToHex
|
|
15
15
|
} from "./chunk-VYOMXE6I.js";
|
|
16
16
|
|
|
17
|
+
// src/catalog/inputs.ts
|
|
18
|
+
var EFFECT_INPUTS = ["image", "video", "svg", "text", "mask", "path"];
|
|
19
|
+
var EFFECT_INTERACTIONS = ["hover", "press", "click", "trail", "pointer"];
|
|
20
|
+
function isTextImage(url) {
|
|
21
|
+
if (!url.startsWith("data:image/svg+xml;charset=utf-8,")) return false;
|
|
22
|
+
try {
|
|
23
|
+
return decodeURIComponent(url.slice(url.indexOf(",") + 1)).includes("<text");
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var PATH_DATA = /^\s*[Mm]\s*[-+.\d]/;
|
|
29
|
+
function textSlot(control) {
|
|
30
|
+
const value = String(control.default);
|
|
31
|
+
const holds2 = control.name === "font" || /\bfont\b/i.test(control.label) ? "font" : PATH_DATA.test(value) ? "path" : control.name === "glyphs" ? "glyphs" : "copy";
|
|
32
|
+
return { name: control.name, label: control.label, holds: holds2, default: value };
|
|
33
|
+
}
|
|
34
|
+
function shaderInteractions(source) {
|
|
35
|
+
const code = source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, "");
|
|
36
|
+
const found = /* @__PURE__ */ new Set();
|
|
37
|
+
if (/\biClicks\b/.test(code)) found.add("click");
|
|
38
|
+
if (/\biTrail\b/.test(code)) found.add("trail");
|
|
39
|
+
if (/\biPointer\s*\.\s*z\b/.test(code)) found.add("hover");
|
|
40
|
+
if (/\biPointer\s*\.\s*w\b/.test(code) || /\biMouse\s*\.\s*z\b/.test(code)) found.add("press");
|
|
41
|
+
if (/\biPointer\s*\.\s*xy?\b/.test(code) || /\biMouse\s*\.\s*xy?\b/.test(code)) found.add("pointer");
|
|
42
|
+
return EFFECT_INTERACTIONS.filter((i) => found.has(i));
|
|
43
|
+
}
|
|
44
|
+
function inputsOf(effect, controls) {
|
|
45
|
+
const accepts = /* @__PURE__ */ new Set();
|
|
46
|
+
const images = [];
|
|
47
|
+
const texts = [];
|
|
48
|
+
for (const control of controls) {
|
|
49
|
+
if (control.type === "sampler2D") {
|
|
50
|
+
const value = String(control.default);
|
|
51
|
+
const video = effect.kind === "shader" ? effect.video : void 0;
|
|
52
|
+
const wants = isTextImage(value) ? "text" : video === "none" ? "mask" : "picture";
|
|
53
|
+
images.push({ name: control.name, label: control.label, wants });
|
|
54
|
+
if (wants === "picture") {
|
|
55
|
+
accepts.add("image").add("svg");
|
|
56
|
+
if (video && video !== "none") accepts.add("video");
|
|
57
|
+
} else {
|
|
58
|
+
accepts.add("mask").add("svg").add("text").add("image");
|
|
59
|
+
}
|
|
60
|
+
} else if (control.type === "text") {
|
|
61
|
+
const slot = textSlot(control);
|
|
62
|
+
texts.push(slot);
|
|
63
|
+
if (slot.holds === "copy") accepts.add("text");
|
|
64
|
+
if (slot.holds === "path") accepts.add("path");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const interactions = effect.kind === "vector" ? effect.trigger ? [effect.trigger] : [] : shaderInteractions(effect.source);
|
|
68
|
+
return {
|
|
69
|
+
accepts: EFFECT_INPUTS.filter((i) => accepts.has(i)),
|
|
70
|
+
images,
|
|
71
|
+
texts,
|
|
72
|
+
...effect.kind === "shader" && effect.video ? { video: effect.video } : {},
|
|
73
|
+
interactions,
|
|
74
|
+
...effect.kind === "vector" && effect.trigger ? { trigger: effect.trigger } : {},
|
|
75
|
+
transparent: effect.kind === "shader" ? Boolean(effect.transparent) : false
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
17
79
|
// src/catalog/glsl.ts
|
|
18
80
|
var HASH = `
|
|
19
81
|
float hash12(vec2 p) {
|
|
@@ -456,17 +518,16 @@ var imageDuotone = {
|
|
|
456
518
|
kind: "shader",
|
|
457
519
|
id: "image-duotone",
|
|
458
520
|
name: "Duotone",
|
|
459
|
-
description: "An image mapped onto two colours,
|
|
521
|
+
description: "An image mapped onto two colours, from its shadows to its highlights. For a passing glare, lay `shine-sweep` over it.",
|
|
460
522
|
category: "image",
|
|
461
523
|
video: "filter",
|
|
462
524
|
tags: ["image", "brand", "editorial", "colour"],
|
|
463
525
|
source: glsl(
|
|
464
|
-
`// Duotone: an image mapped onto two colours
|
|
526
|
+
`// Duotone: an image mapped onto two colours by its brightness.
|
|
465
527
|
uniform sampler2D uImage; // @control filter=linear wrap=clamp default=${SAMPLE_IMAGES.landscape} label="Image"
|
|
466
528
|
uniform vec3 uShadow; // @control color default=#1E1B4B label="Shadows"
|
|
467
529
|
uniform vec3 uHighlight; // @control color default=#FB7185 label="Highlights"
|
|
468
530
|
uniform float uContrast; // @control min=0.5 max=3 default=1.2 label="Contrast"
|
|
469
|
-
uniform float uSweep; // @control min=0 max=1 default=0.3 label="Light sweep"
|
|
470
531
|
${BACKDROP_CONTROLS}`,
|
|
471
532
|
PICTURE,
|
|
472
533
|
`void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
@@ -474,9 +535,7 @@ ${BACKDROP_CONTROLS}`,
|
|
|
474
535
|
vec4 src = pictureRGBA(uImage, uv);
|
|
475
536
|
float l = dot(src.rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
476
537
|
l = clamp((l - 0.5) * uContrast + 0.5, 0.0, 1.0);
|
|
477
|
-
|
|
478
|
-
vec3 col = mix(uShadow, uHighlight, l) + sweep * uSweep;
|
|
479
|
-
fragColor = vec4(col, src.a);
|
|
538
|
+
fragColor = vec4(mix(uShadow, uHighlight, l), src.a);
|
|
480
539
|
}`
|
|
481
540
|
),
|
|
482
541
|
presets: [
|
|
@@ -10245,7 +10304,7 @@ var fireworks = {
|
|
|
10245
10304
|
name: "Fireworks",
|
|
10246
10305
|
description: "Shells rising on faint trails and bursting into peonies, chrysanthemums, gold willows and rings that droop and twinkle out; clicks fire more.",
|
|
10247
10306
|
category: "pyrotechnics",
|
|
10248
|
-
tags: ["pyro", "overlay", "fireworks", "celebration", "festive", "night", "click"],
|
|
10307
|
+
tags: ["pyro", "overlay", "fireworks", "celebration", "festive", "night", "click", "interactive"],
|
|
10249
10308
|
transparent: true,
|
|
10250
10309
|
source: glsl(
|
|
10251
10310
|
`// Fireworks: staggered shells rising and bursting into peony, chrysanthemum, willow and ring patterns.
|
|
@@ -10464,7 +10523,7 @@ var explosion = {
|
|
|
10464
10523
|
name: "Explosion",
|
|
10465
10524
|
description: "A fireball cooling from white-hot to orange to rolling dark smoke, with a shockwave ring and flying debris; it loops and also goes off at each click.",
|
|
10466
10525
|
category: "pyrotechnics",
|
|
10467
|
-
tags: ["pyro", "overlay", "explosion", "fire", "smoke", "action", "click"],
|
|
10526
|
+
tags: ["pyro", "overlay", "explosion", "fire", "smoke", "action", "click", "interactive"],
|
|
10468
10527
|
transparent: true,
|
|
10469
10528
|
loop: 3,
|
|
10470
10529
|
source: glsl(
|
|
@@ -11311,7 +11370,7 @@ var bulletTime = {
|
|
|
11311
11370
|
description: "A shockwave sweeping out from the centre or a click, freezing the picture grey and zoomed behind it while the rest moves on.",
|
|
11312
11371
|
category: "timewarp",
|
|
11313
11372
|
video: "stills",
|
|
11314
|
-
tags: ["time", "image", "freeze", "shockwave", "click", "cinematic"],
|
|
11373
|
+
tags: ["time", "image", "freeze", "shockwave", "click", "cinematic", "interactive"],
|
|
11315
11374
|
loop: 8,
|
|
11316
11375
|
source: glsl(
|
|
11317
11376
|
`// Bullet time: every 4 s (or on a click) a wave freezes the picture behind it, then lets go.
|
|
@@ -11662,7 +11721,7 @@ var silhouetteMorph = {
|
|
|
11662
11721
|
name: "Silhouette morph",
|
|
11663
11722
|
description: "One silhouette or logo flowing into another as a gooey blob, its colour blending from the first shape's to the second's.",
|
|
11664
11723
|
category: "morph",
|
|
11665
|
-
video: "
|
|
11724
|
+
video: "none",
|
|
11666
11725
|
tags: ["morph", "shape", "logo", "goo", "blob", "text"],
|
|
11667
11726
|
loop: 4,
|
|
11668
11727
|
source: glsl(
|
|
@@ -20131,6 +20190,12 @@ var byId = new Map(EFFECTS.map((e) => [e.id, e]));
|
|
|
20131
20190
|
function getEffect(id) {
|
|
20132
20191
|
return byId.get(id);
|
|
20133
20192
|
}
|
|
20193
|
+
var inputsCache = /* @__PURE__ */ new WeakMap();
|
|
20194
|
+
function effectInputs(effect) {
|
|
20195
|
+
let inputs = inputsCache.get(effect);
|
|
20196
|
+
if (!inputs) inputsCache.set(effect, inputs = inputsOf(effect, effectControls(effect)));
|
|
20197
|
+
return inputs;
|
|
20198
|
+
}
|
|
20134
20199
|
function findEffects(query = {}) {
|
|
20135
20200
|
const words = (query.text ?? "").toLowerCase().split(/\s+/).filter(Boolean);
|
|
20136
20201
|
return EFFECTS.filter((e) => {
|
|
@@ -20138,6 +20203,15 @@ function findEffects(query = {}) {
|
|
|
20138
20203
|
if (query.kind && e.kind !== query.kind) return false;
|
|
20139
20204
|
if (query.tags && !query.tags.every((t) => e.tags.includes(t))) return false;
|
|
20140
20205
|
if (query.video && !(e.kind === "shader" && e.video && query.video.includes(e.video))) return false;
|
|
20206
|
+
if (query.accepts || query.interaction || query.transparent !== void 0) {
|
|
20207
|
+
const inputs = effectInputs(e);
|
|
20208
|
+
if (query.accepts && !query.accepts.every((i) => inputs.accepts.includes(i))) return false;
|
|
20209
|
+
if (query.interaction) {
|
|
20210
|
+
const answers = query.interaction.length === 0 ? inputs.interactions.length === 0 : query.interaction.some((i) => inputs.interactions.includes(i));
|
|
20211
|
+
if (!answers) return false;
|
|
20212
|
+
}
|
|
20213
|
+
if (query.transparent !== void 0 && inputs.transparent !== query.transparent) return false;
|
|
20214
|
+
}
|
|
20141
20215
|
const haystack = [e.id, e.name, e.description, e.category, ...e.tags].join(" ").toLowerCase();
|
|
20142
20216
|
return words.every((w) => haystack.includes(w));
|
|
20143
20217
|
});
|
|
@@ -20153,6 +20227,8 @@ function effectDefaults(effect, options = {}) {
|
|
|
20153
20227
|
}
|
|
20154
20228
|
|
|
20155
20229
|
export {
|
|
20230
|
+
EFFECT_INPUTS,
|
|
20231
|
+
EFFECT_INTERACTIONS,
|
|
20156
20232
|
HASH,
|
|
20157
20233
|
NOISE,
|
|
20158
20234
|
FBM,
|
|
@@ -20178,8 +20254,9 @@ export {
|
|
|
20178
20254
|
SHADER_EFFECTS,
|
|
20179
20255
|
EFFECTS,
|
|
20180
20256
|
getEffect,
|
|
20257
|
+
effectInputs,
|
|
20181
20258
|
findEffects,
|
|
20182
20259
|
effectControls,
|
|
20183
20260
|
effectDefaults
|
|
20184
20261
|
};
|
|
20185
|
-
//# sourceMappingURL=chunk-
|
|
20262
|
+
//# sourceMappingURL=chunk-4F4KL4KU.js.map
|