@idle-screens/saver-metaquarium 0.21.0 → 0.22.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-5DJ5WBVN.js → chunk-42RIVUT4.js} +232 -29
- package/dist/chunk-42RIVUT4.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/{lofi-tank-Z2GDMEPV.js → lofi-tank-BJY5Z3J5.js} +2 -2
- package/dist/{manifest-CiE6U104.d.ts → manifest-nIf510iL.d.ts} +22 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +1 -1
- package/dist/{tank-3CC56AJN.js → tank-EOBD2TLR.js} +572 -308
- package/dist/tank-EOBD2TLR.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-5DJ5WBVN.js.map +0 -1
- package/dist/tank-3CC56AJN.js.map +0 -1
- /package/dist/{lofi-tank-Z2GDMEPV.js.map → lofi-tank-BJY5Z3J5.js.map} +0 -0
|
@@ -1620,7 +1620,7 @@ function shardGeometry(rng) {
|
|
|
1620
1620
|
for (let i = 0; i < n; i += 1) tris.push([top[i], tip, top[(i + 1) % n]]);
|
|
1621
1621
|
const positions = new Float32Array(tris.length * 9);
|
|
1622
1622
|
const normals = new Float32Array(tris.length * 9);
|
|
1623
|
-
const
|
|
1623
|
+
const smooth4 = new Float32Array(tris.length * 9);
|
|
1624
1624
|
tris.forEach((tri, t) => {
|
|
1625
1625
|
const [a, b, c] = tri;
|
|
1626
1626
|
const ux = b[0] - a[0], uy = b[1] - a[1], uz = b[2] - a[2];
|
|
@@ -1648,12 +1648,12 @@ function shardGeometry(rng) {
|
|
|
1648
1648
|
normals[o + 2] = nz;
|
|
1649
1649
|
const sy = (p[1] - 0.55) * 0.25;
|
|
1650
1650
|
const sl = Math.hypot(p[0], sy, p[2]) || 1;
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1651
|
+
smooth4[o] = p[0] / sl;
|
|
1652
|
+
smooth4[o + 1] = sy / sl;
|
|
1653
|
+
smooth4[o + 2] = p[2] / sl;
|
|
1654
1654
|
});
|
|
1655
1655
|
});
|
|
1656
|
-
return { positions, normals, smooth:
|
|
1656
|
+
return { positions, normals, smooth: smooth4, triangles: tris.length };
|
|
1657
1657
|
}
|
|
1658
1658
|
var HABIT_RINGS = {
|
|
1659
1659
|
lotus: [[1, 0], [6, 30], [9, 55], [16, 85]],
|
|
@@ -2500,10 +2500,190 @@ function parseSignMix(value) {
|
|
|
2500
2500
|
return { entries, problems };
|
|
2501
2501
|
}
|
|
2502
2502
|
|
|
2503
|
+
// src/choreo.ts
|
|
2504
|
+
var STARFISH_MOVE_NAMES = [
|
|
2505
|
+
"march",
|
|
2506
|
+
"jacks",
|
|
2507
|
+
"reach",
|
|
2508
|
+
"kick",
|
|
2509
|
+
"twist",
|
|
2510
|
+
"circles",
|
|
2511
|
+
"disco",
|
|
2512
|
+
"spin",
|
|
2513
|
+
"mambo",
|
|
2514
|
+
"sway",
|
|
2515
|
+
"twirl",
|
|
2516
|
+
"dip",
|
|
2517
|
+
"hold",
|
|
2518
|
+
"walk",
|
|
2519
|
+
"lie",
|
|
2520
|
+
"crawl",
|
|
2521
|
+
"curl",
|
|
2522
|
+
"wave",
|
|
2523
|
+
"pop",
|
|
2524
|
+
"rise",
|
|
2525
|
+
"sit"
|
|
2526
|
+
];
|
|
2527
|
+
var CHOREO_MARKS = {
|
|
2528
|
+
home: [0, 0],
|
|
2529
|
+
left: [-2, 0],
|
|
2530
|
+
right: [2, 0],
|
|
2531
|
+
front: [0, 1.2],
|
|
2532
|
+
back: [0, -1.5],
|
|
2533
|
+
centre: "centre"
|
|
2534
|
+
};
|
|
2535
|
+
var MAX_CUES = 256;
|
|
2536
|
+
function parseChoreography(value, moves) {
|
|
2537
|
+
const lines = /* @__PURE__ */ new Map(), problems = [];
|
|
2538
|
+
const known = new Set(moves);
|
|
2539
|
+
for (const rawLine of value.split("|").map((s) => s.trim()).filter(Boolean)) {
|
|
2540
|
+
const head = /^([a-z]|\*)\s*:\s*(?=\d|\.)/.exec(rawLine);
|
|
2541
|
+
const actor = head ? head[1] === "*" ? "*" : head[1].charCodeAt(0) - 97 : "*";
|
|
2542
|
+
const body = head ? rawLine.slice(head[0].length) : rawLine;
|
|
2543
|
+
if (lines.has(actor)) problems.push(`dancer ${actor === "*" ? "*" : String.fromCharCode(97 + actor)} has two lines; the later one wins`);
|
|
2544
|
+
const cues = [];
|
|
2545
|
+
let b0 = 0;
|
|
2546
|
+
for (const raw of body.split(/,\s*(?=(?:\d+(?:\.\d+)?|\.\d+)\s*:)/).map((s) => s.trim()).filter(Boolean)) {
|
|
2547
|
+
if (cues.length >= MAX_CUES) {
|
|
2548
|
+
problems.push(`more than ${MAX_CUES} cues on one line; the rest are dropped`);
|
|
2549
|
+
break;
|
|
2550
|
+
}
|
|
2551
|
+
const m = /^(\d+(?:\.\d+)?|\.\d+)\s*:\s*([a-z][a-z_]*)([^a-z_].*)?$/.exec(raw);
|
|
2552
|
+
if (!m) {
|
|
2553
|
+
problems.push(`"${raw}" is not <beats>:<move>`);
|
|
2554
|
+
continue;
|
|
2555
|
+
}
|
|
2556
|
+
const beats = Number(m[1]);
|
|
2557
|
+
if (!(beats > 0)) {
|
|
2558
|
+
problems.push(`"${raw}": a cue needs some beats`);
|
|
2559
|
+
continue;
|
|
2560
|
+
}
|
|
2561
|
+
if (!known.has(m[2])) {
|
|
2562
|
+
problems.push(`"${raw}": no move "${m[2]}" (moves: ${moves.join(" ")})`);
|
|
2563
|
+
continue;
|
|
2564
|
+
}
|
|
2565
|
+
const cue = { b0, beats: Math.min(beats, 512), move: m[2], turn: 0, lift: 0 };
|
|
2566
|
+
for (const tok of (m[3] ?? "").replace(/^[,\s]+/, "").split(/\s+/).filter(Boolean)) {
|
|
2567
|
+
const mod = /^([>@~^/%*])(.+)$/.exec(tok);
|
|
2568
|
+
if (!mod) {
|
|
2569
|
+
problems.push(`"${raw}": "${tok}" is not >to, @face, ~turn, ^leap, /lean, %crouch or *groove`);
|
|
2570
|
+
continue;
|
|
2571
|
+
}
|
|
2572
|
+
const [, op, arg] = mod;
|
|
2573
|
+
if (op === ">") {
|
|
2574
|
+
const mark = CHOREO_MARKS[arg];
|
|
2575
|
+
const xy = /^(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)$/.exec(arg);
|
|
2576
|
+
if (mark) cue.to = mark;
|
|
2577
|
+
else if (xy) cue.to = [clamp(Number(xy[1]), -6, 6), clamp(Number(xy[2]), -6, 6)];
|
|
2578
|
+
else problems.push(`"${raw}": travel to "${arg}" \u2014 a mark (${Object.keys(CHOREO_MARKS).join(" ")}) or side,depth`);
|
|
2579
|
+
} else if (op === "@") {
|
|
2580
|
+
const named = { cam: "cam", room: 0, front: 0, back: 180, left: -90, right: 90 };
|
|
2581
|
+
if (arg in named) cue.face = named[arg];
|
|
2582
|
+
else if (Number.isFinite(Number(arg))) cue.face = Number(arg);
|
|
2583
|
+
else problems.push(`"${raw}": face "${arg}" \u2014 degrees, cam, room, left, right or back`);
|
|
2584
|
+
} else if (op === "/") {
|
|
2585
|
+
if (Number.isFinite(Number(arg))) cue.lean = clamp(Number(arg), -60, 60);
|
|
2586
|
+
else problems.push(`"${raw}": lean "${arg}" is not degrees`);
|
|
2587
|
+
} else if (op === "%") {
|
|
2588
|
+
if (Number.isFinite(Number(arg)) && Number(arg) > 0) cue.squash = clamp(Number(arg), 0.4, 1.5);
|
|
2589
|
+
else problems.push(`"${raw}": crouch "${arg}" is not a height scale`);
|
|
2590
|
+
} else if (op === "*") {
|
|
2591
|
+
if (Number.isFinite(Number(arg)) && Number(arg) > 0) cue.groove = clamp(Number(arg), 0.02, 0.3);
|
|
2592
|
+
else problems.push(`"${raw}": groove "${arg}" is not a depth`);
|
|
2593
|
+
} else if (op === "~") {
|
|
2594
|
+
if (Number.isFinite(Number(arg))) cue.turn = clamp(Number(arg), -1440, 1440);
|
|
2595
|
+
else problems.push(`"${raw}": turn "${arg}" is not degrees`);
|
|
2596
|
+
} else {
|
|
2597
|
+
if (Number.isFinite(Number(arg)) && Number(arg) >= 0) cue.lift = Math.min(Number(arg), 3);
|
|
2598
|
+
else problems.push(`"${raw}": leap "${arg}" is not a height`);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
cues.push(cue);
|
|
2602
|
+
b0 += cue.beats;
|
|
2603
|
+
}
|
|
2604
|
+
if (cues.length) lines.set(actor, { cues, beats: b0 });
|
|
2605
|
+
else problems.push(`line "${rawLine}" has no cues`);
|
|
2606
|
+
}
|
|
2607
|
+
return { lines, problems };
|
|
2608
|
+
}
|
|
2609
|
+
var CHOREO_HANDOVER = 0.5;
|
|
2610
|
+
var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
2611
|
+
var smooth3 = (u) => {
|
|
2612
|
+
const c = clamp(u, 0, 1);
|
|
2613
|
+
return c * c * (3 - 2 * c);
|
|
2614
|
+
};
|
|
2615
|
+
var posMod = (v, m) => (v % m + m) % m;
|
|
2616
|
+
function choreoLine(sheet, slot) {
|
|
2617
|
+
return sheet?.lines.get(slot) ?? sheet?.lines.get("*") ?? null;
|
|
2618
|
+
}
|
|
2619
|
+
function choreoAt(line, beats) {
|
|
2620
|
+
const b = posMod(beats, line.beats);
|
|
2621
|
+
const n = line.cues.length;
|
|
2622
|
+
let i = 0;
|
|
2623
|
+
while (i < n - 1 && b >= line.cues[i].b0 + line.cues[i].beats) i++;
|
|
2624
|
+
const cue = line.cues[i], next = line.cues[(i + 1) % n], prev = line.cues[(i + n - 1) % n];
|
|
2625
|
+
let side = 0, depth = 0, centre = 0, face = 0, faceCam = 0, turn = 0;
|
|
2626
|
+
const end = (c) => {
|
|
2627
|
+
if (c.to === "centre") centre = 1;
|
|
2628
|
+
else if (c.to) {
|
|
2629
|
+
side = c.to[0];
|
|
2630
|
+
depth = c.to[1];
|
|
2631
|
+
centre = 0;
|
|
2632
|
+
}
|
|
2633
|
+
turn += c.turn;
|
|
2634
|
+
};
|
|
2635
|
+
const facing = (c) => {
|
|
2636
|
+
if (c.face === "cam") faceCam = 1;
|
|
2637
|
+
else if (c.face !== void 0) {
|
|
2638
|
+
face = c.face;
|
|
2639
|
+
faceCam = 0;
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
for (let k = 0; k < i; k++) {
|
|
2643
|
+
end(line.cues[k]);
|
|
2644
|
+
facing(line.cues[k]);
|
|
2645
|
+
}
|
|
2646
|
+
facing(cue);
|
|
2647
|
+
const beat = b - cue.b0, u = clamp(beat / cue.beats, 0, 1);
|
|
2648
|
+
const s = smooth3(u);
|
|
2649
|
+
if (cue.to === "centre") centre += (1 - centre) * s;
|
|
2650
|
+
else if (cue.to) {
|
|
2651
|
+
side += (cue.to[0] - side) * s;
|
|
2652
|
+
depth += (cue.to[1] - depth) * s;
|
|
2653
|
+
centre *= 1 - s;
|
|
2654
|
+
}
|
|
2655
|
+
turn += cue.turn * s;
|
|
2656
|
+
const lift = cue.lift > 0 ? cue.lift * Math.sin(Math.PI * u) : 0;
|
|
2657
|
+
const last = i === n - 1;
|
|
2658
|
+
const h = Math.min(CHOREO_HANDOVER, cue.beats / 2, next.beats / 2);
|
|
2659
|
+
const ahead = smooth3((beat - (cue.beats - h)) / h);
|
|
2660
|
+
if (ahead > 0) {
|
|
2661
|
+
if (next.face === "cam") faceCam += (1 - faceCam) * ahead;
|
|
2662
|
+
else if (next.face !== void 0 && !last) {
|
|
2663
|
+
face += angleTo(face, next.face) * ahead;
|
|
2664
|
+
faceCam *= 1 - ahead;
|
|
2665
|
+
} else if (last) {
|
|
2666
|
+
face += angleTo(face, next.face === void 0 ? 0 : next.face) * ahead;
|
|
2667
|
+
faceCam *= 1 - ahead;
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
const lean = (cue.lean ?? 0) + ((next.lean ?? 0) - (cue.lean ?? 0)) * ahead;
|
|
2671
|
+
let squash = (cue.squash ?? 1) + ((next.squash ?? 1) - (cue.squash ?? 1)) * ahead;
|
|
2672
|
+
if (next.lift > 0) squash *= 1 - 0.16 * ahead;
|
|
2673
|
+
if (cue.lift > 0) squash *= u < 0.15 ? 0.84 + 0.26 * smooth3(u / 0.15) : 1 + 0.1 * Math.sin(Math.PI * u) - 0.16 * smooth3((u - 0.85) / 0.15);
|
|
2674
|
+
if (prev.lift > 0 && n > 1) squash *= 0.84 + 0.16 * smooth3(beat / Math.min(0.75, cue.beats));
|
|
2675
|
+
const groove = cue.groove ?? 0;
|
|
2676
|
+
if (groove > 0 && cue.lift === 0) squash *= 1 - groove * (1 + Math.cos(2 * Math.PI * posMod(beats, 1))) / 2;
|
|
2677
|
+
return { cue, beat, u, next, ahead, side, depth, centre, face, faceCam, turn, lift, lean, squash };
|
|
2678
|
+
}
|
|
2679
|
+
function angleTo(a, b) {
|
|
2680
|
+
return posMod(b - a + 180, 360) - 180;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2503
2683
|
// src/vignette.ts
|
|
2504
2684
|
var DANCES = ["toprock", "footwork", "windmill", "headspin", "freeze", "drop"];
|
|
2505
|
-
var GESTURES = ["talk", "nod", "shake", "hop", "spin", "wiggle", "rest", "peek", "bow", "ink", ...DANCES];
|
|
2506
|
-
var BREED_GESTURES = { ink: ["octopus"] };
|
|
2685
|
+
var GESTURES = ["talk", "nod", "shake", "hop", "spin", "wiggle", "rest", "peek", "bow", "ink", "puff", ...DANCES];
|
|
2686
|
+
var BREED_GESTURES = { ink: ["octopus"], puff: ["blowfish"] };
|
|
2507
2687
|
var OPEN_MARKS = {
|
|
2508
2688
|
centre: { x: 0, y: 36, z: 0 },
|
|
2509
2689
|
left: { x: -70, y: 34, z: 0 },
|
|
@@ -2788,6 +2968,7 @@ function poseOf(v, actor, tSec, own) {
|
|
|
2788
2968
|
pitch = -0.08 * e;
|
|
2789
2969
|
break;
|
|
2790
2970
|
// ink: the body holds still; the octopus squirts its cloud (the tank's InkLayer) and pales.
|
|
2971
|
+
// puff: the body holds still; the blowfish gulps itself round (puffer.ts PufferInput.puffCue).
|
|
2791
2972
|
// The dances, for a fish with no clips for them: the whole body does what it can.
|
|
2792
2973
|
case "toprock":
|
|
2793
2974
|
roll += Math.sin(bt * Math.PI * 2) * 0.3 * e;
|
|
@@ -3121,23 +3302,23 @@ var PARAM_DOCS = {
|
|
|
3121
3302
|
cameraAzimuth: "Orbit bearing in degrees. 0 looks at the village from the front.",
|
|
3122
3303
|
cameraElevation: "Degrees above the floor. 8\u201315 is eye level with the fish; 40+ looks down on a castle.",
|
|
3123
3304
|
cameraDistance: "Distance from the tank centre. 80 is a close-up, 170\u2013220 a village, 300+ a landmark.",
|
|
3124
|
-
shot: "A framing: `orbit
|
|
3305
|
+
shot: "A framing: `orbit`, `hero` (three-quarter), `front` (level, long lens), `low`, `top` (a map), `surface`, `macro` (nearest landmark), `cast` (the mix's first three). Azimuth and autoRotate turn it, distance scales it.",
|
|
3125
3306
|
shotBlend: "Seconds a change of `shot` takes (0 = a cut): the camera moves to the new framing, eased.",
|
|
3126
3307
|
cameraFollow: "Ride with one fish (cast slot); -1 is the orbit camera, whose params are ignored while following. With `followSpot` on the slot, a spotlit chase.",
|
|
3127
3308
|
followAngle: "Where round the followed fish the chase camera stands, degrees: 0 behind (default), 90 beside, 180 in front looking back at its face.",
|
|
3128
3309
|
followDistance: "How far behind the followed fish the camera rides (40\u201370 is a chase). Under ~18 it is the fish's eye; a floor walker sees from its own head height.",
|
|
3129
3310
|
autoRotate: "Turntable speed, degrees/second. 0 holds the shot (stages, vignettes); 1\u20132 is a slow reveal. frame.state.camera.bearing: where it stands now.",
|
|
3130
3311
|
followAvoid: "Keep the followed fish in view, 0\u20131: the chase camera rises over low clutter or pulls in, eased. For walks through a village.",
|
|
3131
|
-
nearFade: "A creature at the lens dissolves
|
|
3312
|
+
nearFade: "A creature at the lens dissolves, not sliced, 0\u20131. The followed fish never fades.",
|
|
3132
3313
|
// cast
|
|
3133
3314
|
fishCount: "How many fish when `fishMix` is empty (all are `fishUrl`).",
|
|
3134
3315
|
finish: "A final full-screen pass: gentle grade, soft vignette, dither against banding, and restrained bloom on high-end devices (0 = none; never on the low tier).",
|
|
3135
3316
|
tiltShift: "Tilt-shift, 0\u20131: sharp through the middle, soft above and below, like a model. Mid/high tiers.",
|
|
3136
|
-
depthOfField: "Depth of field, 0\u20131: the subject
|
|
3317
|
+
depthOfField: "Depth of field, 0\u20131: the subject (followed fish, `cast` leads) sharp, the rest soft. High tier.",
|
|
3137
3318
|
ambientOcclusion: "Ambient occlusion, 0\u20131: crevices darken. High tier.",
|
|
3138
|
-
highlights: "Bright light rolls off instead of clipping, 0\u20131: a fish in a shaft stays a fish.
|
|
3319
|
+
highlights: "Bright light rolls off instead of clipping, 0\u20131: a fish in a shaft stays a fish. Mid/high tiers.",
|
|
3139
3320
|
fishUrl: "The single model used when `fishMix` is empty: ipfs://, https://assets.idlescreens.com/, or a URL on the page's own origin. Any other host is refused and the default fish swims.",
|
|
3140
|
-
fishMix: "The cast: `id[:count][@style]`, comma-separated: `100:2@drift,
|
|
3321
|
+
fishMix: "The cast: `id[:count][@style]`, comma-separated: `100:2@drift, seahorse:3, shark:1@patrol`. Minted breeds plus bundled: shark crab dori glowfish babyfish hackerfish blowfish starfish octopus snail dot dolphin. Floor walkers keep their own pace: crab, starfish (dances: `starfishDance`, `choreography`), snail. `dot` (a box on legs), `dolphin` (flips, breaches) play vignette gestures. Overrides fishCount/fishUrl.",
|
|
3141
3322
|
dracoPath: "Where the Draco decoder lives; leave empty on a channel. Only the page's own origin or the shipped copy is used.",
|
|
3142
3323
|
swimSpeed: "Global swim speed multiplier. 0.4 is contemplative, 1 lively.",
|
|
3143
3324
|
swimStyle: "How the cast swims unless a fishMix entry says otherwise (`@style`). `auto` picks by breed.",
|
|
@@ -3161,14 +3342,16 @@ var PARAM_DOCS = {
|
|
|
3161
3342
|
fishGlow: "How strongly GLOW- parts of a fish bloom and light their neighbours and the floor.",
|
|
3162
3343
|
fishMetal: "`on` (default) gives METAL- parts a polished, reflective finish.",
|
|
3163
3344
|
snailShell: "Snail shells: `banded`, `pearl` (iridescent), `gold`, `glow` (a spiral breathing light; best at night); `mix` (default), each its own. Lit fish only. frame.state.fish[i].shell says which.",
|
|
3164
|
-
starfishDance: "Starfish dance: `aerobics
|
|
3165
|
-
danceTempo: "
|
|
3345
|
+
starfishDance: "Starfish dance: `aerobics` (a class in unison), `freestyle` (a move each per eight counts), `duet` (couples), `off`. Cast a few: `starfish:7`.",
|
|
3346
|
+
danceTempo: "Dance BPM; glides on the beat.",
|
|
3347
|
+
choreography: "Starfish dance cues, on the beat (see grammar).",
|
|
3166
3348
|
fishLook: "`neon` dresses the bundled creatures for blacklight: near-black coats, eyes (and a crab's mouth) glowing a neon of their own. Best in a dark room with `finish`. Default `natural`.",
|
|
3167
3349
|
fishRim: "A thin edge of the water's light round each fish, 0\u20131 (lit mode): dark fish on dark water. 0.6\u20131 in dark rooms.",
|
|
3168
|
-
fishShadows: "Soft shadows
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3350
|
+
fishShadows: "Soft shadows under the swimmers, 0\u20131: dark near the sand, faint high up.",
|
|
3351
|
+
fishAO: "A fish's own corners darken, 0\u20131: solid fish. All tiers.",
|
|
3352
|
+
fishFadeIn: "Seconds an arriving fish takes to fade in (0 pops in).",
|
|
3353
|
+
sceneryShadows: "Soft shadows under rocks, homes, castle, pyramids, geodes, lamps, 0\u20131: nothing floats.",
|
|
3354
|
+
voxelAO: "Plant cubes darken where they touch each other and the sand, 0\u20131. All tiers.",
|
|
3172
3355
|
swimWave: "Fish bend as they swim: a wave nose to tail, the body curling into turns (0 = rigid wiggle). Skips the turtle, crab and fish with a skeleton; the seahorse gets fin, tail and nod instead.",
|
|
3173
3356
|
fishAvoid: "Fish make way for each other: a pair about to meet parts a second ahead, the smaller giving more, over or under before round. 1 (default) on, 0 pass-through. `inspect().crowding` counts pairs still touching.",
|
|
3174
3357
|
eyeLife: "Eyes blink, look, and emote (0 = painted on). Redraws each token's own pixel-grid eye; black and white only.",
|
|
@@ -3188,7 +3371,7 @@ var PARAM_DOCS = {
|
|
|
3188
3371
|
waterY: "Height of the water ceiling; -1 = the environment's own.",
|
|
3189
3372
|
rayStrength: "Surface light shafts, within device budget: 5 high tier, 2 standard; none on the lowest tier with a surface (abyss, vent, universe keep 2; perceiveChannel then reads 0).",
|
|
3190
3373
|
raySoftness: "Shafts as soft volume, not flat sheets, 0\u20131. 1 for anything cinematic.",
|
|
3191
|
-
floorDetail: "A seabed, not a coloured plane, 0\u20131: ripples, silt, grain;
|
|
3374
|
+
floorDetail: "A seabed, not a coloured plane, 0\u20131: ripples, silt, grain; its far edge fades into the fog.",
|
|
3192
3375
|
caustics: "The dancing net of light from the surface on the floor, rocks, plants and fish (0 = none). Sharp near the top, soft and dim deep down.",
|
|
3193
3376
|
causticScale: "Size of the caustic cells: below 1 a fine shimmer, above 1 broad slow bands.",
|
|
3194
3377
|
surfaceMirror: "The surface from below: a window to the light in a rippling mirror of the tank (0 = plain). Needs reef, kelp, ice or lagoon; for the `surface` and `low` shots. High tier mirrors the tank, mid the deep water.",
|
|
@@ -3243,7 +3426,7 @@ var PARAM_DOCS = {
|
|
|
3243
3426
|
spotColor: "Colour of the single `followSpot`.",
|
|
3244
3427
|
spotShadow: "The spotted fish's shadow in its pool. 0 none, 1 true size.",
|
|
3245
3428
|
spotRig: "Up to three spots: `slot[/color][*radius]` follows a fish, `@mark` stands on a mark (`@mic` lights whoever steps up). They are a, b, c in order. Overrides followSpot.",
|
|
3246
|
-
spotCues: "
|
|
3429
|
+
spotCues: "Looping cues for the rig: `8s:a, 12s:a+b, 4s:-` (`-` blackout, cues \u2265 2 s). Spots cross-fade.",
|
|
3247
3430
|
vignette: "A small scene for the first 2\u20133 fish: a preset (tea\xB7bedtime\xB7seek indoors; duet\xB7trio\xB7openmic on the open stage) or a script of beats. A floor creature cast as an actor stays on the floor. Grammar below."
|
|
3248
3431
|
};
|
|
3249
3432
|
var GRAMMAR = `
|
|
@@ -3269,13 +3452,14 @@ geodeMineral world | mineral, \u2026 amethyst agate celestine citrine carneli
|
|
|
3269
3452
|
floraPalette world | #rrggbb, \u2026 (\u22646) world \xB7 #ff4fa0, #ffb347, #4fd1ff
|
|
3270
3453
|
spotRig slot|@mark[/color][*radius], \u2026 (\u22643; they become a, b, c) 0/#ffd27a*24, 1/#ff8ad0*24, 2/#7fdcff*24
|
|
3271
3454
|
spotCues <sec>s:<spots>, \u2026 loops 4s:-, 7s:a, 7s:b, 12s:a+b
|
|
3455
|
+
choreography [a|*:] <beats>:<move> [>to @face ~turn ^leap /lean %crouch *groove],\u2026|\u2026 moves ${STARFISH_MOVE_NAMES.join(" ")}
|
|
3272
3456
|
signs kind[@place][>target][/#color][*size][:text], \u2026 plank@gate:"Welcome to the reef", neon@home1/#ff4fa0:OPEN, led@plaza:TIDE 4.2M
|
|
3273
3457
|
kinds plank arrow ring porthole neon led \xB7 places gate plaza courtyard hub fountain home1 home2 home3 centre left right front back
|
|
3274
3458
|
an arrow points at >target \xB7 text \u2264 plank 24, arrow 16, ring 10, porthole 4 (empty = a fish), neon 14, led 64 (scrolls) \xB7 \u2264 8 signs
|
|
3275
3459
|
vignette beats separated by |, cues by comma; actors a b c d are fish slots 0 1 2 3
|
|
3276
3460
|
[<sec>s:] actor =mark be there, no travel (a later beat's = snaps at its start) actor >mark swim there
|
|
3277
3461
|
actor @mark | @actor face it a b circle mark each named actor rings it, back to its spot by the beat's end; others stay put
|
|
3278
|
-
actor follow actor gestures: talk nod shake hop spin wiggle rest peek bow \xB7 ink (octopus
|
|
3462
|
+
actor follow actor gestures: talk nod shake hop spin wiggle rest peek bow \xB7 ink (octopus) \xB7 puff (blowfish)
|
|
3279
3463
|
dances: toprock footwork windmill headspin freeze drop (a betafish dances them with its own body; 2 s beats keep them on a 120 bpm bar)
|
|
3280
3464
|
Give every beat a duration and end where you began and a spotCues sheet stays in step forever.
|
|
3281
3465
|
Fish cast @audience sit out front facing the stage: they laugh as each talk ends and applaud each bow.
|
|
@@ -3288,7 +3472,7 @@ vignette beats separated by |, cues by comma; actors a b c d are fish slots 0 1
|
|
|
3288
3472
|
var NIGHT = { fogColor: "#0a0a1a", fogNear: 120, fogFar: 700 };
|
|
3289
3473
|
var STAGE = { fogColor: "#01030a", floorColor: "#0a1322", fogNear: 120, fogFar: 650, autoRotate: 0 };
|
|
3290
3474
|
var ALIVE = { eyeLife: 1 };
|
|
3291
|
-
var CINEMATIC = { highlights: 1, raySoftness: 1, nearFade: 1, finish: 0.6 };
|
|
3475
|
+
var CINEMATIC = { highlights: 1, raySoftness: 1, nearFade: 1, voxelAO: 1, fishAO: 1, finish: 0.6 };
|
|
3292
3476
|
var RECIPES = [
|
|
3293
3477
|
{
|
|
3294
3478
|
id: "geode-harbor",
|
|
@@ -3567,7 +3751,7 @@ var RECIPES = [
|
|
|
3567
3751
|
{
|
|
3568
3752
|
id: "starfish-class",
|
|
3569
3753
|
label: "Starfish aerobics",
|
|
3570
|
-
what: "Seven starfish stand up on a pale ice floor, face the camera and dance
|
|
3754
|
+
what: "Seven starfish stand up on a pale ice floor, face the camera and dance aerobics in unison, an instructor in front.",
|
|
3571
3755
|
params: { environment: "ice", fishMix: "starfish:7", starfishDance: "aerobics", danceTempo: 120, shot: "front", autoRotate: 0 }
|
|
3572
3756
|
},
|
|
3573
3757
|
{
|
|
@@ -3609,7 +3793,7 @@ var RECIPES = [
|
|
|
3609
3793
|
{
|
|
3610
3794
|
id: "snail-night",
|
|
3611
3795
|
label: "Snails by night",
|
|
3612
|
-
what: "Glowing snails on a dark floor: each spiral breathes light,
|
|
3796
|
+
what: "Glowing snails on a dark floor: each spiral breathes light, feelers pool green on the sand, the camera beside one.",
|
|
3613
3797
|
params: {
|
|
3614
3798
|
...ALIVE,
|
|
3615
3799
|
...NIGHT,
|
|
@@ -3628,7 +3812,7 @@ var RECIPES = [
|
|
|
3628
3812
|
{
|
|
3629
3813
|
id: "reef-cinematic",
|
|
3630
3814
|
label: "Reef, cinematic",
|
|
3631
|
-
what: "A small reef cast framed close wherever it swims, in soft shafts, each fish over its shadow.
|
|
3815
|
+
what: "A small reef cast framed close wherever it swims, in soft shafts, each fish over its shadow.",
|
|
3632
3816
|
params: {
|
|
3633
3817
|
...ALIVE,
|
|
3634
3818
|
...CINEMATIC,
|
|
@@ -3653,7 +3837,7 @@ var RECIPES = [
|
|
|
3653
3837
|
{
|
|
3654
3838
|
id: "night-cinematic",
|
|
3655
3839
|
label: "Deep night, cinematic",
|
|
3656
|
-
what: "The deep at night: glowfish under jellyfish lanterns, a shark sliding through,
|
|
3840
|
+
what: "The deep at night: glowfish under jellyfish lanterns, a shark sliding through, outlines rimmed in light.",
|
|
3657
3841
|
params: {
|
|
3658
3842
|
...ALIVE,
|
|
3659
3843
|
...CINEMATIC,
|
|
@@ -3677,7 +3861,7 @@ var RECIPES = [
|
|
|
3677
3861
|
{
|
|
3678
3862
|
id: "village-cinematic",
|
|
3679
3863
|
label: "Village, cinematic",
|
|
3680
|
-
what: "Dot, Puff and Hex meet in a sunlit village of stone homes, seen
|
|
3864
|
+
what: "Dot, Puff and Hex meet in a sunlit village of stone homes, seen through a tilt-shift lens.",
|
|
3681
3865
|
params: {
|
|
3682
3866
|
...ALIVE,
|
|
3683
3867
|
...CINEMATIC,
|
|
@@ -3725,6 +3909,7 @@ function validateMetaquariumParams(params) {
|
|
|
3725
3909
|
if (str("townProps")) push("townProps", parseTownProps(str("townProps")).problems);
|
|
3726
3910
|
if (str("floorCover")) push("floorCover", parseFloorCover(str("floorCover")).problems);
|
|
3727
3911
|
if (str("pyramidShow")) push("pyramidShow", parsePyramidShow(str("pyramidShow")).problems);
|
|
3912
|
+
if (str("choreography")) push("choreography", parseChoreography(str("choreography"), STARFISH_MOVE_NAMES).problems);
|
|
3728
3913
|
if (str("geodeMineral")) push("geodeMineral", parseGeodeMineral(str("geodeMineral")).problems);
|
|
3729
3914
|
const rig = parseSpotRig(str("spotRig"));
|
|
3730
3915
|
push("spotRig", rig.problems);
|
|
@@ -3841,7 +4026,9 @@ function dependencyProblems(params) {
|
|
|
3841
4026
|
if (dance !== "off" && !starfishSwims) {
|
|
3842
4027
|
out.push({ path: "starfishDance", also: ["fishMix"], message: "no starfish in the cast to dance \u2014 add e.g. starfish:7 (slots past the cap never swim)" });
|
|
3843
4028
|
}
|
|
3844
|
-
|
|
4029
|
+
const choreographed = !!str("choreography").trim();
|
|
4030
|
+
if (set("danceTempo") && dance === "off" && !choreographed) out.push({ path: "danceTempo", also: ["starfishDance"], message: "does nothing while starfishDance is off" });
|
|
4031
|
+
if (choreographed && !starfishSwims) out.push({ path: "choreography", also: ["fishMix"], message: "no starfish in the cast to dance it \u2014 add e.g. starfish:5" });
|
|
3845
4032
|
if (follow < 0) {
|
|
3846
4033
|
for (const k of ["followDistance", "followAngle", "followAvoid"]) if (set(k)) out.push({ path: k, also: ["cameraFollow"], message: "does nothing while cameraFollow is -1 (the orbit camera)" });
|
|
3847
4034
|
} else if (follow < cast) {
|
|
@@ -3995,6 +4182,7 @@ function describeMetaquarium(params, timed = []) {
|
|
|
3995
4182
|
stage.push(VIGNETTES[v] ? `vignette: ${v}` : `vignette: ${v.split(/[|\n]/).filter((b) => b.trim()).length} beats`);
|
|
3996
4183
|
}
|
|
3997
4184
|
if (str("starfishDance") !== "off") stage.push(`starfish ${str("starfishDance")}${has("danceTempo") ? ` at ${num("danceTempo")} bpm` : ""}`);
|
|
4185
|
+
if (str("choreography").trim()) stage.push(`a starfish choreography${has("danceTempo") ? ` at ${num("danceTempo")} bpm` : ""}`);
|
|
3998
4186
|
const camera = [];
|
|
3999
4187
|
const follow = Math.round(num("cameraFollow"));
|
|
4000
4188
|
if (follow >= 0) {
|
|
@@ -4284,6 +4472,10 @@ var METAQUARIUM_PARAMS = {
|
|
|
4284
4472
|
* mode), brighter on top: what separates a dark fish from dark water.
|
|
4285
4473
|
* 0 is none. */
|
|
4286
4474
|
fishRim: { type: "number", default: 0, min: 0, max: 1, ease: "smooth" },
|
|
4475
|
+
/** The fish's own corners darken — a fin's root, the step at the head, the
|
|
4476
|
+
* gap under a shell — read off the voxels they are built from. Baked once
|
|
4477
|
+
* per breed, the first frame it is on; every tier. 0 is off. */
|
|
4478
|
+
fishAO: { type: "number", default: 0, min: 0, max: 1, ease: "smooth" },
|
|
4287
4479
|
/** A soft shadow on the ground under every swimmer: small and dark near
|
|
4288
4480
|
* the sand, wide and faint high up — what puts a fish at a height instead
|
|
4289
4481
|
* of floating in front of the floor. 0 is none (floor walkers always
|
|
@@ -4352,6 +4544,13 @@ var METAQUARIUM_PARAMS = {
|
|
|
4352
4544
|
/** The dance's tempo, beats per minute. Every move is a bar of four beats.
|
|
4353
4545
|
* Integrated when steered, so a glide speeds the class up on the beat. */
|
|
4354
4546
|
danceTempo: { type: "number", default: 128, min: 60, max: 180, ease: "smooth" },
|
|
4547
|
+
/** An authored dance on the beat (choreo.ts): a cue sheet per dancer —
|
|
4548
|
+
* `a: 8:lie, 4:rise, 4:reach >right @cam | *: 4:march ~360, 4:jacks ^0.5`.
|
|
4549
|
+
* Set, every starfish dances it (in the class's places, or the couples'
|
|
4550
|
+
* under `starfishDance: duet`), facing `cameraAzimuth`; a dancer it leaves
|
|
4551
|
+
* out keeps `starfishDance`'s routine, or stands and waits. Beats on the
|
|
4552
|
+
* `danceTempo` clock from the start, so a sheet lines up with music. */
|
|
4553
|
+
choreography: { type: "string", default: "", ease: "step" },
|
|
4355
4554
|
/** Eye life, 0..1: blinks on a personal clock, idle saccades, pupils that
|
|
4356
4555
|
* lead a turn or a climb, eyes on whoever a vignette has it talking to, a
|
|
4357
4556
|
* glance at the camera now and then, wide for a hop and shut for a rest.
|
|
@@ -4751,6 +4950,10 @@ export {
|
|
|
4751
4950
|
SIGN_TEXT_MAX,
|
|
4752
4951
|
MAX_SIGNS,
|
|
4753
4952
|
parseSignMix,
|
|
4953
|
+
STARFISH_MOVE_NAMES,
|
|
4954
|
+
parseChoreography,
|
|
4955
|
+
choreoLine,
|
|
4956
|
+
choreoAt,
|
|
4754
4957
|
GESTURES,
|
|
4755
4958
|
OPEN_MARKS,
|
|
4756
4959
|
parseVignette,
|
|
@@ -4777,4 +4980,4 @@ export {
|
|
|
4777
4980
|
paramSpaceWith,
|
|
4778
4981
|
coerceNum
|
|
4779
4982
|
};
|
|
4780
|
-
//# sourceMappingURL=chunk-
|
|
4983
|
+
//# sourceMappingURL=chunk-42RIVUT4.js.map
|