{
  "slug": "ai-mesh-weapon-rig",
  "skill": "ai-mesh-weapon-rig",
  "upstream": "GameSkill original (onsite/<slug>/original)",
  "sourceHash": "d22c4872e08f9c3df13bf522378069180302a6b63904d21a48dc4e83ba7729bd",
  "date": "2026-10-28",
  "engine": "Blender 5.2.3 LTS (background) + three.js r186 in Chrome 156 headless",
  "env": [
    "Node v22.11.0",
    "Blender 5.2.3 LTS (linux x64), background mode, no add-ons or Python packages",
    "Node 20+ for the spec linter and GLB validator (no dependencies)",
    "three.js r186 vendored in viewer/vendor/three, puppeteer-core 24 from package-lock.json",
    "Google Chrome 156 headless (SwiftShader WebGL)"
  ],
  "trigger": "static",
  "passed": 45,
  "total": 45,
  "commands": [
    "(cd ../original && sh -c npm ci --silent --no-audit --no-fund && node --test --test-reporter=tap test/logic.test.mjs)",
    "(cd ../original && env BLENDER={blender} node test/blender.test.mjs)",
    "(cd ../original && node test/browser.test.mjs)",
    "(cd . && cp ../original/shots/sheet.png screenshot.png)"
  ],
  "checks": [
    {
      "criterion": "trigger",
      "name": "SKILL.md description says when to use it",
      "pass": true,
      "detail": "Turn one prop mesh (hand-built, or generated from an image by an image-to-3D model) into a first-person viewmodel GLB. I"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"I generated a sci-fi tool prop with an AI 3D model, split it into parts and rig it with fire and reload animations for my FPS\"",
      "pass": true,
      "detail": "rank 1/118, overlap 10"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"Rig this blaster prop for first person: slide, trigger and magazine bones plus a muzzle socket, export GLB\"",
      "pass": true,
      "detail": "rank 1/118, overlap 10"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"Check my viewmodel GLB: are the weapon bones, sockets and fire/reload clips set up right?\"",
      "pass": true,
      "detail": "rank 1/118, overlap 9"
    },
    {
      "criterion": "trigger",
      "name": "does not trigger on: \"Tune the recoil pattern and ADS feel of my FPS gun\"",
      "pass": true,
      "detail": "rank 7/118, overlap 1"
    },
    {
      "criterion": "trigger",
      "name": "does not trigger on: \"Export my Blender character to Unreal as FBX\"",
      "pass": true,
      "detail": "rank 45/118, overlap 0"
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: example spec passes both routes; the two greys are flagged as close and covered by the hint",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: linter catches a missing hint, real-gun names, non-fictional props, bad bones, orient and travel",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: grey parts used for orientation give a warning, not an error",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: shaded and lit versions of each coloured part still map to that part",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: prompt colours list every part as hex",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: GLB reader rejects other files and composes node transforms",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: example rig: four deform bones, rigid skin, three clips, four sockets, muzzle in front",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: validator flags broken rigs",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: example build report: six closed parts, mechanism passes",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: CLIs: exit codes 0 / 1 / 2",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "spec linter, GLB reader and validator, shipped example rig and build report, CLI exit codes: exits 0 with no script errors",
      "pass": true,
      "detail": "exit 0"
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: Blender runs headless (Blender 5.2.3 LTS)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: procedural route builds the example rig (88132 bytes)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: six closed parts, no open or non-manifold edges",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: mechanism: cartridge drops clear of the body, cover travels, muzzle at the front (drop 0.1537 m, slide 0.045 m)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: GLB passes the viewmodel validator (632 triangles)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: rebuild matches the shipped example/rivet-launcher.glb",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: pose renders written to shots/",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: stand-in generated mesh: one shell, baked texture, tilted OBJ ([fake-ai] faces 13112)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: AI route splits it by colour into the six parts (body 5759, grip 2251, nozzle 1168, cover 1396, trigger 347, mag 2191)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: AI route: orientation found, mechanism passes, GLB validates",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: AI route: every cut opens a hole that is only capped flat (no interior is modelled) (728 open edges before capping, 0 after, 17 non-manifold)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "Blender: build the example rig, mechanism check, rebuild matches the shipped GLB, AI route on a stand-in generated mesh: exits 0 with no script errors",
      "pass": true,
      "detail": "exit 0"
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: viewer loads the rigged GLB with no errors (fire, reload, inspect)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: muzzle flash sits on socket_muzzle, in front of the prop (local 0.01, -0.045, -0.248)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: demo spray plays the fire clip once per shot (10 shots, fire played 10)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: muzzle flash is visible at the socket while firing (luma 255 with flash, 148 without)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: R plays reload; the cartridge drops; holding fire does not interrupt it (cartridge down 0.162 m while the trigger is held)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: F plays inspect",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: ?box keeps the original box carbine and loads no GLB",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: a missing GLB is reported, not thrown",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: contact sheet: Blender poses above, FPS views below (8 tiles)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "FPS viewer in headless Chrome: clips on shoot / R / F, muzzle flash on the socket, reload not interrupted, fallbacks: exits 0 with no script errors",
      "pass": true,
      "detail": "exit 0"
    },
    {
      "criterion": "output",
      "name": "screenshot screenshot.png rendered",
      "pass": true
    },
    {
      "criterion": "output",
      "name": "self-check list has at least 3 items",
      "pass": true,
      "detail": "6 items"
    },
    {
      "criterion": "single",
      "name": "one job per skill (reviewed)",
      "pass": true,
      "detail": "One job: turn one fictional prop mesh into a rigged, animated first-person viewmodel GLB (split by colour, rigid rig with sockets, fire/reload/inspect clips, mechanism and GLB checks) and show it in an FPS viewer. Gun feel and recoil stay in threejs-fps-weapon-feel; general Blender export presets in blender-export-pipelines; generating the mesh itself is the user's image-to-3D tool."
    },
    {
      "criterion": "bilingual",
      "name": "English SKILL.md",
      "pass": true
    },
    {
      "criterion": "bilingual",
      "name": "Chinese SKILL.zh.md shipped next to SKILL.md",
      "pass": true,
      "detail": "3792 chars"
    },
    {
      "criterion": "bilingual",
      "name": "Chinese guide written",
      "pass": true,
      "detail": "1694 chars"
    }
  ]
}
