Your Own Shapes: Recipes 🍪¶
Invent a shape once, then make as many as you like
Why Recipes? 🤔¶
Say you've drawn a great face: a head, two eyes and a smile. Now you want five faces. You could copy them, but what if you want some faces bigger, or a different colour?
A recipe tells VeeLang how to make a shape of your own. Like a recipe for cookies, you write it once, and then you can make as many as you want.
Your First Recipe 🙂¶
You write a recipe with the word shape, a name, and its parts inside { }:
Canvas paper having width 500, length 200
shape face {
circle head at 0, 0 having radius 50, fill "gold"
circle leftEye at -20, -12 having radius 8, fill "black"
circle rightEye at 20, -12 having radius 8, fill "black"
arc smile from 25, 18 to -25, 18 having radius 35, thickness 4
}
draw face at 100, 100
draw face at 250, 100
draw face at 400, 100
The recipe on its own draws nothing. It only says what a face looks like. Each draw face makes a new face, and at says where the recipe's 0, 0 goes. Here, 0, 0 is the middle of the head, so each face is centred on its at.
Where's 0, 0?
Put 0, 0 in the middle of your recipe's shape. Then draw face at 100, 100 puts the face's middle at 100, 100, which is easy to remember.
Settings: Make Each One Different 🎚️¶
A recipe can have settings: things you can change each time you make one. Write them after having, each with a starting value (its default):
Canvas paper having width 450, length 250
shape face having size 100 {
circle head at 0, 0 having radius size / 2, fill "gold"
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
circle rightEye at size / 5, -size / 8 having radius size / 12, fill "black"
}
draw face at 80, 100
draw face at 220, 100 having size 160
draw face at 360, 100 having size 50
Inside the recipe, size is a number, just like a number variable. Everything is worked out from it, so the whole face grows and shrinks together.
Settings can be words too. This face has a skin setting:
Canvas paper having width 450, length 200
shape face having size 100, skin "gold" {
circle head at 0, 0 having radius size / 2, fill skin
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
circle rightEye at size / 5, -size / 8 having radius size / 12, fill "black"
}
draw face at 80, 100
draw face at 220, 100 having skin "pink"
draw face at 360, 100 having skin "lightgreen", size 70
Explain Your Settings 💬¶
Put a comment after each setting to say what it does:
Canvas paper having width 250, length 200
shape face having
size 100, // how wide the face is
skin "gold" // the colour of the face
{
circle head at 0, 0 having radius size / 2, fill skin
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
}
draw face at 150, 120
In the playground, point at face anywhere in your code to see its settings, what each one is for, and what it changes. And when you type having after a face, the playground offers its settings for you!
Naming Your Faces 🏷️¶
Faces can have names, like any shape. Then you can reach their parts with a dot, and change them:
Canvas paper having width 400, length 250
shape face having size 100, skin "gold" {
circle head at 0, 0 having radius size / 2, fill skin
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
circle rightEye at size / 5, -size / 8 having radius size / 12, fill "black"
}
face sam at 120, 120 having skin "pink"
sam.leftEye.fill = "blue"
sam.rightEye.fill = "blue"
draw sam
face kim at 300, 120
kim.size = 140
draw kim
You can change a setting later too, like kim.size = 140. VeeLang rebuilds kim with the new size, and keeps any changes you made to kim's parts.
Send a Setting Straight to a Part 📬¶
Sometimes a setting just changes one part, like the colour of the head. Instead of using it inside the recipe, you can say where it goes with is:
Canvas paper having width 350, length 200
shape face having size 100, skin is head.fill {
circle head at 0, 0 having radius size / 2, fill "gold"
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
}
draw face at 100, 100
draw face at 250, 100 having skin "tomato"
skin is head.fill means "skin is the head's fill". Its default is whatever the recipe gives the head, here "gold".
Choices: When Something Is... 🔀¶
Some settings choose between different parts. A face could have short hair, curly hair, or no hair at all. Use when to say what to draw for each choice:
Canvas paper having width 450, length 200
shape face having size 100, hair "short" {
circle head at 0, 0 having radius size / 2, fill "peachpuff"
circle leftEye at -size / 5, -size / 8 having radius size / 12, fill "black"
circle rightEye at size / 5, -size / 8 having radius size / 12, fill "black"
when hair is "short" {
arc fringe from -size / 2, -size / 8 to size / 2, -size / 8 having radius size / 2, thickness size / 10, color "saddlebrown"
}
when hair is "curly" {
repeat 7 times with n {
circle at -size / 2 + size / 8 * n, -size / 2 having radius size / 10, fill "saddlebrown"
}
}
when hair is "bald" { }
}
draw face at 90, 110
draw face at 230, 110 having hair "curly"
draw face at 370, 110 having hair "bald"
The when blocks also decide which choices there are. If you write having hair "spiky", VeeLang tells you that hair can be "short", "curly" or "bald".
Recipes Inside Recipes 🪆¶
A recipe can use other recipes, as long as they're written above it:
Canvas paper having width 300, length 250
shape eye having size 10, colour "black" {
circle white at 0, 0 having radius size, fill "white", stroke "gray"
circle pupil at 0, 0 having radius size / 2, fill colour
}
shape face having size 100 {
circle head at 0, 0 having radius size / 2, fill "gold"
eye left at -size / 5, -size / 8 having size size / 10
eye right at size / 5, -size / 8 having size size / 10, colour "green"
}
draw face at 150, 120 having size 160
Let's Build a Street 🏘️¶
A house recipe with a setting for how many floors it has. A loop adds the windows:
Canvas paper having width 850, length 400
shape house having floors 2, wall "wheat", roof "firebrick" {
rectangle walls at 0, -60 * floors having width 120, length 60 * floors, fill wall
triangle top having corner1 at -15, -60 * floors, corner2 at 135, -60 * floors, corner3 at 60, -60 * floors - 50, fill roof
repeat floors times with f {
square at 15, -60 * f + 15 having size 30, fill "lightblue"
square at 75, -60 * f + 15 having size 30, fill "lightblue"
}
}
draw rectangle at 0, 300 having width 800, length 40, fill "forestgreen"
draw house at 20, 300
draw house at 170, 300 having floors 3, wall "lightpink"
draw house at 320, 300 having floors 1, roof "slateblue"
draw house at 470, 300 having floors 4, wall "lightsteelblue", roof "dimgray"
This house puts its 0, 0 at the bottom-left corner, on the ground. So every house stands on the grass, however tall it is.
Challenge Time! 🏆¶
- 🌟 Challenge 1: Make a
treerecipe with aheightsetting, and plant a forest of trees of different heights. - 🌟 Challenge 2: Give the face recipe a
moodsetting withwhen mood is "happy"andwhen mood is "sad". - 🌟 Challenge 3: Make a
flowerrecipe with apetalssetting, and use a loop to draw the petals. - 🌟 Challenge 4: Make a
robotrecipe that uses aneyerecipe for its eyes.
What's Next? 🚀¶
You can now invent your own shapes with recipes: give them settings, explain them with comments, send settings straight to parts, make choices with when, and build recipes out of other recipes.
You've learned all of VeeLang! 🎉 Now it's your turn: open the playground and invent something only you could imagine. ✨