SOURCE / PINNED RELEASE
Made of little things.
Napplet Machines V8
- Release
- b3f614e739f0…
- Author-recorded commit
- 534f19acb4ba…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b5572362d4a
Archive hash verified: 0f7feb97e2c3d336…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { Road, clamp } from './track.js';
export type Building = {
x: number;
y: number;
z: number;
angle: number;
width: number;
length: number;
radius: number;
kind: 'garage' | 'stand' | 'tower';
color: number;
};
// Geometry-derived seed: guests regenerate identical scenery without network traffic.
export function raceBuildings(road: Road): Building[] {
let seed = 2166136261;
for (const p of road.track.points)
for (const n of [p.x, p.y, p.z, p.width])
seed = Math.imul(seed ^ Math.round(n * 100), 16777619) >>> 0;
const random = () => {
seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0;
return seed / 4294967296;
};
const result: Building[] = [];
const count = Math.min(12, Math.max(5, Math.floor(road.length / 28)));
for (let attempt = 0; attempt < 160 && result.length < count; attempt++) {
const p = road.at(12 + random() * Math.max(1, road.length - 24));
const kind = (['garage', 'stand', 'tower'] as const)[result.length % 3];
const length =
kind === 'tower' ? 3.5 : kind === 'stand' ? 7.5 : 5.8 + random() * 1.5;
const width = kind === 'stand' ? 4.4 : 3.8;
const radius = Math.hypot(length / 2 + 0.5, width / 2 + 0.5);
const side = random() < 0.5 ? -1 : 1;
const offset =
(p.width / 2 + p.wallThickness / 2 + radius + 2 + random() * 1.8) * side;
const x = p.x - p.ty * offset,
y = p.y + p.tx * offset;
if (
Math.abs(x) + radius >
Math.max(
76,
Math.abs(road.bounds.minX) + 17,
Math.abs(road.bounds.maxX) + 17,
) ||
Math.abs(y) + radius >
Math.max(
68,
Math.abs(road.bounds.minY) + 17,
Math.abs(road.bounds.maxY) + 17,
)
)
continue;
if (
result.some((b) => Math.hypot(x - b.x, y - b.y) < radius + b.radius + 2)
)
continue;
// Check all road segments, including other branches and changing widths.
const clear = road.samples.slice(0, -1).every((a, i) => {
const b = road.samples[i + 1],
dx = b.x - a.x,
dy = b.y - a.y;
const t = clamp(
((x - a.x) * dx + (y - a.y) * dy) / (dx * dx + dy * dy || 1),
0,
1,
);
return (
Math.hypot(x - a.x - dx * t, y - a.y - dy * t) >
radius +
Math.max(a.width, b.width) / 2 +
(a.wall ? a.wallThickness / 2 : 0) +
1.5
);
});
if (!clear) continue;
result.push({
x,
y,
z: Math.max(0, p.z - 0.6),
angle: Math.atan2(p.ty, p.tx) + (side < 0 ? Math.PI : 0),
width,
length,
radius,
kind,
color: Math.floor(random() * 4),
});
}
return result;
}
