SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { anatomyLabels } from './anatomy-contract.js';
import { muscleCatalog, organCatalog } from './atlas-catalog.js';
import { skeletonCatalog } from './skeleton-catalog.js';
import { mouthCatalog } from './mouth-catalog.js';
import type { AnatomyLayer } from './layers.js';
export interface AnatomyNode { id: string; label: string; children?: AnatomyNode[] }
const sides = ['left', 'right'] as const;
const digits = ['thumb', 'index', 'middle', 'ring', 'pinky'];
const title = (s: string) => s[0].toUpperCase() + s.slice(1);
const region = (id: string, label: string, children?: AnatomyNode[]): AnatomyNode => ({ id: `region:${id}`, label, ...(children ? { children } : {}) });
export function flattenAnatomy(node: AnatomyNode): AnatomyNode[] { return [node, ...(node.children || []).flatMap(flattenAnatomy)]; }
export function anatomyLeaves(node: AnatomyNode): string[] { return node.children ? node.children.flatMap(anatomyLeaves) : [node.id]; }
/** One leaf per dominant rig bone, so adjacent regions never overlap. */
export function skinLeafForBone(bone: string): string {
if (bone === 'head') return 'region:head';
if (bone.startsWith('neck')) return 'region:neck';
if (bone.startsWith('spine')) return 'region:torso';
if (bone.startsWith('clavicle_')) return `region:${bone.endsWith('_l') ? 'left' : 'right'}-upperarm`;
const match = bone.match(/^(upperarm|lowerarm|hand|thigh|calf|foot|ball|thumb_0[123]|index_0[123]|middle_0[123]|ring_0[123]|pinky_0[123])_([lr])$/);
if (!match) return 'region:pelvis-surface';
const [, part, side] = match, prefix = side === 'l' ? 'left' : 'right';
if (part.includes('_0')) { const [digit, n] = part.split('_0'); return `region:${prefix}-${digit}-${['base','middle','tip'][Number(n)-1]}`; }
return `region:${prefix}-${({ lowerarm: 'forearm-surface', calf: 'calf-surface', hand: 'palm', ball: 'foot' } as Record<string,string>)[part] || part}`;
}
const cache = new Map<AnatomyLayer, AnatomyNode>();
export function anatomyTree(layer: AnatomyLayer): AnatomyNode {
const saved = cache.get(layer); if (saved) return saved;
if (layer === 'mouth') {
const leaf = (p: typeof mouthCatalog[number]): AnatomyNode => ({ id: `structure:${p.id}`, label: p.label });
const jaws = (['upper','lower'] as const).map(jaw => region(`${jaw}-mouth`, `${title(jaw)} jaw`, [
...sides.map(side => region(`${jaw}-${side}-teeth`, `${title(jaw)} ${side} teeth`, mouthCatalog.filter(p => p.kind === 'tooth' && p.jaw === jaw && p.label.toLowerCase().startsWith(side)).sort((a,b) => ('fdi' in a ? a.fdi : 0)-('fdi' in b ? b.fdi : 0)).map(leaf))),
...mouthCatalog.filter(p => p.jaw === jaw && p.kind !== 'tooth').map(leaf),
]));
const root = region('body','All anatomy',[region('mouth','Mouth',jaws), {id:'outline',label:'Body outline (orientation)'}]);
cache.set(layer,root); return root;
}
const root = region('body', 'All anatomy', [region('head', 'Head / face'), region('neck', 'Neck'), region('torso', 'Chest / abdomen / back'), region('pelvis', 'Pelvis')]);
for (const side of sides) {
const t = title(side);
const hand = region(`${side}-hand`, `${t} hand`, [region(`${side}-palm`, `${t} palm / wrist`), ...digits.map(digit => region(`${side}-${digit}`, `${t} ${digit === 'pinky' ? 'little' : digit}${digit === 'thumb' ? '' : ' finger'}`, layer === 'skin' ? ['base','middle','tip'].map((segment, i) => region(`${side}-${digit}-${segment}`, `${t} ${digit === 'pinky' ? 'little finger' : digit} · ${digit === 'thumb' && i === 1 ? 'knuckle' : segment} segment`)) : []))]);
root.children!.push(region(`${side}-arm`, `${t} arm`, [region(`${side}-upperarm`, `${t} upper arm / shoulder`), region(`${side}-forearm`, `${t} forearm + hand`, [region(`${side}-forearm-surface`, `${t} forearm`), hand])]));
root.children!.push(region(`${side}-leg`, `${t} leg`, [region(`${side}-thigh`, `${t} thigh`), region(`${side}-calf`, `${t} lower leg + foot`, [region(`${side}-calf-surface`, `${t} lower leg / knee`), region(`${side}-foot`, `${t} foot`)])]));
}
const nodes = new Map(flattenAnatomy(root).map(n => [n.id, n]));
if (layer === 'skin') {
nodes.get('region:pelvis')!.children = [region('pelvis-surface','Pelvic surface'), ...Object.entries(anatomyLabels).map(([id,label]) => ({id:`structure:${id}`,label}))];
} else {
for (const n of nodes.values()) if (!n.children) n.children = [];
const entries = layer === 'skeleton' ? skeletonCatalog : layer === 'muscles' ? muscleCatalog : organCatalog;
for (const p of entries) {
let part = p.part.replace('-shoulder','-upperarm').replace('-knee','-calf');
if (part.endsWith('-forearm') || part.endsWith('-calf')) part += '-surface';
if (part.endsWith('-hand')) {
const side = part.split('-')[0], label = p.label.toLowerCase();
const digit = /thumb|pollicis|first metacarpal/.test(label) ? 'thumb' : /index finger|second metacarpal/.test(label) ? 'index' : /middle finger|third metacarpal/.test(label) ? 'middle' : /ring finger|fourth metacarpal/.test(label) ? 'ring' : /little finger|digiti minimi|fifth metacarpal/.test(label) ? 'pinky' : 'palm';
part = `${side}-${digit}`;
}
(nodes.get(`region:${part}`) || nodes.get('region:torso'))!.children!.push({id:`structure:${p.id}`,label:p.label});
}
if (layer === 'muscles' || layer === 'organs') root.children!.push({id:'outline',label:'Body outline (orientation)'});
}
const prune = (n: AnatomyNode): AnatomyNode | undefined => {
if (!n.children) return n;
n.children = n.children.map(prune).filter((v): v is AnatomyNode => !!v);
return n.children.length ? n : undefined;
};
prune(root); cache.set(layer, root); return root;
}
export function descendants(layer: AnatomyLayer, id: string): string[] {
const node = flattenAnatomy(anatomyTree(layer)).find(n => n.id === id);
return node ? anatomyLeaves(node) : [];
}
export function visibilityState(node: AnatomyNode, hidden: ReadonlySet<string>): 'checked' | 'mixed' | 'unchecked' {
const leaves = anatomyLeaves(node), count = leaves.filter(id => hidden.has(id)).length;
return count === 0 ? 'checked' : count === leaves.length ? 'unchecked' : 'mixed';
}
