Skip to content

Hand-drawn → 3D

vectorize(image("...")) is the bitmap counterpart to svg(): it traces a raster line drawing to a uniform single-line centreline (binarize → bridge gaps → thin → trace → simplify), then strokes + extrudes it to a watertight 3D solid — same depth / size / round controls. Tracing runs once and is cached, so the animation stays smooth.

The original hand drawing:

The original hand-drawn line sketch

…and the same sketch, vectorized to one uniform line and extruded to a turning 3D mark:

rendering…
runner "0.0.13";

use std.shapes.*;
use std.scene3d.*;
use std.lighting.*;
use std.anim.*;

scene handdrawn(duration: Duration = 8s) -> Frame {
  let bg = rect(width: 1080px, height: 1080px, fill: oklch(0.10, 0.03, 280));

  // vectorize() traces a raster line drawing to a uniform single-line
  // centreline (binarize -> bridge gaps -> thin -> trace -> simplify) and
  // extrudes it just like svg(): one hand drawing -> a turning 3D mark.
  let spin = animate { 0s => -20deg, 4s => 20deg, 8s => -20deg } with { easing: easing.in_out_cubic };

  let mark = vectorize(image("/img/handdrawn.jpg"),
                       stroke_width: 8px, simplify: 2.0, bridge: 5, stitch: 110,
                       depth: 70px, size: 780px, round: 10px)
               .material(fill: oklch(0.72, 0.15, 250), metalness: 0.3, roughness: 0.3)
               .rotate(x: 12deg, y: spin);

  let lights = [
    ambient(0.5),
    directional(from: vec3(2, 3, 5), intensity: 1.4),
    point(at: vec3(-220px, 220px, 420px), intensity: 1.0),
  ];

  compose [ bg, render3d(mark, lights: lights, camera: camera(distance: 2166)) ]
}