Drawing 3D Models in the Browser - with Python!
Tags: python, webdev, graphics
Published: 2020-12-18 10:18:32

## A 3D Christmas Tree in the Browser - With Nothing But 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, in 3D.

**Even more good news:** I can do it all with nothing but Python!

[Anvil](https://anvil.works) lets me build web apps with Python. And I can use [three.js](https://threejs.org), the browser-based 3D engine - without writing any Javascript at all! That's because Anvil lets you [use Javascript libraries from Python](https://anvil.works/docs/client/javascript).

<br>
Here's what the finished app looks like:

![The finished app](https://anvil-website-static.s3.eu-west-2.amazonaws.com/advent-calendar/3d-tree/Selection_418.png)

#### [Try it yourself >>](https://3d-tree.anvil.app)

<br>If you're feeling impatient, you can just [grab the source code](https://anvil.works/build#clone:K6XYLHB3Z6VZDLDQ=UNU6F7PYDLXY4JC34KB6YEPV) - or read on to find out how it works.

## How I built it

### 1. Setup

Driving a Javascript library in Anvil is easy. First, I included the library in my [Native Libraries](https://anvil.works/docs/client/javascript#using-native-javascript-libraries):

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r122/three.min.js"></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 Python code that actually builds the tree:

```python
# 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
  self.scene.add(cone)
```

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

![A 3D Christmas tree with no decoration](https://anvil.works/advent/img/3d-tree/simple-tree.png)

---

### 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:

```python
      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))
          cone.add(bauble)
```

---

### 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](https://anvil.works/articles/drag-and-drop-builder) to build a little control panel, and wire up the dropdowns to control the construction of the tree:

![Adding UI to control the tree](https://anvil-website-static.s3.eu-west-2.amazonaws.com/advent-calendar/3d-tree/add-tree-control.gif)

---

### Sharing it with the world

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

#### https://3d-tree.anvil.app

And you can get the whole source code here:

#### [Source code >>](https://anvil.works/build#clone:K6XYLHB3Z6VZDLDQ=UNU6F7PYDLXY4JC34KB6YEPV)

Happy decorating! And if you enjoyed this, you should check out the rest of the [Anvil Advent Calendar](https://anvil.works/advent). We're building a web app a day with nothing but Python -- every day until Christmas!