app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
master
John Lauer
Add native thermal-pour expansion experiment, finite-difference comparison and recording scripts
33c4ac5
1mo ago
"""Native action at 3x, explicitly labeled inspection holds and postproduction analysis."""
import json,subprocess,textwrap
from pathlib import Path
from PIL import Image,ImageDraw,ImageFont
P=Path(__file__).resolve().parent;E=P/'edit';V=next((P/'recording').glob('*.mp4'));voices=json.loads((E/'voices.json').read_text())
font='/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf'
cuts={'intro':(3,6),'VAC1':(7,20),'VBUS':(21,33),'VAC2':(34,45),'VBAT':(48,61),'ground':(2,6),'final':(78,85)}
clips=[];manifest=[];pos=0
for i,v in enumerate(voices):
key=v['key'];dur=v['duration']+1.2;out=E/f'clip-{i:02}.mp4';chart=key not in cuts
im=Image.new('RGBA',(1920,1080),'#101925');im.paste((0,0,0,0),(10,125,1450,990));d=ImageDraw.Draw(im)
d.text((30,24),'CODEX ASTRA / FUSION',font=ImageFont.truetype(font,23),fill='#50c9d6')
d.text((30,60),v['title'],font=ImageFont.truetype(font,34),fill='white')
y=220
for line in v['lines']:
for s in textwrap.wrap(line,27):d.text((1480,y),s,font=ImageFont.truetype(font,23),fill='#d7e7f0');y+=37
y+=25
if key in ['VAC1','VBUS','VAC2','VBAT']:
d.text((1480,650),'Native bridge calls',font=ImageFont.truetype(font,24),fill='#50c9d6')
for z,s in enumerate(['fusion_run_modeling_script','Electron.run POLYGON','CHANGE / RATSNEST','SHOW '+key]):d.text((1480,700+z*38),s,font=ImageFont.truetype(font,19),fill='#d7e7f0')
if key in ['model','mask','limits']:d.text((1480,680),'ESTIMATE',font=ImageFont.truetype(font,28),fill='#edb659');d.text((1480,725),'Not measured temperature',font=ImageFont.truetype(font,21),fill='#d7e7f0')
footer='POSTPRODUCTION ANALYSIS / stated assumptions' if chart else 'NATIVE FUSION / 3x action + inspection hold / waits removed'
d.text((30,1025),footer,font=ImageFont.truetype(font,22),fill='#aebfcf');im.save(E/(key+'-overlay.png'))
if chart:
ins=['-loop','1','-i',str(E/(key+'.png'))]
flt='[0:v]scale=1420:860,pad=1920:1080:20:125:color=0x101925[v]'
else:
a,b=cuts[key];ins=['-ss',str(a),'-t',str(b-a),'-i',str(P/'recording/ground-highlight.mp4' if key=='ground' else V)]
flt=f'[0:v]setpts=(PTS-STARTPTS)/3,crop=3020:1570:20:370,scale=1420:-2,pad=1420:860:0:60:color=0x101925,pad=1920:1080:20:125:color=0x101925,tpad=stop_mode=clone:stop_duration={dur}[v]'
flt+=';[v][1:v]overlay=0:0,fps=30,format=yuv420p[out];[2:a]adelay=400|400,apad[a]'
if key=='ground' or not out.exists():subprocess.run(['ffmpeg','-v','error',*ins,'-i',str(E/(key+'-overlay.png')),'-i',v['audio'],'-filter_complex',flt,'-map','[out]','-map','[a]','-t',str(dur),'-c:v','libx264','-preset','fast','-crf','19','-threads','4','-c:a','aac','-b:a','192k','-ar','48000','-y',str(out)],check=True)
clips.append(out);manifest.append({**v,'outputStart':pos,'outputDuration':dur,'sourceInterval':cuts.get(key),'sourceFile':str(P/'recording/ground-highlight.mp4' if key=='ground' else V) if not chart else str(E/(key+'.png')),'speed':3 if not chart else None,'hold':not chart});pos+=dur;print(key,round(pos,1),flush=True)
# Last frame held for five seconds; silent audio remains compatible for concatenation.
last=E/'hold.mp4';subprocess.run(['ffmpeg','-v','error','-sseof','-0.1','-i',str(clips[-1]),'-f','lavfi','-i','anullsrc=r=48000:cl=mono','-vf','tpad=stop_mode=clone:stop_duration=5','-t','5','-map','0:v','-map','1:a','-c:v','libx264','-preset','fast','-crf','19','-threads','4','-c:a','aac','-y',str(last)],check=True);clips.append(last)
(E/'concat.txt').write_text(''.join("file '"+str(x)+"'\n" for x in clips))
subprocess.run(['ffmpeg','-v','error','-f','concat','-safe','0','-i',str(E/'concat.txt'),'-c','copy','-y',str(E/'joined.mp4')],check=True)
# Loudness normalization is done separately, with measured two-pass values.
(E/'edit-manifest.json').write_text(json.dumps({'chapters':manifest,'duration':pos+5,'source':str(V),'cutMethod':'Actual encoded frames inspected every six seconds; initial black frames and validation waits removed. Native action accelerated 3x followed by explicit inspection holds. PGND highlighting uses a supplemental native-window take. Analysis charts are postproduction.'},indent=2))