Day 8 of the Anvil Advent Calendar

Build a web app every day until Christmas, with nothing but Python!

A 3D Christmas Tree in the Browser with Python

Good news: It’s time to decorate the tree! Bad news: Nobody will see it inside my house this year. So I’m putting up a virtual one.

It’s going to be 3D, and in the browser, and in Python! I’m using three.js, the browser-based 3D engine, and I’m driving it from Python with Anvil’s Python<->Javascript bridge.

You can open the source code yourself to see it:

How I built it

1. Setup

Driving a Javascript library like Three.js in Anvil is easy. First, I included the library in my Native Libraries:

<script src=""></script>

Now I can open my Python code and import the three.js library into Python, with from anvil.js.window import THREE.

I’m making my tree out of three ConeGeometry objects – although they’re Javascript objects, we can construct them straight from Python. Here’s the code fragment that actually builds the tree:

# Import the three.js library from Javascript-land:
from anvil.js.window import THREE

for i in range(3):
  geom = THREE.ConeGeometry(1, 1-0.2*i, 32)
  cone = THREE.Mesh(geom, green_tree)
  cone.position.y = i

And voila: A tree – in my browser, built with Python!

2. Time to decorate!

Now, a tree on its own isn’t very interesting, so it’s time to add some baubles. I’m adding spheres of random colours along the outside of each cone.

So, for each cone, we do some trigonometry - we’ll walk round the cone, adding baubles at random intervals. Remember that a cone is wider at the bottom than at the top, so we use Python’s random.triangular() to pick lower positions more often:

      bauble_geom = THREE.SphereGeometry(0.1)
      theta = 0
      while theta < 2*math.pi:
          # Move a bit further round the tree
          theta += random.triangular(0, 0.5, 1);
          # How far down the cone? (0=top point, 1=bottom edge)
          fh = random.triangular(0.3, 0.9, 0.9)
          # What's the radius of the cone, this far down?
          d = fh*r

          # What colour?
          material = THREE.MeshLambertMaterial({ 'color': f"hsl({random()*360}, 100%, 50%)" })
          bauble = THREE.Mesh(bauble_geom, material)
          # Hang it on the tree
          bauble.position.set(d*math.sin(theta), cone_base + (1-fh)*h, d*math.cos(theta))

3. Making it interactive

A Christmas tree is a personal expression, and everyone wants to customise theirs. So I’ve used Anvil’s drag-and-drop UI designer to build a little control panel, and wire up the dropdowns to control the construction of the tree:

Note: This guide includes screenshots of the Classic Editor. Since we created this guide, we've released the new Anvil Editor, which is more powerful and easier to use.

All the code in this guide will work, but the Anvil Editor will look a little different to the screenshots you see here!

Sharing it with the world

Time to publish my app and share it with the world! You can open it here:

And ou can get the whole source code here:

Happy decorating! And if you enjoyed this, you should hit the link below to get the rest of our Advent Calendar. We’re building a web app a day with nothing but Python – every day until Christmas.

Give the Gift of Python

Share this post: