Day 14 of the Anvil Advent Calendar
Build a web app every day until Christmas, with nothing but Python!
Procedurally-generated Christmas tree
Today’s app draws a Christmas tree based on your design specifications.
The app procedurally generates a tree based on the values of the sliders - the code runs some geometry to draw each branch, the trunk, the pot, tinsel, star and baubles. The Canvas gets updated every time a slider changes.
Try it here:
Take a look at the code for yourself:
Share your tree design
You can share your tree with friends using the ‘share’ button - it copies a URL to the clipboard containing the tree’s parameters.
The URL contains the value of each slider in its query parameters:
When the app loads, we use
get_url_hash(), which automatically extracts the query params as a dictionary.
Then we can just set the sliders to the correct values and draw the tree.
There’s also a ‘random’ button that produces a range of unnatural monstrosities:
The less said about that, the better.
Build your own procedural drawing app
This was great fun to build and it presented some interesting challenges. Making the baubles work was particularly fun - have you noticed that the baubles shift naturally as the branches change shape?
If you would like to try building a procedural drawing app of your own, here’s a simple example to start from. It draws a Christmas present using a rectangle and a cross shape:
The code for this app is very simple, and it’s easy to see how to extend it. Here’s a clone link:
Once you’ve hacked about for a bit, we’d love to see what you come up with! Head to the Show and Tell section of the Forum to show it off.
Bonus: Blueprint mode
If you need a schematic view, there’s a blueprint mode. This is useful for sharing your tree with architects:
Blueprint mode was easy to build: you just need to get each rgb hex for the tree’s various elements from a variable that you can switch when the Blueprint Mode slider changes:
class TreeGenerator(TreeGeneratorTemplate): # ... def toggle_switch_blueprint_x_change(self, **event_args): """This method is called when the switch is toggled""" if self.toggle_switch_blueprint.checked: self.palette = BLUEPRINT_PALETTE else: self.palette = DEFAULT_PALETTE self.refresh()
Give the Gift of Python
Share this post: