import { access, mkdir } from 'node:fs/promises' import { constants } from 'node:fs' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { spawn } from 'node:child_process' const here = dirname(fileURLToPath(import.meta.url)) const harnessRoot = resolve(here, '..') const projectRoot = resolve(harnessRoot, '..') const blendFile = resolve(projectRoot, 'blender_prototype', 'sanctification_card_material_prototype.blend') const pythonScript = resolve(here, 'export_card_mesh.py') const outputFile = resolve(harnessRoot, 'public', 'reference', 'card-mesh.glb') const explicit = process.env.BLENDER_EXECUTABLE const platformCandidates = process.platform === 'win32' ? [ 'C:\\Program Files\\Blender Foundation\\Blender 5.2\\blender.exe', 'C:\\Program Files\\Blender Foundation\\Blender 5.1\\blender.exe', 'C:\\Program Files\\Blender Foundation\\Blender 5.0\\blender.exe', ] : [ '/usr/bin/blender', '/usr/local/bin/blender', '/snap/bin/blender', ] async function exists(path) { try { await access(path, constants.X_OK) return true } catch { return false } } let blender = explicit if (blender && !(await exists(blender))) { throw new Error(`BLENDER_EXECUTABLE does not exist or is not executable: ${blender}`) } if (!blender) { for (const candidate of platformCandidates) { if (await exists(candidate)) { blender = candidate break } } } if (!blender) blender = 'blender' await mkdir(dirname(outputFile), { recursive: true }) const args = [ '--background', blendFile, '--python', pythonScript, '--', '--output', outputFile, ] console.log(`Exporting card mesh with ${blender}`) const child = spawn(blender, args, { stdio: 'inherit', shell: false }) const exitCode = await new Promise((resolveExit, reject) => { child.once('error', reject) child.once('exit', (code) => resolveExit(code ?? 1)) }) if (exitCode !== 0) { throw new Error(`Blender export failed with exit code ${exitCode}`) } console.log(`Card mesh exported to ${outputFile}`)