⬆️

Interactive Icosidodecahedron – Rotate and Change Colors!


Interactive 3D wireframe rendering of an icosidodecahedron, a shape with 20 triangles and 12 pentagons. This is the logo for John Wise’s website, chosen for its mathematical symmetry and symbolic meaning—representing beauty, balance, and the desire for transparency in technology. Drag or tap to rotate the shape. Use the color pickers above to adjust the wireframe and background colors.

How I Made My Logo: A Data-Driven Polyhedron

Step 1: Choosing a Shape

I’ve always loved Archimedean solids. It’s a long story, but when I was inside, I spent a lot of time making modular origami models of these shapes (I’d even name each one “Wilson,” like in Castaway). When it came time to create a logo, I knew I wanted an icosidodecahedron. I ended up at dmccooey.com/polyhedra -- a massive catalog of beautiful, data-rich polyhedra. I went straight for the icosidodecahedron page, which has all the vertex coordinates and face definitions I needed.

Step 2: From Math to Code (Jupyter Notebook)

I copied the vertex coordinates and face definitions from McCooey’s page on the icosidodecahedron into a Python Jupyter Notebook and used the trimesh and numpy libraries to build and render the shape in 3D. It took quite a lot of tinkering, but this let me check the geometry and rotate the wireframe to find the best angle for my logo.

You can try it yourself! Here’s the code I used:


import trimesh
import numpy as np

#Constants, Vertices, and Faces, all pulled from dmccooey.com
C0 = (1 + 5 ** 0.5) / 4
C1 = (3 + 5 ** 0.5) / 4
C2 = (1 + 5 ** 0.5) / 2

vertices = np.array([
    [ 0.0,  0.0,   C2],
    [ 0.0,  0.0,  -C2],
    [  C2,  0.0,  0.0],
    [ -C2,  0.0,  0.0],
    [ 0.0,   C2,  0.0],
    [ 0.0,  -C2,  0.0],
    [ 0.5,   C0,   C1],
    [ 0.5,   C0,  -C1],
    [ 0.5,  -C0,   C1],
    [ 0.5,  -C0,  -C1],
    [-0.5,   C0,   C1],
    [-0.5,   C0,  -C1],
    [-0.5,  -C0,   C1],
    [-0.5,  -C0,  -C1],
    [  C1,  0.5,   C0],
    [  C1,  0.5,  -C0],
    [  C1, -0.5,   C0],
    [  C1, -0.5,  -C0],
    [ -C1,  0.5,   C0],
    [ -C1,  0.5,  -C0],
    [ -C1, -0.5,   C0],
    [ -C1, -0.5,  -C0],
    [  C0,   C1,  0.5],
    [  C0,   C1, -0.5],
    [  C0,  -C1,  0.5],
    [  C0,  -C1, -0.5],
    [ -C0,   C1,  0.5],
    [ -C0,   C1, -0.5],
    [ -C0,  -C1,  0.5],
    [ -C0,  -C1, -0.5],
])

faces = [
    [0, 8, 16, 14, 6],
    [0, 10, 18, 20, 12],
    [1, 7, 15, 17, 9],
    [1, 13, 21, 19, 11],
    [2, 15, 23, 22, 14],
    [2, 16, 24, 25, 17],
    [3, 18, 26, 27, 19],
    [3, 21, 29, 28, 20],
    [4, 23, 7, 11, 27],
    [4, 26, 10, 6, 22],
    [5, 24, 8, 12, 28],
    [5, 29, 13, 9, 25],
    [0, 6, 10],
    [0, 12, 8],
    [1, 9, 13],
    [1, 11, 7],
    [2, 14, 16],
    [2, 17, 15],
    [3, 19, 21],
    [3, 20, 18],
    [4, 22, 23],
    [4, 27, 26],
    [5, 25, 24],
    [5, 28, 29],
    [6, 14, 22],
    [7, 23, 15],
    [8, 24, 16],
    [9, 17, 25],
    [10, 26, 18],
    [11, 19, 27],
    [12, 20, 28],
    [13, 29, 21]
]

# Generate edges only from original faces
edge_set = set()

