@idle-screens/saver-metaquarium 0.4.1 → 0.5.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/{chunk-52CJC2KV.js → chunk-23P73MYY.js} +345 -19
- package/dist/chunk-23P73MYY.js.map +1 -0
- package/dist/chunk-SBRO3JPO.js +36 -0
- package/dist/chunk-SBRO3JPO.js.map +1 -0
- package/dist/index.d.ts +3 -42
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{manifest-CapCN3BJ.d.ts → manifest-Bk9LNZb9.d.ts} +160 -3
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +5 -1
- package/dist/{tank-HV27OOXH.js → tank-6IEOYV4X.js} +241 -51
- package/dist/tank-6IEOYV4X.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-52CJC2KV.js.map +0 -1
- package/dist/chunk-UXMO57ND.js +0 -133
- package/dist/chunk-UXMO57ND.js.map +0 -1
- package/dist/tank-HV27OOXH.js.map +0 -1
|
@@ -107,29 +107,87 @@ function fishVariation(index, variance) {
|
|
|
107
107
|
}
|
|
108
108
|
var FISH_LENGTH = 18;
|
|
109
109
|
var FORMATION_HALF_WIDTH = 62;
|
|
110
|
-
|
|
110
|
+
var FORMATION_SHAPES = ["phalanx", "line", "ring", "wedge", "ball"];
|
|
111
|
+
function formationSlot(index, count, variance, halfWidth = FORMATION_HALF_WIDTH, shape = "phalanx") {
|
|
112
|
+
const j = 0.35 + 0.65 * Math.max(0, Math.min(1, variance));
|
|
113
|
+
if (shape === "line") {
|
|
114
|
+
const FILE = 6;
|
|
115
|
+
const files = Math.ceil(Math.max(1, count) / FILE);
|
|
116
|
+
const col2 = Math.floor(index / FILE);
|
|
117
|
+
const within = index % FILE;
|
|
118
|
+
const fileLen = Math.min(FILE, count - col2 * FILE);
|
|
119
|
+
return {
|
|
120
|
+
side: (col2 - (files - 1) / 2) * FISH_LENGTH * 1.6 + (fishHash(index, 4) - 0.5) * FISH_LENGTH * 0.4 * j,
|
|
121
|
+
up: (fishHash(index, 5) - 0.5) * FISH_LENGTH * 0.5 * j,
|
|
122
|
+
back: (within - (fileLen - 1) / 2) * FISH_LENGTH * 1.7
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (shape === "ring") {
|
|
126
|
+
const r = Math.max(FISH_LENGTH * 1.6, count * FISH_LENGTH * 1.35 / (Math.PI * 2));
|
|
127
|
+
const a = index / Math.max(1, count) * Math.PI * 2;
|
|
128
|
+
return {
|
|
129
|
+
side: Math.cos(a) * r,
|
|
130
|
+
up: (fishHash(index, 5) - 0.5) * FISH_LENGTH * 0.6 * j,
|
|
131
|
+
back: Math.sin(a) * r
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (shape === "wedge") {
|
|
135
|
+
const VSIZE = 9;
|
|
136
|
+
const layers = Math.ceil(Math.max(1, count) / VSIZE);
|
|
137
|
+
const layer = Math.floor(index / VSIZE);
|
|
138
|
+
const within = index % VSIZE;
|
|
139
|
+
const rank = within + 1 >> 1;
|
|
140
|
+
const wing = within === 0 ? 0 : within % 2 === 1 ? -1 : 1;
|
|
141
|
+
return {
|
|
142
|
+
side: wing * rank * FISH_LENGTH * 1.25 + (fishHash(index, 4) - 0.5) * FISH_LENGTH * 0.3 * j,
|
|
143
|
+
// 1.5 body lengths per layer with a small jitter: adjacent layers seat
|
|
144
|
+
// the same rank directly above each other, so pitch minus worst-case
|
|
145
|
+
// jitter closure must clear one body length.
|
|
146
|
+
up: (layer - (layers - 1) / 2) * FISH_LENGTH * 1.5 + (fishHash(index, 5) - 0.5) * FISH_LENGTH * 0.2 * j,
|
|
147
|
+
back: (rank - 2) * FISH_LENGTH * 1.35
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (shape === "ball") {
|
|
151
|
+
const r = FISH_LENGTH * (1.1 + 0.34 * Math.sqrt(count));
|
|
152
|
+
const g = (1 + Math.sqrt(5)) / 2;
|
|
153
|
+
const u = count <= 1 ? 0 : index / (count - 1);
|
|
154
|
+
const incl = Math.acos(1 - 2 * u);
|
|
155
|
+
const az = 2 * Math.PI * index / (g * g);
|
|
156
|
+
return {
|
|
157
|
+
side: r * Math.sin(incl) * Math.cos(az),
|
|
158
|
+
// Vertically squashed, hard-capped at 28: the water column is 57 units
|
|
159
|
+
// and the carrier's y-clamp needs the shell's top inside it whatever
|
|
160
|
+
// the cast size makes of the radius.
|
|
161
|
+
up: Math.cos(incl) * Math.min(r * 0.62, 28),
|
|
162
|
+
back: r * Math.sin(incl) * Math.sin(az)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
111
165
|
const cols = Math.max(1, Math.ceil(Math.sqrt(Math.max(1, count))));
|
|
112
166
|
const col = index % cols;
|
|
113
167
|
const row = Math.floor(index / cols);
|
|
114
|
-
const j = 0.35 + 0.65 * Math.max(0, Math.min(1, variance));
|
|
115
168
|
const span = Math.max(1, cols - 1);
|
|
116
169
|
const pitch = Math.min(FISH_LENGTH * 1.9, halfWidth * 2 / span);
|
|
117
170
|
const jit = pitch * 0.35;
|
|
171
|
+
const rows = Math.ceil(Math.max(1, count) / cols);
|
|
118
172
|
return {
|
|
119
173
|
side: (col - (cols - 1) / 2) * pitch + (fishHash(index, 4) - 0.5) * jit * j,
|
|
120
174
|
up: (fishHash(index, 5) - 0.5) * FISH_LENGTH * j,
|
|
121
|
-
|
|
175
|
+
// Centred fore-aft like every other shape — a 24-fish lattice trailing
|
|
176
|
+
// its whole depth behind the carrier pushed the extent past what the
|
|
177
|
+
// centre-clamp could absorb.
|
|
178
|
+
back: (row - (rows - 1) / 2) * FISH_LENGTH * 1.6 + fishHash(index, 6) * FISH_LENGTH * 0.4 * j
|
|
122
179
|
};
|
|
123
180
|
}
|
|
124
|
-
function formationExtent(count, variance) {
|
|
125
|
-
let side = 0, up = 0, back = 0;
|
|
181
|
+
function formationExtent(count, variance, shape = "phalanx") {
|
|
182
|
+
let side = 0, up = 0, back = 0, reach = 0;
|
|
126
183
|
for (let i = 0; i < count; i += 1) {
|
|
127
|
-
const s = formationSlot(i, count, variance);
|
|
184
|
+
const s = formationSlot(i, count, variance, void 0, shape);
|
|
128
185
|
side = Math.max(side, Math.abs(s.side));
|
|
129
186
|
up = Math.max(up, Math.abs(s.up));
|
|
130
187
|
back = Math.max(back, Math.abs(s.back));
|
|
188
|
+
reach = Math.max(reach, Math.hypot(s.side, s.back));
|
|
131
189
|
}
|
|
132
|
-
return { side, up, back };
|
|
190
|
+
return { side, up, back, reach };
|
|
133
191
|
}
|
|
134
192
|
function bandRange(band) {
|
|
135
193
|
switch (band) {
|
|
@@ -147,6 +205,225 @@ function bandRange(band) {
|
|
|
147
205
|
}
|
|
148
206
|
}
|
|
149
207
|
|
|
208
|
+
// src/plan.ts
|
|
209
|
+
var ARC_SAMPLES = 1024;
|
|
210
|
+
function catmullRom(p0, p1, p2, p3, u) {
|
|
211
|
+
const u2 = u * u;
|
|
212
|
+
const u3 = u2 * u;
|
|
213
|
+
return 0.5 * (2 * p1 + (-p0 + p2) * u + (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 + (-p0 + 3 * p1 - 3 * p2 + p3) * u3);
|
|
214
|
+
}
|
|
215
|
+
function splineAt(points, g) {
|
|
216
|
+
const n = points.length;
|
|
217
|
+
const i = Math.floor(g) % n;
|
|
218
|
+
const u = g - Math.floor(g);
|
|
219
|
+
const p0 = points[(i - 1 + n) % n];
|
|
220
|
+
const p1 = points[i];
|
|
221
|
+
const p2 = points[(i + 1) % n];
|
|
222
|
+
const p3 = points[(i + 2) % n];
|
|
223
|
+
return [
|
|
224
|
+
catmullRom(p0[0], p1[0], p2[0], p3[0], u),
|
|
225
|
+
catmullRom(p0[1], p1[1], p2[1], p3[1], u),
|
|
226
|
+
catmullRom(p0[2], p1[2], p2[2], p3[2], u)
|
|
227
|
+
];
|
|
228
|
+
}
|
|
229
|
+
var PATH_SHAPES = ["wander", "orbit", "eight", "helix", "canyon"];
|
|
230
|
+
function shapeWaypoints(shape, rng, bounds) {
|
|
231
|
+
const points = [];
|
|
232
|
+
const ySpan = bounds.yMax - bounds.yMin;
|
|
233
|
+
if (shape === "orbit") {
|
|
234
|
+
const n2 = 14 + rng.int(0, 4);
|
|
235
|
+
const r0 = bounds.radius * rng.range(0.45, 0.8);
|
|
236
|
+
const y0 = bounds.yMin + ySpan * rng.range(0.25, 0.75);
|
|
237
|
+
const dir = rng.next() < 0.5 ? 1 : -1;
|
|
238
|
+
for (let i = 0; i < n2; i++) {
|
|
239
|
+
const a = dir * (i / n2) * Math.PI * 2;
|
|
240
|
+
const r = r0 * (1 + rng.range(-0.08, 0.08));
|
|
241
|
+
points.push([Math.cos(a) * r, y0 + ySpan * rng.range(-0.08, 0.08), Math.sin(a) * r]);
|
|
242
|
+
}
|
|
243
|
+
return points;
|
|
244
|
+
}
|
|
245
|
+
if (shape === "eight") {
|
|
246
|
+
const n2 = 20 + rng.int(0, 4);
|
|
247
|
+
const rx = bounds.radius * rng.range(0.6, 0.85);
|
|
248
|
+
const rz = bounds.radius * rng.range(0.35, 0.55);
|
|
249
|
+
const y0 = bounds.yMin + ySpan * rng.range(0.3, 0.7);
|
|
250
|
+
const phase = rng.range(0, Math.PI * 2);
|
|
251
|
+
for (let i = 0; i < n2; i++) {
|
|
252
|
+
const u = i / n2 * Math.PI * 2;
|
|
253
|
+
points.push([
|
|
254
|
+
Math.sin(u + phase) * rx,
|
|
255
|
+
y0 + Math.sin(u * 2 + phase) * ySpan * 0.12,
|
|
256
|
+
Math.sin(u * 2 + phase * 2) * rz
|
|
257
|
+
]);
|
|
258
|
+
}
|
|
259
|
+
return points;
|
|
260
|
+
}
|
|
261
|
+
if (shape === "helix") {
|
|
262
|
+
const n2 = 24;
|
|
263
|
+
const r0 = bounds.radius * rng.range(0.35, 0.6);
|
|
264
|
+
const phase = rng.range(0, Math.PI * 2);
|
|
265
|
+
for (let i = 0; i < n2; i++) {
|
|
266
|
+
const u = i / n2;
|
|
267
|
+
const a = phase + u * Math.PI * 4;
|
|
268
|
+
const climb = 1 - Math.abs(1 - 2 * u);
|
|
269
|
+
points.push([
|
|
270
|
+
Math.cos(a) * r0,
|
|
271
|
+
bounds.yMin + ySpan * (0.1 + climb * 0.8),
|
|
272
|
+
Math.sin(a) * r0
|
|
273
|
+
]);
|
|
274
|
+
}
|
|
275
|
+
return points;
|
|
276
|
+
}
|
|
277
|
+
if (shape === "canyon") {
|
|
278
|
+
const n2 = 16;
|
|
279
|
+
const axis = rng.range(0, Math.PI);
|
|
280
|
+
const ax = Math.cos(axis), az = Math.sin(axis);
|
|
281
|
+
const y0 = bounds.yMin + ySpan * rng.range(0.08, 0.28);
|
|
282
|
+
const len = bounds.radius * 0.85;
|
|
283
|
+
const width = bounds.radius * rng.range(0.12, 0.3);
|
|
284
|
+
for (let i = 0; i < n2; i++) {
|
|
285
|
+
const u = i / n2 * Math.PI * 2;
|
|
286
|
+
const along = Math.sin(u) * len;
|
|
287
|
+
const across = Math.cos(u) * width;
|
|
288
|
+
points.push([
|
|
289
|
+
ax * along - az * across,
|
|
290
|
+
y0 + ySpan * rng.range(0, 0.08),
|
|
291
|
+
az * along + ax * across
|
|
292
|
+
]);
|
|
293
|
+
}
|
|
294
|
+
return points;
|
|
295
|
+
}
|
|
296
|
+
const n = 16 + rng.int(0, 4);
|
|
297
|
+
for (let i = 0; i < n; i++) {
|
|
298
|
+
const baseAngle = i / n * Math.PI * 2;
|
|
299
|
+
const angle = baseAngle + rng.range(-0.25, 0.25);
|
|
300
|
+
const inner = i % 2 === 0;
|
|
301
|
+
const radius = inner ? bounds.radius * rng.range(0.15, 0.45) : bounds.radius * rng.range(0.55, 0.85);
|
|
302
|
+
const y = bounds.yMin + ySpan * rng.range(0.2, 0.8);
|
|
303
|
+
points.push([Math.cos(angle) * radius, y, Math.sin(angle) * radius]);
|
|
304
|
+
}
|
|
305
|
+
return points;
|
|
306
|
+
}
|
|
307
|
+
function compileSwimPlan(rng, bounds, shape = "wander") {
|
|
308
|
+
const points = shapeWaypoints(shape, rng, bounds);
|
|
309
|
+
const n = points.length;
|
|
310
|
+
const arc = new Float32Array(ARC_SAMPLES + 1);
|
|
311
|
+
let prev = splineAt(points, 0);
|
|
312
|
+
let total = 0;
|
|
313
|
+
for (let s = 1; s <= ARC_SAMPLES; s++) {
|
|
314
|
+
const g = s / ARC_SAMPLES * n;
|
|
315
|
+
const p = splineAt(points, g);
|
|
316
|
+
total += Math.hypot(p[0] - prev[0], p[1] - prev[1], p[2] - prev[2]);
|
|
317
|
+
arc[s] = total;
|
|
318
|
+
prev = p;
|
|
319
|
+
}
|
|
320
|
+
const cruise = 8 + rng.range(0, 4);
|
|
321
|
+
const wobble = [
|
|
322
|
+
{ amp: cruise * 0.18, w: 0.11 + rng.range(0, 0.05), phase: rng.range(0, Math.PI * 2) },
|
|
323
|
+
{ amp: cruise * 0.1, w: 0.043 + rng.range(0, 0.02), phase: rng.range(0, Math.PI * 2) }
|
|
324
|
+
];
|
|
325
|
+
return { points, arc, totalLength: total, cruise, wobble };
|
|
326
|
+
}
|
|
327
|
+
function distanceAt(plan, tSec, speed) {
|
|
328
|
+
let d = plan.cruise * tSec;
|
|
329
|
+
for (const h of plan.wobble) {
|
|
330
|
+
d += h.amp / h.w * (Math.cos(h.phase) - Math.cos(h.w * tSec + h.phase));
|
|
331
|
+
}
|
|
332
|
+
return d * speed;
|
|
333
|
+
}
|
|
334
|
+
function paramForDistance(plan, dist) {
|
|
335
|
+
const n = plan.points.length;
|
|
336
|
+
const d = (dist % plan.totalLength + plan.totalLength) % plan.totalLength;
|
|
337
|
+
const arc = plan.arc;
|
|
338
|
+
let lo = 0;
|
|
339
|
+
let hi = ARC_SAMPLES;
|
|
340
|
+
while (lo + 1 < hi) {
|
|
341
|
+
const mid = lo + hi >> 1;
|
|
342
|
+
if (arc[mid] <= d) lo = mid;
|
|
343
|
+
else hi = mid;
|
|
344
|
+
}
|
|
345
|
+
const seg = arc[hi] - arc[lo] || 1;
|
|
346
|
+
const frac = (d - arc[lo]) / seg;
|
|
347
|
+
return (lo + frac) / ARC_SAMPLES * n;
|
|
348
|
+
}
|
|
349
|
+
function swimPoseAtDistance(plan, dist) {
|
|
350
|
+
const g = paramForDistance(plan, dist);
|
|
351
|
+
const [x, y, z] = splineAt(plan.points, g);
|
|
352
|
+
const step = plan.points.length / ARC_SAMPLES * 8;
|
|
353
|
+
const ahead = splineAt(plan.points, g + step);
|
|
354
|
+
const behind = splineAt(plan.points, g - step + plan.points.length);
|
|
355
|
+
let fx = ahead[0] - behind[0];
|
|
356
|
+
let fy = ahead[1] - behind[1];
|
|
357
|
+
let fz = ahead[2] - behind[2];
|
|
358
|
+
const m = Math.hypot(fx, fy, fz) || 1;
|
|
359
|
+
fx /= m;
|
|
360
|
+
fy /= m;
|
|
361
|
+
fz /= m;
|
|
362
|
+
const h0 = Math.atan2(z - behind[2], x - behind[0]);
|
|
363
|
+
const h1 = Math.atan2(ahead[2] - z, ahead[0] - x);
|
|
364
|
+
let turn = h1 - h0;
|
|
365
|
+
if (turn > Math.PI) turn -= Math.PI * 2;
|
|
366
|
+
if (turn < -Math.PI) turn += Math.PI * 2;
|
|
367
|
+
const roll = Math.max(-0.35, Math.min(0.35, turn * 3.5));
|
|
368
|
+
return { x, y, z, fx, fy, fz, roll, dist };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/maneuver.ts
|
|
372
|
+
var MANEUVERS = ["none", "dart", "startle", "graze", "curious", "zoomies"];
|
|
373
|
+
var SPECS = {
|
|
374
|
+
dart: { name: "dart", dur: 2.4, interval: 14, advance: 4.5, kick: 0.5, lift: 0, flurry: 1.1, bursts: 1 },
|
|
375
|
+
startle: { name: "startle", dur: 1.8, interval: 18, advance: 1.2, kick: 2.8, lift: 0.4, flurry: 1.3, bursts: 1 },
|
|
376
|
+
graze: { name: "graze", dur: 5.5, interval: 16, advance: -3.2, kick: 0.6, lift: -0.7, flurry: 0.3, bursts: 1 },
|
|
377
|
+
curious: { name: "curious", dur: 4, interval: 15, advance: 0.8, kick: 2, lift: 0.2, flurry: 0.5, bursts: 1 },
|
|
378
|
+
zoomies: { name: "zoomies", dur: 3.2, interval: 20, advance: 7.5, kick: 0.9, lift: 0.15, flurry: 1.5, bursts: 3 }
|
|
379
|
+
};
|
|
380
|
+
function maneuverSpecOf(name) {
|
|
381
|
+
return Object.hasOwn(SPECS, name) ? SPECS[name] : null;
|
|
382
|
+
}
|
|
383
|
+
var smooth = (u) => u <= 0 ? 0 : u >= 1 ? 1 : u * u * (3 - 2 * u);
|
|
384
|
+
var bump = (u) => {
|
|
385
|
+
if (u <= 0 || u >= 1) return 0;
|
|
386
|
+
const b = 4 * u * (1 - u);
|
|
387
|
+
return b * b;
|
|
388
|
+
};
|
|
389
|
+
function surges(u, bursts) {
|
|
390
|
+
if (u <= 0) return 0;
|
|
391
|
+
if (u >= 1) return 1;
|
|
392
|
+
const x = u * bursts;
|
|
393
|
+
return (Math.floor(x) + smooth(x - Math.floor(x))) / bursts;
|
|
394
|
+
}
|
|
395
|
+
var IDLE = { along: 0, alongBump: 0, side: 0, up: 0, flurry: 0 };
|
|
396
|
+
function maneuverAt(spec, index, tSec, rate, intensity) {
|
|
397
|
+
if (!spec || rate <= 0 || intensity <= 0 || tSec < 0) return IDLE;
|
|
398
|
+
const interval = spec.interval * (3 - 2 * Math.min(1, rate));
|
|
399
|
+
const k0 = Math.floor(tSec / interval);
|
|
400
|
+
let along = 0;
|
|
401
|
+
let side = 0;
|
|
402
|
+
let up = 0;
|
|
403
|
+
let flurry = 0;
|
|
404
|
+
let alongBump = 0;
|
|
405
|
+
const done = Math.max(0, k0 - 1);
|
|
406
|
+
along += done * spec.advance * intensity;
|
|
407
|
+
for (const k of [k0 - 1, k0, k0 + 1]) {
|
|
408
|
+
if (k < 0) continue;
|
|
409
|
+
const start = (k + fishHash(index, 11 + k)) * interval;
|
|
410
|
+
const u = (tSec - start) / spec.dur;
|
|
411
|
+
if (u <= 0) continue;
|
|
412
|
+
if (u >= 1) {
|
|
413
|
+
if (k >= done) along += spec.advance * intensity;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
const sign = fishHash(index, 23 + k) < 0.5 ? -1 : 1;
|
|
417
|
+
const env = bump(u) * intensity;
|
|
418
|
+
along += spec.advance * surges(u, spec.bursts) * intensity;
|
|
419
|
+
alongBump += spec.advance * bump(u) * intensity;
|
|
420
|
+
side += sign * spec.kick * env;
|
|
421
|
+
up += spec.lift * spec.kick * env;
|
|
422
|
+
flurry += spec.flurry * env;
|
|
423
|
+
}
|
|
424
|
+
return { along, alongBump, side, up, flurry };
|
|
425
|
+
}
|
|
426
|
+
|
|
150
427
|
// src/asset-cids.ts
|
|
151
428
|
var ASSET_CIDS = [
|
|
152
429
|
"QmZCzKVLJ1MYRzaZEFyuMCVmrPR3urQYMFR9RWerJYpCEr",
|
|
@@ -702,14 +979,19 @@ var BREEDS = [
|
|
|
702
979
|
metadataCid: "QmZTntNpvwxe8Mii7s1XTpTrbaci4ZgYUXs9sEbsBodtaF",
|
|
703
980
|
model: "sea-turtle"
|
|
704
981
|
},
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
{ breed: "
|
|
982
|
+
// Unminted: `model` names the CURRENT basename in the original aquarium's
|
|
983
|
+
// NPC set (versioned there; these are the ones its entity classes load,
|
|
984
|
+
// except glow-fish, where the app loads the 503 KB glow-fish5 while an
|
|
985
|
+
// identical-material 30 KB Draco glow-fish4 sits beside it — we take the
|
|
986
|
+
// small one). All are clip-less and unrigged, so they swim on `bodyWiggle`.
|
|
987
|
+
{ breed: "blowfish", minted: false, count: 0, model: "blow-fish4" },
|
|
988
|
+
{ breed: "hackerfish", minted: false, count: 0, model: "hacker-fish3" },
|
|
989
|
+
{ breed: "glowfish", minted: false, count: 0, model: "glow-fish4" },
|
|
990
|
+
{ breed: "babyfish", minted: false, count: 0, model: "baby-fish2" },
|
|
991
|
+
{ breed: "shark", minted: false, count: 0, model: "shark3" },
|
|
992
|
+
{ breed: "crab", minted: false, count: 0, model: "crab3" },
|
|
711
993
|
{ breed: "jellyfish", minted: false, count: 0, model: "jellyfish" },
|
|
712
|
-
{ breed: "dori", minted: false, count: 0, model: "
|
|
994
|
+
{ breed: "dori", minted: false, count: 0, model: "dori3" }
|
|
713
995
|
];
|
|
714
996
|
function breedOf(id) {
|
|
715
997
|
if (!isMintedId(id)) return null;
|
|
@@ -800,6 +1082,16 @@ var FISH_CATALOG = [
|
|
|
800
1082
|
{ id: 497, name: "Fish 497", breed: "seaturtle", ipfs3d: "ipfs://QmTBNvoUiwPw9HSUmy1qKCWPBKkBRAensgooYVqMmsviaE/fish_497_of_the_metaquarium_3d.glb", localGlb: "" }
|
|
801
1083
|
];
|
|
802
1084
|
var DEFAULT_FISH = FISH_CATALOG[0];
|
|
1085
|
+
var NPC_CATALOG = [
|
|
1086
|
+
{ id: 601, name: "Blowfish", breed: "blowfish", ipfs3d: "", localGlb: "/assets/metaquarium/npc-blowfish.glb" },
|
|
1087
|
+
{ id: 602, name: "Hackerfish", breed: "hackerfish", ipfs3d: "", localGlb: "/assets/metaquarium/npc-hackerfish.glb" },
|
|
1088
|
+
{ id: 603, name: "Glowfish", breed: "glowfish", ipfs3d: "", localGlb: "/assets/metaquarium/npc-glowfish.glb" },
|
|
1089
|
+
{ id: 604, name: "Babyfish", breed: "babyfish", ipfs3d: "", localGlb: "/assets/metaquarium/npc-babyfish.glb" },
|
|
1090
|
+
{ id: 605, name: "Shark", breed: "shark", ipfs3d: "", localGlb: "/assets/metaquarium/shark3.glb" },
|
|
1091
|
+
{ id: 606, name: "Crab", breed: "crab", ipfs3d: "", localGlb: "/assets/metaquarium/npc-crab.glb" },
|
|
1092
|
+
{ id: 607, name: "Jellyfish", breed: "jellyfish", ipfs3d: "", localGlb: "/assets/metaquarium/npc-jellyfish.glb" },
|
|
1093
|
+
{ id: 608, name: "Dori", breed: "dori", ipfs3d: "", localGlb: "/assets/metaquarium/npc-dori.glb" }
|
|
1094
|
+
];
|
|
803
1095
|
function parseFishMix(mix, catalog = FISH_CATALOG) {
|
|
804
1096
|
const entries = [];
|
|
805
1097
|
const problems = [];
|
|
@@ -815,16 +1107,22 @@ function parseFishMix(mix, catalog = FISH_CATALOG) {
|
|
|
815
1107
|
let fish = /^\d+$/.test(key) ? catalog.find((f) => f.id === Number(key)) : catalog.find((f) => f.breed.toLowerCase() === key);
|
|
816
1108
|
if (!fish && catalog === FISH_CATALOG && /^\d+$/.test(key)) {
|
|
817
1109
|
const n = Number(key);
|
|
818
|
-
const
|
|
1110
|
+
const url2 = fishAsset(n, "3d");
|
|
819
1111
|
const breed = breedOf(n);
|
|
820
|
-
if (
|
|
1112
|
+
if (url2 && breed) fish = { id: n, name: `Fish ${n}`, breed, ipfs3d: url2, localGlb: "" };
|
|
821
1113
|
}
|
|
822
1114
|
if (!fish) {
|
|
1115
|
+
const breeds = [...new Set(catalog.map((f) => f.breed))].join(", ");
|
|
823
1116
|
problems.push(
|
|
824
|
-
/^\d+$/.test(key) ? catalog === FISH_CATALOG ? `"${key}": not a minted token id (1-${TOTAL_SUPPLY})` : `"${key}": not a catalog id` : `"${key}": not a breed (${
|
|
1117
|
+
/^\d+$/.test(key) ? catalog === FISH_CATALOG ? `"${key}": not a minted token id (1-${TOTAL_SUPPLY})` : `"${key}": not a catalog id` : `"${key}": not a breed (${breeds})`
|
|
825
1118
|
);
|
|
826
1119
|
continue;
|
|
827
1120
|
}
|
|
1121
|
+
const url = fish.ipfs3d;
|
|
1122
|
+
if (!url) {
|
|
1123
|
+
problems.push(`"${key}": model not hosted here (catalog carries no URL for it)`);
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
828
1126
|
let count = 1;
|
|
829
1127
|
if (countRaw !== void 0) {
|
|
830
1128
|
const n = Number(countRaw.trim());
|
|
@@ -839,7 +1137,7 @@ function parseFishMix(mix, catalog = FISH_CATALOG) {
|
|
|
839
1137
|
count = n;
|
|
840
1138
|
}
|
|
841
1139
|
}
|
|
842
|
-
entries.push({ id: fish.id, url
|
|
1140
|
+
entries.push({ id: fish.id, url, count });
|
|
843
1141
|
}
|
|
844
1142
|
return { entries, problems };
|
|
845
1143
|
}
|
|
@@ -921,10 +1219,30 @@ var METAQUARIUM_PARAMS = {
|
|
|
921
1219
|
* default changes nothing. A small named set on purpose: a silhouette of
|
|
922
1220
|
* movement you can name is one you can choose from. */
|
|
923
1221
|
swimStyle: { type: "enum", default: "loop", options: [...SWIM_STYLE_NAMES], ease: "step" },
|
|
1222
|
+
/** The shape a fish's loop is drawn on. `wander` is the original roaming
|
|
1223
|
+
* itinerary, so the default changes nothing. `orbit` laps, `eight` crosses
|
|
1224
|
+
* the middle, `helix` tours the water column, `canyon` sweeps low — same
|
|
1225
|
+
* spline engine, different itinerary. */
|
|
1226
|
+
pathShape: { type: "enum", default: "wander", options: [...PATH_SHAPES], ease: "step" },
|
|
1227
|
+
/** How a `school` holds together: the original lattice, single file, a
|
|
1228
|
+
* carousel ring, the migratory V, or a bait-ball. Ignored by every
|
|
1229
|
+
* non-formation style; the same no-pair-inside-a-body-length law holds
|
|
1230
|
+
* for all of them. */
|
|
1231
|
+
formationShape: { type: "enum", default: "phalanx", options: [...FORMATION_SHAPES], ease: "step" },
|
|
924
1232
|
/** Per-fish spread: 0 a uniform shoal, 1 every fish visibly its own animal
|
|
925
1233
|
* (±40% speed, ±25% size, own phase). The uniqueness dial — one number
|
|
926
1234
|
* instead of per-fish values nobody wants to author. */
|
|
927
1235
|
swimVariance: { type: "number", default: 0, min: 0, max: 1, ease: "smooth" },
|
|
1236
|
+
/** Named event layered over the swim style — the thing that turns uniform
|
|
1237
|
+
* cruising into behaviour a viewer recognizes. Each fish runs its own
|
|
1238
|
+
* seeded schedule of the chosen event; displacement-based, so frames stay
|
|
1239
|
+
* addressable. `none` (default) changes nothing. */
|
|
1240
|
+
maneuver: { type: "enum", default: "none", options: [...MANEUVERS], ease: "step" },
|
|
1241
|
+
/** How often events fire: 0 never, 1 the maneuver's own tempo (roughly
|
|
1242
|
+
* every 14-20s per fish, desynchronised). */
|
|
1243
|
+
maneuverRate: { type: "number", default: 0.5, min: 0, max: 1, ease: "smooth" },
|
|
1244
|
+
/** How hard: scales the surge, the kick, and the tail flurry together. */
|
|
1245
|
+
maneuverIntensity: { type: "number", default: 0.7, min: 0, max: 1, ease: "smooth" },
|
|
928
1246
|
/** Procedural body yaw for models that carry NO animation clip — most of
|
|
929
1247
|
* the breed library. Distance-driven like the tail beat, so it speeds up
|
|
930
1248
|
* with the fish and stays frame-addressable. Clipped models ignore it:
|
|
@@ -1038,9 +1356,16 @@ export {
|
|
|
1038
1356
|
fishHash,
|
|
1039
1357
|
fishVariation,
|
|
1040
1358
|
FISH_LENGTH,
|
|
1359
|
+
FORMATION_SHAPES,
|
|
1041
1360
|
formationSlot,
|
|
1042
1361
|
formationExtent,
|
|
1043
1362
|
bandRange,
|
|
1363
|
+
PATH_SHAPES,
|
|
1364
|
+
compileSwimPlan,
|
|
1365
|
+
distanceAt,
|
|
1366
|
+
swimPoseAtDistance,
|
|
1367
|
+
maneuverSpecOf,
|
|
1368
|
+
maneuverAt,
|
|
1044
1369
|
ASSET_CIDS,
|
|
1045
1370
|
TOTAL_SUPPLY,
|
|
1046
1371
|
isMintedId,
|
|
@@ -1058,6 +1383,7 @@ export {
|
|
|
1058
1383
|
resolveIpfsUrls,
|
|
1059
1384
|
FISH_CATALOG,
|
|
1060
1385
|
DEFAULT_FISH,
|
|
1386
|
+
NPC_CATALOG,
|
|
1061
1387
|
parseFishMix,
|
|
1062
1388
|
expandFishMix,
|
|
1063
1389
|
METAQUARIUM_PARAMS,
|
|
@@ -1068,4 +1394,4 @@ export {
|
|
|
1068
1394
|
paramSpaceWith,
|
|
1069
1395
|
coerceNum
|
|
1070
1396
|
};
|
|
1071
|
-
//# sourceMappingURL=chunk-
|
|
1397
|
+
//# sourceMappingURL=chunk-23P73MYY.js.map
|