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 lets me build web apps with Python. And I can use three.js, the browser-based 3D engine - without writing any Javascript at all! That's because Anvil lets you use Javascript libraries from Python.
Here's what the finished app looks like:
Try it yourself >>
If you're feeling impatient, you can just grab the source code - 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:
<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:
# 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:
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))
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 to build a little control panel, and wire up the dropdowns to control the construction of the tree:
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 >>
Happy decorating! And if you enjoyed this, you should check out the rest of the Anvil Advent Calendar. We're building a web app a day with nothing but Python -- every day until Christmas!
Top comments (0)