"""Write job.json + sheet prompt for the military batch (10 Oct 2026 ~11:45 CET): wheeled, tanks, rotor, jets.
usage: python3 tools/vehicles/make_jobs_military.py   (order -> /tmp/mil-20261010/order.txt)"""
import json, os
ROOT = os.path.expanduser('~/forge-build/forge-assets')

GAME = ('GAME WEIGHT overrides the budget above: every texture image at most 1024 px, ORM / occlusion maps at most 512 px; share '
        'baked texture sets between parts and use tiling materials + trim textures on big surfaces (a 1024 bake cannot hold a 40 m '
        'fuselage). ')
NOMARK = ('No national insignia, roundels, flags, unit badges, serial numbers or any text: games give these to their own '
          'factions. No manufacturer logos. ')
PIVOTS = ('MOVING PARTS: never apply transforms to a moving node: each rotor, tail rotor, turret, gun, wheel and control '
          'surface keeps its object origin ON its own pivot (rotor hub, turret ring axis, gun trunnion or chin-turret ball, '
          'wheel centre, hinge line). Check it in Blender before export: rotate each moving node 30 degrees in a test render; '
          'nothing may leave its place. A helicopter chin gun aims DOWN and sideways from its turret. ')
SCRATCH = ('Keep this directory clean: put any helper tools you install (node_modules, vendored three.js, browser checks) under '
           '/tmp, never here. ')
TIME = ('Pace: deliver a first complete GLB within about 25 minutes, then use what is left of about 45 minutes to improve what '
        'the renders show is weakest. Use Cycles with the GPU (OptiX/CUDA) and modest samples for bakes and renders. ')


def paint(default, paints, extra=''):
    return ('PAINT CONTRACT (how games get variants of one model): the main paint lives in ONE material named exactly "Paint". Its '
            'base colour TEXTURE holds only light neutral detail (near white, with grey grime, mud, dust, soot, rain streaks, panel '
            f'lines, chipped edges baked in) and its baseColorFactor holds the paint colour; default factor = {default}. A game '
            'changes that factor, so nothing else (rubber, metal, tracks, glass, lamps, weapons, interior) may use Paint. Matte '
            f'military paint: no clearcoat. {extra}In nodes.json add "paints": six real paints for this model as linear RGB '
            f'triples with names, the default first, chosen from: {paints}; and render paints.png: a 3x2 grid of the same 3/4 view in '
            'those six paints (EEVEE or low-sample Cycles) to prove the recolour works. ')


GROUND_PAINTS = 'olive drab, NATO green, desert tan, field grey, winter white, dark green-black, sand, forest green'
AIR_PAINTS = 'air-superiority light grey, dark grey, navy blue-grey, desert sand, olive, black, two-tone grey'
FRAME4 = ('Front toward +Z, up = +Y, +X = the vehicle\'s LEFT side, centred on X = 0; origin (0,0,0) on the ground plane midway '
          'between the front axle and the rearmost axle (Forge Garage contract v2). Tyres touch y = 0.')
WHEELED = ('Separate named mesh nodes: Body (everything fixed to it), Wheel_FL, Wheel_FR, Wheel_RL, Wheel_RR (and Wheel_RL2, '
           'Wheel_RR2 for a third axle; tyre + rim + hub, origin exactly at the wheel centre: a game spins them about X and steers '
           'the front ones about Y), SteeringWheel (origin at its hub). Empty nodes (no mesh): Seat_Driver, Door_L, Door_R, '
           'Exhaust, Light_Head_L, Light_Head_R, Light_Tail_L, Light_Tail_R; Troop_1..Troop_n (seated hip points) where it '
           'carries troops. A believable cab interior visible through the glass. Windows: one material "Glass" (alpha BLEND). Lamps: '
           'one material "Lamps" (emissive). ')
FRAME_T = ('Gun forward toward +Z, up = +Y, +X = the tank\'s LEFT side, centred on X = 0; origin (0,0,0) on the ground plane at '
           'the centre of the hull footprint. Tracks touch y = 0. Turret straight ahead, gun level.')
