@krizaka/ui 3.41.0 → 3.42.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/dist/bird-plate.js +1 -1
- package/dist/{chunk-M4DBVG43.js → chunk-MHUUNC5W.js} +4 -3
- package/dist/chunk-MHUUNC5W.js.map +1 -0
- package/dist/{chunk-EZC54B5C.js → chunk-MIMOTE4W.js} +3 -3
- package/dist/{chunk-EZC54B5C.js.map → chunk-MIMOTE4W.js.map} +1 -1
- package/dist/{chunk-7JFHTPI3.js → chunk-P4TTKYC4.js} +8 -8
- package/dist/chunk-P4TTKYC4.js.map +1 -0
- package/dist/flock.d.ts +7 -1
- package/dist/flock.js +386 -50
- package/dist/flock.js.map +1 -1
- package/dist/mascot-quote.js +1 -1
- package/dist/mascot-state.js +1 -1
- package/dist/mascots.d.ts +3 -1
- package/dist/mascots.js +1 -1
- package/dist/nav-bar.js +1 -1
- package/dist/site-footer.d.ts +6 -4
- package/dist/site-footer.js +30 -6
- package/dist/site-footer.js.map +1 -1
- package/dist/sites.js +7 -7
- package/dist/sites.js.map +1 -1
- package/package.json +6 -6
- package/registry/examples/flock/scenes.d.ts +4 -0
- package/registry/examples/flock/scenes.js +28 -0
- package/registry/examples/flock/scenes.tsx +24 -0
- package/registry/examples/specimen-tag/product.js +1 -1
- package/registry/examples/specimen-tag/product.tsx +1 -1
- package/registry/flock.json +33 -5
- package/registry/index.json +8 -8
- package/registry/map.json +1 -1
- package/registry/mascots.json +15 -1
- package/registry/nav-bar.json +1 -1
- package/registry/rail-nav.json +1 -1
- package/registry/site-footer.json +16 -2
- package/registry/sites.json +1 -1
- package/registry/specimen-tag.json +2 -2
- package/dist/chunk-7JFHTPI3.js.map +0 -1
- package/dist/chunk-M4DBVG43.js.map +0 -1
package/dist/flock.js
CHANGED
|
@@ -1,14 +1,232 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
|
-
Mascot
|
|
4
|
-
|
|
3
|
+
Mascot,
|
|
4
|
+
PARCEL
|
|
5
|
+
} from "./chunk-MHUUNC5W.js";
|
|
5
6
|
import {
|
|
6
7
|
cn
|
|
7
8
|
} from "./chunk-WU4VLSEA.js";
|
|
8
9
|
|
|
9
10
|
// src/flock/flock.tsx
|
|
11
|
+
import * as React2 from "react";
|
|
12
|
+
|
|
13
|
+
// src/flock/scenes.tsx
|
|
10
14
|
import * as React from "react";
|
|
11
|
-
import { jsx } from "react/jsx-runtime";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var side = (s, i, j) => s.birds[j].x >= s.birds[i].x ? 1 : -1;
|
|
17
|
+
var towards = (s, i, j) => side(s, i, j) > 0 ? "right" : "left";
|
|
18
|
+
function neighbourOf(s, i) {
|
|
19
|
+
const at = s.order.indexOf(i);
|
|
20
|
+
const near = [s.order[at - 1], s.order[at + 1]].filter((n) => n !== void 0);
|
|
21
|
+
if (!near.length) return null;
|
|
22
|
+
return near.reduce((a, b) => Math.abs(s.birds[a].x - s.birds[i].x) <= Math.abs(s.birds[b].x - s.birds[i].x) ? a : b);
|
|
23
|
+
}
|
|
24
|
+
var BOOK_MS = 4800;
|
|
25
|
+
var LOG_MS = 3800;
|
|
26
|
+
var GLINT_MS = 3400;
|
|
27
|
+
var SAY_MS = 1500;
|
|
28
|
+
async function read(s, i) {
|
|
29
|
+
const j = neighbourOf(s, i);
|
|
30
|
+
s.look(i, "left");
|
|
31
|
+
s.show(i, "book", BOOK_MS);
|
|
32
|
+
await s.wait(BOOK_MS * 0.45);
|
|
33
|
+
if (j !== null && s.random() < 0.5) {
|
|
34
|
+
s.look(j, towards(s, j, i));
|
|
35
|
+
await s.wait(1100);
|
|
36
|
+
s.rest(j);
|
|
37
|
+
}
|
|
38
|
+
await s.wait(BOOK_MS * 0.5);
|
|
39
|
+
s.rest(i);
|
|
40
|
+
}
|
|
41
|
+
async function chat(s, i) {
|
|
42
|
+
const j = neighbourOf(s, i);
|
|
43
|
+
s.look(i, j === null ? "up" : towards(s, i, j));
|
|
44
|
+
s.say(i, "\u2026", SAY_MS);
|
|
45
|
+
await s.wait(SAY_MS * 0.6);
|
|
46
|
+
if (j === null) {
|
|
47
|
+
await s.wait(SAY_MS * 0.6);
|
|
48
|
+
s.rest(i);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
s.look(j, towards(s, j, i));
|
|
52
|
+
await s.wait(SAY_MS * 0.7);
|
|
53
|
+
s.say(j, s.random() < 0.5 ? "!" : "?", SAY_MS);
|
|
54
|
+
s.poke(j);
|
|
55
|
+
await s.wait(SAY_MS * 0.5);
|
|
56
|
+
s.poke(i);
|
|
57
|
+
await s.wait(SAY_MS * 0.7);
|
|
58
|
+
s.rest(i, j);
|
|
59
|
+
}
|
|
60
|
+
async function bow(s, i) {
|
|
61
|
+
const j = neighbourOf(s, i);
|
|
62
|
+
const dir = j === null ? 1 : side(s, i, j);
|
|
63
|
+
const step = `${(s.birds[i].size * 0.14 * dir).toFixed(2)}cqw`;
|
|
64
|
+
const lean = `rotate(${dir * 11}deg)`;
|
|
65
|
+
const at = (x, r) => `translateX(${x}) ${r}`;
|
|
66
|
+
const run = s.move(
|
|
67
|
+
i,
|
|
68
|
+
[
|
|
69
|
+
{ transform: at("0cqw", "rotate(0deg)"), easing: "ease-in-out" },
|
|
70
|
+
{ transform: at(step, "rotate(0deg)"), offset: 0.22, easing: "ease-in-out" },
|
|
71
|
+
{ transform: at(step, lean), offset: 0.42, easing: "ease-in-out" },
|
|
72
|
+
{ transform: at(step, lean), offset: 0.6, easing: "ease-in-out" },
|
|
73
|
+
{ transform: at(step, "rotate(0deg)"), offset: 0.74, easing: "ease-in-out" },
|
|
74
|
+
{ transform: at("0cqw", "rotate(0deg)") }
|
|
75
|
+
],
|
|
76
|
+
3800
|
|
77
|
+
);
|
|
78
|
+
if (j !== null) {
|
|
79
|
+
await s.wait(1700);
|
|
80
|
+
s.look(j, towards(s, j, i));
|
|
81
|
+
await s.wait(1200);
|
|
82
|
+
s.poke(j);
|
|
83
|
+
await s.wait(500);
|
|
84
|
+
s.rest(j);
|
|
85
|
+
}
|
|
86
|
+
await run;
|
|
87
|
+
}
|
|
88
|
+
async function tap(s, i) {
|
|
89
|
+
s.show(i, "log", LOG_MS, s.birds[i].x > 50 ? 1 : -1);
|
|
90
|
+
await s.wait(LOG_MS * 0.3);
|
|
91
|
+
for (let n = 0; n < 3; n++) {
|
|
92
|
+
s.poke(i, 420);
|
|
93
|
+
await s.wait(520);
|
|
94
|
+
}
|
|
95
|
+
await s.wait(LOG_MS * 0.3);
|
|
96
|
+
}
|
|
97
|
+
async function shine(s, i) {
|
|
98
|
+
const dir = s.birds[i].x > 50 ? -1 : 1;
|
|
99
|
+
const to = dir > 0 ? "right" : "left";
|
|
100
|
+
s.show(i, "glint", GLINT_MS, dir);
|
|
101
|
+
await s.wait(GLINT_MS * 0.28);
|
|
102
|
+
s.look(i, to);
|
|
103
|
+
await s.wait(GLINT_MS * 0.3);
|
|
104
|
+
s.poke(i);
|
|
105
|
+
await s.wait(GLINT_MS * 0.25);
|
|
106
|
+
s.look(i, "up");
|
|
107
|
+
await s.wait(GLINT_MS * 0.2);
|
|
108
|
+
s.rest(i);
|
|
109
|
+
}
|
|
110
|
+
async function build(s, i) {
|
|
111
|
+
for (let n = 0; n < 4; n++) {
|
|
112
|
+
s.poke(i, 300);
|
|
113
|
+
await s.wait(380);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function scan(s, i) {
|
|
117
|
+
for (const to of ["left", "up", "right"]) {
|
|
118
|
+
s.look(i, to);
|
|
119
|
+
await s.wait(1100);
|
|
120
|
+
}
|
|
121
|
+
s.rest(i);
|
|
122
|
+
}
|
|
123
|
+
async function receive(s, i, from) {
|
|
124
|
+
const bird = s.birds[i].bird;
|
|
125
|
+
s.look(i, towards(s, i, from));
|
|
126
|
+
s.show(i, "gift", 2400);
|
|
127
|
+
await s.wait(350);
|
|
128
|
+
if (bird === "crane") await bow(s, i);
|
|
129
|
+
else if (bird === "magpie") {
|
|
130
|
+
s.poke(i);
|
|
131
|
+
await s.wait(700);
|
|
132
|
+
s.show(i, "glint", GLINT_MS * 0.6, side(s, i, from));
|
|
133
|
+
await s.wait(1200);
|
|
134
|
+
} else if (bird === "beaver" || bird === "duck") {
|
|
135
|
+
s.poke(i, 420);
|
|
136
|
+
await s.wait(520);
|
|
137
|
+
s.poke(i, 420);
|
|
138
|
+
await s.wait(900);
|
|
139
|
+
} else if (bird === "owl") {
|
|
140
|
+
s.say(i, "?", SAY_MS);
|
|
141
|
+
await s.wait(900);
|
|
142
|
+
s.poke(i);
|
|
143
|
+
await s.wait(700);
|
|
144
|
+
} else {
|
|
145
|
+
s.say(i, "!", SAY_MS);
|
|
146
|
+
s.poke(i);
|
|
147
|
+
await s.wait(1500);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
var BEATS = [
|
|
151
|
+
{ id: "read", bird: "owl", run: read },
|
|
152
|
+
{ id: "chat", bird: "flamingo", run: chat },
|
|
153
|
+
{ id: "chat", bird: "lovebird", run: chat },
|
|
154
|
+
{ id: "bow", bird: "crane", run: bow },
|
|
155
|
+
{ id: "tap", bird: "beaver", run: tap },
|
|
156
|
+
{ id: "shine", bird: "magpie", run: shine },
|
|
157
|
+
{ id: "build", bird: "duck", run: build },
|
|
158
|
+
{ id: "scan", bird: "falcon", run: scan }
|
|
159
|
+
];
|
|
160
|
+
var PAPER = "var(--kz-surface-1)";
|
|
161
|
+
var INK = "var(--kz-text-primary)";
|
|
162
|
+
var LINE = "var(--kz-border-strong, currentColor)";
|
|
163
|
+
function lifeFrames(from, to) {
|
|
164
|
+
return [
|
|
165
|
+
{ opacity: 0, transform: from, offset: 0 },
|
|
166
|
+
{ opacity: 1, transform: "none", offset: 0.14 },
|
|
167
|
+
{ opacity: 1, transform: "none", offset: 0.84 },
|
|
168
|
+
{ opacity: 0, transform: to, offset: 1 }
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
var LEAF = [
|
|
172
|
+
{ transform: "scaleX(1)", offset: 0 },
|
|
173
|
+
{ transform: "scaleX(1)", offset: 0.25 },
|
|
174
|
+
{ transform: "scaleX(-1)", offset: 0.38 },
|
|
175
|
+
{ transform: "scaleX(1)", offset: 0.39 },
|
|
176
|
+
{ transform: "scaleX(1)", offset: 0.62 },
|
|
177
|
+
{ transform: "scaleX(-1)", offset: 0.75 },
|
|
178
|
+
{ transform: "scaleX(-1)", offset: 1 }
|
|
179
|
+
];
|
|
180
|
+
function Prop({ shown, size }) {
|
|
181
|
+
const ref = React.useRef(null);
|
|
182
|
+
const leaf = React.useRef(null);
|
|
183
|
+
const dir = shown.side ?? 1;
|
|
184
|
+
React.useEffect(() => {
|
|
185
|
+
const el = ref.current;
|
|
186
|
+
if (!el || typeof el.animate !== "function") return;
|
|
187
|
+
const from = {
|
|
188
|
+
say: ["translateY(30%) scale(.5)", "translateY(-12%) scale(.9)"],
|
|
189
|
+
book: ["translateY(40%) scale(.8)", "translateY(20%) scale(.9)"],
|
|
190
|
+
log: [`translateX(${190 * dir}%)`, `translateX(${190 * dir}%)`],
|
|
191
|
+
glint: ["scale(.2) rotate(-60deg)", `translate(${-90 * dir}%, -170%) scale(.2) rotate(60deg)`],
|
|
192
|
+
gift: ["translateY(40%) scale(.3)", "translateY(-30%) scale(1.4)"]
|
|
193
|
+
};
|
|
194
|
+
const [a, b] = from[shown.kind];
|
|
195
|
+
const animations = [el.animate(lifeFrames(a, b), { duration: shown.ms, fill: "both", easing: "ease-out" })];
|
|
196
|
+
if (shown.kind === "book" && leaf.current) animations.push(leaf.current.animate(LEAF, { duration: shown.ms, fill: "both", easing: "ease-in-out" }));
|
|
197
|
+
if (shown.kind === "glint") animations.push(el.firstElementChild.animate([{ transform: "scale(1)" }, { transform: "scale(1.35)" }, { transform: "scale(1)" }], { duration: 700, iterations: Math.ceil(shown.ms / 700), easing: "ease-in-out" }));
|
|
198
|
+
return () => animations.forEach((x) => x.cancel());
|
|
199
|
+
}, [shown, dir]);
|
|
200
|
+
const unit = (n) => `calc(${size}cqw * ${n})`;
|
|
201
|
+
const base = { position: "absolute", pointerEvents: "none", opacity: 0 };
|
|
202
|
+
if (shown.kind === "say")
|
|
203
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-flock-prop": "say", style: { ...base, left: "58%", top: "-6%", width: unit(0.34), height: unit(0.24), transformOrigin: "20% 100%" }, children: [
|
|
204
|
+
/* @__PURE__ */ jsx(
|
|
205
|
+
"span",
|
|
206
|
+
{
|
|
207
|
+
style: { position: "absolute", inset: 0, display: "grid", placeItems: "center", background: PAPER, border: `1.5px solid ${LINE}`, borderRadius: "999px", color: INK, font: `600 ${unit(0.17)}/1 var(--font-mono, ui-monospace, monospace)` },
|
|
208
|
+
children: shown.mark ?? "\u2026"
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
/* @__PURE__ */ jsx("span", { style: { position: "absolute", left: "14%", bottom: "-12%", width: unit(0.07), height: unit(0.07), background: PAPER, borderRight: `1.5px solid ${LINE}`, borderBottom: `1.5px solid ${LINE}`, transform: "rotate(45deg)" } })
|
|
212
|
+
] });
|
|
213
|
+
if (shown.kind === "book")
|
|
214
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-flock-prop": "book", style: { ...base, left: "17%", bottom: "-2%", width: "66%", height: unit(0.2), transformOrigin: "50% 100%" }, children: [
|
|
215
|
+
[0, 1].map((n) => /* @__PURE__ */ jsx("span", { style: { position: "absolute", top: 0, bottom: 0, [n ? "right" : "left"]: 0, width: "50%", background: `repeating-linear-gradient(${PAPER} 0 18%, ${LINE} 18% 24%)`, border: `1.5px solid ${LINE}`, borderRadius: n ? "0 3px 3px 0" : "3px 0 0 3px" } }, n)),
|
|
216
|
+
/* @__PURE__ */ jsx("div", { ref: leaf, style: { position: "absolute", top: 0, bottom: 0, left: "50%", width: "50%", transformOrigin: "0 50%", background: PAPER, border: `1.5px solid ${LINE}`, borderRadius: "0 3px 3px 0" } })
|
|
217
|
+
] });
|
|
218
|
+
if (shown.kind === "log")
|
|
219
|
+
return /* @__PURE__ */ jsx("div", { ref, "data-flock-prop": "log", style: { ...base, left: "22%", bottom: "-3%", width: "56%", height: unit(0.17), background: PARCEL[2], borderRadius: "999px", boxShadow: `inset -${unit(0.04)} 0 0 ${PARCEL[1]}` }, children: /* @__PURE__ */ jsx("span", { style: { position: "absolute", left: 0, top: 0, bottom: 0, aspectRatio: "1", borderRadius: "50%", background: `radial-gradient(${PARCEL[0]} 0 25%, ${PARCEL[1]} 26% 55%, ${PARCEL[2]} 56%)`, border: `1px solid ${PARCEL[2]}` } }) });
|
|
220
|
+
if (shown.kind === "glint")
|
|
221
|
+
return /* @__PURE__ */ jsx("div", { ref, "data-flock-prop": "glint", style: { ...base, [dir > 0 ? "left" : "right"]: "94%", bottom: "2%", width: unit(0.2), height: unit(0.2) }, children: /* @__PURE__ */ jsx("span", { style: { position: "absolute", inset: 0, background: PARCEL[0], clipPath: "polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%)" } }) });
|
|
222
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-flock-prop": "gift", style: { ...base, left: "58%", top: "2%", width: unit(0.26), height: unit(0.22), background: PARCEL[0], border: `1.5px solid ${PARCEL[2]}`, borderRadius: 2 }, children: [
|
|
223
|
+
/* @__PURE__ */ jsx("span", { style: { position: "absolute", left: "44%", top: 0, bottom: 0, width: "12%", background: PARCEL[2] } }),
|
|
224
|
+
/* @__PURE__ */ jsx("span", { style: { position: "absolute", top: "42%", left: 0, right: 0, height: "16%", background: PARCEL[2] } })
|
|
225
|
+
] });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/flock/flock.tsx
|
|
229
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
12
230
|
var GLANCE_HOLD_MS = [1500, 2400];
|
|
13
231
|
var GLANCE_EVERY_MS = [4200, 9e3];
|
|
14
232
|
var COURIER_FIRST_MS = 9e3;
|
|
@@ -17,26 +235,32 @@ var FLIGHT_MS = 2600;
|
|
|
17
235
|
var HAND_OVER_MS = 1300;
|
|
18
236
|
var LOOK_BACK_MS = 1600;
|
|
19
237
|
var between = (random, [lo, hi], tempo = 1) => (lo + random() * (hi - lo)) / tempo;
|
|
238
|
+
var SCENE_EVERY_MS = [2600, 5200];
|
|
239
|
+
var SCENE_PAUSE_MS = [8e3, 12e3];
|
|
20
240
|
var GREET_STEP_MS = 110;
|
|
21
241
|
var POKE_MS = 700;
|
|
22
242
|
function useMayMove() {
|
|
23
|
-
const [may, setMay] =
|
|
24
|
-
|
|
243
|
+
const [may, setMay] = React2.useState(false);
|
|
244
|
+
React2.useEffect(() => {
|
|
25
245
|
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
26
|
-
const
|
|
246
|
+
const settled = () => document.documentElement.getAttribute("data-motion") !== "settling";
|
|
247
|
+
const update = () => setMay(!query.matches && document.visibilityState !== "hidden" && settled());
|
|
27
248
|
update();
|
|
28
249
|
query.addEventListener("change", update);
|
|
29
250
|
document.addEventListener("visibilitychange", update);
|
|
251
|
+
const watch = typeof MutationObserver === "undefined" ? null : new MutationObserver(update);
|
|
252
|
+
watch?.observe(document.documentElement, { attributes: true, attributeFilter: ["data-motion"] });
|
|
30
253
|
return () => {
|
|
31
254
|
query.removeEventListener("change", update);
|
|
32
255
|
document.removeEventListener("visibilitychange", update);
|
|
256
|
+
watch?.disconnect();
|
|
33
257
|
};
|
|
34
258
|
}, []);
|
|
35
259
|
return may;
|
|
36
260
|
}
|
|
37
261
|
function useOnScreen(ref) {
|
|
38
|
-
const [on, setOn] =
|
|
39
|
-
|
|
262
|
+
const [on, setOn] = React2.useState(false);
|
|
263
|
+
React2.useEffect(() => {
|
|
40
264
|
const el = ref.current;
|
|
41
265
|
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
42
266
|
const observer = new IntersectionObserver(([entry]) => setOn(Boolean(entry?.isIntersecting)), { threshold: 0.1 });
|
|
@@ -45,19 +269,61 @@ function useOnScreen(ref) {
|
|
|
45
269
|
}, [ref]);
|
|
46
270
|
return on;
|
|
47
271
|
}
|
|
48
|
-
function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier = true, react = true, random = Math.random, tempo = 1, active = null, greet = false, className, style, ...props }) {
|
|
49
|
-
const stage =
|
|
50
|
-
const bodies =
|
|
272
|
+
function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier = true, react = true, scenes = false, random = Math.random, tempo = 1, active = null, greet = false, className, style, ...props }) {
|
|
273
|
+
const stage = React2.useRef(null);
|
|
274
|
+
const bodies = React2.useRef([]);
|
|
51
275
|
const may = useMayMove();
|
|
52
276
|
const onScreen = useOnScreen(stage);
|
|
53
277
|
const running = may && onScreen;
|
|
54
|
-
const [looks, setLooks] =
|
|
55
|
-
const [flying, setFlying] =
|
|
56
|
-
const [poked, setPoked] =
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
278
|
+
const [looks, setLooks] = React2.useState({});
|
|
279
|
+
const [flying, setFlying] = React2.useState(null);
|
|
280
|
+
const [poked, setPoked] = React2.useState({});
|
|
281
|
+
const [shown, setShown] = React2.useState([]);
|
|
282
|
+
const [empty, setEmpty] = React2.useState({});
|
|
283
|
+
const held = React2.useRef(/* @__PURE__ */ new Set());
|
|
284
|
+
const busy = React2.useRef(null);
|
|
285
|
+
const ids = React2.useRef(0);
|
|
286
|
+
const order = React2.useMemo(() => birds.map((_, i) => i).sort((a, b) => birds[a].x - birds[b].x), [birds]);
|
|
287
|
+
const look = React2.useCallback((index, to) => setLooks((l) => l[index] === to ? l : { ...l, [index]: to }), []);
|
|
288
|
+
const rest = React2.useCallback((...indexes) => setLooks((l) => Object.fromEntries(Object.entries(l).filter(([k]) => !indexes.includes(Number(k))))), []);
|
|
289
|
+
const stageFor = React2.useCallback((run) => {
|
|
290
|
+
const later = (fn, ms) => {
|
|
291
|
+
const t = setTimeout(() => {
|
|
292
|
+
run.timers.delete(t);
|
|
293
|
+
fn();
|
|
294
|
+
}, ms);
|
|
295
|
+
run.timers.add(t);
|
|
296
|
+
};
|
|
297
|
+
const poke = (index, ms = POKE_MS) => {
|
|
298
|
+
setPoked((p) => ({ ...p, [index]: true }));
|
|
299
|
+
later(() => setPoked((p) => ({ ...p, [index]: false })), ms);
|
|
300
|
+
};
|
|
301
|
+
const show = (index, kind, ms, side2, mark) => {
|
|
302
|
+
const item = { id: ++ids.current, at: index, kind, ms, side: side2, mark };
|
|
303
|
+
setShown((all) => [...all, item]);
|
|
304
|
+
later(() => setShown((all) => all.filter((x) => x.id !== item.id)), ms);
|
|
305
|
+
};
|
|
306
|
+
return {
|
|
307
|
+
birds,
|
|
308
|
+
order,
|
|
309
|
+
random,
|
|
310
|
+
look,
|
|
311
|
+
rest,
|
|
312
|
+
poke,
|
|
313
|
+
show,
|
|
314
|
+
say: (index, mark, ms) => show(index, "say", ms, void 0, mark),
|
|
315
|
+
wait: (ms) => new Promise((resolve) => later(resolve, ms)),
|
|
316
|
+
move: async (index, keyframes, ms) => {
|
|
317
|
+
const el = bodies.current[index];
|
|
318
|
+
if (!el || typeof el.animate !== "function") return;
|
|
319
|
+
const animation = el.animate(keyframes, { duration: ms });
|
|
320
|
+
run.anims.add(animation);
|
|
321
|
+
await animation.finished.catch(() => void 0);
|
|
322
|
+
run.anims.delete(animation);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}, [birds, order, random, look, rest]);
|
|
326
|
+
React2.useEffect(() => {
|
|
61
327
|
if (!running || !glance || order.length < 2) return;
|
|
62
328
|
let timer;
|
|
63
329
|
let back;
|
|
@@ -65,6 +331,7 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
65
331
|
timer = setTimeout(() => {
|
|
66
332
|
const at = Math.floor(random() * (order.length - 1));
|
|
67
333
|
const [a, b] = [order[at], order[at + 1]];
|
|
334
|
+
if (held.current.has(a) || held.current.has(b)) return next();
|
|
68
335
|
look(a, "right");
|
|
69
336
|
look(b, "left");
|
|
70
337
|
back = setTimeout(() => {
|
|
@@ -78,23 +345,28 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
78
345
|
clearTimeout(timer);
|
|
79
346
|
clearTimeout(back);
|
|
80
347
|
};
|
|
81
|
-
}, [running, glance, order, random, tempo]);
|
|
82
|
-
|
|
348
|
+
}, [running, glance, order, random, tempo, look, rest]);
|
|
349
|
+
React2.useEffect(() => {
|
|
83
350
|
const pigeon = birds.findIndex((b) => b.bird === "pigeon");
|
|
84
351
|
if (!running || !courier || pigeon < 0 || birds.length < 2) return;
|
|
85
352
|
let alive = true;
|
|
353
|
+
const heldNow = held.current;
|
|
86
354
|
let timer;
|
|
87
355
|
let animation;
|
|
356
|
+
const run = { timers: /* @__PURE__ */ new Set(), anims: /* @__PURE__ */ new Set() };
|
|
357
|
+
const from = birds[pigeon];
|
|
358
|
+
const target = birds.reduce((far, b, i) => i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far].x - from.x) ? i : far, pigeon === 0 ? 1 : 0);
|
|
88
359
|
const wait = (ms) => new Promise((resolve) => timer = setTimeout(resolve, ms));
|
|
89
360
|
const trip = async () => {
|
|
361
|
+
while (alive && scenes && busy.current === "scene") await wait(400);
|
|
362
|
+
if (!alive) return;
|
|
363
|
+
busy.current = "trip";
|
|
90
364
|
const el = bodies.current[pigeon];
|
|
91
365
|
const box = stage.current?.getBoundingClientRect();
|
|
92
366
|
if (!el || !box || typeof el.animate !== "function") return;
|
|
93
|
-
const from = birds[pigeon];
|
|
94
|
-
const target = birds.reduce((far, b, i) => i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far].x - from.x) ? i : far, pigeon === 0 ? 1 : 0);
|
|
95
367
|
const to = birds[target];
|
|
96
|
-
const
|
|
97
|
-
const dx = (to.x - from.x) / 100 * box.width -
|
|
368
|
+
const side2 = to.x > from.x ? 1 : -1;
|
|
369
|
+
const dx = (to.x - from.x) / 100 * box.width - side2 * (to.size / 100) * box.width * 0.55;
|
|
98
370
|
const lift = from.size / 100 * box.width * 0.35;
|
|
99
371
|
const fly = async (fromX, toX) => {
|
|
100
372
|
setFlying({ index: pigeon, bank: Math.sign(toX - fromX) });
|
|
@@ -109,21 +381,35 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
109
381
|
await animation.finished.catch(() => void 0);
|
|
110
382
|
setFlying(null);
|
|
111
383
|
};
|
|
112
|
-
look(target,
|
|
384
|
+
look(target, side2 > 0 ? "left" : "right");
|
|
385
|
+
held.current.add(target);
|
|
113
386
|
await fly(0, dx);
|
|
114
387
|
if (!alive) return;
|
|
115
388
|
setPoked((p) => ({ ...p, [pigeon]: true }));
|
|
116
|
-
|
|
389
|
+
if (scenes) {
|
|
390
|
+
setEmpty((e) => ({ ...e, [pigeon]: true }));
|
|
391
|
+
const reaction = receive(stageFor(run), target, pigeon);
|
|
392
|
+
await wait(HAND_OVER_MS);
|
|
393
|
+
if (!alive) return;
|
|
394
|
+
setPoked((p) => ({ ...p, [pigeon]: false }));
|
|
395
|
+
await reaction;
|
|
396
|
+
} else {
|
|
397
|
+
await wait(HAND_OVER_MS);
|
|
398
|
+
if (!alive) return;
|
|
399
|
+
setPoked((p) => ({ ...p, [pigeon]: false }));
|
|
400
|
+
}
|
|
117
401
|
if (!alive) return;
|
|
118
|
-
setPoked((p) => ({ ...p, [pigeon]: false }));
|
|
119
402
|
look(target, "up");
|
|
120
403
|
await fly(dx, 0);
|
|
121
404
|
animation?.cancel();
|
|
405
|
+
setEmpty((e) => ({ ...e, [pigeon]: false }));
|
|
122
406
|
rest(target);
|
|
123
407
|
};
|
|
124
408
|
const schedule = (ms) => {
|
|
125
409
|
timer = setTimeout(async () => {
|
|
126
410
|
await trip();
|
|
411
|
+
busy.current = null;
|
|
412
|
+
held.current.delete(target);
|
|
127
413
|
if (alive) schedule(between(random, COURIER_EVERY_MS, tempo));
|
|
128
414
|
}, ms);
|
|
129
415
|
};
|
|
@@ -132,11 +418,56 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
132
418
|
alive = false;
|
|
133
419
|
clearTimeout(timer);
|
|
134
420
|
animation?.cancel();
|
|
421
|
+
run.timers.forEach(clearTimeout);
|
|
422
|
+
run.anims.forEach((a) => a.cancel());
|
|
423
|
+
if (scenes) {
|
|
424
|
+
setShown([]);
|
|
425
|
+
setEmpty({});
|
|
426
|
+
heldNow.clear();
|
|
427
|
+
busy.current = null;
|
|
428
|
+
}
|
|
135
429
|
setFlying(null);
|
|
136
430
|
};
|
|
137
|
-
}, [running, courier, birds, random, tempo]);
|
|
138
|
-
|
|
139
|
-
|
|
431
|
+
}, [running, courier, birds, random, tempo, scenes, stageFor, look, rest]);
|
|
432
|
+
React2.useEffect(() => {
|
|
433
|
+
if (!running || !scenes || birds.length < 1) return;
|
|
434
|
+
let alive = true;
|
|
435
|
+
const heldNow = held.current;
|
|
436
|
+
const run = { timers: /* @__PURE__ */ new Set(), anims: /* @__PURE__ */ new Set() };
|
|
437
|
+
const st = stageFor(run);
|
|
438
|
+
const beats = BEATS.flatMap((beat) => birds.flatMap((b, i) => b.bird === beat.bird ? [{ beat, index: i }] : []));
|
|
439
|
+
if (!beats.length) return;
|
|
440
|
+
let last = -1;
|
|
441
|
+
const next = async () => {
|
|
442
|
+
const long = random() < 0.2;
|
|
443
|
+
await st.wait(between(random, long ? SCENE_PAUSE_MS : SCENE_EVERY_MS, tempo));
|
|
444
|
+
while (alive && busy.current === "trip") await st.wait(600);
|
|
445
|
+
if (!alive) return;
|
|
446
|
+
const pool = beats.filter((x) => x.index !== last);
|
|
447
|
+
const pick = (pool.length ? pool : beats)[Math.floor(random() * (pool.length ? pool.length : beats.length))];
|
|
448
|
+
last = pick.index;
|
|
449
|
+
busy.current = "scene";
|
|
450
|
+
const near = neighbourOf(st, pick.index);
|
|
451
|
+
held.current.add(pick.index);
|
|
452
|
+
if (near !== null) held.current.add(near);
|
|
453
|
+
await pick.beat.run(st, pick.index);
|
|
454
|
+
held.current.delete(pick.index);
|
|
455
|
+
if (near !== null) held.current.delete(near);
|
|
456
|
+
if (busy.current === "scene") busy.current = null;
|
|
457
|
+
if (alive) void next();
|
|
458
|
+
};
|
|
459
|
+
void next();
|
|
460
|
+
return () => {
|
|
461
|
+
alive = false;
|
|
462
|
+
run.timers.forEach(clearTimeout);
|
|
463
|
+
run.anims.forEach((a) => a.cancel());
|
|
464
|
+
setShown([]);
|
|
465
|
+
heldNow.clear();
|
|
466
|
+
busy.current = null;
|
|
467
|
+
};
|
|
468
|
+
}, [running, scenes, birds, random, tempo, stageFor]);
|
|
469
|
+
const greeted = React2.useRef(false);
|
|
470
|
+
React2.useEffect(() => {
|
|
140
471
|
if (!running || !greet || greeted.current) return;
|
|
141
472
|
greeted.current = true;
|
|
142
473
|
const timers = [];
|
|
@@ -146,7 +477,7 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
146
477
|
});
|
|
147
478
|
return () => timers.forEach(clearTimeout);
|
|
148
479
|
}, [running, greet, order]);
|
|
149
|
-
|
|
480
|
+
React2.useEffect(() => {
|
|
150
481
|
const index = active ? birds.findIndex((b) => b.bird === active) : -1;
|
|
151
482
|
if (!running || index < 0) return;
|
|
152
483
|
const start = setTimeout(() => {
|
|
@@ -160,7 +491,7 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
160
491
|
setPoked((p) => ({ ...p, [index]: false }));
|
|
161
492
|
rest(index);
|
|
162
493
|
};
|
|
163
|
-
}, [active, running, birds]);
|
|
494
|
+
}, [active, running, birds, look, rest]);
|
|
164
495
|
const hover = (index, event) => {
|
|
165
496
|
if (!running || !react || event.pointerType !== "mouse") return;
|
|
166
497
|
look(index, "up");
|
|
@@ -169,7 +500,7 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
169
500
|
if (!react) return;
|
|
170
501
|
rest(index);
|
|
171
502
|
};
|
|
172
|
-
const
|
|
503
|
+
const tap2 = (index) => {
|
|
173
504
|
if (!running || !react) return;
|
|
174
505
|
look(index, "up");
|
|
175
506
|
setPoked((p) => ({ ...p, [index]: true }));
|
|
@@ -178,17 +509,18 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
178
509
|
rest(index);
|
|
179
510
|
}, LOOK_BACK_MS);
|
|
180
511
|
};
|
|
181
|
-
return /* @__PURE__ */
|
|
512
|
+
return /* @__PURE__ */ jsx2(
|
|
182
513
|
"div",
|
|
183
514
|
{
|
|
184
515
|
ref: stage,
|
|
185
516
|
"aria-hidden": true,
|
|
186
517
|
"data-flock": "",
|
|
187
518
|
"data-running": running ? "" : void 0,
|
|
519
|
+
"data-motion-scope": "",
|
|
188
520
|
className: cn("relative w-full", className),
|
|
189
521
|
style: { aspectRatio: String(ratio), containerType: "inline-size", ...style },
|
|
190
522
|
...props,
|
|
191
|
-
children: birds.map((b, i) => /* @__PURE__ */
|
|
523
|
+
children: birds.map((b, i) => /* @__PURE__ */ jsxs2(
|
|
192
524
|
"div",
|
|
193
525
|
{
|
|
194
526
|
ref: (el) => {
|
|
@@ -199,21 +531,25 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
|
|
|
199
531
|
style: { left: `${b.x - b.size / 2}%`, width: `${b.size}%`, top: `calc(${b.y}% - ${b.size * 0.9}cqw)`, aspectRatio: "1", pointerEvents: react ? "auto" : "none" },
|
|
200
532
|
onPointerEnter: (event) => hover(i, event),
|
|
201
533
|
onPointerLeave: () => leave(i),
|
|
202
|
-
onPointerDown: () =>
|
|
203
|
-
children:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
534
|
+
onPointerDown: () => tap2(i),
|
|
535
|
+
children: [
|
|
536
|
+
/* @__PURE__ */ jsx2(
|
|
537
|
+
Mascot,
|
|
538
|
+
{
|
|
539
|
+
bird: b.bird,
|
|
540
|
+
tone,
|
|
541
|
+
life: true,
|
|
542
|
+
look: looks[i],
|
|
543
|
+
flying: flying?.index === i,
|
|
544
|
+
bank: flying?.index === i ? flying.bank : 0,
|
|
545
|
+
poked: poked[i],
|
|
546
|
+
carrying: !empty[i],
|
|
547
|
+
size: 120,
|
|
548
|
+
style: { width: "100%", height: "100%", display: "block", overflow: "visible" }
|
|
549
|
+
}
|
|
550
|
+
),
|
|
551
|
+
shown.filter((x) => x.at === i).map((x) => /* @__PURE__ */ jsx2(Prop, { shown: x, size: b.size }, x.id))
|
|
552
|
+
]
|
|
217
553
|
},
|
|
218
554
|
`${b.bird}-${i}`
|
|
219
555
|
))
|