@idle-screens/saver-metaquarium 0.17.0 → 0.19.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 +3 -3
- package/dist/{chunk-3RP7VMWG.js → chunk-7ZYKA2WS.js} +77 -23
- package/dist/chunk-7ZYKA2WS.js.map +1 -0
- package/dist/dolphin-ZNNAKAZX.js +5 -0
- package/dist/{dot-CQ4RN5B2.js → dot-RHN772E3.js} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/lofi-tank-6ARMHEA2.js +781 -0
- package/dist/lofi-tank-6ARMHEA2.js.map +1 -0
- package/dist/{manifest-D21Oi2_c.d.ts → manifest-s5dcKyZb.d.ts} +18 -2
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +1 -1
- package/dist/{tank-TNOWLYRS.js → tank-VB33FZ7W.js} +998 -440
- package/dist/tank-VB33FZ7W.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-3RP7VMWG.js.map +0 -1
- package/dist/lofi-tank-HTZWHFJZ.js +0 -504
- package/dist/lofi-tank-HTZWHFJZ.js.map +0 -1
- package/dist/tank-TNOWLYRS.js.map +0 -1
package/README.md
CHANGED
|
@@ -185,11 +185,11 @@ Every one of them defaults to off — 0, `none`, −1 for `followSpot`, empty fo
|
|
|
185
185
|
| --- | --- | --- |
|
|
186
186
|
| `rockDensity` | 0–1 | Crystal-root boulders, sparse satellite rocks, a distant ridge and an open arch. Any positive value provides foundations; density adds satellites. |
|
|
187
187
|
| `rockVeins` | 0–1 (0.7) | How hard the crystals broke out of the stone. Each rock's crown is heaved into a pit with chips of stone on the rim and a few short dark fractures, and a colony of real crystals (druse or spire, the same shards, material, pulse and halo as `propMix`) grows out of it, rooted inside the rock. A rock under a `propMix` cluster is broken open under that cluster instead. More veins, more rocks split, and bigger colonies. The colonies add no floor light. 0 is plain stone. |
|
|
188
|
-
| `geodeHomes` | 0–3 | Geode homes: a broken boulder with an agate rind and a throat of crystal teeth, and a voxel house recessed inside — round door, lit window, lamp, steps, a chimney that vents bubbles. Habits cycle cottage / hall / tower; each home lights the floor at its door. Weak devices retain at most two. |
|
|
188
|
+
| `geodeHomes` | 0–3 | Geode homes: a broken boulder with an agate rind and a throat of crystal teeth, and a voxel house recessed inside — round door, lit window, lamp, steps, a chimney that vents bubbles. Habits cycle cottage / hall / tower; each home lights the floor at its door. Weak devices retain at most two: geodeHomes is capped at 2 on basic and minimal tiers (3 on standard and high); a house that is dropped takes its `homeN`/`homeNin` marks with it, and indoors (`interior: geode`) there are no `homeN` marks. |
|
|
189
189
|
| `interior` | `none` · `geode` | Sets the scene INSIDE a geode home: crystal-lined dome with agate strata, plank floor and rug, voxel furniture, a chandelier / lamp / stove / window that light the floor and the fish. Use with the `void` environment; the default orbit camera stays indoors (keep `cameraDistance` ≲ 130). |
|
|
190
190
|
| `followSpot` | -1…23 | A follow-spot on one fish (its cast slot; -1 off): a beam from the rig, a pool of moving caustics on the floor beneath it, a light that rides with the fish, and the house lights down — a performer on a stage. `spotStrength` 0–1, `spotColor`. Closed-form: it follows the fish's own deterministic path. |
|
|
191
|
-
| `vignette` | string | A small scene for the first 2–3 fish: a preset (`tea`, `bedtime`, `seek`) or a script of beats — `a =table, b =door \| b >table @a \| a @b talk, b @a nod \| a b circle rug`. `=mark` start
|
|
192
|
-
| `floraDensity` | 0–1 | Voxel plants — seventeen species (grass, tube worms, lantern bulbs, fans, kelp, anemone, staghorn, brain coral, sea whip, barrel sponge, glow caps, sea pen, bubble algae, fiddlehead curls, orb pods, and two specimens: the giant clam and the elder blossom tree). They grow in colonies that share a colour, ramp from base to tip, and one colony in thirty is a rare nacreous morph; they lean toward the nearest crystal and, on mid/high tiers, are lit by it and by follow-spots. Stony coral stands still, kelp and whips sway, tentacles writhe; a gust travels across the field, tips breathe. With `floraMix` empty the room picks the garden (coral on a reef, kelp and whips in the kelp forest, glow caps in the abyss). Plants answer passing fish: anemone crowns fold, worms duck, sea pens pull down, pods swell, lamps flare. |
|
|
191
|
+
| `vignette` | string | A small scene for the first 2–3 fish: a preset (`tea`, `bedtime`, `seek`) or a script of beats — `a =table, b =door \| b >table @a \| a @b talk, b @a nod \| a b circle rug`. `=mark` places an actor with no travel (in a later beat it snaps at the start of the beat), `>mark` swims there, `@x` face a mark or actor, `circle x` (each named actor from wherever it stands onto a ring round the mark and back to its own spot by the end of the beat; actors not named stay put), `follow x`, gestures `talk nod shake hop spin wiggle bow peek rest`, and `ink` (an octopus's own: it squirts a cloud of ink on its mark; other breeds ignore it, with a warning), leading `6s:` sets a beat's length. Marks indoors: rug table bed shelf stove lamp armchair door window chest chandelier (bearings and distances in `GRAMMAR`; they scale with the room, by `max(crystalScale, 0.85)`); outdoors: centre left right front back high low. A floor creature cast as an actor keeps its feet on the floor at its marks, and maneuvers leave actors alone. Closed-form, looping; other fish swim as usual. |
|
|
192
|
+
| `floraDensity` | 0–1 | Voxel plants — seventeen species (grass, tube worms, lantern bulbs, fans, kelp, anemone, staghorn, brain coral, sea whip, barrel sponge, glow caps, sea pen, bubble algae, fiddlehead curls, orb pods, and two specimens: the giant clam and the elder blossom tree). They grow in colonies that share a colour, ramp from base to tip, and one colony in thirty is a rare nacreous morph; they lean toward the nearest crystal and, on mid/high tiers, are lit by it and by follow-spots. Stony coral stands still, kelp and whips sway, tentacles writhe; a gust travels across the field, tips breathe. With `floraMix` empty the room picks the garden (coral on a reef, kelp and whips in the kelp forest, glow caps in the abyss). Plants answer passing fish: anemone crowns fold, worms duck, sea pens pull down, pods swell, lamps flare. The density sets one tank-wide plant budget (density × 36 / 72 / 108 by tier), shared round-robin among the crystals and geodes (or six bare spots when there are none): more crystals means sparser gardens, not more plants. |
|
|
193
193
|
| `floraPalette` | string | One colour scheme for the garden: `world` (seeded) or up to six comma-separated `#rrggbb` values. Empty = each species' own colours. |
|
|
194
194
|
| `geodes` | 0–1 | Wild geodes, few and made properly: split geodes (one in three a thunder egg), amethyst cathedrals, crystal clusters and one mega cavern geode. Agate banding drawn per pixel, crystals in real quartz habit and colour-zoned root to tip, twinkling druse, self-lit so they read in a flat tank; one in twenty is an iridescent aura morph, and their crystals wake when a fish comes close. |
|
|
195
195
|
| `geodeMix` | string | Which kinds: `kind[:weight]`, comma-separated — `geode, cathedral, cluster, cavern`. |
|
|
@@ -125,6 +125,7 @@ var AUTO_STYLE_BY_BREED = {
|
|
|
125
125
|
octopus: "bottom",
|
|
126
126
|
snail: "bottom",
|
|
127
127
|
dot: "bottom",
|
|
128
|
+
dolphin: "loop",
|
|
128
129
|
dori: "school"
|
|
129
130
|
};
|
|
130
131
|
function autoStyleFor(breed) {
|
|
@@ -185,7 +186,8 @@ var BREED_SIZE = {
|
|
|
185
186
|
starfish: 1,
|
|
186
187
|
octopus: 1.2,
|
|
187
188
|
snail: 0.8,
|
|
188
|
-
dot: 1.2
|
|
189
|
+
dot: 1.2,
|
|
190
|
+
dolphin: 1.8
|
|
189
191
|
};
|
|
190
192
|
function breedSize(breed) {
|
|
191
193
|
return breed && BREED_SIZE[breed.toLowerCase()] || 1;
|
|
@@ -1249,7 +1251,9 @@ var NPC_CATALOG = [
|
|
|
1249
1251
|
// The third, a floor creature (breeds/rig/snail-model.mjs).
|
|
1250
1252
|
{ id: 611, name: "Snail", breed: "snail", ipfs3d: `${BUNDLED_BREED_SCHEME}snail`, localGlb: "" },
|
|
1251
1253
|
// The first character (experimental): Dot, the courier (breeds/rig/dot-model.mjs).
|
|
1252
|
-
{ id: 612, name: "Dot", breed: "dot", ipfs3d: `${BUNDLED_BREED_SCHEME}dot`, localGlb: "" }
|
|
1254
|
+
{ id: 612, name: "Dot", breed: "dot", ipfs3d: `${BUNDLED_BREED_SCHEME}dot`, localGlb: "" },
|
|
1255
|
+
// Dot's friend (experimental): a dolphin (breeds/rig/dolphin-model.mjs).
|
|
1256
|
+
{ id: 613, name: "Dolphin", breed: "dolphin", ipfs3d: `${BUNDLED_BREED_SCHEME}dolphin`, localGlb: "" }
|
|
1253
1257
|
];
|
|
1254
1258
|
var findInDefault = (key) => /^\d+$/.test(key) ? FISH_CATALOG.find((f) => f.id === Number(key)) ?? NPC_CATALOG.find((f) => f.id === Number(key)) : FISH_CATALOG.find((f) => f.breed.toLowerCase() === key) ?? NPC_CATALOG.find((f) => f.breed.toLowerCase() === key);
|
|
1255
1259
|
function parseFishMix(mix, catalog = FISH_CATALOG) {
|
|
@@ -2493,7 +2497,8 @@ function parseSignMix(value) {
|
|
|
2493
2497
|
|
|
2494
2498
|
// src/vignette.ts
|
|
2495
2499
|
var DANCES = ["toprock", "footwork", "windmill", "headspin", "freeze", "drop"];
|
|
2496
|
-
var GESTURES = ["talk", "nod", "shake", "hop", "spin", "wiggle", "rest", "peek", "bow", ...DANCES];
|
|
2500
|
+
var GESTURES = ["talk", "nod", "shake", "hop", "spin", "wiggle", "rest", "peek", "bow", "ink", ...DANCES];
|
|
2501
|
+
var BREED_GESTURES = { ink: ["octopus"] };
|
|
2497
2502
|
var OPEN_MARKS = {
|
|
2498
2503
|
centre: { x: 0, y: 36, z: 0 },
|
|
2499
2504
|
left: { x: -70, y: 34, z: 0 },
|
|
@@ -2567,6 +2572,7 @@ function parseVignette(script, marks) {
|
|
|
2567
2572
|
if (word[0] === "=") at[i] = dest;
|
|
2568
2573
|
else longest = Math.max(longest, Math.hypot(dest.x - at[i].x, dest.y - at[i].y, dest.z - at[i].z) / CRUISE);
|
|
2569
2574
|
state[i] = { ...state[i], to: dest, moved: word[0] === ">", facePoint: state[i].facePoint ?? mk };
|
|
2575
|
+
if (word[0] === "=" && bi > 0) state[i] = { ...state[i], from: dest, placed: true };
|
|
2570
2576
|
}
|
|
2571
2577
|
} else if (word[0] === "@") {
|
|
2572
2578
|
const tg = target(word.slice(1));
|
|
@@ -2634,7 +2640,7 @@ function placeOf(v, actor, tSec, depth = 0) {
|
|
|
2634
2640
|
if (bi < 0) bi = v.beats.length - 1;
|
|
2635
2641
|
const beat = v.beats[bi], me = beat.actors[actor];
|
|
2636
2642
|
const prev = v.beats[(bi + v.beats.length - 1) % v.beats.length].actors[actor];
|
|
2637
|
-
const from = bi === 0 ? me.
|
|
2643
|
+
const from = me.from ?? (bi === 0 ? me.to : prev.to);
|
|
2638
2644
|
const u = (t - beat.t0) / beat.dur;
|
|
2639
2645
|
if (me.follow !== null && depth < 2) {
|
|
2640
2646
|
const lead = placeOf(v, me.follow, tSec - 1.7, depth + 1);
|
|
@@ -2662,6 +2668,19 @@ function placeOf(v, actor, tSec, depth = 0) {
|
|
|
2662
2668
|
z: from.z + dz * w + dx / (dist || 1) * arc
|
|
2663
2669
|
};
|
|
2664
2670
|
}
|
|
2671
|
+
function snapBetween(v, actor, t1, t2) {
|
|
2672
|
+
if (!v.duration || actor >= v.actors) return false;
|
|
2673
|
+
const lo = Math.min(t1, t2), span = Math.abs(t2 - t1);
|
|
2674
|
+
const a = (lo % v.duration + v.duration) % v.duration;
|
|
2675
|
+
return v.beats.some((b) => {
|
|
2676
|
+
if (!b.actors[actor]?.placed) return false;
|
|
2677
|
+
const d = ((b.t0 - a) % v.duration + v.duration) % v.duration;
|
|
2678
|
+
return d > 0 && d <= span;
|
|
2679
|
+
});
|
|
2680
|
+
}
|
|
2681
|
+
function poseAcross(v, actor, tSec, dt, own) {
|
|
2682
|
+
return poseOf(v, actor, snapBetween(v, actor, tSec, tSec + dt) ? tSec : tSec + dt, own);
|
|
2683
|
+
}
|
|
2665
2684
|
function poseOf(v, actor, tSec, own) {
|
|
2666
2685
|
if (actor >= v.actors || !v.duration) return null;
|
|
2667
2686
|
const t = (tSec % v.duration + v.duration) % v.duration;
|
|
@@ -2670,8 +2689,9 @@ function poseOf(v, actor, tSec, own) {
|
|
|
2670
2689
|
const beat = v.beats[bi], me = beat.actors[actor];
|
|
2671
2690
|
const u = (t - beat.t0) / beat.dur;
|
|
2672
2691
|
const p = placeOf(v, actor, tSec);
|
|
2673
|
-
const
|
|
2674
|
-
const
|
|
2692
|
+
const cut = snapBetween(v, actor, tSec, tSec + 0.12);
|
|
2693
|
+
const ahead = placeOf(v, actor, tSec + (cut ? -0.12 : 0.12));
|
|
2694
|
+
const tx = (ahead.x - p.x) * (cut ? -1 : 1), ty = (ahead.y - p.y) * (cut ? -1 : 1), tz = (ahead.z - p.z) * (cut ? -1 : 1);
|
|
2675
2695
|
const speed = Math.hypot(tx, ty, tz) / 0.12;
|
|
2676
2696
|
let fx = tx, fy = ty * 0.5, fz = tz;
|
|
2677
2697
|
const target = me.faceActor !== null ? placeOf(v, me.faceActor, tSec) : me.facePoint;
|
|
@@ -2689,7 +2709,8 @@ function poseOf(v, actor, tSec, own) {
|
|
|
2689
2709
|
fz = fz / ml * (1 - settled) + gz / gl * settled;
|
|
2690
2710
|
}
|
|
2691
2711
|
} else if (Math.hypot(fx, fz) < 1e-4) {
|
|
2692
|
-
const
|
|
2712
|
+
const end = me.placed ? beat.t0 - 1e-3 : beat.t0;
|
|
2713
|
+
const back = placeOf(v, actor, end - 0.2), here = placeOf(v, actor, end);
|
|
2693
2714
|
fx = here.x - back.x;
|
|
2694
2715
|
fz = here.z - back.z;
|
|
2695
2716
|
fy = 0;
|
|
@@ -2754,6 +2775,7 @@ function poseOf(v, actor, tSec, own) {
|
|
|
2754
2775
|
roll += 0.22 * e;
|
|
2755
2776
|
pitch = -0.08 * e;
|
|
2756
2777
|
break;
|
|
2778
|
+
// ink: the body holds still; the octopus squirts its cloud (the tank's InkLayer) and pales.
|
|
2757
2779
|
// The dances, for a fish with no clips for them: the whole body does what it can.
|
|
2758
2780
|
case "toprock":
|
|
2759
2781
|
roll += Math.sin(bt * Math.PI * 2) * 0.3 * e;
|
|
@@ -2798,6 +2820,17 @@ function poseOf(v, actor, tSec, own) {
|
|
|
2798
2820
|
return { x, y: Math.max(9, y), z, fx, fy, fz, roll, doing, lookAt: target ?? null, ...gesture ? { gesture } : {} };
|
|
2799
2821
|
}
|
|
2800
2822
|
var polar = (deg, r, y) => ({ x: Math.cos(deg * Math.PI / 180) * r, y, z: Math.sin(deg * Math.PI / 180) * r });
|
|
2823
|
+
var INTERIOR_MARK_POLAR = {
|
|
2824
|
+
door: { deg: 28, r: 124, y: 22 },
|
|
2825
|
+
stove: { deg: 88, r: 106, y: 33 },
|
|
2826
|
+
window: { deg: 128, r: 124, y: 46 },
|
|
2827
|
+
table: { deg: 150, r: 46, y: 27, note: "on the rug" },
|
|
2828
|
+
bed: { deg: 205, r: 104, y: 21 },
|
|
2829
|
+
chest: { deg: 232, r: 110, y: 24 },
|
|
2830
|
+
lamp: { deg: 262, r: 102, y: 32 },
|
|
2831
|
+
armchair: { deg: 271, r: 100, y: 22 },
|
|
2832
|
+
shelf: { deg: 330, r: 110, y: 30 }
|
|
2833
|
+
};
|
|
2801
2834
|
var INTERIOR_MARKS = {
|
|
2802
2835
|
rug: { x: 6, y: 26, z: -4 },
|
|
2803
2836
|
centre: { x: 6, y: 30, z: -4 },
|
|
@@ -2896,13 +2929,14 @@ var PARAM_DOCS = {
|
|
|
2896
2929
|
shot: "A named framing to cut to: `orbit` (default), `hero` (three-quarter establishing), `front` (level, long lens), `low` (among the plants looking up), `top` (steep, the floor as a map), `surface` (looking up at the water's underside), `macro` (close on the landmark nearest the front). Azimuth and autoRotate turn it; distance scales it.",
|
|
2897
2930
|
cameraFollow: "Ride with one fish (cast slot, 0 = first); -1 is the orbit camera. Orbit params are ignored while following. Pair with `followSpot` on the same slot for a spotlit chase.",
|
|
2898
2931
|
followAngle: "Where round the followed fish the chase camera stands, degrees: 0 behind (default), 90 beside, 180 in front looking back at its face.",
|
|
2899
|
-
followDistance: "How far behind the followed fish the camera rides, along its own path (40\u201370 a chase). Under ~18 it is the fish's eye and the fish is hidden.",
|
|
2900
|
-
autoRotate: "Turntable speed, degrees/second. 0 holds the shot (stages, vignettes); 1\u20132 is a slow reveal.",
|
|
2932
|
+
followDistance: "How far behind the followed fish the camera rides, along its own path (40\u201370 a chase). Under ~18 it is the fish's eye and the fish is hidden; a floor walker (Dot, crab, octopus, snail, starfish) sees from its own head height, pitched with the ground ahead.",
|
|
2933
|
+
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.",
|
|
2934
|
+
followAvoid: "Keep the followed fish in view, 0\u20131 (default 0): with something in the way (a home, a wall, a lamp, a kelp stand) the chase camera rises a little over low clutter and otherwise pulls in toward the fish \u2014 eased, like a game camera's spring arm. Use it for long walking takes through a village. No effect in the fish's own eye (followDistance under about 16).",
|
|
2901
2935
|
// cast
|
|
2902
2936
|
fishCount: "How many fish when `fishMix` is empty (all are `fishUrl`).",
|
|
2903
2937
|
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).",
|
|
2904
2938
|
fishUrl: "The single model used when `fishMix` is empty. ipfs:// or https.",
|
|
2905
|
-
fishMix: "The cast: `id[:count][@style]`, comma-separated. `100:2@drift, 257:1, seahorse:3, shark:1@patrol`. Minted breeds plus bundled creatures (shark crab dori glowfish babyfish hackerfish blowfish starfish octopus snail dot). A hackerfish's face is a screen (faces, code rain, crash and reboot); a glowfish fishes with its lure. A crab walks the seabed on its own legs at its own pace (swimSpeed does not hurry it), climbs the rocks, and stops to forage, pinch, wave and cheer. A starfish crawls the floor too, walks some of the way upright on its front arms, and stops to curl up, wave, or stand facing you; with `starfishDance` it dances. A snail glides the floor very slowly and stops to look about, look at you, graze, stretch up tall, or pull into its shell and peek back out. `dot` is a character (experimental): Dot, the town courier, a box on two legs whose face is a screen; it walks, runs and sneaks the floor, stops to wave, cheer, think, tip its cap, deliver a letter, dance, laugh and more, and as a vignette actor plays the gestures with its own body. Overrides fishCount/fishUrl.",
|
|
2939
|
+
fishMix: "The cast: `id[:count][@style]`, comma-separated. `100:2@drift, 257:1, seahorse:3, shark:1@patrol`. Minted breeds plus bundled creatures (shark crab dori glowfish babyfish hackerfish blowfish starfish octopus snail dot dolphin). A hackerfish's face is a screen (faces, code rain, crash and reboot); a glowfish fishes with its lure. A crab walks the seabed on its own legs at its own pace (swimSpeed does not hurry it), climbs the rocks, and stops to forage, pinch, wave and cheer. A starfish crawls the floor too, walks some of the way upright on its front arms, and stops to curl up, wave, or stand facing you; with `starfishDance` it dances. A snail glides the floor very slowly and stops to look about, look at you, graze, stretch up tall, or pull into its shell and peek back out. `dot` is a character (experimental): Dot, the town courier, a box on two legs whose face is a screen; it walks, runs and sneaks the floor, stops to wave, cheer, think, tip its cap, deliver a letter, dance, laugh and more, and as a vignette actor plays the gestures with its own body. `dolphin` (experimental) is Dot's friend: a bottlenose with flat flukes that strokes up and down, coasts, and every so often chatters (its laugh), nods, waves a flipper, blows a bubble, spins or flips \u2014 turning an eye to you for the friendly ones; in a vignette it chatters for talk, flips for hop, waves for wiggle and blows a bubble for peek. Overrides fishCount/fishUrl.",
|
|
2906
2940
|
dracoPath: "Where the Draco decoder lives; leave empty on a channel.",
|
|
2907
2941
|
swimSpeed: "Global swim speed multiplier. 0.4 is contemplative, 1 lively.",
|
|
2908
2942
|
swimStyle: "How the cast swims unless a fishMix entry says otherwise (`@style`). `auto` picks by breed.",
|
|
@@ -2911,7 +2945,7 @@ var PARAM_DOCS = {
|
|
|
2911
2945
|
swimVariance: "How differently individual fish swim from one another (speed, phase).",
|
|
2912
2946
|
fishSize: "Every fish bigger or smaller, over each breed's own size (a shark is 2.2\xD7 a minted fish, a babyfish 0.45\xD7).",
|
|
2913
2947
|
sizeVariance: "How much fish of one breed differ in size: 0 all alike, 1 from about half to nearly double.",
|
|
2914
|
-
maneuver: "Which set-piece moves the cast may break into.",
|
|
2948
|
+
maneuver: "Which set-piece moves the cast may break into. Vignette actors (slots 0\u20132) keep their marks: the script owns them.",
|
|
2915
2949
|
maneuverRate: "How often maneuvers happen.",
|
|
2916
2950
|
maneuverIntensity: "How big they are.",
|
|
2917
2951
|
bodyWiggle: "Body yaw while swimming, for models without an animation clip. A fish the swim wave bends (`swimWave` > 0) ignores it.",
|
|
@@ -2925,8 +2959,8 @@ var PARAM_DOCS = {
|
|
|
2925
2959
|
fishAmbient: "The water's light on the fish in lit mode: the sunlit water on their backs, the water around on their flanks, the floor under their bellies, mirrored in metal plates. Fixes fish reading dark; 0.6\u20131 in bright tanks. Dims with a follow-spot's house lights.",
|
|
2926
2960
|
fishGlow: "How strongly GLOW- parts of a fish bloom and light their neighbours and the floor.",
|
|
2927
2961
|
fishMetal: "`on` (default) gives METAL- parts a polished, reflective finish.",
|
|
2928
|
-
snailShell: "What the snails' shells are made of: `banded` (the coat with a spiral, as drawn), `pearl` (iridescent nacre: a rainbow sheen that slides as it turns), `gold` (polished metal), `glow` (a dark shell whose spiral breathes light \u2014 best at night). `mix` (default): each snail its own. Lit fish only: flat lighting and the neon look keep the banded coat.",
|
|
2929
|
-
starfishDance: "Starfish dance: `aerobics` stands every starfish up in a class facing the camera (an instructor in front) dancing a routine in unison \u2014 march, jacks, reaches, kicks, twists, arm circles, disco, a spin; `freestyle`, each its own move every eight counts; `duet`, the partner dance (Dirty Dancing): couples face to face \u2014 the basic, a sway, a twirl, the dip, and the lift \u2014 best with `spotRig: 0/#ffd27a*26, 1/#ff8ad0*26`. Cast a few: `fishMix: starfish:7`. Best with `shot: front`, `autoRotate: 0`, a bright room. `off` (default): they crawl, walk upright and wave on their own.",
|
|
2962
|
+
snailShell: "What the snails' shells are made of: `banded` (the coat with a spiral, as drawn), `pearl` (iridescent nacre: a rainbow sheen that slides as it turns), `gold` (polished metal), `glow` (a dark shell whose spiral breathes light \u2014 best at night). `mix` (default): each snail its own. Lit fish only: flat lighting and the neon look keep the banded coat. Glow keeps each coat's hue; frame.state.fish[i].shell says which.",
|
|
2963
|
+
starfishDance: "Starfish dance: `aerobics` stands every starfish up in a class facing the camera (an instructor in front) dancing a routine in unison \u2014 march, jacks, reaches, kicks, twists, arm circles, disco, a spin; `freestyle`, each its own move every eight counts; `duet`, the partner dance (Dirty Dancing): couples face to face \u2014 the basic, a sway, a twirl, the dip, and the lift \u2014 best with `spotRig: 0/#ffd27a*26, 1/#ff8ad0*26`. Cast a few: `fishMix: starfish:7`. Best with `shot: front`, `autoRotate: 0`, a bright room. `off` (default): they crawl, walk upright and wave on their own. The class re-faces the live camera every frame: under autoRotate it stays put on screen while the room turns behind it (a follow camera uses cameraAzimuth).",
|
|
2930
2964
|
danceTempo: "Beats per minute for the starfish dance (60\u2013180, default 128). Glides on the beat.",
|
|
2931
2965
|
fishLook: "`neon` dresses the bundled creatures (crab, glowfish, shark\u2026) for blacklight: near-black coats, eyes and a crab's mouth glowing a neon of their own. Best in a dark room (abyss, void) with `finish`. `natural` is the default.",
|
|
2932
2966
|
swimWave: "Fish bend as they swim: a wave runs nose to tail and the body curls into turns (0 = rigid wiggle). Skips the turtle, crab and fish that already have a skeleton; the seahorse gets its own motion instead \u2014 fin, tail and nod.",
|
|
@@ -2960,9 +2994,9 @@ var PARAM_DOCS = {
|
|
|
2960
2994
|
crystalTint: "How much nearby light sources colour a passing fish. 0.5\u20130.7 ties the cast to the place.",
|
|
2961
2995
|
rockDensity: "Faceted boulders, an arch and a back ridge around the crystals.",
|
|
2962
2996
|
rockVeins: "Crystals bursting out of the rocks: each crown broken open, chips on the rim, a colony of the same crystal growing from the breach. 0 is plain stone.",
|
|
2963
|
-
geodeHomes: "Geode houses (0\u20133) in a crescent: a village. Their doors are vignette marks `home1`\u2026, `home1in`\u2026.",
|
|
2997
|
+
geodeHomes: "Geode houses (0\u20133) in a crescent: a village. Their doors are vignette marks `home1`\u2026, `home1in`\u2026. Capped at 2 on basic/minimal tiers (3 on standard/high); a dropped house takes its homeN/homeNin marks, and indoors there are none.",
|
|
2964
2998
|
interior: "`geode` sets the whole scene INSIDE a geode home: furniture, chandelier, marks like `table`, `bed`, `door`.",
|
|
2965
|
-
floraDensity: "Voxel plants
|
|
2999
|
+
floraDensity: "Voxel plants, swaying, lit and shedding spores: one tank-wide budget (density \xD7 36/72/108 by tier) shared round-robin among crystals and geodes (or six bare spots), so more crystals means sparser gardens. What grows is `floraMix`; with it empty the room picks (coral on a reef, kelp in the kelp forest, glow caps in the abyss).",
|
|
2966
3000
|
geodes: "Wild geodes about the floor (0 = none): split geodes (one in three a thunder egg), amethyst cathedrals, crystal clusters, one mega cavern geode. They follow the world's rules \u2014 slate crust lit by the same key as the rocks, crystals that glow and pulse like the crystals (crystalGlow, crystalPulse), the mineral of the crystal nearest them, the crystals' light on their stone \u2014 and flora grows round them as round a crystal. Agate banding is drawn per pixel; one in twenty is an iridescent aura morph; their crystals wake when a fish comes close.",
|
|
2967
3001
|
geodeMix: "Which geodes: `kind[:weight]`, comma-separated. geode cathedral cluster cavern (the cavern is one at most).",
|
|
2968
3002
|
geodeMineral: "What they are made of: amethyst agate celestine citrine carnelian rose emerald quartz smoky. Empty = the mineral nearest in colour to the crystal nearest each geode (it belongs to its world, as flora and homes do); `world` = two from the seed; or a list.",
|
|
@@ -2994,12 +3028,12 @@ var PARAM_DOCS = {
|
|
|
2994
3028
|
landmark: "One thing bigger than everything else. `castle`: voxel walls, crystal-spired towers, gate, road, plaza. `citadel`: two storeys. Marks: `gate`, `plaza`, `courtyard`.",
|
|
2995
3029
|
// stage
|
|
2996
3030
|
followSpot: "A follow-spot on one fish slot (0 = first of the cast); -1 off. House lights drop with it.",
|
|
2997
|
-
spotStrength: "How hard the spots are on and how far the house lights fall.",
|
|
3031
|
+
spotStrength: "How hard the spots are on and how far the house lights fall. House lights dim only lit fish's key/fill (to 40% at full) and fishAmbient; reflections, glow, flat fish and the unlit floor/scenery keep theirs, and a `-` blackout only puts out the spots.",
|
|
2998
3032
|
spotColor: "Colour of the single `followSpot`.",
|
|
2999
3033
|
spotShadow: "The spotted fish's shadow in its pool. 0 none, 1 true size.",
|
|
3000
3034
|
spotRig: "Up to three spots: `slot[/color][*radius]`. `0/#ff8ad0*26, 1/#7fdcff`. They are a, b, c in order. Overrides followSpot.",
|
|
3001
3035
|
spotCues: "A looping cue sheet for the rig: `8s:a, 8s:b, 12s:a+b, 4s:-` (`-` = blackout). Spots cross-fade at each cue.",
|
|
3002
|
-
vignette: "A small scene for the first 2\u20133 fish: a preset (tea\xB7bedtime\xB7seek indoors; duet\xB7trio on the open stage) or a script of beats."
|
|
3036
|
+
vignette: "A small scene for the first 2\u20133 fish: a preset (tea\xB7bedtime\xB7seek indoors; duet\xB7trio on the open stage) or a script of beats. A floor creature cast as an actor stays on the floor. Grammar below."
|
|
3003
3037
|
};
|
|
3004
3038
|
var GRAMMAR = `
|
|
3005
3039
|
fishMix id[:count][@style][*size], \u2026 100:2@drift, 257:1, seahorse:3, shark:1@patrol*1.5
|
|
@@ -3028,14 +3062,16 @@ signs kind[@place][>target][/#color][*size][:text], \u2026 plank@gate:"Wel
|
|
|
3028
3062
|
kinds plank arrow ring porthole neon led \xB7 places gate plaza courtyard hub fountain home1 home2 home3 centre left right front back
|
|
3029
3063
|
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
|
|
3030
3064
|
vignette beats separated by |, cues by comma; actors a b c are fish slots 0 1 2
|
|
3031
|
-
[<sec>s:] actor =mark
|
|
3032
|
-
actor @mark | @actor
|
|
3033
|
-
actor follow actor
|
|
3065
|
+
[<sec>s:] actor =mark be there, no travel (a later beat's = snaps at its start) actor >mark swim there
|
|
3066
|
+
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
|
|
3067
|
+
actor follow actor gestures: talk nod shake hop spin wiggle rest peek bow \xB7 ink (octopus only: a cloud of ink)
|
|
3034
3068
|
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)
|
|
3035
3069
|
Give every beat a duration and end where you began and a spotCues sheet stays in step forever.
|
|
3036
3070
|
Marks outdoors: ${Object.keys(OPEN_MARKS).join(" ")} \u2014 plus the world's own:
|
|
3037
3071
|
home1 home1in \u2026 (geodeHomes), gate plaza courtyard (landmark), hub (paths), fountain (fountain).
|
|
3038
3072
|
Marks indoors (interior: geode): ${Object.keys(INTERIOR_MARKS).join(" ")}
|
|
3073
|
+
rug centre: middle; chandelier: overhead; others bearing\xB0/distance/height (0\xB0=+x, 90\xB0=+z), \xD7max(crystalScale, 0.85):
|
|
3074
|
+
${Object.entries(INTERIOR_MARK_POLAR).map(([n, p]) => `${n} ${p.deg}/${p.r}/${p.y}`).join(" \xB7 ")}
|
|
3039
3075
|
`.trim();
|
|
3040
3076
|
var NIGHT = { fogColor: "#0a0a1a", fogNear: 120, fogFar: 700 };
|
|
3041
3077
|
var STAGE = { fogColor: "#01030a", floorColor: "#0a1322", fogNear: 120, fogFar: 650, autoRotate: 0 };
|
|
@@ -3470,8 +3506,17 @@ function dependencyProblems(params) {
|
|
|
3470
3506
|
else if (spot2 >= cast) out.push({ path: "followSpot", also: castParams, message: noFish(spot2) });
|
|
3471
3507
|
for (const s of rig) if (s.slot >= cast) out.push({ path: "spotRig", also: castParams, message: noFish(s.slot) });
|
|
3472
3508
|
if (str("vignette")) {
|
|
3473
|
-
const
|
|
3509
|
+
const v = parseVignette(resolveVignette(str("vignette")), { ...OPEN_MARKS, ...INTERIOR_MARKS });
|
|
3510
|
+
const { actors } = v;
|
|
3474
3511
|
if (actors > cast) out.push({ path: "vignette", also: castParams, message: `needs ${actors} fish (actors a\u2013${"abc"[actors - 1]} are slots 0\u2013${actors - 1}), but ${castWhy}` });
|
|
3512
|
+
const slotBreeds = expandFishMixSlots(mix, 3).map((sl) => sl.breed);
|
|
3513
|
+
for (const [g, breeds] of Object.entries(BREED_GESTURES)) {
|
|
3514
|
+
for (let a = 0; a < actors; a++) {
|
|
3515
|
+
if (!v.beats.some((b) => b.actors[a]?.gesture === g)) continue;
|
|
3516
|
+
const breed = slotBreeds[a] ?? "fish";
|
|
3517
|
+
if (!breeds.includes(breed)) out.push({ path: "vignette", also: ["fishMix"], message: `"${"abc"[a]} ${g}" does nothing: ${g} is the ${breeds.join("/")}'s own, and actor ${"abc"[a]} (slot ${a}) is a ${breed}` });
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3475
3520
|
}
|
|
3476
3521
|
const dance = str("starfishDance", "off") || "off";
|
|
3477
3522
|
const starfishSwims = mix.some((e, i) => e.breed === "starfish" && mix.slice(0, i).reduce((n, p) => n + p.count, 0) < CAST_CAP);
|
|
@@ -3480,7 +3525,7 @@ function dependencyProblems(params) {
|
|
|
3480
3525
|
}
|
|
3481
3526
|
if (set("danceTempo") && dance === "off") out.push({ path: "danceTempo", also: ["starfishDance"], message: "does nothing while starfishDance is off" });
|
|
3482
3527
|
if (follow < 0) {
|
|
3483
|
-
for (const k of ["followDistance", "followAngle"]) if (set(k)) out.push({ path: k, also: ["cameraFollow"], message: "does nothing while cameraFollow is -1 (the orbit camera)" });
|
|
3528
|
+
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)" });
|
|
3484
3529
|
} else if (follow < cast) {
|
|
3485
3530
|
for (const k of ORBIT_PARAMS) if (set(k)) out.push({ path: k, also: ["cameraFollow"], message: `ignored while cameraFollow rides with slot ${follow} \u2014 they return when it is -1` });
|
|
3486
3531
|
}
|
|
@@ -3510,6 +3555,7 @@ var BREED_NOUN = {
|
|
|
3510
3555
|
octopus: ["octopus", "octopuses"],
|
|
3511
3556
|
snail: ["snail", "snails"],
|
|
3512
3557
|
dot: ["Dot", "Dots"],
|
|
3558
|
+
dolphin: ["dolphin", "dolphins"],
|
|
3513
3559
|
starfish: ["starfish", "starfish"],
|
|
3514
3560
|
crab: ["crab", "crabs"],
|
|
3515
3561
|
shark: ["shark", "sharks"],
|
|
@@ -3708,6 +3754,12 @@ var METAQUARIUM_PARAMS = {
|
|
|
3708
3754
|
* it (the default), 90 at its side, 180 in front looking back at its face
|
|
3709
3755
|
* — a hackerfish's screen, a crab's smile. */
|
|
3710
3756
|
followAngle: { type: "number", default: 0, min: -180, max: 180, ease: "smooth" },
|
|
3757
|
+
/** Keep the followed fish in view (sightline.ts): when a home, a wall, a lamp
|
|
3758
|
+
* or a kelp stand comes between it and the chase camera, the camera rises a
|
|
3759
|
+
* little to look over low clutter and otherwise pulls in toward the fish, as
|
|
3760
|
+
* a game camera's spring arm does — eased, never a snap. 0 (default) is the
|
|
3761
|
+
* plain chase camera; 1 the full arm. Not the fish's-eye view (it has none). */
|
|
3762
|
+
followAvoid: { type: "number", default: 0, min: 0, max: 1, ease: "smooth" },
|
|
3711
3763
|
/** Continuous orbit speed, degrees/second. Zero by default: the tank is
|
|
3712
3764
|
* still, letting the fish movement carry the scene. Steer up for an orbit. */
|
|
3713
3765
|
autoRotate: { type: "number", default: 0, min: 0, max: 12, ease: "smooth" },
|
|
@@ -4317,6 +4369,8 @@ export {
|
|
|
4317
4369
|
GESTURES,
|
|
4318
4370
|
OPEN_MARKS,
|
|
4319
4371
|
parseVignette,
|
|
4372
|
+
snapBetween,
|
|
4373
|
+
poseAcross,
|
|
4320
4374
|
poseOf,
|
|
4321
4375
|
INTERIOR_MARKS,
|
|
4322
4376
|
VIGNETTES,
|
|
@@ -4338,4 +4392,4 @@ export {
|
|
|
4338
4392
|
paramSpaceWith,
|
|
4339
4393
|
coerceNum
|
|
4340
4394
|
};
|
|
4341
|
-
//# sourceMappingURL=chunk-
|
|
4395
|
+
//# sourceMappingURL=chunk-7ZYKA2WS.js.map
|