Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/thatstupidcomputer / apps/web/src/animation/office/model.ts |
| Date | Not specified in source |
| Repository | Janady13/thatstupidcomputer |
| Revision | 57555cde46910102dd25d6c1c1fb2c359e9655bd |
| Branch | main |
| Path or archive member | apps/web/src/animation/office/model.ts |
| Original SHA-256 | 1c46d5ebe3a75dac48ea12cef9e5b4b1b6adc646f35c6f065325aa4f6d54fc7e |
| Git blob SHA | 7a0cc47c1022e0a52ae31ae21d48b6bd9ebd30a0 |
| Reading-copy SHA-256 | 1c46d5ebe3a75dac48ea12cef9e5b4b1b6adc646f35c6f065325aa4f6d54fc7e |
Recovered source transcript
Download complete source text ↓54 lines · 2.4 KB
import { DEFAULT_OBJECTS, LAYERS } from './catalog';
import type { RoomAddition, RoomItem, RoomOverrides } from './types';
const NAME = /^[a-z][a-z0-9-]*$/;
/** Validate a small, explicit scene graph before rendering it. */
export function resolveObjects(
overrides: RoomOverrides = {}, additions: readonly RoomAddition[] = [],
): RoomItem[] {
const templates = new Map(DEFAULT_OBJECTS.map(item => [item.kind, item]));
const all: RoomItem[] = DEFAULT_OBJECTS.map(item => ({ ...item }));
const ids = new Set(all.map(item => item.id));
for (const addition of additions) {
if (!NAME.test(addition.id) || ids.has(addition.id)) {
throw new Error(`Room object ID must be unique and kebab-case: ${addition.id}`);
}
const template = templates.get(addition.kind);
if (!template) throw new Error(`Unknown room artwork kind: ${addition.kind}`);
all.push({ ...template, ...addition });
ids.add(addition.id);
}
for (const key of Object.keys(overrides)) {
if (!ids.has(key)) throw new Error(`Cannot override unknown room object: ${key}`);
}
for (let i = 0; i < all.length; i++) {
const item = all[i] = { ...all[i], ...overrides[all[i].id] };
for (const property of ['x', 'y', 'scale', 'rotation'] as const) {
if (!Number.isFinite(item[property])) throw new TypeError(`${item.id}.${property} must be finite.`);
}
if (item.scale <= 0) throw new RangeError(`${item.id}.scale must be positive.`);
if (!LAYERS.includes(item.layer)) throw new RangeError(`Unknown room layer: ${item.layer}`);
if (item.parent !== null && !ids.has(item.parent)) throw new Error(`Missing parent of ${item.id}: ${item.parent}`);
}
const map = new Map(all.map(item => [item.id, item]));
for (const item of all) {
const seen = new Set([item.id]);
let parent = item.parent;
while (parent) {
if (seen.has(parent)) throw new Error(`Scene parenting cycle at: ${item.id}`);
seen.add(parent);
parent = map.get(parent)!.parent;
}
}
return all;
}
/** Never strip characters from an ID: lossless encoding avoids sanitizer collisions. */
export function instancePrefix(id: string): string {
return 'office-' + Array.from(id, char => char.codePointAt(0)!.toString(16)).join('-');
}
export function placement(item: Pick<RoomItem, 'x' | 'y' | 'rotation' | 'scale'>): string {
return `translate(${item.x} ${item.y}) rotate(${item.rotation}) scale(${item.scale})`;
}