ShiboSoftwareDev/linux-gameboy-advance
A multilayer PCB carrier board routing the MCU, USB‑C, battery/AA power selector and TPS63020 regulator, LCD/SD interfaces, UART/I²C/SPI service headers, controls, audio/status LEDs, and backlight with reviewed traces and vias.
- Version
- 1.0.125
- License
- unset
- Stars
- 0
scripts/check-enclosure-design.mjs
import { readFileSync } from "node:fs"
import { fileURLToPath } from "node:url"
import assert from "node:assert/strict"
const root = new URL("../", import.meta.url)
const spec = JSON.parse(readFileSync(new URL("mechanical/enclosure-spec.json", root), "utf8"))
const source = readFileSync(new URL("mechanical/GbaEnclosure.tsx", root), "utf8")
assert.equal(spec.schemaVersion, 1)
assert.equal(spec.pcbMounts.length, 4, "exactly four structural PCB/case fasteners are required")
assert.equal(spec.lcdMounts.length, 4, "the LCD carrier must have four intentional mounts")
assert.equal(new Set(spec.externalOpenings.map(({ id }) => id)).size, spec.externalOpenings.length,
"external opening IDs must be unique")
for (const opening of spec.externalOpenings) {
assert.ok(opening.purpose.trim().length > 5, `${opening.id} needs a stated purpose`)
}
for (const internal of ["J_BAT", "J_UART", "J_I2C", "J_SPI", "SW_RESET", "JP_BOOT", "J_SPK"]) {
assert.ok(spec.intentionallyInternal.some((entry) => entry.includes(internal)), `${internal} needs an aperture decision`)
}
for (const name of spec.requiredPrintedParts) {
const isDynamicButton = name.startsWith("BUTTON_CAP_") && source.includes("name={`BUTTON_CAP_${name}`}")
assert.ok(source.includes(`name=\"${name}\"`) || isDynamicButton,
`${name} is missing from the mechanical assembly source`)
}
for (const required of [
"M3 heat-set insert", "M3 nylon PCB washer", "M2.5 x 6 mm LCD-carrier screw",
"Keystone 210", "LCD_FRONT_GASKET", "LCD_REAR_GASKET", "SPK_FOAM_GASKET",
"STATUS_LIGHT_PIPE",
]) assert.ok(source.includes(required), `mechanical assembly is missing ${required}`)
assert.ok(!source.includes("LidSnaps"), "snap-only case closure must not return")
assert.ok(source.includes("DPAD_CAP"), "four bare directional stems are not an acceptable user control")
assert.ok(source.includes("SHOULDER_PADDLE_L") && source.includes("SHOULDER_PADDLE_R"),
"shoulder switches require external paddles")
assert.match(spec.battery.charging, /No on-board AA charging/)
assert.equal(spec.battery.contactInsideWallSpacingMm, 57.7,
"two-cell 209/210 contact layout must retain its manufacturer inside-wall spacing")
assert.ok(spec.battery.contactMountWallThicknessMm >= 1.52 &&
spec.battery.contactMountWallThicknessMm <= 1.78,
"snap-on battery-contact wall must stay inside the manufacturer mounting range")
assert.ok(spec.prototypeGates.length >= 5, "physical-validation gates must remain explicit")
console.log(`[mechanical] ${spec.requiredPrintedParts.length} printed parts, ${spec.externalOpenings.length} intentional openings, 4 structural mounts, 4 LCD mounts`)