lingmodeler
↓ 0 downloadsLingModeler: box modeling with quads and tris, rigging + weight painting, 2D vector illustration and animation, procedural textures and game assets; .lmesh / .ling native formats, OBJ, glTF and SVG import / export
Keywords 3d, modeling, vector, svg, gltf, obj, rigging, animation, textures, ling
lingfu install lingmodelerCode / Files (67)
ling/icons.ling
# ━━━ icons.ling — small vector icons (Feather-style line work), drawn centred at (cx, cy) ━━━
fn icon_draw(name, cx, cy, size, c) {
bind h = size * 0.5
# polygon primitives ignore the clip rectangle: cull icons outside it
if st_get("clip_on", 0.0) > 0.5 {
if cy - h < st_get("clip_y0", 0.0) || cy + h > st_get("clip_y1", 99999.0) || cx - h < st_get("clip_x0", 0.0) || cx + h > st_get("clip_x1", 99999.0) { return 0.0 }
}
bind x0 = cx - h
bind x1 = cx + h
bind y0 = cy - h
bind y1 = cy + h
if name == "play" { g_tri(cx - h * 0.55, y0, cx - h * 0.55, y1, cx + h * 0.95, cy, c) return 0.0 }
if name == "pause" { g_rect(cx - h * 0.7, cy - h * 0.85, h * 0.5, h * 1.7, c) g_rect(cx + h * 0.2, cy - h * 0.85, h * 0.5, h * 1.7, c) return 0.0 }
if name == "stop" { g_rect(cx - h * 0.8, cy - h * 0.8, h * 1.6, h * 1.6, c) return 0.0 }
if name == "rec" { g_disc(cx, cy, h * 0.85, c) return 0.0 }
if name == "skip_l" { g_tri(x1, y0, x1, y1, cx - h * 0.3, cy, c) g_rect(x0, y0, 2.0, size, c) return 0.0 }
if name == "skip_r" { g_tri(x0, y0, x0, y1, cx + h * 0.3, cy, c) g_rect(x1 - 2.0, y0, 2.0, size, c) return 0.0 }
if name == "loop" {
g_line(x0 + 2.0, y0 + 2.0, x1 - 1.0, y0 + 2.0, c)
g_line(x1 - 1.0, y0 + 2.0, x1 - 1.0, y1 - 3.0, c)
g_line(x0 + 1.0, y1 - 2.0, x1 - 2.0, y1 - 2.0, c)
g_line(x0 + 1.0, y0 + 3.0, x0 + 1.0, y1 - 2.0, c)
g_tri(x1 - 4.0, y0 - 1.0, x1 - 4.0, y0 + 5.0, x1 + 1.0, y0 + 2.0, c)
g_tri(x0 + 4.0, y1 - 5.0, x0 + 4.0, y1 + 1.0, x0 - 1.0, y1 - 2.0, c)
return 0.0
}
if name == "chev_r" { g_tri(cx - h * 0.4, cy - h * 0.65, cx - h * 0.4, cy + h * 0.65, cx + h * 0.55, cy, c) return 0.0 }
if name == "chev_l" { g_tri(cx + h * 0.4, cy - h * 0.65, cx + h * 0.4, cy + h * 0.65, cx - h * 0.55, cy, c) return 0.0 }
if name == "chev_d" { g_tri(cx - h * 0.65, cy - h * 0.4, cx + h * 0.65, cy - h * 0.4, cx, cy + h * 0.55, c) return 0.0 }
if name == "chev_u" { g_tri(cx - h * 0.65, cy + h * 0.4, cx + h * 0.65, cy + h * 0.4, cx, cy - h * 0.55, c) return 0.0 }
if name == "plus" { g_rect(x0, cy - 1.0, size, 2.0, c) g_rect(cx - 1.0, y0, 2.0, size, c) return 0.0 }
if name == "minus" { g_rect(x0, cy - 1.0, size, 2.0, c) return 0.0 }
if name == "x" { g_line(x0 + 1.0, y0 + 1.0, x1 - 1.0, y1 - 1.0, c) g_line(x1 - 1.0, y0 + 1.0, x0 + 1.0, y1 - 1.0, c) g_line(x0 + 2.0, y0 + 1.0, x1, y1 - 1.0, c) g_line(x1, y0 + 1.0, x0 + 2.0, y1 - 1.0, c) return 0.0 }
if name == "check" { g_line(x0 + 1.0, cy, cx - 1.0, y1 - 2.0, c) g_line(cx - 1.0, y1 - 2.0, x1 - 1.0, y0 + 2.0, c) g_line(x0 + 2.0, cy, cx, y1 - 2.0, c) g_line(cx, y1 - 2.0, x1, y0 + 2.0, c) return 0.0 }
if name == "trash" {
g_rect(x0 + 1.0, y0 + 2.0, size - 2.0, 2.0, c)
g_rect(cx - 2.0, y0, 4.0, 2.0, c)
g_frame(x0 + 2.0, y0 + 4.0, size - 4.0, size - 4.0, c)
g_line(cx - 2.0, y0 + 6.0, cx - 2.0, y1 - 2.0, c)
g_line(cx + 2.0, y0 + 6.0, cx + 2.0, y1 - 2.0, c)
return 0.0
}
if name == "folder" {
g_frame(x0, y0 + 2.0, size, size - 3.0, c)
g_rect(x0, y0 + 2.0, h * 0.8, 2.0, c)
g_line(x0, y0 + 5.0, x1, y0 + 5.0, c)
return 0.0
}
if name == "file" {
g_frame(x0 + 2.0, y0, size - 4.0, size, c)
g_line(x1 - 5.0, y0, x1 - 2.0, y0 + 3.0, c)
g_line(x0 + 4.0, cy, x1 - 4.0, cy, c)
g_line(x0 + 4.0, cy + 3.0, x1 - 4.0, cy + 3.0, c)
return 0.0
}
if name == "save" {
g_frame(x0, y0, size, size, c)
g_rect(x0 + 3.0, y0 + 1.0, size - 6.0, h * 0.6, c)
g_frame(x0 + 2.0, cy + 1.0, size - 4.0, h - 2.0, c)
return 0.0
}
if name == "import" { g_line(cx, y0, cx, y1 - 3.0, c) g_tri(cx - 4.0, y1 - 6.0, cx + 4.0, y1 - 6.0, cx, y1 - 1.0, c) g_rect(x0, y1 - 1.0, size, 2.0, c) return 0.0 }
if name == "export" { g_line(cx, y0 + 3.0, cx, y1 - 2.0, c) g_tri(cx - 4.0, y0 + 5.0, cx + 4.0, y0 + 5.0, cx, y0, c) g_rect(x0, y1 - 1.0, size, 2.0, c) return 0.0 }
if name == "undo" {
g_line(x0 + 2.0, cy - 1.0, x1 - 2.0, cy - 1.0, c)
g_line(x1 - 2.0, cy - 1.0, x1 - 2.0, cy + 3.0, c)
g_line(x1 - 2.0, cy + 3.0, x0 + 4.0, cy + 3.0, c)
g_tri(x0 + 4.0, cy - 4.0, x0 + 4.0, cy + 2.0, x0 - 1.0, cy - 1.0, c)
return 0.0
}
if name == "redo" {
g_line(x0 + 2.0, cy - 1.0, x1 - 2.0, cy - 1.0, c)
g_line(x0 + 2.0, cy - 1.0, x0 + 2.0, cy + 3.0, c)
g_line(x0 + 2.0, cy + 3.0, x1 - 4.0, cy + 3.0, c)
g_tri(x1 - 4.0, cy - 4.0, x1 - 4.0, cy + 2.0, x1 + 1.0, cy - 1.0, c)
return 0.0
}
if name == "eye" {
g_line(x0, cy, cx - h * 0.5, cy - h * 0.7, c)
g_line(cx - h * 0.5, cy - h * 0.7, cx + h * 0.5, cy - h * 0.7, c)
g_line(cx + h * 0.5, cy - h * 0.7, x1, cy, c)
g_line(x0, cy, cx - h * 0.5, cy + h * 0.7, c)
g_line(cx - h * 0.5, cy + h * 0.7, cx + h * 0.5, cy + h * 0.7, c)
g_line(cx + h * 0.5, cy + h * 0.7, x1, cy, c)
g_disc(cx, cy, h * 0.3, c)
return 0.0
}
if name == "eye_off" { g_line(x0, cy, x1, cy, c) g_line(x0 + 1.0, y1 - 1.0, x1 - 1.0, y0 + 1.0, c) return 0.0 }
if name == "layers" {
g_tri(cx, y0, x1, cy - h * 0.4, cx, cy + h * 0.2, c)
g_tri(cx, y0, cx, cy + h * 0.2, x0, cy - h * 0.4, c)
g_line(x0, cy + h * 0.2, cx, y1, c)
g_line(cx, y1, x1, cy + h * 0.2, c)
return 0.0
}
if name == "copy" { g_frame(x0, y0 + 3.0, size - 3.0, size - 3.0, c) g_frame(x0 + 3.0, y0, size - 3.0, size - 3.0, c) return 0.0 }
if name == "edit" { g_line(x0 + 1.0, y1 - 1.0, x1 - 2.0, y0 + 2.0, c) g_line(x0 + 2.0, y1, x1 - 1.0, y0 + 3.0, c) g_rect(x0, y1 - 3.0, 4.0, 3.0, c) return 0.0 }
if name == "gear" {
g_ring(cx, cy, h * 0.75, c)
g_disc(cx, cy, h * 0.3, c)
bind k = 0.0
while k < 8.0 {
bind a = k * 0.785398
g_line(cx + cos(a) * h * 0.6, cy + sin(a) * h * 0.6, cx + cos(a) * h, cy + sin(a) * h, c)
bind k = k + 1.0
}
return 0.0
}
if name == "info" { g_ring(cx, cy, h, c) g_rect(cx - 1.0, cy - 1.0, 2.0, h, c) g_rect(cx - 1.0, cy - h * 0.6, 2.0, 2.0, c) return 0.0 }
if name == "help" { g_ring(cx, cy, h, c) g_text_c(cx, cy - h * 0.75, size * 0.9, c, "?") return 0.0 }
if name == "refresh" {
bind k = 0.0
while k < 10.0 {
bind a0 = k * 0.5
bind a1 = a0 + 0.5
g_line(cx + cos(a0) * h * 0.8, cy + sin(a0) * h * 0.8, cx + cos(a1) * h * 0.8, cy + sin(a1) * h * 0.8, c)
bind k = k + 1.0
}
g_tri(x1 - 1.0, cy - 4.0, x1 + 2.0, cy + 1.0, x1 - 5.0, cy, c)
return 0.0
}
if name == "bars" { g_rect(x0, y0 + 1.0, size, 2.0, c) g_rect(x0, cy - 1.0, size, 2.0, c) g_rect(x0, y1 - 3.0, size, 2.0, c) return 0.0 }
if name == "arrow_up" { g_line(cx, y1, cx, y0 + 2.0, c) g_tri(cx - 4.0, y0 + 5.0, cx + 4.0, y0 + 5.0, cx, y0, c) return 0.0 }
if name == "arrow_down" { g_line(cx, y0, cx, y1 - 2.0, c) g_tri(cx - 4.0, y1 - 5.0, cx + 4.0, y1 - 5.0, cx, y1, c) return 0.0 }
# ── modeling ──
if name == "select" {
g_tri(x0 + 1.0, y0, x0 + 1.0, y1 - 1.0, cx + h * 0.6, cy + h * 0.3, c)
g_line(cx, cy + h * 0.2, x1 - 1.0, y1, c)
g_line(cx + 1.0, cy + h * 0.2, x1, y1 - 1.0, c)
return 0.0
}
if name == "move" {
g_line(x0, cy, x1, cy, c) g_line(cx, y0, cx, y1, c)
g_tri(x0, cy, x0 + 4.0, cy - 3.0, x0 + 4.0, cy + 3.0, c)
g_tri(x1, cy, x1 - 4.0, cy - 3.0, x1 - 4.0, cy + 3.0, c)
g_tri(cx, y0, cx - 3.0, y0 + 4.0, cx + 3.0, y0 + 4.0, c)
g_tri(cx, y1, cx - 3.0, y1 - 4.0, cx + 3.0, y1 - 4.0, c)
return 0.0
}
if name == "rotate" {
bind k = 0.0
while k < 9.0 {
bind a0 = 0.6 + k * 0.5
bind a1 = a0 + 0.5
g_line(cx + cos(a0) * h * 0.8, cy + sin(a0) * h * 0.8, cx + cos(a1) * h * 0.8, cy + sin(a1) * h * 0.8, c)
bind k = k + 1.0
}
g_tri(cx + h * 0.9, cy - h * 0.1, cx + h * 0.2, cy, cx + h * 0.85, cy + h * 0.7, c)
return 0.0
}
if name == "scale" { g_frame(x0, cy, h, h, c) g_line(x0 + h * 0.5, cy + h * 0.5, x1, y0, c) g_tri(x1, y0, x1 - 5.0, y0, x1, y0 + 5.0, c) return 0.0 }
if name == "cube" {
bind q = h * 0.5
g_line(x0, cy - q, cx, y0, c) g_line(cx, y0, x1, cy - q, c) g_line(x1, cy - q, cx, cy, c) g_line(cx, cy, x0, cy - q, c)
g_line(x0, cy - q, x0, cy + q, c) g_line(x0, cy + q, cx, y1, c) g_line(cx, y1, x1, cy + q, c) g_line(x1, cy + q, x1, cy - q, c)
g_line(cx, cy, cx, y1, c)
return 0.0
}
if name == "vertex" { g_frame(x0, y0, size, size, c) g_rect(x0 - 1.0, y0 - 1.0, 4.0, 4.0, c) g_rect(x1 - 3.0, y0 - 1.0, 4.0, 4.0, c) g_rect(x0 - 1.0, y1 - 3.0, 4.0, 4.0, c) g_rect(x1 - 3.0, y1 - 3.0, 4.0, 4.0, c) return 0.0 }
if name == "edge" { g_frame(x0, y0, size, size, c) g_rect(x0, y0 - 1.0, size, 3.0, c) return 0.0 }
if name == "face" { g_frame(x0, y0, size, size, c) ds_hatch(x0 + 2.0, y0 + 2.0, size - 4.0, size - 4.0, c, 45.0, 3.0, 0.9) return 0.0 }
if name == "extrude" { g_frame(x0, cy, size, h, c) g_line(x0, cy, x0, y0, c) g_line(x1, cy, x1, y0, c) g_dash(x0, y0, x1, y0, c, 3.0) return 0.0 }
if name == "inset" { g_frame(x0, y0, size, size, c) g_frame(x0 + 3.0, y0 + 3.0, size - 6.0, size - 6.0, c) return 0.0 }
if name == "bevel" { g_line(x0, y1, x0, cy, c) g_line(x0, cy, cx, y0, c) g_line(cx, y0, x1, y0, c) g_line(x0, y1, x1, y1, c) g_line(x1, y0, x1, y1, c) return 0.0 }
if name == "loopcut" { g_frame(x0, y0, size, size, c) g_dash(cx, y0 - 1.0, cx, y1 + 1.0, c, 2.0) return 0.0 }
if name == "knife" { g_line(x0, y1, x1, y0, c) g_line(x0 + 1.0, y1, x1 + 1.0, y0, c) g_rect(x0, y1 - 3.0, 4.0, 3.0, c) return 0.0 }
if name == "merge" { g_line(x0, y0, cx, cy, c) g_line(x1, y0, cx, cy, c) g_line(x0, y1, cx, cy, c) g_line(x1, y1, cx, cy, c) g_disc(cx, cy, 2.5, c) return 0.0 }
if name == "subdiv" { g_frame(x0, y0, size, size, c) g_line(cx, y0, cx, y1, c) g_line(x0, cy, x1, cy, c) return 0.0 }
if name == "mirror" { g_tri(x0, y0, x0, y1, cx - 2.0, cy, c) g_tri(x1, y0, x1, y1, cx + 2.0, cy, c) g_dash(cx, y0 - 1.0, cx, y1 + 1.0, c, 2.0) return 0.0 }
if name == "grid" { g_frame(x0, y0, size, size, c) g_line(cx, y0, cx, y1, c) g_line(x0, cy, x1, cy, c) g_line(x0 + h * 0.5, y0, x0 + h * 0.5, y1, c) g_line(x1 - h * 0.5, y0, x1 - h * 0.5, y1, c) g_line(x0, y0 + h * 0.5, x1, y0 + h * 0.5, c) g_line(x0, y1 - h * 0.5, x1, y1 - h * 0.5, c) return 0.0 }
if name == "camera" { g_frame(x0, y0 + 2.0, size - 4.0, size - 4.0, c) g_tri(x1 - 4.0, cy, x1, cy - 4.0, x1, cy + 4.0, c) return 0.0 }
if name == "sphere" { g_ring(cx, cy, h, c) g_line(x0, cy, x1, cy, c) g_line(cx, y0, cx, y1, c) return 0.0 }
if name == "cylinder" { g_frame(x0, y0 + 2.0, size, size - 4.0, c) g_line(x0, y0 + 2.0, x1, y0 + 2.0, c) g_line(x0, y0 + 5.0, x1, y0 + 5.0, c) return 0.0 }
if name == "bone" { g_disc(cx - h * 0.6, cy + h * 0.6, 2.5, c) g_disc(cx + h * 0.6, cy - h * 0.6, 2.5, c) g_line(cx - h * 0.6, cy + h * 0.6, cx + h * 0.6, cy - h * 0.6, c) g_line(cx - h * 0.6 + 1.0, cy + h * 0.6, cx + h * 0.6 + 1.0, cy - h * 0.6, c) return 0.0 }
if name == "brush" { g_line(x0, y1, cx, cy, c) g_line(x0 + 1.0, y1, cx + 1.0, cy, c) g_line(cx, cy, x1, y0, c) g_disc(x0 + 2.0, y1 - 2.0, 2.5, c) return 0.0 }
if name == "pose" { g_disc(cx, y0 + 2.0, 2.5, c) g_line(cx, y0 + 4.0, cx, cy + 2.0, c) g_line(x0, cy - 2.0, x1, cy - 2.0, c) g_line(cx, cy + 2.0, x0 + 1.0, y1, c) g_line(cx, cy + 2.0, x1 - 1.0, y1, c) return 0.0 }
if name == "key" { g_tri(cx, y0, x1, cy, cx, y1, c) g_tri(cx, y0, cx, y1, x0, cy, c) return 0.0 }
if name == "key_off" { g_line(cx, y0, x1, cy, c) g_line(x1, cy, cx, y1, c) g_line(cx, y1, x0, cy, c) g_line(x0, cy, cx, y0, c) return 0.0 }
if name == "anim" { g_frame(x0, y0, size, size, c) g_tri(cx - 3.0, cy - 4.0, cx - 3.0, cy + 4.0, cx + 4.0, cy, c) return 0.0 }
if name == "texture" { g_frame(x0, y0, size, size, c) g_rect(x0, y0, h, h, c) g_rect(cx, cy, h, h, c) return 0.0 }
if name == "image" { g_frame(x0, y0, size, size, c) g_tri(x0 + 2.0, y1 - 2.0, cx, cy - 1.0, x1 - 2.0, y1 - 2.0, c) g_disc(x1 - 4.0, y0 + 4.0, 1.5, c) return 0.0 }
if name == "link" { g_ring(cx - h * 0.4, cy, h * 0.5, c) g_ring(cx + h * 0.4, cy, h * 0.5, c) return 0.0 }
if name == "target" { g_ring(cx, cy, h, c) g_line(x0, cy, x1, cy, c) g_line(cx, y0, cx, y1, c) return 0.0 }
if name == "lock" { g_rect(x0 + 1.0, cy - 1.0, size - 2.0, h + 1.0, c) g_ring(cx, cy - h * 0.5, h * 0.45, c) return 0.0 }
if name == "pin" { g_disc(cx, cy - 2.0, h * 0.6, c) g_line(cx, cy, cx, y1, c) return 0.0 }
# ── vector ──
if name == "node" { g_line(x0, y1, cx, y0, c) g_line(cx, y0, x1, y1, c) g_rect(x0 - 2.0, y1 - 2.0, 4.0, 4.0, c) g_rect(cx - 2.0, y0 - 2.0, 4.0, 4.0, c) g_rect(x1 - 2.0, y1 - 2.0, 4.0, 4.0, c) return 0.0 }
if name == "pen" { g_line(x0, y1, x1 - 2.0, y0 + 2.0, c) g_line(x0 + 1.0, y1, x1 - 1.0, y0 + 2.0, c) g_tri(x1 - 3.0, y0, x1, y0 + 3.0, x1, y0, c) g_disc(x0 + 1.0, y1 - 1.0, 1.5, c) return 0.0 }
if name == "rect" { g_frame(x0, y0 + 2.0, size, size - 4.0, c) return 0.0 }
if name == "ellipse" { g_ring(cx, cy, h, c) return 0.0 }
if name == "polygon" {
bind k = 0.0
while k < 6.0 {
bind a0 = k * 1.0472 - 1.5708
bind a1 = a0 + 1.0472
g_line(cx + cos(a0) * h, cy + sin(a0) * h, cx + cos(a1) * h, cy + sin(a1) * h, c)
bind k = k + 1.0
}
return 0.0
}
if name == "star" {
bind k = 0.0
while k < 5.0 {
bind a0 = k * 1.25664 - 1.5708
bind a1 = a0 + 2.51327
g_line(cx + cos(a0) * h, cy + sin(a0) * h, cx + cos(a1) * h, cy + sin(a1) * h, c)
bind k = k + 1.0
}
return 0.0
}
if name == "line" { g_line(x0, y1, x1, y0, c) g_line(x0 + 1.0, y1, x1 + 1.0, y0, c) return 0.0 }
if name == "hand" { g_frame(x0 + 2.0, cy - 2.0, size - 4.0, h + 2.0, c) g_line(x0 + 4.0, cy - 2.0, x0 + 4.0, y0, c) g_line(cx, cy - 2.0, cx, y0 - 1.0, c) g_line(x1 - 4.0, cy - 2.0, x1 - 4.0, y0, c) return 0.0 }
if name == "text" { g_rect(x0, y0, size, 2.0, c) g_rect(cx - 1.0, y0, 2.0, size, c) return 0.0 }
if name == "fill" { g_frame(x0, y0, size, size, c) ds_cross(x0 + 1.0, y0 + 1.0, size - 2.0, size - 2.0, c, 3.0, 0.8) return 0.0 }
if name == "stroke" { g_frame(x0, y0, size, size, c) g_frame(x0 + 1.0, y0 + 1.0, size - 2.0, size - 2.0, c) return 0.0 }
if name == "up" { g_tri(x0, cy + 2.0, x1, cy + 2.0, cx, y0, c) return 0.0 }
if name == "down" { g_tri(x0, cy - 2.0, x1, cy - 2.0, cx, y1, c) return 0.0 }
if name == "onion" { g_ring(cx - 2.0, cy, h * 0.7, c) g_ring(cx + 2.0, cy, h * 0.7, c) return 0.0 }
if name == "zoom_in" { g_ring(cx - 1.0, cy - 1.0, h * 0.7, c) g_line(cx + h * 0.4, cy + h * 0.4, x1, y1, c) g_line(cx - 4.0, cy - 1.0, cx + 2.0, cy - 1.0, c) g_line(cx - 1.0, cy - 4.0, cx - 1.0, cy + 2.0, c) return 0.0 }
if name == "fit" { g_frame(x0, y0, size, size, c) g_tri(x0 + 2.0, y0 + 2.0, x0 + 6.0, y0 + 2.0, x0 + 2.0, y0 + 6.0, c) g_tri(x1 - 2.0, y1 - 2.0, x1 - 6.0, y1 - 2.0, x1 - 2.0, y1 - 6.0, c) return 0.0 }
if name == "wire" { g_frame(x0, y0, size, size, c) g_line(x0, y0, x1, y1, c) return 0.0 }
if name == "solid" { g_rect(x0, y0, size, size, c) return 0.0 }
if name == "xray" { g_frame(x0, y0, size, size, c) ds_hatch(x0 + 1.0, y0 + 1.0, size - 2.0, size - 2.0, c, 135.0, 3.0, 0.6) return 0.0 }
if name == "gen" { g_tri(cx, y0, x1, y1, x0, y1, c) g_ring(cx, cy + 2.0, 2.5, 0.0) return 0.0 }
if name == "rock" { g_line(x0, y1, x0 + 2.0, cy, c) g_line(x0 + 2.0, cy, cx - 1.0, y0, c) g_line(cx - 1.0, y0, x1 - 2.0, cy - 2.0, c) g_line(x1 - 2.0, cy - 2.0, x1, y1, c) g_line(x1, y1, x0, y1, c) return 0.0 }
if name == "tree" { g_tri(cx, y0, x1, cy + 2.0, x0, cy + 2.0, c) g_rect(cx - 1.0, cy + 2.0, 3.0, h - 2.0, c) return 0.0 }
if name == "weight" { g_ring(cx, cy, h, c) ds_hatch(x0 + 1.0, cy, size - 2.0, h - 1.0, c, 45.0, 2.0, 0.7) return 0.0 }
if name == "spin" { g_ring(cx, cy, h, c) g_line(cx, y0, cx, y1, c) return 0.0 }
# unknown: a hollow square
g_frame(x0, y0, size, size, c)
return 0.0
}