TANK = ('Separate named mesh nodes: Hull (everything fixed to the hull), Turret (origin ON the turret ring\'s vertical axis, turns '
        'about Y), Gun (child of Turret: mantlet + barrel, origin on the trunnion axis, elevates about X), Track_L, Track_R (the '
        'track belts: their texture V coordinate runs ALONG the track so a game scrolls it to animate; links modelled where they '
        'shape the silhouette), every road wheel, sprocket and idler as its own node Wheel_L1..Wheel_Ln and Wheel_R1..Wheel_Rn '
        '(front to back, origin at its hub, spin about X), Hatch_Commander (origin on its hinge), MG (roof machine gun, child of '
        'Turret, origin at its pivot) where the type has one. Empty nodes (no mesh): Muzzle (barrel tip, child of Gun), '
        'Seat_Commander (head-out hatch point), Seat_Driver, Exhaust, Light_Head_L, Light_Head_R. Lamps: material "Lamps". ')
FRAME_R = ('Nose toward +Z, up = +Y, +X = the aircraft\'s LEFT side, centred on X = 0; origin (0,0,0) on the ground plane directly '
           'below the main rotor mast (the front rotor mast for a tandem), wheels or skids resting on y = 0.')
ROTOR = ('Separate named mesh nodes: Fuselage (everything fixed), MainRotor (hub + blades, origin ON the mast axis at the hub, '
         'spins about Y; for a tandem: Rotor_Front and Rotor_Rear, no tail rotor), TailRotor (origin at its hub, spins about its '
         'shaft; write the axis in nodes.json), Door_L, Door_R where doors open (origin on the hinge or slide line), Gun (chin or '
         'nose turret, origin at its pivot) where the type has one. Rotor blades are real twisted airfoils, not planks. Empty nodes: '
         'Seat_Pilot, Seat_Copilot (or Seat_Gunner), Troop_1..Troop_n (cabin seat hip points) for troop carriers, Hardpoint_L1, '
         'Hardpoint_R1... (pylon attach points), Light_Nav_L, Light_Nav_R, Light_Beacon, Exhaust_L, Exhaust_R. Cockpit '
         'glazing: material "Glass" (alpha BLEND) with a visible cockpit (seats, panels, sticks) behind it. Lamps: "Lamps". ')
FRAME_J = ('Nose toward +Z, up = +Y, +X = the aircraft\'s LEFT side, centred on X = 0; origin (0,0,0) on the ground plane below the '
           'main landing gear axles (gear down, tyres on y = 0).')
JET = ('Separate named mesh nodes: Fuselage (everything fixed), Canopy (origin on its hinge) where it has one, Gear_Nose, Gear_L, '
       'Gear_R (each leg with wheel and doors, gear DOWN; extra legs Gear_*), control surfaces with their origin ON the hinge line: '
       'Aileron_L/Aileron_R (or Elevon_L/Elevon_R on a delta), Elevator_L/Elevator_R (or Stabilator_L/R), Rudder (Rudder_L/Rudder_R '
       'for twin fins), Canard_L/Canard_R and Flap_L/Flap_R where the type has them. Empty nodes: Seat_Pilot (and more crew seats), '
       'Nozzle (or Nozzle_L/Nozzle_R, Engine_1..n for airliner-type engines: the exhaust centre where a game adds flame or heat), '
       'Center_Of_Mass, Hardpoint_* (each pylon / wingtip rail, empty: games hang their own weapons), Light_Nav_L (left wingtip), '
       'Light_Nav_R, Light_Beacon. Cockpit glazing: material "Glass" (alpha BLEND) with a visible cockpit behind it. Lamps: "Lamps". ')

