Back to Supersonic RC Revive
SOURCE / PINNED RELEASE

Made of little things.

Supersonic RC Revive

Release
1ba42f1ca1d6…
Author-recorded commit
baecad10b1cd…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f

Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/game/level/data.ts
// Game-ready level data built by tools/extract/build_level.py (the originals)
// or tools/assets/build.ts (the custom bundle).
import { Matrix4, Vector3 } from 'three';
import type { StaticBody } from '../physics/havok.js';

/** Group node naming the car's start in levels built by tools/assets. */
export const START_NODE = 'ssrc_start';

export interface W3DNode {
  kind: 'group' | 'model' | 'view';
  name: string;
  parent: string;
  user: string;
  /** Row-vector convention (translation in 12..14), Director Z-up. */
  matrix: number[];
}

export interface Markers {
  raymesh_models: string[];
  car_hull: { name: string; node_matrix: number[]; positions: number[][] };
  level: W3DNode[];
  car: W3DNode[];
}

export interface CollisionFile {
  gravity: number[];
  scale: number;
  bodies: Array<{ name: string; convex: boolean; friction: number; restitution: number; verts: number[]; faces: number[] }>;
}

export interface RayMesh {
  positions: Float32Array;
  indices: Uint32Array;
  owner: Uint16Array;
}

export interface LevelData {
  markers: Markers;
  collision: CollisionFile;
  rayMesh: RayMesh;
}

export function parseRayMesh(buffer: ArrayBuffer): RayMesh {
  const view = new DataView(buffer);
  const nv = view.getUint32(0, true);
  const nt = view.getUint32(4, true);
  let off = 8;
  const positions = new Float32Array(buffer.slice(off, off + nv * 12));
  off += nv * 12;
  const indices = new Uint32Array(buffer.slice(off, off + nt * 12));
  off += nt * 12;
  const owner = new Uint16Array(buffer.slice(off, off + nt * 2));
  return { positions, indices, owner };
}

export function staticBodies(collision: CollisionFile): StaticBody[] {
  return collision.bodies.map((b) => ({
    name: b.name,
    convex: b.convex,
    friction: b.friction,
    restitution: b.restitution,
    verts: new Float32Array(b.verts),
    faces: new Uint32Array(b.faces),
  }));
}

/** W3D row-vector matrix to a three.js (column-vector) Matrix4. */
export function nodeMatrix(m: number[]): Matrix4 {
  return new Matrix4().fromArray(m);
}

export function nodePosition(node: W3DNode): Vector3 {
  return new Vector3(node.matrix[12], node.matrix[13], node.matrix[14]);
}

export function findNode(nodes: W3DNode[], name: string): W3DNode | undefined {
  return nodes.find((n) => n.name === name);
}