import bpy, math, os from mathutils import Vector bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False) OUT='/Users/simon/Documents/Codex/2026-09-04/use-x20/outputs' def mat(name,color,metal=0,rough=.4): m=bpy.data.materials.new(name); m.diffuse_color=(*color,1); m.use_nodes=True p=m.node_tree.nodes.get('Principled BSDF'); p.inputs['Base Color'].default_value=(*color,1); p.inputs['Metallic'].default_value=metal; p.inputs['Roughness'].default_value=rough return m white=mat('Warm ivory plumage',(.94,.92,.83)); cream=mat('Cream feather tips',(.78,.81,.73)); orange=mat('Golden orange bill',(1,.42,.065)); pouch=mat('Soft amber throat pouch',(1,.62,.19)); black=mat('Graphite rubber',(.028,.043,.048)); teal=mat('Turquoise enamel',(.015,.42,.43),.45,.26); chrome=mat('Brushed aluminum',(.6,.73,.74),.8,.23); dark=mat('Deep teal leather',(.035,.13,.14)); eye=mat('Obsidian eyes',(.009,.014,.016),0,.16); yellow=mat('Butter yellow',(.98,.75,.25)); ground=mat('Sage studio',(.43,.67,.60)); pink=mat('Warm cheek',(.99,.69,.4)) def smooth(obj,material): obj.data.materials.append(material) if obj.type=='MESH': for p in obj.data.polygons:p.use_smooth=True return obj def ell(name,loc,scale,material): bpy.ops.mesh.primitive_uv_sphere_add(segments=40,ring_count=24,location=loc); o=bpy.context.object; o.name=name; o.scale=scale; smooth(o,material); return o def rod(name,a,b,r,material): a,b=Vector(a),Vector(b); d=b-a bpy.ops.mesh.primitive_cylinder_add(vertices=24,radius=r,depth=d.length,location=(a+b)/2); o=bpy.context.object; o.name=name; o.rotation_euler=d.to_track_quat('Z','Y').to_euler(); smooth(o,material) bevel=o.modifiers.new('Rounded edges','BEVEL'); bevel.width=r*.28; bevel.segments=3 o.modifiers.new('Weighted normals','WEIGHTED_NORMAL'); return o def path(name,coords,r,material): c=bpy.data.curves.new(name,'CURVE'); c.dimensions='3D'; c.bevel_depth=r; c.bevel_resolution=4 s=c.splines.new('BEZIER'); s.bezier_points.add(len(coords)-1) for p,co in zip(s.bezier_points,coords):p.co=co;p.handle_left_type='AUTO';p.handle_right_type='AUTO' o=bpy.data.objects.new(name,c);bpy.context.collection.objects.link(o);o.data.materials.append(material);return o def torus(name,loc,major,minor,material): bpy.ops.mesh.primitive_torus_add(major_segments=80,minor_segments=16,location=loc,major_radius=major,minor_radius=minor,rotation=(math.pi/2,0,0));o=bpy.context.object;o.name=name;smooth(o,material);return o def mesh(name,verts,faces,material,bevel=.06): me=bpy.data.meshes.new(name);me.from_pydata(verts,[],faces);me.update();o=bpy.data.objects.new(name,me);bpy.context.collection.objects.link(o);smooth(o,material) if bevel: mod=o.modifiers.new('Soft sculpted edges','BEVEL');mod.width=bevel;mod.segments=3;o.modifiers.new('Weighted normals','WEIGHTED_NORMAL') return o # Bicycle, facing right. Both wheel axles lie along Y. rear=(-1.35,0,1.02);front=(1.4,0,1.02);bb=(-.2,0,1.05);seat=(-.64,0,2.27);head=(.99,0,2.3) for label,c in [('Rear',rear),('Front',front)]: torus(label+' tire',c,.91,.095,black);torus(label+' silver rim',c,.82,.035,chrome) rod(label+' hub',(c[0],-.15,c[2]),(c[0],.15,c[2]),.10,chrome) for i in range(28): t=i*math.tau/28 rod(label+' spoke', (c[0],-.035 if i%2 else .035,c[2]),(c[0]+.81*math.cos(t),0,c[2]+.81*math.sin(t)),.009,chrome) # Painted mudguards, deliberately floating just above tires. pts=[(c[0]+1.04*math.cos(t),0,c[2]+1.04*math.sin(t)) for t in [math.radians(24+i*132/18) for i in range(19)]] path(label+' curved mudguard',pts,.055,yellow) for a,b in [(rear,seat),(seat,bb),(bb,rear),(seat,head),(head,bb)]:rod('Enamel frame tube',a,b,.065,teal) for y in [-.13,.13]:rod('Front fork',(1.01,y,2.33),(1.4,y,1.02),.043,teal) rod('Seat post',seat,(-.72,0,2.54),.04,chrome);ell('Leather saddle',(-.72,0,2.55),(.38,.22,.09),dark) rod('Steering stem',head,(.90,0,2.72),.045,chrome) path('Sweeping handlebar',[(.9,-.46,2.69),(1.02,-.29,2.82),(.9,0,2.76),(1.02,.29,2.82),(.9,.46,2.69)],.037,chrome) for y in [-1,1]:rod('Hand grips',(.90,y*.37,2.7),(.87,y*.57,2.65),.058,dark) ell('Bicycle bell',(.91,-.28,2.87),(.095,.095,.065),chrome) torus('Chainring',(-.2,-.15,1.05),.225,.026,chrome) path('Bicycle chain',[(-1.35,-.17,1.13),(-.22,-.17,1.29),(.035,-.17,1.07),(-.19,-.17,.82),(-1.35,-.17,.91),(-1.45,-.17,1.02),(-1.35,-.17,1.13)],.017,dark) for y,dx,dz in [(-.23,.23,-.20),(.23,-.23,.20)]: rod('Crank',(-.2,y,1.05),(-.2+dx,y,1.05+dz),.034,chrome) rod('Pedal',(-.2+dx,y-.12,1.05+dz),(-.2+dx,y+.12,1.05+dz),.055,dark) # Friendly, oversized pelican with a distinct long bill and hanging gular pouch. body=ell('Plump pelican body',(-.62,0,3.04),(.79,.5,.88),white);body.rotation_euler[1]=-.25 for y in [-.17,0,.17]: o=ell('Tail plume',(-1.27,y,2.92),(.56,.13,.17),cream if y else white);o.rotation_euler[1]=-.38 path('Curving pelican neck',[(-.42,0,3.24),(-.02,0,3.58),(.02,0,4.02),(.20,0,4.45)],.27,white) ell('Head',(.30,0,4.49),(.46,.34,.42),white) for y in [-1,1]: ell('Golden eye surround',(.44,y*.301,4.56),(.127,.042,.135),pouch) ell('Bright black eye',(.46,y*.337,4.58),(.069,.032,.08),eye) ell('Eye glint',(.48,y*.362,4.605),(.021,.013,.023),white) # Upper bill is a long tapered wedge; the throat pouch swells below it. mesh('Long upper bill',[(.55,-.24,4.43),(.55,.24,4.43),(1.89,.045,4.34),(1.98,0,4.29),(1.89,-.045,4.34),(.55,-.23,4.32),(.55,.23,4.32),(1.91,0,4.27)],[(0,1,2,3,4),(0,5,6,1),(5,7,6),(1,6,7,3,2),(0,4,3,7,5)],orange,.045) mesh('Pelican hanging throat pouch',[(.57,-.225,4.32),(.57,.225,4.32),(1.91,0,4.27),(.76,-.17,3.91),(.76,.17,3.91),(1.30,0,4.02)],[(0,1,2),(0,3,4,1),(0,2,5,3),(1,4,5,2),(3,5,4)],pouch,.11) path('Bill smile seam',[(.61,-.238,4.325),(1.17,-.15,4.30),(1.90,-.018,4.28)],.012,dark) for i in range(3): o=ell('Swept crown feather',(-.04-i*.09,0,4.81+i*.025),(.24,.10,.075),white);o.rotation_euler[1]=.35 # Near and far wings reach the handle grips. for y in [1,-1]: path('Wing reaching handlebars',[(-.78,y*.38,3.40),(-.32,y*.49,3.25),(.17,y*.51,2.96),(.87,y*.49,2.70)],.145,white) for i in range(3): path('Layered wing feather',[(-.92,y*(.42+i*.035),3.42-i*.12),(-.48,y*(.54+i*.027),3.15-i*.09),(.12+i*.09,y*.53,2.94-i*.025)],.066,cream if i==2 else white) # Bent legs and broad orange webbed feet sit on the two pedals. for y,foot in [(-.29,(.03,-.31,.91)),(.25,(-.43,.27,1.31))]: path('Bent orange leg',[(-.67,y,2.52),(-.04,y,1.91),(-.38,y,1.57),foot],.072,orange) x,fy,z=foot mesh('Webbed pedal foot',[(x-.13,fy-.09,z+.03),(x-.13,fy+.09,z+.03),(x+.29,fy+.16,z-.02),(x+.36,fy,z-.035),(x+.29,fy-.16,z-.02)],[(0,1,2,3,4)],orange,.045) # A little scarf adds motion and a complementary color accent. scarf=mat('Coral scarf',(.86,.16,.105)) ell('Scarf knot',(-.14,-.26,3.9),(.13,.11,.13),scarf) path('Scarf collar',[(-.19,-.23,3.88),(.10,-.22,3.87),(.24,0,3.9),(.10,.24,3.91),(-.2,.2,3.91)],.07,scarf) mesh('Scarf flutter',[(-.18,.09,3.92),(-.62,.11,4.03),(-1.16,.10,3.93),(-1.52,.10,4.08),(-1.39,.10,3.79),(-.99,.10,3.73),(-.53,.10,3.84),(-.18,.09,3.80)],[(0,1,2,3,4,5,6,7)],scarf,.045) # Studio floor and lighting. bpy.ops.mesh.primitive_plane_add(size=200,location=(0,0,0));smooth(bpy.context.object,ground) world=bpy.context.scene.world;world.use_nodes=True;world.node_tree.nodes['Background'].inputs[0].default_value=(.43,.63,.57,1);world.node_tree.nodes['Background'].inputs[1].default_value=.35 def area(name,loc,power,size): bpy.ops.object.light_add(type='AREA',location=loc);o=bpy.context.object;o.name=name;o.data.energy=power;o.data.shape='DISK';o.data.size=size;o.rotation_euler=(Vector((0,0,2.3))-o.location).to_track_quat('-Z','Y').to_euler() area('Large warm key',(-3,-5,8),1100,5);area('Soft front fill',(5,-2,5),600,4);area('Rim light',(0,5,7),1400,3) bpy.ops.object.camera_add(location=(7,-14,7));cam=bpy.context.object;cam.rotation_euler=(Vector((.05,0,2.45))-cam.location).to_track_quat('-Z','Y').to_euler();cam.data.type='ORTHO';cam.data.ortho_scale=6.7;bpy.context.scene.camera=cam s=bpy.context.scene;s.render.engine='CYCLES';s.cycles.samples=48;s.cycles.use_denoising=True;s.render.resolution_x=1440;s.render.resolution_y=1440;s.render.resolution_percentage=100 s.view_settings.view_transform='AgX';s.render.image_settings.file_format='PNG';s.render.filepath=OUT+'/pelican-bicycle.png' bpy.ops.wm.save_as_mainfile(filepath=OUT+'/pelican-bicycle.blend');bpy.ops.render.render(write_still=True)