@fabi-play/engine 0.4.0 → 0.7.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/README.md +14 -0
- package/dist/fabi-play-engine.d.ts +68 -8
- package/dist/fabi-play-engine.js +13 -13
- package/dist/fabi-play-engine.lite.d.ts +68 -8
- package/dist/fabi-play-engine.lite.js +13 -13
- package/dist/fabi-play-engine.lite.umd.js +119 -20
- package/dist/fabi-play-engine.lite.umd.min.js +13 -13
- package/dist/fabi-play-engine.umd.js +119 -20
- package/dist/fabi-play-engine.umd.min.js +13 -13
- package/dist/index.d.ts +68 -8
- package/dist/index.development.js +118 -19
- package/dist/index.js +13 -13
- package/dist/integrity.json +9 -9
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -71,6 +71,36 @@ export interface BackdropView {
|
|
|
71
71
|
/** Height, a fraction of the viewport's height. */
|
|
72
72
|
h: number;
|
|
73
73
|
}
|
|
74
|
+
/** A hand: the child's own left or right. */
|
|
75
|
+
export type HandSide = "left" | "right";
|
|
76
|
+
declare class AimHold {
|
|
77
|
+
readonly holdMs: number;
|
|
78
|
+
private readonly last;
|
|
79
|
+
constructor(holdMs?: number);
|
|
80
|
+
/** A number for a player's hand. */
|
|
81
|
+
static key(player: number, side: HandSide): number;
|
|
82
|
+
/** The aim to use at time t (ms) for the hand key, given what aimPoint said now (p, or null if lost). */
|
|
83
|
+
at(key: number, p: Point | null, t: number): Point | null;
|
|
84
|
+
/** Forgets every hand. */
|
|
85
|
+
clear(): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The parts of the game's viewport a phone's notch, rounded corners or home bar may cover, in fractions of the
|
|
89
|
+
* viewport (top and bottom of its height, left and right of its width; each 0–0.25). The game's frame cannot read
|
|
90
|
+
* env(safe-area-inset-*), so the screen sends it (init.safeArea): keep buttons, scores and targets out of it, and
|
|
91
|
+
* still paint the background under it. Zeros where nothing is covered (a TV, a tablet, older hosts).
|
|
92
|
+
*/
|
|
93
|
+
export interface SafeArea {
|
|
94
|
+
top: number;
|
|
95
|
+
bottom: number;
|
|
96
|
+
left: number;
|
|
97
|
+
right: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A screen's orientation: 'landscape' when its width is at least its height, else 'portrait' (see orientationOf).
|
|
101
|
+
* GameManifest.orientations lists those a game supports; HostMessage init.orientation says the one it starts in.
|
|
102
|
+
*/
|
|
103
|
+
export type Orientation = "landscape" | "portrait";
|
|
74
104
|
/**
|
|
75
105
|
* Small pure helpers: 2D affine matrices, colours, easing. No DOM here, so they run in Node tests.
|
|
76
106
|
*/
|
|
@@ -1324,11 +1354,18 @@ export declare function wrists(body: Body): {
|
|
|
1324
1354
|
}[];
|
|
1325
1355
|
/** A player's colour (CSS), as the TV draws them: player 1 orange, 2 blue, 3 green, 4 lilac, then again. */
|
|
1326
1356
|
export declare const playerColor: (player: number) => "#EE6A43" | "#6FA0E0" | "#8CC9A0" | "#C49BE0";
|
|
1357
|
+
/** handsOf's aim: the screen's orientation and, in portrait, what keeps hands through short losses (and its clock, ms). */
|
|
1358
|
+
export interface HandsAim {
|
|
1359
|
+
orientation?: Orientation;
|
|
1360
|
+
hold?: AimHold;
|
|
1361
|
+
t?: number;
|
|
1362
|
+
}
|
|
1327
1363
|
/**
|
|
1328
|
-
* Every player's hands in stage units
|
|
1329
|
-
*
|
|
1364
|
+
* Every player's hands in stage units, where they aim (the protocol's aimPoint), times the stage size; bodyOf(frame)
|
|
1365
|
+
* is the body to read (null: the frame's own). Landscape (the default): its wrists through toScreen (player space to
|
|
1366
|
+
* screen fractions). Portrait (aim.orientation): the wrists stretched to the whole screen, held by aim.hold if given.
|
|
1330
1367
|
*/
|
|
1331
|
-
export declare function handsOf(frames: readonly PlayerFrame[], toScreen: (p: Point) => Point, width: number, height: number, bodyOf?: (f: PlayerFrame) => Body | null): Hand[];
|
|
1368
|
+
export declare function handsOf(frames: readonly PlayerFrame[], toScreen: (p: Point) => Point, width: number, height: number, bodyOf?: (f: PlayerFrame) => Body | null, aim?: HandsAim): Hand[];
|
|
1332
1369
|
/** What a node offers to hit tests: its world transform, size and anchor, or a radius. */
|
|
1333
1370
|
export interface Hittable {
|
|
1334
1371
|
/** The node's transform to the stage. */
|
|
@@ -1505,6 +1542,10 @@ export interface PlayLike {
|
|
|
1505
1542
|
readonly backdrop?: Backdrop;
|
|
1506
1543
|
/** Where the camera image is on the screen, in fractions; null if unknown. */
|
|
1507
1544
|
readonly view?: BackdropView | null;
|
|
1545
|
+
/** The screen's orientation at the start ('landscape' if unknown): in 'portrait' the hands aim (see Engine.hands). */
|
|
1546
|
+
readonly orientation?: Orientation;
|
|
1547
|
+
/** What a phone's notch and home bar cover, fractions of the viewport (see Engine.safeArea). */
|
|
1548
|
+
readonly safeArea?: SafeArea;
|
|
1508
1549
|
/** The screen's sound is off. */
|
|
1509
1550
|
readonly muted?: boolean;
|
|
1510
1551
|
/** What the screen knows about the device (init.device): a starting tier and the display's rate. */
|
|
@@ -1614,6 +1655,18 @@ export interface Engine {
|
|
|
1614
1655
|
readonly backdrop: Backdrop;
|
|
1615
1656
|
/** Where the camera image is on the screen, in fractions; null if the host didn't say. */
|
|
1616
1657
|
readonly view: BackdropView | null;
|
|
1658
|
+
/**
|
|
1659
|
+
* The screen's orientation when the game started: 'landscape' (a TV, a tablet; also before the host says) or
|
|
1660
|
+
* 'portrait' (a phone held upright). It decides where hands() are (see there).
|
|
1661
|
+
*/
|
|
1662
|
+
readonly orientation: Orientation;
|
|
1663
|
+
/**
|
|
1664
|
+
* What a phone's notch, rounded corners and home bar cover, in fractions of the viewport (top and bottom of its
|
|
1665
|
+
* height, left and right of its width; each 0–0.25; zeros on a TV, a tablet, and from hosts that don't say). The
|
|
1666
|
+
* game's frame can't read env(safe-area-inset-*): keep buttons, scores and targets out of it (in stage units, top
|
|
1667
|
+
* × 720, left × stage.width), still paint the background under it.
|
|
1668
|
+
*/
|
|
1669
|
+
readonly safeArea: Readonly<SafeArea>;
|
|
1617
1670
|
/** Paused by the host (pause, break) or by pause(): game time, tweens, particles and sound are stopped. */
|
|
1618
1671
|
readonly paused: boolean;
|
|
1619
1672
|
/** Sounds and tones, quiet while paused or muted. */
|
|
@@ -1700,9 +1753,16 @@ export interface Engine {
|
|
|
1700
1753
|
* bitmap fonts (.fnt, or a BMFont .json, + page images), sounds and fonts, by name.
|
|
1701
1754
|
*/
|
|
1702
1755
|
load(assets: Record<string, string>): Promise<void>;
|
|
1703
|
-
/**
|
|
1756
|
+
/**
|
|
1757
|
+
* This frame's hands (of one player, or everyone's), stage units, where they aim: what they touch, catch, press.
|
|
1758
|
+
* Landscape (a TV, a tablet): in the avatar's hands, or on the real ones over the video. Portrait (a phone held
|
|
1759
|
+
* upright, where the camera image is small at the bottom): the wrists stretched around the shoulders to the whole
|
|
1760
|
+
* stage (the protocol's aimPoint), so arms straight up reach the top (y ≈ 0.15 × 720) and arms out the sides, held
|
|
1761
|
+
* for 300 ms when the camera loses a wrist; the avatars are still drawn small in the view. To draw on the body
|
|
1762
|
+
* itself, use toScreen(wrist) of the SDK. touched() and handMarkers() use these hands.
|
|
1763
|
+
*/
|
|
1704
1764
|
hands(player?: number): Hand[];
|
|
1705
|
-
/** The first hand (of one player, or anyone's) touching the node, or null. padding: stage units. */
|
|
1765
|
+
/** The first hand (of one player, or anyone's) touching the node, or null; the hands are hands()'s. padding: stage units. */
|
|
1706
1766
|
touched(node: Node, player?: number, opts?: {
|
|
1707
1767
|
padding?: number;
|
|
1708
1768
|
}): Hand | null;
|
|
@@ -1912,7 +1972,7 @@ export interface FaceDef {
|
|
|
1912
1972
|
/** Eyebrows of this colour (people): a little attitude. */
|
|
1913
1973
|
brows?: string;
|
|
1914
1974
|
}
|
|
1915
|
-
/** The age band an avatar is for, or 'all':
|
|
1975
|
+
/** The age band an avatar is for, or 'all': of no band (Fabi the fox, the app's mascot: the host, in no picker). */
|
|
1916
1976
|
export type AvatarBand = AgeRange | "all";
|
|
1917
1977
|
/** An avatar, as data: one renderer draws any definition. */
|
|
1918
1978
|
export interface AvatarDef {
|
|
@@ -1925,7 +1985,7 @@ export interface AvatarDef {
|
|
|
1925
1985
|
};
|
|
1926
1986
|
/**
|
|
1927
1987
|
* The age band the avatar is for, its home: its style and its body proportions (see BAND_BODY in rig.ts). 'all': in
|
|
1928
|
-
*
|
|
1988
|
+
* no band's list (the mascot), drawn with the 6–8 proportions. See alsoIn for an avatar offered in other bands too.
|
|
1929
1989
|
*/
|
|
1930
1990
|
band: AvatarBand;
|
|
1931
1991
|
/**
|
|
@@ -1934,7 +1994,7 @@ export interface AvatarDef {
|
|
|
1934
1994
|
* (outline), bandOf, and its proportions when the band shown is not known. Not for 'all' (the mascot).
|
|
1935
1995
|
*/
|
|
1936
1996
|
alsoIn?: readonly AgeRange[];
|
|
1937
|
-
/** A special avatar (the mascot):
|
|
1997
|
+
/** A special avatar (the mascot): the host, not a player; in no band's list (AVATAR_BANDS). */
|
|
1938
1998
|
special?: boolean;
|
|
1939
1999
|
/** Its colours. */
|
|
1940
2000
|
palette: Palette;
|
|
@@ -28,6 +28,77 @@ var DEFAULT_AVATARS_BY_AGE = {
|
|
|
28
28
|
};
|
|
29
29
|
var DEFAULT_AVATARS = DEFAULT_AVATARS_BY_AGE["6-8"];
|
|
30
30
|
var toScreen = (view, p) => view ? { x: view.x + p.x * view.w, y: view.y + p.y * view.h } : { x: p.x, y: p.y };
|
|
31
|
+
var AIM_VISIBLE = 0.5;
|
|
32
|
+
var HAND_SPACE = { left: 1.6, top: 1.6, w: 3.2, h: 3 };
|
|
33
|
+
var TORSO_PER_SHOULDER_WIDTH = 1.2;
|
|
34
|
+
function aimPoint(who, side, opts = {}) {
|
|
35
|
+
const body = Array.isArray(who) ? who : who.body;
|
|
36
|
+
if (!Array.isArray(body)) return null;
|
|
37
|
+
const w2 = side === "left" ? P.leftWrist : P.rightWrist;
|
|
38
|
+
const at = (i) => isNumber(body[i * 3]) && isNumber(body[i * 3 + 1]) && (body[i * 3 + 2] ?? 0) >= AIM_VISIBLE ? i : -1;
|
|
39
|
+
if (at(w2) < 0) return null;
|
|
40
|
+
const wx = body[w2 * 3];
|
|
41
|
+
const wy = body[w2 * 3 + 1];
|
|
42
|
+
if (opts.orientation !== "portrait") return toScreen(opts.view, { x: wx, y: wy });
|
|
43
|
+
if (at(P.leftShoulder) < 0 || at(P.rightShoulder) < 0) return null;
|
|
44
|
+
const ls = P.leftShoulder * 3;
|
|
45
|
+
const rs = P.rightShoulder * 3;
|
|
46
|
+
const sx = (body[ls] + body[rs]) / 2;
|
|
47
|
+
const sy = (body[ls + 1] + body[rs + 1]) / 2;
|
|
48
|
+
const lh = P.leftHip * 3;
|
|
49
|
+
const rh = P.rightHip * 3;
|
|
50
|
+
const hx = (body[lh] + body[rh]) / 2;
|
|
51
|
+
const hy = (body[lh + 1] + body[rh + 1]) / 2;
|
|
52
|
+
let torso = isNumber(hx) && isNumber(hy) ? Math.hypot(hx - sx, hy - sy) : 0;
|
|
53
|
+
if (at(P.leftHip) < 0 || at(P.rightHip) < 0) torso = Math.max(torso, TORSO_PER_SHOULDER_WIDTH * Math.hypot(body[ls] - body[rs], body[ls + 1] - body[rs + 1]));
|
|
54
|
+
torso = Math.max(torso, 0.01);
|
|
55
|
+
return {
|
|
56
|
+
x: clamp01((wx - sx + HAND_SPACE.left * torso) / (HAND_SPACE.w * torso)),
|
|
57
|
+
y: clamp01((wy - sy + HAND_SPACE.top * torso) / (HAND_SPACE.h * torso))
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
var AIM_HOLD_MS = 300;
|
|
61
|
+
var AimHold = class {
|
|
62
|
+
constructor(holdMs = AIM_HOLD_MS) {
|
|
63
|
+
__publicField(this, "holdMs", holdMs);
|
|
64
|
+
__publicField(this, "last", /* @__PURE__ */ new Map());
|
|
65
|
+
}
|
|
66
|
+
/** A number for a player's hand. */
|
|
67
|
+
static key(player, side) {
|
|
68
|
+
return player * 2 + (side === "right" ? 1 : 0);
|
|
69
|
+
}
|
|
70
|
+
/** The aim to use at time t (ms) for the hand key, given what aimPoint said now (p, or null if lost). */
|
|
71
|
+
at(key, p, t) {
|
|
72
|
+
const l = this.last.get(key);
|
|
73
|
+
if (p) {
|
|
74
|
+
if (l) {
|
|
75
|
+
l.x = p.x;
|
|
76
|
+
l.y = p.y;
|
|
77
|
+
l.t = t;
|
|
78
|
+
} else this.last.set(key, { x: p.x, y: p.y, t });
|
|
79
|
+
return p;
|
|
80
|
+
}
|
|
81
|
+
if (!l) return null;
|
|
82
|
+
if (t - l.t <= this.holdMs) return { x: l.x, y: l.y };
|
|
83
|
+
this.last.delete(key);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
/** Forgets every hand. */
|
|
87
|
+
clear() {
|
|
88
|
+
this.last.clear();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var MAX_SAFE_INSET = 0.25;
|
|
92
|
+
var NO_SAFE_AREA = Object.freeze({ top: 0, bottom: 0, left: 0, right: 0 });
|
|
93
|
+
function parseSafeArea(v) {
|
|
94
|
+
if (!isObject(v)) return void 0;
|
|
95
|
+
const f = (n) => isNumber(n) ? Math.min(Math.max(n, 0), MAX_SAFE_INSET) : 0;
|
|
96
|
+
return { top: f(v.top), bottom: f(v.bottom), left: f(v.left), right: f(v.right) };
|
|
97
|
+
}
|
|
98
|
+
var COVER_ASPECT = 16 / 9;
|
|
99
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
100
|
+
var isNumber = (v) => typeof v === "number" && Number.isFinite(v);
|
|
101
|
+
var clamp01 = (n) => Math.min(Math.max(n, 0), 1);
|
|
31
102
|
var POSE_HEADER = 12;
|
|
32
103
|
var POSE_BODY_BYTES = LANDMARKS * 4;
|
|
33
104
|
var poseBytes = (bodies) => POSE_HEADER + bodies * POSE_BODY_BYTES;
|
|
@@ -4335,11 +4406,20 @@ function wrists(body) {
|
|
|
4335
4406
|
return out;
|
|
4336
4407
|
}
|
|
4337
4408
|
var playerColor = (player) => PLAYER_COLORS[((player - 1) % PLAYER_COLORS.length + PLAYER_COLORS.length) % PLAYER_COLORS.length];
|
|
4338
|
-
|
|
4409
|
+
var SIDES = ["left", "right"];
|
|
4410
|
+
function handsOf(frames, toScreen2, width, height, bodyOf = () => null, aim = {}) {
|
|
4339
4411
|
const out = [];
|
|
4340
4412
|
for (const f of frames) {
|
|
4341
4413
|
const body = bodyOf(f) ?? f.body;
|
|
4342
4414
|
if (!Array.isArray(body)) continue;
|
|
4415
|
+
if (aim.orientation === "portrait") {
|
|
4416
|
+
for (const side of SIDES) {
|
|
4417
|
+
let p = aimPoint(body, side, { orientation: "portrait" });
|
|
4418
|
+
if (aim.hold) p = aim.hold.at(AimHold.key(f.id, side), p, aim.t ?? 0);
|
|
4419
|
+
if (p) out.push({ player: f.id, side, x: p.x * width, y: p.y * height, color: playerColor(f.id) });
|
|
4420
|
+
}
|
|
4421
|
+
continue;
|
|
4422
|
+
}
|
|
4343
4423
|
for (const w2 of wrists(body)) {
|
|
4344
4424
|
const s = toScreen2(w2);
|
|
4345
4425
|
out.push({ player: f.id, side: w2.side, x: s.x * width, y: s.y * height, color: playerColor(f.id) });
|
|
@@ -5001,6 +5081,10 @@ var HandMarkers = class extends Node {
|
|
|
5001
5081
|
}
|
|
5002
5082
|
};
|
|
5003
5083
|
var now = () => performance.now();
|
|
5084
|
+
var frozenSafeArea = (v) => {
|
|
5085
|
+
const sa = parseSafeArea(v);
|
|
5086
|
+
return sa && Object.freeze(sa);
|
|
5087
|
+
};
|
|
5004
5088
|
async function createEngine(opts = {}) {
|
|
5005
5089
|
const play = opts.play ?? null;
|
|
5006
5090
|
let canvas = opts.canvas ?? null;
|
|
@@ -5135,6 +5219,8 @@ async function createEngine(opts = {}) {
|
|
|
5135
5219
|
ro?.observe(canvas);
|
|
5136
5220
|
let backdrop = play?.backdrop === "video" ? "video" : "none";
|
|
5137
5221
|
let view = play?.view ?? null;
|
|
5222
|
+
let orientation = play?.orientation === "portrait" ? "portrait" : "landscape";
|
|
5223
|
+
let safeArea = frozenSafeArea(play?.safeArea) ?? NO_SAFE_AREA;
|
|
5138
5224
|
let livePlayers = [];
|
|
5139
5225
|
let lastPlayersAt = -Infinity;
|
|
5140
5226
|
let hostPaused = false;
|
|
@@ -5162,7 +5248,7 @@ async function createEngine(opts = {}) {
|
|
|
5162
5248
|
lastPlayersAt = now();
|
|
5163
5249
|
}
|
|
5164
5250
|
};
|
|
5165
|
-
const
|
|
5251
|
+
const hold2 = (on) => {
|
|
5166
5252
|
hostPaused = on;
|
|
5167
5253
|
syncSound();
|
|
5168
5254
|
};
|
|
@@ -5176,6 +5262,11 @@ async function createEngine(opts = {}) {
|
|
|
5176
5262
|
};
|
|
5177
5263
|
unlisten.push(
|
|
5178
5264
|
play.on("start", (m) => lateHint(m?.device)),
|
|
5265
|
+
play.on("start", (m) => {
|
|
5266
|
+
if (m?.orientation === "portrait" || m?.orientation === "landscape") orientation = m.orientation;
|
|
5267
|
+
const sa = frozenSafeArea(m?.safeArea);
|
|
5268
|
+
if (sa) safeArea = sa;
|
|
5269
|
+
}),
|
|
5179
5270
|
// The simple API knows muted only from the start (its getter is false before): read it again then.
|
|
5180
5271
|
play.on("start", (m) => {
|
|
5181
5272
|
if (typeof m?.muted === "boolean") sound.muted = m.muted;
|
|
@@ -5184,11 +5275,11 @@ async function createEngine(opts = {}) {
|
|
|
5184
5275
|
play.on("players", (m) => setPlayers(m?.players)),
|
|
5185
5276
|
play.on("backdrop", (m) => setBackdrop(m?.backdrop, m?.view)),
|
|
5186
5277
|
play.on("start", (m) => setBackdrop(m?.backdrop, m?.view ?? play.view)),
|
|
5187
|
-
play.on("pause", () =>
|
|
5188
|
-
play.on("resume", () =>
|
|
5189
|
-
play.on("break-start", () =>
|
|
5190
|
-
play.on("break-done", () =>
|
|
5191
|
-
play.on("break-end", () =>
|
|
5278
|
+
play.on("pause", () => hold2(true)),
|
|
5279
|
+
play.on("resume", () => hold2(false)),
|
|
5280
|
+
play.on("break-start", () => hold2(true)),
|
|
5281
|
+
play.on("break-done", () => hold2(false)),
|
|
5282
|
+
play.on("break-end", () => hold2(false))
|
|
5192
5283
|
);
|
|
5193
5284
|
sound.muted = play.muted === true;
|
|
5194
5285
|
}
|
|
@@ -5199,11 +5290,13 @@ async function createEngine(opts = {}) {
|
|
|
5199
5290
|
let tick = 0;
|
|
5200
5291
|
const live = () => now() - lastPlayersAt < 1e3 ? livePlayers : [];
|
|
5201
5292
|
const toScreen2 = (p) => play ? play.toScreen(p) : toScreen(view, p);
|
|
5293
|
+
const hold = new AimHold();
|
|
5202
5294
|
const allHands = () => {
|
|
5203
5295
|
if (handsAt === tick) return handsCache;
|
|
5204
5296
|
handsAt = tick;
|
|
5205
|
-
const
|
|
5206
|
-
|
|
5297
|
+
const portrait = orientation === "portrait";
|
|
5298
|
+
const bodyOf = backdrop === "video" && !portrait || !play?.smoothedBody ? () => null : (f) => play.smoothedBody(f);
|
|
5299
|
+
handsCache = handsOf(live(), toScreen2, stageW, STAGE_HEIGHT, bodyOf, portrait ? { orientation, hold, t: now() } : void 0);
|
|
5207
5300
|
return handsCache;
|
|
5208
5301
|
};
|
|
5209
5302
|
const box = { x: 0, y: 0, w: 1, h: 1 };
|
|
@@ -5366,6 +5459,12 @@ async function createEngine(opts = {}) {
|
|
|
5366
5459
|
get view() {
|
|
5367
5460
|
return view;
|
|
5368
5461
|
},
|
|
5462
|
+
get orientation() {
|
|
5463
|
+
return orientation;
|
|
5464
|
+
},
|
|
5465
|
+
get safeArea() {
|
|
5466
|
+
return safeArea;
|
|
5467
|
+
},
|
|
5369
5468
|
get paused() {
|
|
5370
5469
|
return hostPaused || userPaused;
|
|
5371
5470
|
},
|
|
@@ -6225,7 +6324,7 @@ ${msg}`);
|
|
|
6225
6324
|
};
|
|
6226
6325
|
|
|
6227
6326
|
// src/filters.ts
|
|
6228
|
-
var
|
|
6327
|
+
var clamp012 = (v) => Math.min(Math.max(v, 0), 1);
|
|
6229
6328
|
var pos = (v) => Math.max(v, 0);
|
|
6230
6329
|
var Base = class {
|
|
6231
6330
|
constructor() {
|
|
@@ -6277,11 +6376,11 @@ var Contrast = class extends Amount {
|
|
|
6277
6376
|
};
|
|
6278
6377
|
var Invert = class extends Amount {
|
|
6279
6378
|
toMatrix(m) {
|
|
6280
|
-
const a =
|
|
6379
|
+
const a = clamp012(this.amount);
|
|
6281
6380
|
linear(m, 1 - 2 * a, a);
|
|
6282
6381
|
}
|
|
6283
6382
|
css() {
|
|
6284
|
-
return `invert(${
|
|
6383
|
+
return `invert(${clamp012(this.amount)})`;
|
|
6285
6384
|
}
|
|
6286
6385
|
};
|
|
6287
6386
|
var Saturate = class extends Amount {
|
|
@@ -6304,7 +6403,7 @@ var Saturate = class extends Amount {
|
|
|
6304
6403
|
};
|
|
6305
6404
|
var Grayscale = class extends Amount {
|
|
6306
6405
|
toMatrix(m) {
|
|
6307
|
-
const k = 1 -
|
|
6406
|
+
const k = 1 - clamp012(this.amount);
|
|
6308
6407
|
m9[0] = 0.2126 + 0.7874 * k;
|
|
6309
6408
|
m9[1] = 0.7152 - 0.7152 * k;
|
|
6310
6409
|
m9[2] = 0.0722 - 0.0722 * k;
|
|
@@ -6317,12 +6416,12 @@ var Grayscale = class extends Amount {
|
|
|
6317
6416
|
rgb3(m, m9);
|
|
6318
6417
|
}
|
|
6319
6418
|
css() {
|
|
6320
|
-
return `grayscale(${
|
|
6419
|
+
return `grayscale(${clamp012(this.amount)})`;
|
|
6321
6420
|
}
|
|
6322
6421
|
};
|
|
6323
6422
|
var Sepia = class extends Amount {
|
|
6324
6423
|
toMatrix(m) {
|
|
6325
|
-
const k = 1 -
|
|
6424
|
+
const k = 1 - clamp012(this.amount);
|
|
6326
6425
|
m9[0] = 0.393 + 0.607 * k;
|
|
6327
6426
|
m9[1] = 0.769 - 0.769 * k;
|
|
6328
6427
|
m9[2] = 0.189 - 0.189 * k;
|
|
@@ -6335,7 +6434,7 @@ var Sepia = class extends Amount {
|
|
|
6335
6434
|
rgb3(m, m9);
|
|
6336
6435
|
}
|
|
6337
6436
|
css() {
|
|
6338
|
-
return `sepia(${
|
|
6437
|
+
return `sepia(${clamp012(this.amount)})`;
|
|
6339
6438
|
}
|
|
6340
6439
|
};
|
|
6341
6440
|
var HueRotate = class extends Amount {
|
|
@@ -6384,7 +6483,7 @@ var Tint = class extends Amount {
|
|
|
6384
6483
|
return i + 2;
|
|
6385
6484
|
}
|
|
6386
6485
|
toMatrix(m) {
|
|
6387
|
-
const a =
|
|
6486
|
+
const a = clamp012(this.amount);
|
|
6388
6487
|
linear(m, 1 - a, 0);
|
|
6389
6488
|
m[4] = (this.c >> 16 & 255) / 255 * a;
|
|
6390
6489
|
m[9] = (this.c >> 8 & 255) / 255 * a;
|
|
@@ -6395,7 +6494,7 @@ var Tint = class extends Amount {
|
|
|
6395
6494
|
return null;
|
|
6396
6495
|
}
|
|
6397
6496
|
paint2d(ctx, x, y, w2, h) {
|
|
6398
|
-
const a =
|
|
6497
|
+
const a = clamp012(this.amount);
|
|
6399
6498
|
if (a <= 0) return;
|
|
6400
6499
|
ctx.save();
|
|
6401
6500
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
@@ -6461,7 +6560,7 @@ var DropShadow = class extends Base {
|
|
|
6461
6560
|
return this.a;
|
|
6462
6561
|
}
|
|
6463
6562
|
set opacity(v) {
|
|
6464
|
-
this.a =
|
|
6563
|
+
this.a = clamp012(v);
|
|
6465
6564
|
}
|
|
6466
6565
|
get color() {
|
|
6467
6566
|
return this.rgb;
|