Files
dyolink/frontend/scripts/extract-tooth-svgs.mjs

55 lines
1.9 KiB
JavaScript
Raw Normal View History

/**
* Regenerates realisticToothAssets.ts from FDI_*.svg files in src/assets/fdi/.
* Usage (from frontend/): node scripts/extract-tooth-svgs.mjs
*/
import fs from 'node:fs';
import path from 'node:path';
const dir = path.resolve('src/assets/fdi');
const files = fs.readdirSync(dir).filter((f) => /^FDI_\d{2}\.svg$/i.test(f));
const out = {};
for (const file of files.sort()) {
const id = file.match(/FDI_(\d{2})/i)?.[1];
if (!id) continue;
const xml = fs.readFileSync(path.join(dir, file), 'utf8');
const vb = xml.match(/viewBox="([^"]+)"/)?.[1];
const toothG = xml.match(/<g id="tooth-\d+"[^>]*>/)?.[0] ?? '';
const transform = toothG.match(/transform="([^"]+)"/)?.[1];
const rootD = xml.match(/id="root-path"[\s\S]*?d="([^"]+)"/)?.[1];
const crownD = xml.match(/id="crown-path"[\s\S]*?d="([^"]+)"/)?.[1];
if (!vb || !rootD || !crownD) throw new Error(`Failed to parse ${file}`);
out[id] = {
viewBox: vb,
...(transform ? { groupTransform: transform } : {}),
crown: crownD,
roots: [rootD],
};
console.log(id, transform ? 'mirrored' : 'plain');
}
const ts = `import type { FdiToothId } from '@/types/treatment';
/**
* Realistic buccal-view assets from src/assets/fdi/FDI_*.svg.
* Upper (1x/2x): root-up. Lower (3x/4x): crown-up.
* Left chart side (Q1/Q4) includes horizontal flip via groupTransform.
*/
export interface RealisticToothAsset {
viewBox: string;
/** Applied inside the svg (e.g. Q1/Q4 mirror baked in source files). */
groupTransform?: string;
crown: string;
roots: string[];
}
export const REALISTIC_TOOTH_ASSETS: Partial<Record<FdiToothId, RealisticToothAsset>> = ${JSON.stringify(out, null, 2)};
export function getRealisticToothAsset(fdi: FdiToothId): RealisticToothAsset | null {
return REALISTIC_TOOTH_ASSETS[fdi] ?? null;
}
`;
fs.writeFileSync(path.resolve('src/components/treatment/realisticToothAssets.ts'), ts);
console.log('Wrote realisticToothAssets.ts for', Object.keys(out).length, 'teeth');