from pathlib import Path from html import escape import json O=Path(__file__).parent p=['A home for movement, connection and quiet.SAMFORD VALLEY / Updated concept plan · 10 September 2026 · Version 003'] def pt(x,y):return (630+13*x,470-13*y) def label(x,y,lines,size=12): X,Y=pt(x,y) for i,t in enumerate(lines):p.append(f'{escape(t)}') def rect(cx,cy,w,d,fill,stroke='#526154',dash=''): X,Y=pt(cx-w/2,cy+d/2);p.append(f'') def line(points,color,width): pts=' '.join(f'{pt(x,y)[0]},{pt(x,y)[1]}' for x,y in points);p.append(f'') layout=json.loads((O/'daily-life-layout.json').read_text()) line(layout['walking_loop'],'#adc49a',14) line([(14,1),(13,4),(13,7),(6,7)],'#adc49a',14) line([(-1,24),(-7,21),(-14,18)],'#adc49a',14) label(9,27.4,['SHADED WALKING LOOP'],12) line([(36,-40),(28,-33),(22,-27),(8,-26),(5,-22),(5,-13),(1,-12),(-3,-12)],'#c9bca1',52) rect(-1,-12.5,12,6,'#c9bca1',stroke='#c9bca1') line([(-3,-10),(-2,-6),(-5.5,-4),(-6.5,-2.8)],'#d5cdbb',12) line([(-3,5.4),(-3,9),(-11,9)],'#b5a88c',16) rect(0,0,12,6,'#ddc8a9');label(1,.7,['SHARED HOME','Kitchen · dining'],10) rect(0,4.2,12,2.4,'#c8d0b8');label(0,4.3,['VERANDA'],11) rect(-7.75,-1.8,3.5,1.2,'#c7bfae');label(-7.8,1.5,['Short link'],10) rect(-11.8,-4.9,8,5,'#ddc8a9');label(-11.8,-4.5,['PARENTS','Bedroom + bath'],11) rect(-11,12,4.5,4.8,'#c9c1a5');label(-11,12.4,['QUIET','ROOM'],11) X,Y=pt(-11,12);p.append(f'') for i,(x,y) in enumerate([(-3,17),(7,15)]): rect(x,y,4.5,4.8,'#e6e8de',stroke='#98a394',dash='stroke-dasharray="5 5"');label(x,y+.6,['FUTURE',f'SPACE {i+1}'],11) label(2,21.4,['Faint outlines only / build when needed'],12) X,Y=pt(-23,2);p.append(f'');label(-23,2,['SAUNA'],10) rect(-27,4.6,1.3,1.3,'#b6c4c5');label(-27,7.5,['Outdoor shower'],11) for x in [-23.95,-26.25]: X,Y=pt(x,-8);p.append(f'') label(-25,-10.5,['Rainwater tanks'],11) rect(-3,-19,8,7,'#bcb9ac');label(-3,-18.6,['GARAGE','8 × 7 m'],12) rect(-4.7,-19.1,1.9,4.35,'#788c83');rect(-.47,-21.5,2.5,.76,'#ab9673') label(-3,-24,['One car · workbench · bike racks'],12) label(20,-25,['4 m gravel access road'],13) rect(24.2,-7.5,4.3,5,'#c3d6c1');label(24.2,-7.4,['GREENHOUSE'],9) for x in [23.8,27.5]: for y in [-1.7,1.5,4.7]:rect(x,y,2.3,1.3,'#b29b73') label(25.5,7.5,['FOOD GARDEN'],12) rect(13.2,-17.7,7.3,5.2,'#71848b');label(13.2,-17.2,['GROUND SOLAR'],10) label(34,-42,['Site approach'],12) rect(*layout['training'],'#b9c8ad');label(-12.2,-16.8,['COVERED','TRAINING','4.8 × 5.4 m'],10) line([(-8.65,-17),(-8.4,-15),(-6.4,-13.4)],'#d5cdbb',12) label(-15.8,-23.2,['Bar · rings · weights','Bench · movable mats'],11) rect(*layout['outdoor_table'],'#d9c19b');rect(10,3.5,3.2,1.03,'#ab8962') rect(10,4.48,2.95,.43,'#bda078');rect(10,2.52,2.95,.43,'#bda078') rect(6.5,4.2,1,1.5,'#c8d0b8');label(10,9,['OUTDOOR TABLE','10 places + tea counter'],11) rect(*layout['table_tennis'],'#ced8c4');rect(11,-8.5,1.525,2.74,'#608570') label(11,-5.9,['TABLE TENNIS'],10);label(11,-12.8,['Folding table / level deck'],10) line([(7.1,-7),(7,-4),(6.4,1.3),(7.1,3.5)],'#d5cdbb',12) rect(*layout['future_basketball'],'#eceee4',stroke='#81947c',dash='stroke-dasharray="7 7"') label(13,-35,['FUTURE','BASKETBALL','10 × 10 m reserve'],11) label(13,-43,['Unbuilt / separate from driveway'],11) rect(30,10.9,1.8,.45,'#a58a66');label(32,14,['QUIET BENCH'],11) rect(29.8,1.5,.78,2.05,'#a58a66');label(35,2.4,['HARVEST','BENCH'],11) label(4,-4.3,['Breakfast · pantry · freezer'],10) rect(-3.8,.1,2.2,.95,'#f4f1e9') p.extend(['N','10 metres','The Blender presentation fades one facade of each building so you can see inside. Walls remain in the model.','Concept layout only. The road approach is illustrative; no surveyed property boundary or approved access is implied.']) (O/'retreat-garage-plan.svg').write_text(''.join(p))