SHEET = ('Video game vehicle design turnaround plate, photorealistic, on a plain light grey background. {desc} No national '
         'insignia, no roundels, no flags, no text markings, no logos. Real size {size}. Layout: big orthographic side view across '
         'the top, front view, rear view and top view below, and a 3/4 front hero view; callouts naming the main parts and '
         'dimensions in metres; material swatches (matte paint, rubber, metal, glass{extra}). Rich real-world construction detail, '
         'light believable field wear. No other text.')

J = [  # (class, slug, title, description, size, family, default paint, extra)
 ('vehicle.military-land.jeep', 'humvee-troop', 'Humvee (troop/cargo)', 'A US military HMMWV (Humvee) four-door troop and cargo variant: soft canvas top over the rear bed, run-flat tyres, brush guard, blackout lamps.', '4.57 m long, 2.16 m wide, 1.83 m high, wheelbase 3.30 m', 'wheeled', '[0.10, 0.12, 0.06] (olive drab)', ''),
 ('vehicle.military-land.jeep', 'humvee-armored', 'Humvee (armoured, gun turret)', 'An up-armoured US HMMWV (M1114 style): armoured doors with thick windows, a roof gunner turret with a shield and a heavy machine gun.', '4.99 m long, 2.30 m wide, 2.60 m high with the turret, wheelbase 3.30 m', 'wheeled', '[0.45, 0.36, 0.22] (desert tan)', 'Also mesh nodes Turret (gunner ring, origin on its vertical axis, turns about Y) and MG (child of Turret, origin at its pivot, elevates about X), empty Muzzle at the gun tip. '),
 ('vehicle.car.suv', 'hummer-h1', 'Hummer H1 (civilian wagon)', 'A civilian Hummer H1 style 4x4 wagon: HMMWV-based, hard-top wagon body, very wide track, high ground clearance, roof rack, body-colour wheels.', '4.69 m long, 2.20 m wide, 1.95 m high, wheelbase 3.30 m', 'wheeled', '[0.02, 0.02, 0.02] (black)', 'Civilian: glossy paint with clearcoat is fine on this one. '),
 ('vehicle.car.suv', 'hummer-h3', 'Hummer H3 (SUV)', 'A Hummer H3 style mid-size SUV: upright boxy body, short slit-like windows, upright slotted grille, round headlamps, flat hood, spare wheel on the tailgate.', '4.74 m long, 1.90 m wide, 1.89 m high, wheelbase 2.84 m', 'wheeled', '[0.62, 0.48, 0.08] (yellow)', 'Civilian: glossy paint with clearcoat is fine on this one. '),
 ('vehicle.military-land.jeep', 'ww2-jeep', 'WWII jeep', 'A World War II US Willys MB style quarter-ton jeep: flat fenders, fold-down windscreen (up), slat grille with round lamps, jerrycan and spare wheel on the back, canvas seats.', '3.33 m long, 1.57 m wide, 1.77 m high with the screen up, wheelbase 2.03 m', 'wheeled', '[0.12, 0.13, 0.07] (olive drab)', ''),
 ('vehicle.military-land.jeep', 'patrol-4x4', 'Patrol 4x4 (open top)', 'A modern open-top military patrol 4x4 in the Land Rover Defender 110 military style: roll cage, pintle machine gun mount, jerrycans, sand ladders, whip antennas, snorkel.', '4.60 m long, 1.80 m wide, 2.00 m high, wheelbase 2.79 m', 'wheeled', '[0.08, 0.12, 0.07] (NATO green)', 'Also mesh node MG (on its pintle, origin at the pivot) and empty Muzzle. '),
 ('vehicle.military-land.truck', 'cargo-truck-m35', 'Troop truck (M35 6x6)', 'A US M35 style 2.5-ton 6x6 military cargo truck (deuce and a half): long bonnet, open cab with canvas roof, wooden troop benches under a canvas cover on hoops over the bed.', '6.71 m long, 2.41 m wide, 2.84 m high, three axles', 'wheeled', '[0.10, 0.12, 0.06] (olive drab)', 'The canvas cover is its own material (not Paint). '),
 ('vehicle.military-land.truck', 'tactical-truck', 'Tactical truck (modern 6x6)', 'A modern NATO 6x6 tactical troop and cargo truck in the MAN HX / FMTV style: armoured cab with a roof hatch, canvas-covered cargo bed with troop seats, large single tyres.', '8.50 m long, 2.55 m wide, 3.30 m high, three axles', 'wheeled', '[0.42, 0.37, 0.25] (sand)', 'The canvas cover is its own material (not Paint). '),
 ('vehicle.military-land.truck', 'ural-truck', 'Troop truck (Ural 6x6)', 'A Soviet / Russian Ural-4320 style 6x6 troop truck: long bonnet, upright two-door cab, canvas tilt over the bed with side benches, big off-road tyres.', '7.37 m long, 2.50 m wide, 2.87 m high, three axles', 'wheeled', '[0.08, 0.11, 0.06] (dark green)', 'The canvas tilt is its own material (not Paint). '),
 ('vehicle.military-land.tank', 'abrams-tank', 'M1 Abrams-style tank', 'A modern US M1A2 Abrams style main battle tank: low flat angular turret with a long 120 mm smoothbore gun, side skirts, commander\'s remote weapon station, bustle rack.', '9.77 m long with the gun forward (hull 7.93 m), 3.66 m wide, 2.44 m high', 'tanks', '[0.45, 0.36, 0.22] (desert tan)', ''),
 ('vehicle.military-land.tank', 'leclerc-tank', 'Leclerc-style tank', 'A French Leclerc style main battle tank: compact angular welded turret with an autoloader bustle, 120 mm gun with thermal sleeve, side skirts, smoke launchers.', '9.87 m long with the gun forward (hull 6.88 m), 3.71 m wide, 2.53 m high', 'tanks', '[0.10, 0.12, 0.07] (NATO green)', ''),
 ('vehicle.military-land.tank', 't90-tank', 'T-90-style tank', 'A Russian T-90 style main battle tank: low rounded cast turret covered in explosive reactive armour blocks, 125 mm gun, rubber side skirts, IR dazzlers, log on the back.', '9.53 m long with the gun forward (hull 6.86 m), 3.78 m wide, 2.23 m high', 'tanks', '[0.12, 0.14, 0.08] (Russian green)', ''),
 ('vehicle.military-land.tank', 'tiger-heavy-tank', 'Tiger I-style heavy tank (WWII)', 'A World War II German Tiger I style heavy tank: boxy slab hull, interleaved large road wheels, 88 mm gun with muzzle brake, cylindrical commander cupola, tools on the hull.', '8.45 m long with the gun forward (hull 6.32 m), 3.56 m wide, 3.00 m high', 'tanks', '[0.47, 0.42, 0.28] (dark yellow)', ''),
 ('vehicle.military-land.tank', 'is3-heavy-tank', 'IS-3-style heavy tank', 'A Soviet IS-3 style heavy tank: pointed pike nose, low dome-shaped cast turret, long 122 mm gun, external fuel tanks on the rear.', '9.85 m long with the gun forward, 3.15 m wide, 2.45 m high', 'tanks', '[0.13, 0.15, 0.08] (Soviet green)', ''),
 ('vehicle.military-land.tank', 'sherman-tank', 'Sherman-style tank (WWII)', 'A World War II US M4 Sherman style medium tank: rounded cast hull, VVSS bogie suspension, 75 mm gun, sandbags and tools.', '5.84 m long, 2.62 m wide, 2.74 m high', 'tanks', '[0.12, 0.13, 0.07] (olive drab)', ''),
 ('vehicle.rotor.attack-helicopter', 'apache-helicopter', 'Apache-style attack helicopter', 'An AH-64 Apache style attack helicopter: tandem stepped cockpit, chin 30 mm chain gun turret, stub wings with rocket pods and missile racks, four-blade main rotor with mast-top radar dome, tailwheel landing gear.', '17.7 m long with rotors turning (fuselage 15.5 m), main rotor 14.6 m diameter, 3.87 m high', 'rotor', '[0.10, 0.11, 0.08] (dark olive)', ''),
 ('vehicle.rotor.attack-helicopter', 'hind-helicopter', 'Hind-style assault helicopter', 'A Mi-24 Hind style assault helicopter: stepped twin bubble canopies, a troop cabin with side doors, stub wings with rocket pods and missile rails, five-blade main rotor, retractable wheels shown down.', '17.5 m fuselage, main rotor 17.3 m diameter, 6.5 m high', 'rotor', '[0.20, 0.22, 0.14] (green and tan)', ''),
 ('vehicle.rotor.attack-helicopter', 'tiger-helicopter', 'Tiger-style attack helicopter', 'A Eurocopter Tiger style attack helicopter: slim fuselage, tandem cockpit, mast-mounted sight, stub wings with rocket pods and missiles, chin gun turret, fixed wheels.', '14.1 m fuselage, main rotor 13.0 m diameter, 3.8 m high', 'rotor', '[0.20, 0.22, 0.20] (grey green)', ''),
 ('vehicle.rotor.helicopter', 'blackhawk-helicopter', 'Black Hawk-style troop helicopter', 'A UH-60 Black Hawk style utility troop helicopter: long low cabin with large sliding side doors, door-mounted machine guns, four-blade main rotor, canted tail rotor, external stores pylons, wheeled gear.', '19.8 m long with rotors turning (fuselage 15.3 m), main rotor 16.4 m diameter, 5.1 m high', 'rotor', '[0.08, 0.09, 0.07] (dark green-black)', 'Doors are sliding: Door_L and Door_R slide back along Z. '),
 ('vehicle.rotor.helicopter', 'chinook-helicopter', 'Chinook-style heavy troop helicopter', 'A CH-47 Chinook style tandem-rotor heavy transport helicopter: long boxy fuselage, two three-blade rotors fore and aft, rear loading ramp, four wheels.', '30.1 m long with rotors turning (fuselage 15.8 m), rotors 18.3 m diameter, 5.7 m high', 'rotor', '[0.10, 0.11, 0.07] (olive drab)', 'Also mesh node Ramp (rear loading ramp, origin on its hinge, closed). '),
 ('vehicle.rotor.helicopter', 'huey-helicopter', 'Huey-style troop helicopter', 'A UH-1H Huey style utility helicopter (Vietnam era): rounded cabin with big sliding doors (open), two-blade main rotor with stabiliser bar, landing skids, door gunner machine guns.', '17.4 m long with rotors turning (fuselage 12.7 m), main rotor 14.6 m diameter, 4.4 m high', 'rotor', '[0.10, 0.11, 0.06] (olive drab)', ''),
 ('vehicle.military-air.fighter', 'rafale-fighter', 'Rafale-style fighter', 'A Dassault Rafale style twin-engine multirole fighter: cranked delta wing with close-coupled canards, single tall fin, twin side intakes under the cockpit, bubble canopy, fixed refuelling probe.', '15.27 m long, 10.80 m wingspan, 5.34 m high', 'jets', '[0.18, 0.20, 0.22] (dark grey)', ''),
 ('vehicle.military-air.fighter', 'f16-fighter', 'F-16-style fighter', 'An F-16 Fighting Falcon style single-engine fighter: blended wing-body, chin air intake, frameless bubble canopy, single fin, ventral fins, wingtip missile rails.', '15.06 m long, 9.96 m wingspan, 4.88 m high', 'jets', '[0.40, 0.42, 0.45] (light grey)', ''),
 ('vehicle.military-air.fighter', 'f18-hornet', 'F/A-18 Hornet-style fighter', 'An F/A-18C Hornet style twin-engine carrier fighter: long leading-edge root extensions, twin canted fins, twin engines, folding-wing joints, sturdy carrier landing gear with launch bar, tail hook.', '17.07 m long, 12.31 m wingspan, 4.66 m high', 'jets', '[0.38, 0.40, 0.43] (navy grey)', 'Also mesh node Hook (tail hook, origin on its hinge, up). '),
 ('vehicle.military-air.bomber', 'b52-bomber', 'B-52-style strategic bomber', 'A B-52 Stratofortress style strategic bomber: long slender fuselage, high swept wing with eight engines in four twin pods, outrigger wheels near the wingtips, tall fin, bomb bay.', '48.5 m long, 56.4 m wingspan, 12.4 m high', 'jets', '[0.22, 0.24, 0.24] (dark grey)', 'Also mesh nodes BayDoor_L, BayDoor_R (bomb bay doors, closed, origin on their hinges). '),
 ('vehicle.military-air.bomber', 'b2-bomber', 'B-2-style stealth bomber', 'A B-2 Spirit style stealth flying-wing bomber: no fuselage or tail, sawtooth trailing edge, buried engines with dorsal intakes, smooth blended skin.', '21.0 m long, 52.4 m wingspan, 5.2 m high', 'jets', '[0.12, 0.12, 0.13] (charcoal)', 'Flying wing: its control surfaces are Elevon_* and the split drag rudders DragRudder_L/R. Also BayDoor_L, BayDoor_R. '),
 ('vehicle.military-air.awacs', 'e3-awacs', 'AWACS (E-3-style)', 'An E-3 Sentry style AWACS early-warning aircraft: four-engine swept-wing airliner body with a large rotating radar dome on two struts above the rear fuselage.', '46.6 m long, 44.4 m wingspan, 12.6 m high, radar dome 9.1 m diameter', 'jets', '[0.55, 0.57, 0.58] (light grey)', 'Also mesh node Rotodome (origin on its vertical axis, turns about Y). '),
]
TRIS = {'wheeled': ('50k to 110k', 8), 'tanks': ('80k to 160k', 8), 'rotor': ('60k to 140k', 8), 'jets': ('60k to 160k', 8)}
FR = {'wheeled': FRAME4, 'tanks': FRAME_T, 'rotor': FRAME_R, 'jets': FRAME_J}
ND = {'wheeled': WHEELED, 'tanks': TANK, 'rotor': ROTOR, 'jets': JET}
SW = {'wheeled': ', canvas', 'tanks': ', track steel', 'rotor': ', canopy', 'jets': ', canopy'}
order = []
for cls, slug, title, desc, size, fam, default, extra in J:
    tris, mats = TRIS[fam]
    big = fam == 'jets' and any(k in slug for k in ('b52', 'b2', 'e3'))
    nodes = GAME + ND[fam] + paint(default, AIR_PAINTS if fam in ('rotor', 'jets') else GROUND_PAINTS, extra) + NOMARK + PIVOTS + SCRATCH + TIME
    jd = f'{ROOT}/jobs/{slug}-v1'
    os.makedirs(jd, exist_ok=True)
    j = dict(id=f'{cls}/{slug}', version=1, name=desc[2:-1] + ' (the one on sheet.jpg)', title=title, slug=slug, refs=['sheet.jpg'],
             size=size, tris='100k to 200k' if big else tris, mats=mats, effort='medium', frame=FR[fam], nodes=nodes, family=fam)
    json.dump(j, open(f'{jd}/job.json', 'w'), indent=1)
    open(f'{jd}/sheet_prompt.txt', 'w').write(SHEET.format(desc=desc, size=size, extra=SW[fam]))
    order.append(slug)
# interleave families so each starts early
fams = {f: [s for (c, s, t, d, z, ff, df, e) in J if ff == f] for f in ('wheeled', 'tanks', 'rotor', 'jets')}
inter = []
while any(fams.values()):
    for f in fams:
        if fams[f]:
            inter.append(fams[f].pop(0))
os.makedirs('/tmp/mil-20261010', exist_ok=True)
open('/tmp/mil-20261010/order.txt', 'w').write('\n'.join(inter) + '\n')
print(len(J), 'jobs:', ' '.join(inter))
