```python
import bpy, math, random
from mathutils import Vector

# ------------------------------------------------------------
# Ramen Samurai: graphic cyberpunk comic panel
# ------------------------------------------------------------
random.seed(14)
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

# Materials
def mat(name, color, emission=0.0, rough=0.8):
    m = bpy.data.materials.new(name)
    m.diffuse_color = (*color, 1)
    m.use_nodes = True
    bs = m.node_tree.nodes.get("Principled BSDF")
    bs.inputs["Base Color"].default_value = (*color, 1)
    bs.inputs["Roughness"].default_value = rough
    bs.inputs["Metallic"].default_value = 0.0
    if emission:
        bs.inputs["Emission Color"].default_value = (*color, 1)
        bs.inputs["Emission Strength"].default_value = emission
    return m

INK = mat("thick ink black", (0.008,0.006,0.018))
INDIGO = mat("indigo concrete", (0.035,0.045,0.11))
BROWN = mat("brown black shadow", (0.10,0.045,0.025))
DIRTY = mat("dirty concrete", (0.28,0.25,0.21))
RED = mat("vermilion print", (0.9,0.035,0.025), 1.8)
CRIMSON = mat("crimson", (0.42,0.012,0.02), 0.8)
ORANGE = mat("sodium orange", (1.0,0.25,0.025), 2.5)
AMBER = mat("broth amber", (1.0,0.52,0.035), 2.2)
YELLOW = mat("acid yellow", (0.85,1.0,0.025), 2.4)
LIME = mat("chartreuse", (0.38,1.0,0.015), 2.0)
CYAN = mat("selective cyan", (0.02,0.8,0.9), 2.0)
TURQ = mat("turquoise", (0.02,0.65,0.48), 1.3)
VIOLET = mat("ultraviolet", (0.42,0.06,0.9), 2.2)
MAGENTA = mat("magenta accent", (0.9,0.03,0.55), 1.8)
CREAM = mat("dirty white", (0.9,0.77,0.52), 0.3)
SKIN = mat("face warm paper", (0.64,0.27,0.14), 0.1)
ROBE = mat("ink blue robe", (0.025,0.08,0.22))
ROBE2 = mat("mustard robe", (0.75,0.35,0.04))
STEEL = mat("printed steel", (0.22,0.31,0.35), 0.2)
BOWL = mat("ceramic vermilion", (0.65,0.025,0.02), 0.6)
BROTH = mat("golden broth", (1.0,0.43,0.01), 2.5)

def cube(name, loc, scale, material, rot=(0,0,0), bevel=0):
    bpy.ops.mesh.primitive_cube_add(size=1, location=loc, rotation=rot)
    o=bpy.context.object; o.name=name; o.dimensions=scale
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    o.data.materials.append(material)
    if bevel:
        mod=o.modifiers.new("graphic softened corners","BEVEL"); mod.width=bevel; mod.segments=1
    return o

def uv(name, loc, scale, material):
    bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=8, location=loc)
    o=bpy.context.object; o.name=name; o.scale=scale; o.data.materials.append(material)
    return o

def cyl(name, loc, radius, depth, material, rot=(0,0,0), verts=12):
    bpy.ops.mesh.primitive_cylinder_add(vertices=verts, radius=radius, depth=depth, location=loc, rotation=rot)
    o=bpy.context.object; o.name=name; o.data.materials.append(material); return o

def curve(name, pts, material, bevel=0.08, outline=True):
    # dark underprint offset gives ink contour
    if outline:
        curve(name+"_INK", pts, INK, bevel*1.9, False)
    cu=bpy.data.curves.new(name, 'CURVE'); cu.dimensions='3D'; cu.resolution_u=1
    spl=cu.splines.new('POLY'); spl.points.add(len(pts)-1)
    for p,co in zip(spl.points,pts): p.co=(*co,1)
    cu.bevel_depth=bevel; cu.bevel_resolution=2; cu.resolution_u=1
    ob=bpy.data.objects.new(name,cu); bpy.context.collection.objects.link(ob); ob.data.materials.append(material)
    return ob

def text(name, body, loc, size, material, extrude=0.012, rot=(math.pi/2,0,0), align='CENTER'):
    cu=bpy.data.curves.new(name,'FONT'); cu.body=body; cu.align_x=align
    cu.size=size; cu.extrude=extrude; cu.space_character=1.0
    ob=bpy.data.objects.new(name,cu); bpy.context.collection.objects.link(ob)
    ob.location=loc; ob.rotation_euler=rot; ob.data.materials.append(material)
    return ob

# Background architecture, layered blocks
cube("deep alley", (0,3,6), (22,1,13), INDIGO)
for x,z,w,h,c in [(-7,7,3,7,BROWN),(-4,8,2.4,8,DIRTY),(5,8,3,8,BROWN),(8,6,3,10,INDIGO),(0,11,18,2,INK)]:
    cube("building layer",(x,2.1,z),(w,.8,h),c)
# street stripes and awnings
cube("street",(0,2,0.1),(22,8,.3),BROWN)
for x in range(-10,11,2):
    cube("pavement stripe",(x,1,0.3),(1.0,5,.06),DIRTY,(0,0,random.uniform(-.06,.06)))
for x in [-8,-5,4,7]:
    cube("patched awning",(x,0.9,9),(3.3,1.0,.28),RED,(0.06,0,random.uniform(-.15,.15)))
    for i in range(5):
        cube("awning stripe",(x-1.3+i*.65,0.35,8.85),(.33,.08,.5),CREAM)

# signs, signage poles
def sign(x,z,w,h,label,color,sub=None):
    cube("lit sign", (x,0.6,z),(w,.32,h),INK, bevel=.04)
    cube("color panel",(x,0.39,z),(w-.15,.06,h-.15),color)
    text("sign lettering",label,(x,0.30,z+.02),min(h*.45,w/len(label)*1.5),INK)
    if sub: text("small print",sub,(x,0.28,z-h*.30),h*.16,CREAM)
sign(-7,9.2,3.4,1.8,"RAMEN",ORANGE,"夜 NOODLE")
sign(-3.8,11.1,2.8,1.25,"拉面",LIME,"DRAGON")
sign(5.5,10.3,3.5,1.45,"라면",CRIMSON,"SEOUL 24")
sign(8,7.2,2.3,1.2,"سوق",YELLOW,"NIGHT")
sign(-8.3,5.7,2.8,1.0,"TAPAS",RED,"BAR")
sign(7.2,4.8,2.8,1.0,"चाय",TURQ,"CHAAT")
sign(3.3,12.4,2.6,.8,"EAT//REPEAT",VIOLET,"OPEN")
# cable webs
for i in range(9):
    x=-10+i*2.5
    curve("hanging cable",[(x,0.0,12.5),(x+.8,0.1,10.5),(x+1.8,.2,9.8)],INK,.035,False)

# lanterns, vending machine, bike silhouettes
for x,z,c in [(-9,8.1,RED),(-5.8,8.0,ORANGE),(6.8,8.5,YELLOW),(9.2,6.2,CRIMSON)]:
    cyl("lantern", (x,.1,z), .35,.7,c, rot=(math.pi/2,0,0), verts=12)
    curve("lantern cord",[(x,.2,z+.6),(x,.2,z+1.5)],INK,.025,False)
cube("vending machine",(9,.25,3.1),(1.2,.8,3.5),CYAN,.0, bevel=.06)
for z in [2.5,3.0,3.5]:
    cube("vending graphic",(9,.0,z),(.8,.06,.17),LIME)
# bike
curve("delivery bike",[(-8,.0,1.3),(-7.5,.0,.5),(-6.7,.0,.5),(-6.2,.0,1.3),(-7.5,.0,.5),(-7.0,.0,1.5),(-6.2,.0,1.3)],INK,.10,False)
cyl("bike wheel",(-7.5,.0,.55),.55,.08,CRIMSON,(math.pi/2,0,0))
cyl("bike wheel",(-6.3,.0,.55),.55,.08,CRIMSON,(math.pi/2,0,0))

# halftone dot clusters in background
for i in range(70):
    x=random.uniform(-10,10); z=random.uniform(1,11)
    if random.random()<.65:
        cyl("halftone dot",(x,-.02,z),.035,.025,random.choice([CRIMSON,VIOLET,LIME,INK]),(math.pi/2,0,0),8)

# ramen cart behind hero
cube("ramen cart",( -2.8,-.1,3.0),(3.8,1.45,1.0),ROBE2,bevel=.08)
cube("cart counter",(-2.8,-.9,3.65),(4.5,1.4,.28),CREAM)
for x in [-4.3,-1.3]:
    cyl("cart wheel",(x,-.1,1.8),.48,.18,INK,(math.pi/2,0,0))
cube("cart canopy",(-2.8,0.0,5.5),(4.7,1.6,.3),RED)
for x in [-4.6,-3.7,-2.8,-1.9,-1.0]:
    curve("canopy fringe",[(x,0,5.45),(x+.15,0,5.0)],CREAM,.08)
text("cart label","熱  RAMEN",( -2.8,-.86,3.05),.46,INK)

# Character, dark silhouette armor and angular pose
# legs
cube("rear leg",(0.75,-1.05,2.0),(.65,.75,2.6),ROBE,(0,.18,-.18),.06)
cube("front leg",(-.45,-1.2,1.8),(.72,.8,2.8),ROBE,(0,-.18,.28),.06)
cube("boot rear",(1.0,-1.5,.75),(1.25,1.0,.45),INK,(0,0,-.18),.05)
cube("boot front",(-.75,-1.55,.65),(1.25,1.0,.45),INK,(0,0,.2),.05)
# torso angled and outline shoulder
cube("torso",(0,-1.1,4.8),(1.65,.9,2.7),ROBE,(0,.12,-.18),.10)
cube("robe slash",(0.1,-1.62,4.2),(1.35,.08,1.25),ROBE2,(0,.1,-.2))
cube("chest armor",(0,-1.7,5.35),(1.45,.18,.95),STEEL,(0,.08,-.18),.04)
cube("armor red plate",(-.48,-1.82,5.25),(.35,.1,.75),RED,(0,.1,-.18))
# shoulder plates
cube("shoulder",( -.92,-1.3,5.55),(.7,.8,.55),CRIMSON,(0,.2,-.25),.08)
cube("shoulder gold",( .9,-1.3,5.3),(.75,.8,.5),ROBE2,(0,.1,.25),.08)
# neck/head
cyl("neck",(0,-1.2,6.55),.32,.35,SKIN)
uv("face",(0,-1.35,7.15),(.7,.48,.82),SKIN)
# hair/topknot
uv("hair",(0,-1.2,7.82),(.78,.52,.48),INK)
cyl("topknot",(0,-1.15,8.45),.24,.75,INK)
# face mask band and eyes
cube("face shadow",(0,-1.83,6.98),(1.12,.08,.25),INK,(0,0,-.05))
for x in [-.25,.25]:
    cube("controlled bright eye",(x,-1.9,7.18),(.16,.04,.07),YELLOW,(0,0,.12 if x<0 else -.12))
# facial scar / print offset
curve("red registration face",[(-.48,-1.93,7.45),(-.15,-1.94,7.48)],RED,.035,False)
curve("cyan registration face",[(.18,-1.94,7.5),(.48,-1.93,7.48)],CYAN,.035,False)

# arms: raised controlling chopsticks and close redirecting hand
curve("raised arm",[(-.62,-1.2,5.65),(-1.15,-1.6,6.4),(-1.5,-1.7,7.1)],ROBE2,.27)
uv("raised glove",(-1.53,-1.75,7.15),(.28,.25,.3),INK)
curve("low arm",[(.72,-1.2,5.35),(1.25,-1.75,5.0),(1.18,-1.85,4.35)],ROBE2,.25)
uv("low glove",(1.15,-1.9,4.28),(.28,.22,.28),INK)

# sword secondary, sheathed
cyl("sheathed sword",(1.35,-.8,3.55),.11,3.2,INK,(0,.15,math.pi/2),10)
cube("sword guard",(0.35,-.9,3.65),(.25,.18,.6),AMBER,(0,.15,.2))

# chopsticks paired batons
curve("chopstick high",[(-1.55,-2.0,7.15),(-.25,-2.1,8.4),(2.1,-1.7,8.7)],CREAM,.055)
curve("chopstick high dark",[(-1.5,-2.03,7.08),(.0,-2.12,8.25),(2.2,-1.7,8.55)],RED,.035,False)
curve("chopstick low",[(1.15,-2.0,4.3),(.0,-2.05,4.8),(-1.6,-1.8,5.2)],CREAM,.055)

# Bowl platform
cyl("spinning ramen bowl",(-2.05,-2.0,4.45),.9,.42,BOWL,(0,0,0),32)
cyl("broth surface",(-2.05,-2.22,4.68),.70,.05,BROTH,(0,0,0),32)
for a in range(0,360,45):
    ang=math.radians(a)
    curve("bowl radial graphic",[(-2.05,-2.27,4.69),(-2.05+math.cos(ang)*.58,-2.28,4.70+math.sin(ang)*.2)],INK,.025,False)

# Noodle choreography: multiple outlined paths
noodles=[
    ([(-2.0,-2.35,4.8),(-1.1,-2.4,6.2),(0.8,-2.3,6.8),(2.5,-2.2,6.0),(3.4,-2.1,4.6),(4.8,-2.0,4.2)],YELLOW,.13),
    ([(-1.9,-2.4,4.8),(-.8,-2.5,5.0),(-.2,-2.6,3.8),(1.1,-2.6,3.3),(2.4,-2.5,4.0),(3.0,-2.4,5.6)],AMBER,.11),
    ([(-1.5,-2.45,4.9),(-2.5,-2.4,6.0),(-4.2,-2.2,6.1),(-4.8,-2.0,4.8),(-4.0,-1.8,3.9),(-2.7,-1.9,4.5)],ORANGE,.12),
    ([(-.3,-2.6,5.8),(1.1,-2.7,7.8),(3.3,-2.5,8.0),(4.3,-2.4,7.1),(3.8,-2.3,6.1)],LIME,.09),
    ([(-.8,-2.5,5.3),(-2.4,-2.6,5.4),(-3.2,-2.55,7.0),(-2.2,-2.5,8.2),(-.5,-2.4,8.4)],CREAM,.075),
    ([(.2,-3.3,4.1),(2.0,-3.6,2.8),(5.0,-3.8,2.5),(8.8,-4.0,3.6)],YELLOW,.24),
]
for j,(pts,ma,bv) in enumerate(noodles):
    curve("noodle attack %02d"%j,pts,ma,bv)
# foreground whip with magenta/cyan registration
curve("foreground noodle red offset",[(-5,-4.4,1.7),(-2,-4.5,2.4),(1,-4.6,2.0),(5,-4.7,1.1),(10,-4.8,1.6)],RED,.18,False)
curve("foreground noodle cyan offset",[(-5.02,-4.42,1.78),(-2.02,-4.52,2.48),(1.02,-4.62,2.08),(5.02,-4.72,1.18),(10.02,-4.82,1.68)],CYAN,.13,False)

# steam calligraphy and broth arcs
for pts in [
    [(-2,-2.5,5.0),(-2.8,-2.4,6.2),(-2.0,-2.3,7.0),(-2.7,-2.2,7.8)],
    [(-1.6,-2.3,5.0),(-.9,-2.3,6.0),(-1.5,-2.2,6.8),(-.7,-2.1,7.5)],
    [(-2.4,-2.3,5.1),(-3.0,-2.2,5.8),(-3.5,-2.1,5.9)]
]:
    curve("steam glyph",pts,CREAM,.10)
curve("broth ribbon",[(-2,-2.35,4.85),(-1.5,-2.4,5.5),(-.4,-2.4,6.0),(.6,-2.3,5.7)],AMBER,.16)
for i in range(18):
    x=random.uniform(-3,3); z=random.uniform(4.7,7)
    uv("broth droplet",(x,-2.5,z),(random.uniform(.035,.09),.04,random.uniform(.035,.12)),AMBER)

# Impact bursts, motion marks, sound effects
def burst(x,z,material,scale=1):
    pts=[]
    for i in range(16):
        a=2*math.pi*i/16; r=1.0 if i%2==0 else .42
        pts.append((x+math.cos(a)*r*scale,-2.0,z+math.sin(a)*r*scale))
    pts.append(pts[0]); curve("angular impact burst",pts,material,.045)
burst(3.15,6.0,LIME,.65); burst(-4.1,5.9,RED,.55); burst(5.0,2.6,ORANGE,.7)
for x,z in [(-6,3.5),(-5.4,4.0),(4.8,7.7),(6.0,6.8)]:
    curve("speed line",[(x,-1.5,z),(x+random.uniform(.7,1.5),-1.6,z+random.uniform(-.2,.2))],CREAM,.035,False)
text("sound effect","WHACK!",(4.2,-2.3,8.6),.55,ORANGE)
text("sound effect","ズバッ",(5.9,-2.2,5.1),.48,LIME)
text("sound effect","SLURP!",(-5.5,-2.0,7.0),.38,CREAM)

# graphic frame border, panel-breaking strands in front
for x in [-10.7,10.7]:
    cube("comic border",(x,-3,6),(.22,.25,13),INK)
cube("comic top",(0,-3,12.4),(22,.25,.22),INK)
cube("comic bottom",(0,-3,-.3),(22,.25,.22),INK)
curve("panel breaking noodle",[(-10.5,-3.2,10.8),(-8,-3.3,9.7),(-6,-3.3,10.1)],LIME,.12)
curve("panel breaking noodle 2",[(10.5,-3.2,2.0),(8,-3.3,2.8),(7,-3.3,1.8)],ORANGE,.15)

# lighting: hard graphic regions, mostly emissive materials
def area(name, loc, color, energy, size):
    bpy.ops.object.light_add(type='AREA', location=loc)
    l=bpy.context.object; l.name=name; l.data.energy=energy; l.data.color=color; l.data.shape='RECTANGLE'; l.data.size=size
    # point at hero
    q=(Vector((0,0,5.5))-l.location).to_track_quat('-Z','Y'); l.rotation_euler=q.to_euler()
area("sodium key",(-6,-6,8),(1,.22,.04),900,5)
area("acid rim",(6,-3,9),(.3,1,.05),800,4)
area("crimson fill",(3,2,5),(1,.02,.01),700,3)
area("small cyan edge",(-8,-2,4),(0,.7,1),450,2)

# Camera and render settings
bpy.ops.object.camera_add(location=(0,-25,7.0))
cam=bpy.context.object; cam.name="Comic Panel Camera"
target=Vector((0,0,6.0)); cam.rotation_euler=(target-cam.location).to_track_quat('-Z','Y').to_euler()
cam.data.lens=48
bpy.context.scene.camera=cam
scene=bpy.context.scene
scene.render.engine='BLENDER_EEVEE_NEXT'
scene.render.resolution_x=1536; scene.render.resolution_y=1536; scene.render.resolution_percentage=60
scene.render.image_settings.file_format='PNG'
scene.render.film_transparent=False
scene.world.color=(0.004,0.003,0.012)
scene.view_settings.look='AgX - Medium High Contrast'
scene.render.filepath='/tmp/ramen_samurai.png'
# Eevee preview but materials and lights Cycles-compatible
scene.render.image_settings.color_mode='RGBA'
bpy.ops.wm.save_as_mainfile(filepath='/tmp/ramen_samurai.blend')
```