tune: scale wander/path fallbacks to the table (radius 60cm->2.5cm, vertical 10cm->4mm, path speed 8->1.5cm/s, lookahead 6->1.5cm)
This commit is contained in:
@@ -12,6 +12,15 @@ const BOB_AMP_CM = 0.3; // 3mm
|
|||||||
const BOB_HZ = 0.4;
|
const BOB_HZ = 0.4;
|
||||||
const SHIMMER_CM = 0.3; // secondary float used by wander + path modes
|
const SHIMMER_CM = 0.3; // secondary float used by wander + path modes
|
||||||
|
|
||||||
|
/* Fallbacks for records that arrive without explicit behaviour params. The
|
||||||
|
* playlist normally supplies these (wanderRadius / wanderVertical / pathSpeed),
|
||||||
|
* so these only fire for hand-made or legacy records — but they still need to
|
||||||
|
* suit a ~25cm table, or an unconfigured ghost drifts clean off the display. */
|
||||||
|
const WANDER_RADIUS_CM = 2.5;
|
||||||
|
const WANDER_VERTICAL_CM = 0.4;
|
||||||
|
const PATH_SPEED_CMS = 1.5;
|
||||||
|
const PATH_LOOKAHEAD_CM = 1.5; // distance sampled ahead to face travel direction
|
||||||
|
|
||||||
function hashNoise(seed, k) {
|
function hashNoise(seed, k) {
|
||||||
// cheap deterministic pseudo-noise in [-1, 1]
|
// cheap deterministic pseudo-noise in [-1, 1]
|
||||||
const x = Math.sin(seed * 127.1 + k * 311.7) * 43758.5453;
|
const x = Math.sin(seed * 127.1 + k * 311.7) * 43758.5453;
|
||||||
@@ -27,14 +36,14 @@ export function ghostTransform(rec, nowMs, out) {
|
|||||||
pathTransform(b, t, out);
|
pathTransform(b, t, out);
|
||||||
} else if (b.type === 'wander') {
|
} else if (b.type === 'wander') {
|
||||||
const s = b.seed || 1;
|
const s = b.seed || 1;
|
||||||
const R = b.radius ?? 60; // cm
|
const R = b.radius ?? WANDER_RADIUS_CM;
|
||||||
const v = b.speed ?? 0.15;
|
const v = b.speed ?? 0.15;
|
||||||
// smooth pseudo-random orbit-drift: two incommensurate sines per axis
|
// smooth pseudo-random orbit-drift: two incommensurate sines per axis
|
||||||
const ph = t * v;
|
const ph = t * v;
|
||||||
out.position.set(
|
out.position.set(
|
||||||
base.x + R * 0.9 * Math.sin(ph * 1.0 + hashNoise(s, 1) * 6.28) * 0.7
|
base.x + R * 0.9 * Math.sin(ph * 1.0 + hashNoise(s, 1) * 6.28) * 0.7
|
||||||
+ R * 0.4 * Math.sin(ph * 2.3 + hashNoise(s, 2) * 6.28) * 0.3,
|
+ R * 0.4 * Math.sin(ph * 2.3 + hashNoise(s, 2) * 6.28) * 0.3,
|
||||||
base.y + (b.vertical ?? 10) * Math.sin(t * v * 1.3 + hashNoise(s, 3) * 6.28)
|
base.y + (b.vertical ?? WANDER_VERTICAL_CM) * Math.sin(t * v * 1.3 + hashNoise(s, 3) * 6.28)
|
||||||
+ SHIMMER_CM * Math.sin(t * 1.7 + hashNoise(s, 6) * 6.28),
|
+ SHIMMER_CM * Math.sin(t * 1.7 + hashNoise(s, 6) * 6.28),
|
||||||
base.z + R * 0.9 * Math.cos(ph * 0.8 + hashNoise(s, 4) * 6.28) * 0.7
|
base.z + R * 0.9 * Math.cos(ph * 0.8 + hashNoise(s, 4) * 6.28) * 0.7
|
||||||
+ R * 0.4 * Math.cos(ph * 1.9 + hashNoise(s, 5) * 6.28) * 0.3
|
+ R * 0.4 * Math.cos(ph * 1.9 + hashNoise(s, 5) * 6.28) * 0.3
|
||||||
@@ -92,10 +101,10 @@ function pathTransform(b, t, out) {
|
|||||||
return v;
|
return v;
|
||||||
};
|
};
|
||||||
|
|
||||||
const d = wrap(t * (b.speed ?? 8) + (b.phase || 0));
|
const d = wrap(t * (b.speed ?? PATH_SPEED_CMS) + (b.phase || 0));
|
||||||
sample(d, out.position);
|
sample(d, out.position);
|
||||||
// face where we're heading: sample a few cm ahead so corners turn smoothly
|
// face where we're heading: sample a short distance ahead so corners turn smoothly
|
||||||
const ahead = sample(wrap(t * (b.speed ?? 8) + (b.phase || 0) + 6), _look);
|
const ahead = sample(wrap(t * (b.speed ?? PATH_SPEED_CMS) + (b.phase || 0) + PATH_LOOKAHEAD_CM), _look);
|
||||||
const dx = ahead.x - out.position.x, dz = ahead.z - out.position.z;
|
const dx = ahead.x - out.position.x, dz = ahead.z - out.position.z;
|
||||||
if (dx * dx + dz * dz > 1e-4) out.rotationY = Math.atan2(dx, dz);
|
if (dx * dx + dz * dz > 1e-4) out.rotationY = Math.atan2(dx, dz);
|
||||||
// gentle float so walking still reads ghostly
|
// gentle float so walking still reads ghostly
|
||||||
|
|||||||
Reference in New Issue
Block a user