#!/usr/bin/env python3
"""
Week 23: Lines, Angles & Symmetry
Phase 4: Geometry & Fractions
Standards: 2.G.A.1 (identify shapes, angles, line segments), 2.G.A.3 (partition shapes)
New Standard:
- Reduced drill (40% fewer problems)
- Estimation before calculating (estimate angles/symmetry lines first)
- Multiple strategies encouraged (folding, mirror, drawing)
- Better word problems (reasoning over keywords)
- Real challenges (open-ended thinking)
- Number talks (explain WITHOUT measuring)
- Friday self-check with reflection
"""
import os
import glob
from weasyprint import HTML
from math_helpers import (
CSS, TEACHER_CSS,
page, page_multi, hdr, sec, b, bw, bl,
tg_page_multi, tg_sec, tg_note, tg_section_title,
shape_svg, grid_svg,
)
from activity_builders import (
build_shape_attributes,
build_symmetry,
build_challenge_box,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_23")
BLUE = "#4a90d9"
GREEN = "#5cb85c"
RED = "#e53935"
# ─── small SVG helpers for this week ───
def line_svg(kind, size=110):
"""Draw a line, line segment, or ray."""
if kind == "segment":
return (f'<svg viewBox="0 0 110 30" width="{size}" height="30">'
'<line x1="15" y1="15" x2="95" y2="15" stroke="#333" stroke-width="2"/>'
'<circle cx="15" cy="15" r="3.5" fill="#333"/>'
'<circle cx="95" cy="15" r="3.5" fill="#333"/></svg>')
if kind == "ray":
return (f'<svg viewBox="0 0 110 30" width="{size}" height="30">'
'<line x1="15" y1="15" x2="90" y2="15" stroke="#333" stroke-width="2"/>'
'<circle cx="15" cy="15" r="3.5" fill="#333"/>'
'<polygon points="88,9 102,15 88,21" fill="#333"/></svg>')
if kind == "line":
return (f'<svg viewBox="0 0 110 30" width="{size}" height="30">'
'<line x1="18" y1="15" x2="92" y2="15" stroke="#333" stroke-width="2"/>'
'<polygon points="22,9 8,15 22,21" fill="#333"/>'
'<polygon points="88,9 102,15 88,21" fill="#333"/></svg>')
if kind == "point":
return (f'<svg viewBox="0 0 110 30" width="{size}" height="30">'
'<circle cx="55" cy="15" r="4" fill="#333"/></svg>')
return ''
def angle_svg(degrees, size=60, show_square=False):
"""Draw an angle: one horizontal ray + one ray at 'degrees' above it."""
import math as _m
rad = _m.radians(degrees)
x2 = 10 + 45 * _m.cos(rad)
y2 = 50 - 45 * _m.sin(rad)
sq = ''
if show_square:
sq = '<rect x="10" y="38" width="12" height="12" fill="none" stroke="#e53935" stroke-width="1.5"/>'
return (f'<svg viewBox="0 0 60 60" width="{size}" height="{size}">'
f'<line x1="10" y1="50" x2="58" y2="50" stroke="#333" stroke-width="2"/>'
f'<line x1="10" y1="50" x2="{x2:.1f}" y2="{y2:.1f}" stroke="#333" stroke-width="2"/>'
f'{sq}<circle cx="10" cy="50" r="2.5" fill="#333"/></svg>')
def sym_shape_svg(shape, size=56, with_line=False):
"""Shapes for symmetry work, optionally with a dashed symmetry line."""
dash = f'<line x1="28" y1="4" x2="28" y2="52" stroke="{RED}" stroke-width="1.5" stroke-dasharray="4,3"/>' if with_line else ''
shapes = {
"heart": '<path d="M28 48 C10 34 6 20 14 13 C20 8 27 11 28 17 C29 11 36 8 42 13 C50 20 46 34 28 48 Z" fill="#f8bbd0" stroke="#333" stroke-width="1.5"/>',
"triangle": f'<polygon points="28,6 50,50 6,50" fill="{GREEN}" opacity="0.5" stroke="#333" stroke-width="1.5"/>',
"square": f'<rect x="8" y="8" width="40" height="40" fill="{BLUE}" opacity="0.5" stroke="#333" stroke-width="1.5"/>',
"circle": f'<circle cx="28" cy="28" r="21" fill="#ffe082" stroke="#333" stroke-width="1.5"/>',
"arrow": '<polygon points="28,6 46,26 36,26 36,50 20,50 20,26 10,26" fill="#b39ddb" stroke="#333" stroke-width="1.5"/>',
"rectangle": f'<rect x="6" y="16" width="44" height="24" fill="{BLUE}" opacity="0.5" stroke="#333" stroke-width="1.5"/>',
"letterT": '<path d="M10 8 H46 V18 H33 V50 H23 V18 H10 Z" fill="#80cbc4" stroke="#333" stroke-width="1.5"/>',
"letterF": '<path d="M16 8 H44 V17 H26 V25 H40 V34 H26 V50 H16 Z" fill="#ffab91" stroke="#333" stroke-width="1.5"/>',
}
return (f'<svg viewBox="0 0 56 56" width="{size}" height="{size}">'
f'{shapes.get(shape, "")}{dash}</svg>')
# ═══════════════════════════════════════════════════
# MONDAY — Points, Lines, Segments & Rays
# ═══════════════════════════════════════════════════
def monday():
# 1: Warm-up — geometry vocabulary matching
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Warm-up</b> — Look at each picture. Circle the correct name.</p>'\
'<div class="mgrid c2">'
for kind, opts in [("point", "point / line"), ("segment", "line segment / ray"),
("ray", "ray / line segment"), ("line", "line / point")]:
s1 += f'<div class="abox" style="text-align:center;">{line_svg(kind)}<p>{opts}</p></div>'
s1 += '</div></div>'
# 2: Learn the four ideas (guided examples)
s2 = '<p class="note">Geometry starts with these four ideas. Trace each one with your finger, then copy it in the box.</p>'
s2 += '<table class="tbl">'
s2 += '<tr><th>Name</th><th>Picture</th><th>What it means</th><th>Draw your own</th></tr>'
rows = [
("Point", "point", "An exact spot. Just a dot!"),
("Line segment", "segment", "Straight path with TWO endpoints."),
("Ray", "ray", "Starts at a point, goes on forever one way."),
("Line", "line", "Goes on forever BOTH ways."),
]
for name, kind, meaning in rows:
s2 += f'<tr><td><b>{name}</b></td><td style="text-align:center;">{line_svg(kind)}</td>'\
f'<td style="font-size:11px;">{meaning}</td>'\
'<td><div style="min-height:34px; min-width:100px;"></div></td></tr>'
s2 += '</table>'
# 3: Identify — reduced from 8 to 5
s3 = '<p class="note">Write <b>point</b>, <b>line segment</b>, <b>ray</b>, or <b>line</b>.</p>'\
'<div class="mgrid c3">'
for kind in ["ray", "segment", "point", "line", "segment"]:
s3 += f'<div class="abox" style="text-align:center;">{line_svg(kind, 90)}<p>{b("7em")}</p></div>'
s3 += '</div>'
# 4: Number Talk — Explain WITHOUT drawing or measuring
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> — Explain WITHOUT calculating or measuring.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>Maya says a line segment is LONGER than a line because you can see both ends. Is she right?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>How is a ray like a flashlight beam? How is it different from a line segment?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Challenge — Show two different ways
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Challenge</b> — Show two different ways to make the letter <b>A</b> using ONLY line segments.</p>'\
'<p style="font-size:11px; color:#666;">Count how many segments each way uses.</p>'\
'<div class="mgrid c2">'
for i in [1, 2]:
s5 += f'<div class="abox"><p><b>Way {i}</b></p>'\
'<div style="min-height:80px; border:1px dashed #999; border-radius:4px;"></div>'\
'<p style="font-size:11px;">Segments used: ' + b("3em") + '</p></div>'
s5 += '</div></div>'
return page(23, "Monday", "Points, Lines, Segments & Rays",
f'''{sec(1, "Warm-up: Name That Picture", s1)}
{sec(2, "Learn: The Four Building Blocks of Geometry", s2)}
{sec(3, "Identify Each One", s3)}
{sec(4, "Number Talk: Think It Through", s4)}
{sec(5, "Challenge: Two Ways to Build a Letter", s5)}''')
# ═══════════════════════════════════════════════════
# TUESDAY — Right Angles
# ═══════════════════════════════════════════════════
def tuesday():
# 1: Warm-up — quick vocabulary review
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Warm-up</b> — True or False? Circle one.</p>'\
'<div class="mgrid c2">'
for stmt in ["A line segment has 2 endpoints. T / F",
"A ray goes on forever in both directions. T / F",
"A point shows an exact spot. T / F",
"A line has 2 endpoints. T / F"]:
s1 += f'<div class="abox"><p>{stmt}</p></div>'
s1 += '</div></div>'
# 2: Learn — What is a right angle?
s2 = '<p class="note">A <b>right angle</b> makes a perfect square corner — like the corner of a book or a door. '\
'We mark right angles with a small square. □</p>'
s2 += '<div class="mgrid c3">'
s2 += f'<div class="abox" style="text-align:center;">{angle_svg(90, show_square=True)}<p style="font-size:11px;"><b>Right angle</b><br>(square corner)</p></div>'
s2 += f'<div class="abox" style="text-align:center;">{angle_svg(45)}<p style="font-size:11px;"><b>Smaller</b> than a right angle</p></div>'
s2 += f'<div class="abox" style="text-align:center;">{angle_svg(135)}<p style="font-size:11px;"><b>Bigger</b> than a right angle</p></div>'
s2 += '</div>'
# 3: Estimate First! — is it a right angle? (before checking with a corner)
s3 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Look with just your eyes: is each angle a right angle? '\
'Write your estimate, THEN check with the corner of an index card.</p>'\
'<div class="mgrid c2">'
# reduced from 6 to 4 angles
for deg in [90, 60, 110, 90]:
s3 += f'<div class="abox" style="text-align:center;">{angle_svg(deg)}'\
f'<p style="font-size:11px;">My estimate (yes/no): {b("3em")}</p>'\
f'<p style="font-size:11px;">Card check (yes/no): {b("3em")}</p></div>'
s3 += '</div></div>'
# 4: Count the right angles in shapes — reduced from 6 to 4
s4 = '<p class="note">How many right angles does each shape have? Mark each one with a small □.</p>'\
'<div class="mgrid c2">'
for name, kind in [("Square", "square"), ("Rectangle", "rectangle"),
("Triangle", "triangle"), ("Circle", "circle")]:
s4 += f'<div class="abox" style="text-align:center;">{shape_svg(kind, size=44)}'\
f'<p><b>{name}</b></p><p>{b("3em")} right angles</p></div>'
s4 += '</div>'
# 5: Strategy — two different ways to check an angle
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Two Ways to Check</b> — Show two different ways to test if the corner of your desk is a right angle.</p>'\
'<p style="font-size:11px; color:#666;">Ideas: corner of paper, corner of a book, fold a circle twice...</p>'\
'<p style="font-size:11px;">Strategy 1: ' + bw() + '</p>'\
'<p style="font-size:11px;">Strategy 2: ' + bw() + '</p>'\
'<p>Was it a right angle? ' + b("4em") + '</p></div>'
return page(23, "Tuesday", "Right Angles: Square Corners",
f'''{sec(1, "Warm-up: True or False", s1)}
{sec(2, "Learn: The Right Angle", s2)}
{sec(3, "Estimate First! Right Angle or Not?", s3)}
{sec(4, "Count Right Angles in Shapes", s4)}
{sec(5, "Two Ways to Check an Angle", s5)}''')
# ═══════════════════════════════════════════════════
# WEDNESDAY — Lines of Symmetry
# ═══════════════════════════════════════════════════
def wednesday():
# 1: Warm-up — right angle hunt
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Warm-up</b> — Room hunt! Find 3 right angles in your room and write where you found them.</p>'\
'<p>1. ' + bw() + '</p><p>2. ' + bw() + '</p><p>3. ' + bw() + '</p></div>'
# 2: Learn — symmetry
s2 = '<p class="note">A shape has <b>symmetry</b> when you can fold it and both halves match exactly. '\
'The fold line is called a <b>line of symmetry</b>.</p>'
s2 += '<div class="mgrid c3">'
s2 += f'<div class="abox" style="text-align:center;">{sym_shape_svg("heart", with_line=True)}<p style="font-size:11px;">The heart folds into two matching halves. ✓</p></div>'
s2 += f'<div class="abox" style="text-align:center;">{sym_shape_svg("letterT", with_line=True)}<p style="font-size:11px;">The letter T matches too. ✓</p></div>'
s2 += f'<div class="abox" style="text-align:center;">{sym_shape_svg("letterF", with_line=True)}<p style="font-size:11px;">The letter F does NOT match! ✗</p></div>'
s2 += '</div>'
# 3: Draw the lines of symmetry — reduced from 8 to 5
s3 = '<p class="note">Draw ALL the lines of symmetry you can find. Then write how many.</p>'\
'<div class="mgrid c3">'
for name, shape, _lines in [("Heart", "heart", 1), ("Square", "square", 4),
("Triangle", "triangle", 3), ("Rectangle", "rectangle", 2),
("Arrow", "arrow", 1)]:
s3 += f'<div class="abox" style="text-align:center;">{sym_shape_svg(shape)}'\
f'<p style="font-size:11px;"><b>{name}</b></p><p>{b("3em")} line(s)</p></div>'
s3 += '</div>'
# 4: Word problems — reasoning about symmetry
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening. Draw if it helps!</p>'\
'<div class="mgrid c2">'
problems = [
"Rosa folds a paper heart in half and both sides match perfectly. Then she folds it the other way (side to side) and the halves do NOT match. How many lines of symmetry does her heart have?",
"Ben says a circle has only 4 lines of symmetry: up-down, side-side, and two diagonal. His sister says there are MANY more. Who is right, and why?",
]
for text in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Answer: ' + b("6em") + '</p></div>'
s4 += '</div></div>'
# 5: Challenge — Create Your Own symmetric design
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own</b> — The dashed line is a line of symmetry. '\
'Draw a design on the LEFT side, then draw its mirror image on the RIGHT side.</p>'\
'<div style="display:flex; justify-content:center;">'\
'<div style="min-height:110px; width:45%; border:1px solid #999; border-right:2px dashed #e53935;"></div>'\
'<div style="min-height:110px; width:45%; border:1px solid #999; border-left:none;"></div>'\
'</div>'\
'<p style="font-size:11px; color:#666;">Check: fold your paper on the dashed line. Do the halves match?</p></div>'
return page(23, "Wednesday", "Lines of Symmetry",
f'''{sec(1, "Warm-up: Right Angle Hunt", s1)}
{sec(2, "Learn: What is Symmetry?", s2)}
{sec(3, "Draw the Lines of Symmetry", s3)}
{sec(4, "Word Problems: Symmetry Thinking", s4)}
{sec(5, "Challenge: Create Your Own Mirror Design", s5)}''')
# ═══════════════════════════════════════════════════
# THURSDAY — Geometry in the Real World
# ═══════════════════════════════════════════════════
def thursday():
# 1: Warm-up — symmetric or not?
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Warm-up</b> — Does each shape have symmetry? Circle YES or NO.</p>'\
'<div class="mgrid c3">'
for shape in ["heart", "letterF", "square"]:
s1 += f'<div class="abox" style="text-align:center;">{sym_shape_svg(shape, size=48)}<p>YES / NO</p></div>'
s1 += '</div></div>'
# 2: Word problems — reasoning, not keywords (reduced from 4 to 3)
s2 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening in the situation. Draw if it helps!</p>'\
'<div class="mgrid c2">'
problems = [
("A stop sign has 8 sides that are all the same length. Amir traces one side with his finger. Is that side a line, a ray, or a line segment? How do you know?", "line segment"),
("Kayla cuts a square sandwich along ONE line of symmetry. What two shapes could she get? (Hint: there are two different answers!)", "rectangles or triangles"),
("A kite has exactly 1 line of symmetry. Dad folds it on that line to pack it. Will the two halves match? Explain.", "yes"),
]
for text, _ans in problems:
s2 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Answer: ' + bw() + '</p></div>'
s2 += '</div></div>'
# 3: Partition shapes into equal shares (2.G.A.3)
s3 = '<p class="note">Use straight line segments to split each shape into <b>equal shares</b>.</p>'\
'<div class="mgrid c3">'
tasks = [("Split into 2 equal halves", "square"), ("Split into 4 equal fourths", "square"),
("Split into 2 equal halves", "circle")]
for label, shape in tasks:
s3 += f'<div class="abox" style="text-align:center;">{sym_shape_svg(shape, size=64)}'\
f'<p style="font-size:11px;">{label}</p></div>'
s3 += '</div>'
# 4: Number Talk — Explain WITHOUT calculating
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> — Explain WITHOUT calculating or counting one by one.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>A square is cut into 4 equal fourths. Jon takes 2 fourths. Ava takes half. Who has more, or is it the same?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>Which has MORE right angles: one square, or two triangles like the one on Tuesday\'s page? How could you decide quickly?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Create Your Own word problem
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own Word Problem</b></p>'\
'<p>Write a geometry question about something in your house (window, table, pizza, flag...). '\
'It should use one of this week\'s words: <b>line segment, right angle,</b> or <b>symmetry</b>. Then answer it.</p>'\
'<p style="min-height:60px; border-bottom:1px solid #333;"></p>'\
'<p style="min-height:30px; border-bottom:1px solid #333;"></p>'\
'<p>Answer: ' + bl() + '</p></div>'
return page(23, "Thursday", "Geometry in the Real World",
f'''{sec(1, "Warm-up: Symmetry Yes or No", s1)}
{sec(2, "Word Problems: Think About What Is Happening", s2)}
{sec(3, "Equal Shares: Halves and Fourths", s3)}
{sec(4, "Number Talk: Compare Without Counting", s4)}
{sec(5, "Challenge: Create Your Own", s5)}''')
# ═══════════════════════════════════════════════════
# FRIDAY — Review & Self-Check
# ═══════════════════════════════════════════════════
def friday():
# 1: Warm-up — mixed vocabulary
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Warm-up</b> — Match! Write the letter next to each picture: '\
'<b>A</b> = line, <b>B</b> = ray, <b>C</b> = line segment, <b>D</b> = right angle.</p>'\
'<div class="mgrid c2">'
for kind in ["segment", "line", "ray"]:
s1 += f'<div class="abox" style="text-align:center;">{line_svg(kind, 90)}<p>{b("3em")}</p></div>'
s1 += f'<div class="abox" style="text-align:center;">{angle_svg(90, show_square=True, size=44)}<p>{b("3em")}</p></div>'
s1 += '</div></div>'
# 2: Estimate First! — lines of symmetry
s2 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Guess how many lines of symmetry each shape has just by looking. '\
'THEN test by drawing (or imagining the fold).</p>'\
'<div class="mgrid c2">'
for name, shape in [("Square", "square"), ("Heart", "heart"),
("Rectangle", "rectangle"), ("Triangle", "triangle")]:
s2 += f'<div class="abox" style="text-align:center;">{sym_shape_svg(shape, size=48)}'\
f'<p style="font-size:11px;"><b>{name}</b></p>'\
f'<p style="font-size:11px;">Estimate: {b("3em")}</p>'\
f'<p style="font-size:11px;">Actual: {b("3em")}</p></div>'
s2 += '</div></div>'
# 3: Mixed review — reduced from 8 to 4
s3 = '<p class="note">Use any strategy you like.</p>'\
'<div class="mgrid c2">'
s3 += f'<div class="abox" style="text-align:center;">{line_svg("ray", 90)}<p>This is a {b("6em")}</p></div>'
s3 += f'<div class="abox" style="text-align:center;">{angle_svg(90, show_square=True, size=44)}<p>This angle is a {b("6em")} angle</p></div>'
s3 += f'<div class="abox" style="text-align:center;">{shape_svg("rectangle", size=40)}<p>A rectangle has {b("3em")} right angles</p></div>'
s3 += f'<div class="abox" style="text-align:center;">{sym_shape_svg("heart", size=44)}<p>A heart has {b("3em")} line(s) of symmetry</p></div>'
s3 += '</div>'
# 4: Word problem review
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Show your thinking.</p>'\
'<div class="mgrid c2">'
problems = [
"Leo draws a shape with 4 sides, 4 right angles, and 4 lines of symmetry. What shape did he draw?",
"Mia splits a rectangle brownie into 4 equal fourths with 2 straight cuts. Draw one way she could cut it.",
]
for text in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Answer: ' + b("6em") + '</p></div>'
s4 += '</div></div>'
# 5: Self-check with emoji reflection
s5 = '<div class="selfcheck">'\
'<p><b>Self-Check: How do you feel about this week\'s geometry?</b></p>'\
'<div style="display:flex; gap:20px; flex-wrap:wrap;">'\
'<div style="background:#fff3e0; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Lines, Segments & Rays</b></p>'\
'<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'\
'</div>'\
'<div style="background:#e3f2fd; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Right Angles</b></p>'\
'<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'\
'</div>'\
'<div style="background:#f3e5f5; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Lines of Symmetry</b></p>'\
'<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'\
'</div>'\
'</div>'\
'<p style="margin-top:10px;"><b>One thing I learned this week:</b> ' + bl() + '</p>'\
'<p><b>One thing I want to practice more:</b> ' + bl() + '</p>'\
'<p><b>The coolest symmetric thing I found in my house:</b> ' + bl() + '</p>'\
'</div>'
return page(23, "Friday", "Week 23 Review & Self-Check",
f'''{sec(1, "Warm-up: Match the Pictures", s1)}
{sec(2, "Estimate First! Lines of Symmetry", s2)}
{sec(3, "Mixed Review", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Self-Check & Reflection", s5)}''')
# ═══════════════════════════════════════════════════
# TEACHER GUIDE
# ═══════════════════════════════════════════════════
def teacher_guide():
return tg_page_multi(
"Week 23", "Lines, Angles & Symmetry — Teacher Guide",
tg_section_title("Monday: Points, Lines, Segments & Rays") +
tg_sec(1, "Warm-up", ["point, line segment, ray, line"]) +
tg_sec(2, "Learn Table", ["Student copies each figure — check endpoints/arrows drawn correctly"]) +
tg_sec(3, "Identify", ["ray, line segment, point, line, line segment"]) +
tg_sec(4, "Number Talk", ["Maya is wrong — a line goes on forever so it is longer; we just can't draw all of it",
"Ray: starts at one point, shines on forever; segment stops at both ends"]) +
tg_sec(5, "Challenge", ["Letter A: usually 3 segments; accept any correct construction, compare counts"]) +
tg_note("Page break"),
tg_section_title("Tuesday: Right Angles") +
tg_sec(1, "Warm-up", ["T, F, T, F"]) +
tg_sec(2, "Learn", ["Point out square-corner mark □"]) +
tg_sec(3, "Estimate First", ["yes (90°), no (60°), no (110°), yes (90°) — praise honest estimates"]) +
tg_sec(4, "Right Angles in Shapes", ["Square: 4, Rectangle: 4, Triangle: 0 (this one), Circle: 0"]) +
tg_sec(5, "Two Ways", ["Any two: paper corner, book corner, folded circle, index card"]) +
tg_note("Page break"),
tg_section_title("Wednesday: Lines of Symmetry") +
tg_sec(1, "Warm-up", ["Any 3 right angles: door, window, book, table corner..."]) +
tg_sec(2, "Learn", ["Emphasize FOLD test — both halves match exactly"]) +
tg_sec(3, "Draw Lines", ["Heart: 1, Square: 4, Triangle (equilateral): 3, Rectangle: 2, Arrow: 1"]) +
tg_sec(4, "Word Problems", ["Rosa's heart: 1 line of symmetry",
"Sister is right — a circle has endless lines of symmetry (every line through the center)"]) +
tg_sec(5, "Create Own", ["Fold test should show matching halves"]) +
tg_note("Page break"),
tg_section_title("Thursday: Geometry in the Real World") +
tg_sec(1, "Warm-up", ["YES (heart), NO (letter F), YES (square)"]) +
tg_sec(2, "Word Problems", ["Line segment — it has two endpoints (the corners)",
"Two rectangles (cut through middles) OR two triangles (cut corner to corner)",
"Yes — that is exactly what a line of symmetry means"]) +
tg_sec(3, "Equal Shares", ["Halves: 1 cut through middle; Fourths: 2 cuts; Circle halves: 1 cut through center"]) +
tg_sec(4, "Number Talk", ["Same! 2 fourths = 1 half", "Square has 4; two right triangles have 1 each = 2, so the square"]) +
tg_sec(5, "Create Own", ["Accept any problem using the week's vocabulary"]) +
tg_note("Page break"),
tg_section_title("Friday: Review & Self-Check") +
tg_sec(1, "Warm-up", ["C, A, B, D"]) +
tg_sec(2, "Estimate First", ["Square: 4, Heart: 1, Rectangle: 2, Triangle: 3"]) +
tg_sec(3, "Mixed Review", ["ray, right, 4, 1"]) +
tg_sec(4, "Word Problems", ["A square", "One vertical + one horizontal cut (cross pattern) makes 4 equal fourths; accept the two-diagonals X pattern too"]) +
tg_sec(5, "Self-Check", ["Accept student self-assessment and reflection"])
)
# ═══════════════════════════════════════════════════
# GENERATE
# ═══════════════════════════════════════════════════
if __name__ == "__main__":
os.makedirs(WEEK, exist_ok=True)
for f in glob.glob(os.path.join(WEEK, "*.pdf")):
os.remove(f)
for f in glob.glob(os.path.join(WEEK, "*.html")):
os.remove(f)
days = [
(monday, "Monday"),
(tuesday, "Tuesday"),
(wednesday, "Wednesday"),
(thursday, "Thursday"),
(friday, "Friday"),
]
for lesson_func, day in days:
html = lesson_func()
fname = f"Week_23_{day}"
path = os.path.join(WEEK, f"{fname}.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, f"{fname}.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
html = teacher_guide()
path = os.path.join(WEEK, "Week_23_Teacher_Guide.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, "Week_23_Teacher_Guide.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
print("\nWeek 23 (Lines, Angles & Symmetry — new standard) complete!")