def add_edges(face):
    n = len(face)
    for i in range(n):
        a, b = face[i], face[(i + 1) % n]
        edge = tuple(sorted((a, b)))
        edge_set.add(edge)

for face in faces:
    add_edges(face)

edges = list(edge_set)

# Create scene
scene = trimesh.Scene()

# Variables to set colors
line_color = [0, 0, 0, 255]  # Black RGBA
background_color = [255, 255, 255, 0]  # White background, 0 alpha for transparency
cylinder_radius = 0.02

# Helper function to create a cylinder between two points with color
def cylinder_between(p1, p2, radius=0.03, color=[0, 0, 0, 255], sections=16):
    v = p2 - p1
    length = np.linalg.norm(v)
    if length == 0:
        return None
    cylinder = trimesh.creation.cylinder(radius=radius, height=length, sections=sections)
    cylinder.visual.vertex_colors = color
    cylinder.apply_translation([0, 0, length / 2])
    T = trimesh.geometry.align_vectors([0, 0, 1], v)
    cylinder.apply_transform(T)
    cylinder.apply_translation(p1)
    return cylinder

# Add cylinders for edges
for edge in edges:
    p1, p2 = vertices[list(edge)]
    cyl = cylinder_between(p1, p2, radius=cylinder_radius, color=line_color)
    if cyl:
        scene.add_geometry(cyl)

# Set background color
scene.background = background_color

# Camera
scene.set_camera(angles=[1, 0.35, 1], distance=4.5)

# Show
scene.show()

Step 3: Inkscape, SVG, and Why It Matters

After rendering it with the code above, then turning it the perfect angle for my logo, I took a screenshot and brought it into Inkscape -- a free, open-source vector graphics editor. I used Inkscape’s “Trace Bitmap” tool to convert my wireframe into vector paths, and removed the background so I’d have a clean, transparent image. (If you ever see a white box behind your SVG, you can always select and delete it in Inkscape!)

But why SVG? SVG stands for Scalable Vector Graphics. It’s not like a regular png or jpg image file -- the file itself is actually code that describes shapes and lines, so you can scale it up or down and it’ll always look sharp, with no blurring or jagged edges. Also, because the file is a text (code) file and instead of an image file, I can open the SVG in a code editor and tweak colors or line thickness - I can even add logic for showing light or dark lines depending on if the user is in dark mode or not.

Using SVG is best practice for logos and icons on the web, since they look perfect at any size and are easy to customize.

Step 4: Building the Interactive Logo Demo (for This Page)

The logo you see in my sidebar and around the site is the clean SVG graphic -- but for this project page, I wanted to go deeper. I wanted visitors to actually experience the underlying geometry, see how a data-driven shape gets built, and even play with it themselves.

So, as a “bonus project” for this page, I rebuilt my icosidodecahedron from scratch (still using the coordinates pulled from dmccooey.com/polyhedra) in JavaScript using Three.js. This isn’t the same SVG that powers the site logo; it’s a fully interactive, 3D wireframe rendering, generated directly from the mathematical data. The goal: give you a hands-on look at the geometry and let you experiment.

How it works: You can drag or tap to rotate the shape in any direction, and use the color pickers above to change the wireframe and background colors in real time. Everything runs live in your browser -- no plugins. The demo works on desktop and mobile, and is designed to be fully accessible.

Under the hood, this demo:

  • Loads the polyhedron’s coordinates and face data in JavaScript (not using any 3D models or images - it is, in essence, a data visualization -- the data in this case being the geometry of the figure.)
  • Draws the wireframe using Three.js’s fast 3D engine
  • Lets you change colors instantly, without reloading
  • Handles mouse and touch for rotation, and includes alt text for accessibility

Why bother building an interactive demo? Because transparency and hands-on learning matter. I want you to see that this logo isn’t magic or marketing -- it’s built on open data, real math, and tools anyone can use. You’re invited to remix, re-use, or just spin it around for fun. And if you’re curious, you can view (or copy!) the full code right here on the page (just right-click and 'view source' or 'inspect' in most browsers).

John Wise logo