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.

Random mode

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
      self.palette = DEFAULT_PALETTE

Give the Gift of Python

Share this post: