Adding Pens
Discover how to use the addShape(pen:) call and what happens when you create multiple independent pens on the same canvas.
Rendering Shapes
Each pen tracks its own path independently. To display a pen's path on the canvas you must call addShape(pen:). You can call it once at the end, or after each pen individually.
var p1 = Pen() p1.addLine(distance: 100) addShape(pen: p1) // render p1's path var p2 = Pen() p2.turn(degrees: 90) p2.addLine(distance: 100) addShape(pen: p2) // render p2's path
| IM1 Concept | Connection |
|---|---|
| Coordinate geometry | Each pen starts at the origin — independent paths share the same coordinate system |
| Line segments | Each addLine call produces a directed segment with defined start and end points |
Multiple Pens
Draw two separate squares side-by-side using two independent pens — one starting at the origin and the other offset to the right.
Your Task
Create two pens. Draw a 100-unit square with p1 starting at the origin. Then use p2 — start it at (150, 0) using move(distance:) or by setting its position — and draw a second 100-unit square.
var p1 = Pen() // Draw first square with p1 var p2 = Pen() // Position p2 and draw second square addShape(pen: p1) addShape(pen: p2)
var p1 = Pen() p1.addLine(distance: 100); p1.turn(degrees: 90) p1.addLine(distance: 100); p1.turn(degrees: 90) p1.addLine(distance: 100); p1.turn(degrees: 90) p1.addLine(distance: 100) addShape(pen: p1) var p2 = Pen() p2.move(distance: 150) // move right without drawing p2.addLine(distance: 100); p2.turn(degrees: 90) p2.addLine(distance: 100); p2.turn(degrees: 90) p2.addLine(distance: 100); p2.turn(degrees: 90) p2.addLine(distance: 100) addShape(pen: p2)
| IM1 Concept | Connection |
|---|---|
| Translations | Offsetting p2 by 150 units is a translation — a rigid motion that shifts every point the same distance |
| Congruence | Both squares are congruent — same shape, same size, different position |
Turning Both Ways
Explore negative degree values — turning right (clockwise) instead of left — and understand how this unlocks a wider range of shapes.
Positive vs Negative Turns
A positive turn angle rotates the pen anti-clockwise (left). A negative angle rotates it clockwise (right). This matches standard mathematical convention.
p.turn(degrees: 90) // rotate LEFT 90° (anti-clockwise) p.turn(degrees: -90) // rotate RIGHT 90° (clockwise)
| IM1 Concept | Connection |
|---|---|
| Directed angles | Positive = anti-clockwise, negative = clockwise — this is the convention used in trigonometry and coordinate geometry |
| Rotations | Turning the pen is equivalent to a rotation of the direction vector around the pen's current position |
Two Squares
Draw a large square (200 units) and a small square (100 units) that shares the same bottom-left corner — creating a nested effect.
Your Task
Use a single pen to draw both squares without lifting it (use move to reposition if needed), or use two separate pens.
var p = Pen() // Draw large square (200 units) // Draw small square (100 units) addShape(pen: p)
var p = Pen() // Large square: 200 units p.addLine(distance: 200); p.turn(degrees: 90) p.addLine(distance: 200); p.turn(degrees: 90) p.addLine(distance: 200); p.turn(degrees: 90) p.addLine(distance: 200); p.turn(degrees: 90) // Small square: 100 units p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Similarity | The two squares are similar — same shape but different sizes, with a scale factor of 2:1 |
| Perimeter | Perimeter of large square = 4 × 200 = 800; small = 4 × 100 = 400 |
Thicker Lines
Use the lineWidth property to draw a bold triangle — and explore how stroke width affects a shape's visual weight.
Your Task
Draw an equilateral triangle (3 sides, turning 120° at each corner) with a lineWidth of 6.
var p = Pen() p.lineWidth = 6 // Draw equilateral triangle addShape(pen: p)
var p = Pen() p.lineWidth = 6 p.addLine(distance: 150); p.turn(degrees: 120) p.addLine(distance: 150); p.turn(degrees: 120) p.addLine(distance: 150) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Equilateral triangle | All three sides equal; all interior angles = 60°; exterior turn = 120° |
| Exterior angle theorem | 360° ÷ 3 sides = 120° per turn; verifies sum of exterior angles = 360° |
Coloured Triangle
Draw a triangle where each side is a different colour — green, red, and blue — by changing penColor between sides.
Your Task
Use three pens (or change the colour on one pen before each side) to produce a triangle with sides in three different colours.
var p = Pen() p.penColor = .green p.addLine(distance: 150) p.turn(degrees: 120) // Continue for red and blue sides… addShape(pen: p)
var p = Pen() p.penColor = .green p.addLine(distance: 150); p.turn(degrees: 120) p.penColor = .red p.addLine(distance: 150); p.turn(degrees: 120) p.penColor = .blue p.addLine(distance: 150) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Triangle classification | Equilateral — three sides equal, three angles equal (60° each) |
| Angle sum | Interior angles of any triangle sum to 180° |
Diamond
Draw a diamond (rhombus) with equal sides but non-right angles — using turn angles less than and greater than 90°.
Your Task
Draw a diamond with side length 150 and interior angles of 60° and 120°. Hint: the exterior turns will be 120° and 60° alternating.
var p = Pen() // 4 equal sides, alternating turns addShape(pen: p)
var p = Pen() p.addLine(distance: 150); p.turn(degrees: 60) p.addLine(distance: 150); p.turn(degrees: 120) p.addLine(distance: 150); p.turn(degrees: 60) p.addLine(distance: 150) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Rhombus properties | 4 equal sides; opposite angles equal; diagonals bisect each other at right angles |
| Supplementary angles | Adjacent interior angles sum to 180°: 60° + 120° = 180° |
Fill It In
Learn about the fillColor property to colour the interior of closed shapes.
Adding Fill
Setting fillColor on a pen before drawing will colour the enclosed area of a closed shape. The path must be closed (return to its starting point) for fill to work correctly.
var p = Pen() p.fillColor = .yellow p.penColor = .orange p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Area vs perimeter | Fill occupies the interior (area); the pen line defines the boundary (perimeter) |
| Closed figures | A shape must be topologically closed for fill to render — a key property in geometry |
Coloured Squares
Draw three filled squares in a row — red, green, and blue — each 80 units wide with a 20-unit gap between them.
Your Task
Use three separate pens positioned at different x-coordinates. Give each pen a different fillColor.
// Three pens at x = 0, 100, 200 // Each draws an 80×80 filled square
var p1 = Pen() p1.fillColor = .red p1.addLine(distance: 80); p1.turn(degrees: 90) p1.addLine(distance: 80); p1.turn(degrees: 90) p1.addLine(distance: 80); p1.turn(degrees: 90) p1.addLine(distance: 80) addShape(pen: p1) var p2 = Pen() p2.move(distance: 100) p2.fillColor = .green p2.addLine(distance: 80); p2.turn(degrees: 90) p2.addLine(distance: 80); p2.turn(degrees: 90) p2.addLine(distance: 80); p2.turn(degrees: 90) p2.addLine(distance: 80) addShape(pen: p2) var p3 = Pen() p3.move(distance: 200) p3.fillColor = .blue p3.addLine(distance: 80); p3.turn(degrees: 90) p3.addLine(distance: 80); p3.turn(degrees: 90) p3.addLine(distance: 80); p3.turn(degrees: 90) p3.addLine(distance: 80) addShape(pen: p3)
| IM1 Concept | Connection |
|---|---|
| Area | Each square: area = 80² = 6400 square units; total area = 3 × 6400 = 19,200 |
| Translations | Each square is a translated copy — same shape, size, and orientation at a different position |
Variables
Store sizes in variables so you can change your shape's dimensions in one place and have the whole drawing update automatically.
Using Variables for Dimensions
A variable is a named container for a value. By storing a side length in a variable, changing it once updates the entire drawing.
let side = 120.0 // change this one value to resize everything var p = Pen() p.addLine(distance: side); p.turn(degrees: 90) p.addLine(distance: side); p.turn(degrees: 90) p.addLine(distance: side); p.turn(degrees: 90) p.addLine(distance: side) addShape(pen: p)
Variables vs Constants
You may have noticed two different keywords in Swift: var and let. They both name a value — but behave differently.
| Keyword | Name | Can it change? | Use it for… |
|---|---|---|---|
var | Variable | Yes | Things that change over time — like a Pen as it moves and turns |
let | Constant | No | Fixed values that should stay the same — like a side length you set once |
let side = 100.0 // constant — the value is fixed var p = Pen() // variable — p changes as we call methods on it
Use let when a value should never change after you set it — Swift will warn you if you accidentally try to modify it. Use var when the value needs to change (or when Swift requires it, as with Pen).
| IM1 Concept | Connection |
|---|---|
| Variables & expressions | Side length s is a variable; perimeter = 4s and area = s² are expressions derived from it |
| Generalisation | Writing a formula in terms of a variable generalises from specific numbers to all cases |
House
Combine a square base and a triangular roof to draw a simple house shape using two pens or careful repositioning.
Your Task
Draw a square (100 units) for the walls, then continue from the top-left corner to draw an isosceles triangle roof. The roof peak should be centred above the square.
var p = Pen() // Square body + triangular roof addShape(pen: p)
var p = Pen() // Square base p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) p.addLine(distance: 100); p.turn(degrees: 90) // Move to top-left of square p.turn(degrees: 90) p.move(distance: 100) p.turn(degrees: -90) // Roof: two sides at 30° from horizontal, meeting at apex p.turn(degrees: 30) p.addLine(distance: 57.74) p.turn(degrees: 120) p.addLine(distance: 57.74) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Composite figures | Total area = area of square + area of triangle — composites are decomposed into simpler shapes |
| Isosceles triangle | Roof triangle has two equal sides and two equal base angles |
Calculate
Use Swift arithmetic to compute side lengths and angles — let the code do the maths rather than calculating by hand.
Your Task
Draw a regular hexagon. Instead of calculating the turn angle yourself, store the number of sides in a constant and use 360.0 / 6 to let Swift compute it. Then write one addLine and one turn for each of the six sides.
let sides = 6 let turn = 360.0 / Double(sides) var p = Pen() // Draw each of the 6 sides using 'turn' addShape(pen: p)
let sides = 6 let turn = 360.0 / Double(sides) var p = Pen() p.addLine(distance: 100); p.turn(degrees: turn) p.addLine(distance: 100); p.turn(degrees: turn) p.addLine(distance: 100); p.turn(degrees: turn) p.addLine(distance: 100); p.turn(degrees: turn) p.addLine(distance: 100); p.turn(degrees: turn) p.addLine(distance: 100); p.turn(degrees: turn) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Regular polygons | Exterior angle = 360° ÷ n; interior angle = 180° − (360° ÷ n) |
| Algebraic reasoning | Expressing the angle as 360/n generalises the formula for all regular polygons |
Variable House
Refactor the House exercise using a variable for the house width, so you can resize the whole building by changing one number.
Your Task
Store the house width in a variable w. The roof height and angles should be derived from w using arithmetic, so the shape scales correctly.
let w = 120.0 // change this to resize the house var p = Pen() // Use w throughout addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Proportional reasoning | Scaling all dimensions by the same factor produces a similar figure |
| Variables in geometry | Writing perimeter/area formulas in terms of w models geometric relationships algebraically |
Red Cross
Draw a filled red cross (plus sign) shape — a composite figure made from rectangles.
Your Task
A cross can be drawn as a 12-sided polygon. Start at the bottom-left of the lower arm and work around the perimeter, alternating between long (100) and short (40) sides.
var p = Pen() p.fillColor = .red p.penColor = .red // 12 sides, 4 outer corners (90°), 8 inner corners (-90°) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Area of composite figures | Cross area = 3 rectangles overlapping; use inclusion-exclusion: 3(100×40) − 2(40×40) |
| Perimeter of irregular shapes | Count each boundary segment: 4 long sides + 8 short sides |
Simple Snowflake
Draw 6 arms radiating from the centre — each arm a straight line — to create a basic snowflake with 6-fold symmetry.
Your Task
Draw 6 arms of equal length, each rotated 60° from the last. After each arm, return to the centre.
var p = Pen() // Arm 1 p.addLine(distance: 100); p.move(distance: -100); p.turn(degrees: 60) // Arm 2 p.addLine(distance: 100); p.move(distance: -100); p.turn(degrees: 60) // Arm 3 p.addLine(distance: 100); p.move(distance: -100); p.turn(degrees: 60) // Arm 4 p.addLine(distance: 100); p.move(distance: -100); p.turn(degrees: 60) // Arm 5 p.addLine(distance: 100); p.move(distance: -100); p.turn(degrees: 60) // Arm 6 p.addLine(distance: 100) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Rotational symmetry | A 6-arm snowflake has order-6 rotational symmetry — it maps onto itself after 60° rotations |
| Angles at a point | 6 arms × 60° = 360° — the angles around the centre sum to one full rotation |
Parallel Lines
Draw four horizontal parallel lines — equally spaced — demonstrating lines that never meet.
Your Task
Draw 4 horizontal lines, each 200 units long, spaced 40 units apart vertically. Use 4 pens — start each one at a different height using turn and move.
// Line 1 — at y = 0 var p1 = Pen() p1.addLine(distance: 200) addShape(pen: p1) // Line 2 — at y = 40 var p2 = Pen() // Move p2 up 40 units, then face right again // Line 3 and 4 — continue the pattern
// Line 1 — at y = 0 var p1 = Pen() p1.addLine(distance: 200) addShape(pen: p1) // Line 2 — at y = 40 var p2 = Pen() p2.turn(degrees: 90); p2.move(distance: 40); p2.turn(degrees: -90) p2.addLine(distance: 200) addShape(pen: p2) // Line 3 — at y = 80 var p3 = Pen() p3.turn(degrees: 90); p3.move(distance: 80); p3.turn(degrees: -90) p3.addLine(distance: 200) addShape(pen: p3) // Line 4 — at y = 120 var p4 = Pen() p4.turn(degrees: 90); p4.move(distance: 120); p4.turn(degrees: -90) p4.addLine(distance: 200) addShape(pen: p4)
| IM1 Concept | Connection |
|---|---|
| Parallel lines | Lines in the same direction that never intersect; have equal gradient (slope) |
| Coordinate geometry | Offsetting the y-start corresponds to a vertical translation |
Letter Z
Draw the letter Z using three line segments — a top horizontal, a diagonal, and a bottom horizontal — observing how the Z-angles relate to parallel lines.
Your Task
Draw: a horizontal line right 100, then turn down-left to draw the diagonal, then turn to draw the bottom horizontal. The diagonal creates Z-angles (alternate interior angles) with the horizontal lines.
var p = Pen() p.addLine(distance: 100) // top line p.turn(degrees: -120) p.addLine(distance: 115.5) // diagonal p.turn(degrees: -60) p.addLine(distance: 100) // bottom line addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Alternate interior angles | The Z-shape shows alternate angles — equal when lines are parallel — visually embedded in the letter |
| Transversal | The diagonal is a transversal crossing two parallel (horizontal) lines |
Rhombus
Draw a filled rhombus with side length 120 and interior angles of 70° and 110°. Explore how opposite angles in a parallelogram are equal.
Your Task
A rhombus has 4 equal sides. Opposite angles are equal; adjacent angles are supplementary (sum to 180°).
let interiorAngle = 70.0 let exterior = 180.0 - interiorAngle var p = Pen() p.fillColor = .purple // Use interior/exterior angles to draw rhombus addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Rhombus properties | All sides equal; opposite angles equal; diagonals bisect each other at 90° |
| Co-interior angles | Adjacent interior angles are supplementary — another transversal property applied to parallel sides |
Parallelogram
Draw a parallelogram — two pairs of parallel sides — showing how it differs from a rhombus when sides have different lengths.
Your Task
Draw a parallelogram with long sides 160 units, short sides 80 units, and interior angles of 70° and 110°.
var p = Pen() p.addLine(distance: 160) p.turn(degrees: 110) p.addLine(distance: 80) p.turn(degrees: 70) p.addLine(distance: 160) p.turn(degrees: 110) p.addLine(distance: 80) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Parallelogram properties | Opposite sides parallel and equal; opposite angles equal; diagonals bisect each other |
| Area formula | Area = base × height = 160 × 80 × sin(70°) ≈ 12,030 sq units |
Polygon Properties Explorer
Draw a selection of regular polygons — from a triangle to a decagon — and observe how the shape approaches a circle as the number of sides increases.
Your Task
Change sides to explore different regular polygons — try 3, 4, 5, 6, 8. Add or remove addLine/turn pairs so the number of lines matches the number of sides. Notice how the shape changes as sides increase.
// Change 'sides' and add/remove lines to match let sides = 6 let turn = 360.0 / Double(sides) var p = Pen() p.addLine(distance: 80); p.turn(degrees: turn) p.addLine(distance: 80); p.turn(degrees: turn) p.addLine(distance: 80); p.turn(degrees: turn) p.addLine(distance: 80); p.turn(degrees: turn) p.addLine(distance: 80); p.turn(degrees: turn) p.addLine(distance: 80); p.turn(degrees: turn) addShape(pen: p)
| IM1 Concept | Connection |
|---|---|
| Regular polygon formulas | Interior angle = (n − 2) × 180° ÷ n; exterior angle = 360° ÷ n |
| Limit concept (preview) | As n → ∞, the polygon approaches a circle — an intuitive preview of limits |
Angle Classification
Draw shapes whose interior angles represent each angle type — acute, right, obtuse, and reflex — then label them with your understanding.
Your Task
Draw at least four shapes: one with a reflex angle, one with all right angles (square), one with acute angles (equilateral triangle), and one with obtuse angles (regular hexagon). Try to draw them adjacent on the canvas.
💡 Think About It
- What is the interior angle of a regular pentagon? Is it acute, right, or obtuse?
- Can a triangle have an obtuse angle? Can it have two?
- What is the minimum number of sides a polygon needs to have a reflex angle?
| IM1 Concept | Connection |
|---|---|
| Angle classification | Acute <90°; right = 90°; obtuse 90°–180°; straight = 180°; reflex >180° |
| Interior angle formula | (n − 2) × 180° ÷ n — determines whether a regular polygon has acute or obtuse angles |