#!/usr/bin/env python3
"""
Week 22: 3D Shapes
Phase 4: Geometry & Fractions
Standards: 2.G.A.1 (identify 3D shapes; faces, edges, vertices;
nets; real-world examples; compare 2D and 3D)
New Standard:
- Reduced drill (40% fewer problems)
- Estimation before counting ("Estimate First!" โ guess faces/edges before counting)
- Multiple strategies (two ways to count/describe solids)
- Better word problems (reasoning, real-world scenarios)
- Open-ended challenges (Create Your Own solids/riddles)
- Number talks (reason about solids WITHOUT counting)
- Friday self-check with emoji reflection
- Fact fluency warmup daily
- Word problems every day
"""
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,
)
from activity_builders import (
build_challenge_box,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_22")
BLUE = "#4a90d9"
GREEN = "#5cb85c"
RED = "#d9534f"
ORANGE = "#f0ad4e"
PURPLE = "#9b59b6"
# โโ Custom 3D shape SVGs (no 3D builders exist in activity_builders.py) โโ
def cube_svg(color=BLUE, size=54):
return (f'<svg viewBox="0 0 54 54" width="{size}" height="{size}">'
f'<polygon points="8,16 34,16 34,42 8,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.55"/>'
f'<polygon points="8,16 20,6 46,6 34,16" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.75"/>'
f'<polygon points="34,16 46,6 46,32 34,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.4"/>'
f'</svg>')
def rect_prism_svg(color=GREEN, size=58):
return (f'<svg viewBox="0 0 66 48" width="{size+8}" height="{size-10}">'
f'<polygon points="4,16 44,16 44,42 4,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.55"/>'
f'<polygon points="4,16 16,6 56,6 44,16" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.75"/>'
f'<polygon points="44,16 56,6 56,32 44,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.4"/>'
f'</svg>')
def sphere_svg(color=RED, size=50):
return (f'<svg viewBox="0 0 50 50" width="{size}" height="{size}">'
f'<circle cx="25" cy="25" r="20" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.55"/>'
f'<ellipse cx="25" cy="25" rx="20" ry="7" fill="none" stroke="#333" stroke-width="1" stroke-dasharray="3,2" opacity="0.6"/>'
f'</svg>')
def cone_svg(color=ORANGE, size=50):
return (f'<svg viewBox="0 0 50 54" width="{size}" height="{size}">'
f'<polygon points="25,4 45,42 5,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.55"/>'
f'<ellipse cx="25" cy="42" rx="20" ry="7" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.7"/>'
f'</svg>')
def cylinder_svg(color=PURPLE, size=50):
return (f'<svg viewBox="0 0 44 54" width="{size-6}" height="{size}">'
f'<rect x="4" y="10" width="36" height="34" fill="{color}" stroke="none" opacity="0.55"/>'
f'<ellipse cx="22" cy="44" rx="18" ry="7" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.7"/>'
f'<line x1="4" y1="10" x2="4" y2="44" stroke="#333" stroke-width="1.5"/>'
f'<line x1="40" y1="10" x2="40" y2="44" stroke="#333" stroke-width="1.5"/>'
f'<ellipse cx="22" cy="10" rx="18" ry="7" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.85"/>'
f'</svg>')
def pyramid_svg(color=RED, size=52):
return (f'<svg viewBox="0 0 54 50" width="{size}" height="{size-4}">'
f'<polygon points="27,4 50,42 12,42" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.6"/>'
f'<polygon points="27,4 12,42 4,34" fill="{color}" stroke="#333" stroke-width="1.5" opacity="0.4"/>'
f'</svg>')
def cube_net_svg(color=BLUE, size=70):
"""Cross-shaped net of a cube."""
c, s = color, 16
cells = [(1, 0), (0, 1), (1, 1), (2, 1), (1, 2), (1, 3)]
rects = ''.join(
f'<rect x="{x*s+2}" y="{y*s+2}" width="{s}" height="{s}" fill="{c}" '
f'stroke="#333" stroke-width="1" opacity="0.5"/>' for x, y in cells)
return f'<svg viewBox="0 0 52 68" width="{size-14}" height="{size}">{rects}</svg>'
def cylinder_net_svg(color=PURPLE, size=70):
"""Net of a cylinder: rectangle + two circles."""
return (f'<svg viewBox="0 0 60 66" width="{size-10}" height="{size}">'
f'<circle cx="30" cy="10" r="8" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<rect x="8" y="20" width="44" height="26" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<circle cx="30" cy="56" r="8" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'</svg>')
def pyramid_net_svg(color=RED, size=70):
"""Net of a square pyramid: square + 4 triangles."""
return (f'<svg viewBox="0 0 64 64" width="{size}" height="{size}">'
f'<rect x="22" y="22" width="20" height="20" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<polygon points="22,22 42,22 32,4" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<polygon points="22,42 42,42 32,60" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<polygon points="22,22 22,42 4,32" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'<polygon points="42,22 42,42 60,32" fill="{color}" stroke="#333" stroke-width="1" opacity="0.5"/>'
f'</svg>')
SOLIDS = {
"cube": cube_svg,
"rectangular prism": rect_prism_svg,
"sphere": sphere_svg,
"cone": cone_svg,
"cylinder": cylinder_svg,
"pyramid": pyramid_svg,
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# MONDAY โ Meet the 3D Shapes
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def monday():
# 1: Fluency warmup โ 2D review (bridge from Week 21)
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Quick 2D review from last week!</p>'\
'<div class="mgrid c2">'
s1 += f'<div class="abox"><p>Sides on a square: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Vertices on a triangle: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Sides on a hexagon: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>A 5-sided polygon is a: {b("7em")}</p></div>'
s1 += '</div></div>'
# 2: New concept โ 2D is flat, 3D is solid; meet the solids
s2 = '<p class="note"><b>2D shapes are flat</b> โ they live on paper. '\
'<b>3D shapes are solid</b> โ you can hold them! Meet the six solids:</p>'\
'<div class="mgrid c3">'
for name in ["cube", "rectangular prism", "sphere", "cone", "cylinder", "pyramid"]:
s2 += f'<div class="abox" style="text-align:center;">{SOLIDS[name](size=48)}'\
f'<p><b>{name.title()}</b></p></div>'
s2 += '</div>'
# 3: Name the solid (reduced from 8 to 5)
s3 = '<p class="note">Write the name of each solid. Use the word bank: '\
'cube, sphere, cone, cylinder, pyramid.</p>'\
'<div class="mgrid c3">'
for name in ["cone", "cube", "sphere", "pyramid", "cylinder"]:
s3 += f'<div class="abox" style="text-align:center;">{SOLIDS[name](size=46)}'\
f'<p>{b("7em")}</p></div>'
s3 += '</div>'
# 4: NEW โ Number Talk
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> โ Explain WITHOUT touching or counting.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>A sphere can roll but a cube cannot. What about their shapes '\
'makes this true?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>Is a circle the same as a sphere? Explain the difference '\
'between flat and solid.</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Word problem
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening.</p>'\
'<div class="abox"><p>Theo is packing a box with blocks. He has 4 cubes, 3 cylinders, '\
'and 2 cones. How many solids that can ROLL does he have? '\
'(Hint: which of these solids have a curved surface?)</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>' + b("3em") + ' rolling solids</p></div></div>'
return page(22, "Monday", "Meet the 3D Shapes",
f'''{sec(1, "Warm-up: 2D Review", s1)}
{sec(2, "Flat vs. Solid: The Six Solids", s2)}
{sec(3, "Name That Solid", s3)}
{sec(4, "Number Talk: Roll or Not?", s4)}
{sec(5, "Word Problem", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TUESDAY โ Faces, Edges & Vertices
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def tuesday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Name that solid, fast!</p>'\
'<div class="mgrid c2">'
clues = [
"I look like a ball:",
"I look like a dice:",
"I look like a can:",
"I look like a party hat:",
]
for c in clues:
s1 += f'<div class="abox"><p>{c} {b("6em")}</p></div>'
s1 += '</div></div>'
# 2: New words โ faces, edges, vertices with guided example
s2 = '<p class="note">Solids have three things we can count:<br>'\
'โข <b>Faces</b> โ the flat sides<br>'\
'โข <b>Edges</b> โ where two faces meet<br>'\
'โข <b>Vertices</b> โ the pointy corners</p>'
s2 += f'<div class="abox"><p style="text-align:center;">{cube_svg(BLUE, 64)}</p>'\
'<p style="text-align:center;">A cube has <b>6 faces</b>, <b>12 edges</b>, and '\
'<b>8 vertices</b>. Grab a dice or a block and touch each one as you count!</p></div>'
# 3: NEW โ Estimate First!
s3 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Before counting, GUESS how many faces each solid has. '\
'Then count with a real object if you can.</p>'\
'<div class="mgrid c2">'
for name in ["rectangular prism", "pyramid"]:
s3 += f'<div class="abox" style="text-align:center;">{SOLIDS[name](size=50)}'\
f'<p><b>{name.title()}</b></p>'\
f'<p>My guess: {b("3em")} Actual: {b("3em")}</p></div>'
s3 += '</div></div>'
# 4: Count faces, edges, vertices (reduced from 6 to 4)
s4 = '<p class="note">Fill in the table. Touch and count slowly โ edges are the trickiest!</p>'
s4 += '<table class="tbl"><tr><th>Solid</th><th>Picture</th><th>Faces</th><th>Edges</th><th>Vertices</th></tr>'
rows = [
("Cube", "cube"),
("Rectangular Prism", "rectangular prism"),
("Pyramid", "pyramid"),
("Sphere", "sphere"),
]
for label, key in rows:
s4 += f'<tr><td>{label}</td><td style="text-align:center;">{SOLIDS[key](size=36)}</td>'\
f'<td>{b("3em")}</td><td>{b("3em")}</td><td>{b("3em")}</td></tr>'
s4 += '</table>'
# 5: Word problem
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Draw if it helps!</p>'\
'<div class="abox"><p>Zara paints one sticker on every face of a cube. '\
'Stickers come in packs of 4. How many packs does she need to cover all the faces? '\
'Will she have any stickers left over?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>Packs: ' + b("3em") + ' Left over: ' + b("3em") + '</p></div></div>'
return page(22, "Tuesday", "Faces, Edges & Vertices",
f'''{sec(1, "Warm-up: Solid Riddles", s1)}
{sec(2, "New Words: Faces, Edges, Vertices", s2)}
{sec(3, "Estimate First: How Many Faces?", s3)}
{sec(4, "Count Faces, Edges & Vertices", s4)}
{sec(5, "Word Problem", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# WEDNESDAY โ Nets & Building Solids
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def wednesday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Faces in a flash!</p>'\
'<div class="mgrid c2">'
s1 += f'<div class="abox"><p>Faces on a cube: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Vertices on a cube: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Faces on a sphere: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Vertices on a cone: {b("3em")}</p></div>'
s1 += '</div></div>'
# 2: What is a net? Match nets to solids (reduced from 5 to 3)
s2 = '<p class="note">A <b>net</b> is a solid unfolded flat โ like unwrapping a box! '\
'Draw a line from each net to the solid it folds into.</p>'\
'<div class="mgrid c2">'
s2 += f'<div class="abox" style="text-align:center;"><p><b>Nets</b></p>'\
f'{cube_net_svg()} {cylinder_net_svg()} {pyramid_net_svg()}</div>'
s2 += f'<div class="abox" style="text-align:center;"><p><b>Solids</b></p>'\
f'{pyramid_svg(size=44)} {cube_svg(size=44)} {cylinder_svg(size=44)}</div>'
s2 += '</div>'
# 3: Reason about nets โ which faces? (two strategies)
s3 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Show Two Different Ways</b> โ How can you tell the cross-shaped net folds into '\
'a cube and NOT a pyramid?</p>'\
'<p style="font-size:11px; color:#666;">Ideas: count the faces in the net; look at the SHAPE of each face.</p>'\
'<p>Way 1: ' + bl() + '</p>'\
'<p>Way 2: ' + bl() + '</p></div>'
# 4: Word problems (reduced from 3 to 2)
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>A cereal box is a rectangular prism. Kim unfolds it flat to '\
'recycle it. How many rectangle faces will she see in the flattened box?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>' + b("3em") + ' faces</p></div>'
s4 += '<div class="abox"><p>A pyramid net has 1 square and 4 triangles. If Ben cuts out '\
'3 pyramid nets, how many triangles does he cut in all?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>' + b("3em") + ' triangles</p></div>'
s4 += '</div></div>'
# 5: Challenge โ Create your own
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own Net</b></p>'\
'<p>Try to draw a net for a cube that is DIFFERENT from the cross shape above. '\
'(There are 11 different cube nets!) Remember: exactly 6 squares.</p>'\
'<p style="min-height:100px; border:1px dashed #999; border-radius:4px;"></p>'\
'<p style="font-size:11px;">Bonus: cut it out and try folding it. Did it work? ' + bw() + '</p></div>'
return page(22, "Wednesday", "Nets: Unfolding Solids",
f'''{sec(1, "Warm-up: Face Facts", s1)}
{sec(2, "Match Nets to Solids", s2)}
{sec(3, "Show Two Different Ways", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Challenge: Create Your Own Net", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# THURSDAY โ 3D Shapes in the Real World
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def thursday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Solid math in your head.</p>'\
'<div class="mgrid c2">'
s1 += f'<div class="abox"><p>Faces on 2 cubes: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Vertices on 2 pyramids: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Faces on a cube + a pyramid: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Edges on a cube โ edges on a pyramid: {b("3em")}</p></div>'
s1 += '</div></div>'
# 2: Real-world matching (reduced from 8 to 5)
s2 = '<p class="note">Solids are everywhere! Write which solid each object looks like.</p>'\
'<div class="mgrid c2">'
objects = [
"A basketball", "A soup can", "An ice cream cone",
"A tissue box", "The Great Pyramid in Egypt",
]
for obj in objects:
s2 += f'<div class="abox"><p>{obj} = {b("8em")}</p></div>'
s2 += '</div>'
# 3: Compare 2D and 3D
s3 = '<p class="note">2D and 3D shapes are related! The faces of solids are 2D shapes.</p>'\
'<div class="mgrid c2">'
pairs = [
("What 2D shape are the faces of a cube?", "square"),
("What 2D shape is the flat face of a cone?", "circle"),
("What 2D shapes make a pyramid's faces?", "square + triangles"),
("What 2D shape do you see at the ends of a cylinder?", "circle"),
]
for q, _ in pairs:
s3 += f'<div class="abox"><p>{q}</p><p>{b("7em")}</p></div>'
s3 += '</div>'
# 4: NEW โ Number Talk
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> โ Explain WITHOUT counting.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>A cube and a rectangular prism have the same number of faces, '\
'edges, and vertices. Why do you think that is?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>Which would stack better in a cupboard: cans (cylinders) or '\
'balls (spheres)? Explain using faces and curves.</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Word problem + create your own
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Then create your own!</p>'\
'<div class="abox"><p>A grocery store stacks 5 soup cans in a row. Each can has 2 circle '\
'faces (top and bottom). How many circle faces are in the whole row?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>' + b("3em") + ' circle faces</p></div>'\
'<div class="abox" style="background:#f3e5f5; margin-top:8px;">'\
'<p><b>Create Your Own</b> โ Go on a 3D shape hunt in your house! '\
'Find one real object for each solid and write it down.</p>'\
'<p>Cube: ' + bw() + ' Sphere: ' + bw() + '</p>'\
'<p>Cylinder: ' + bw() + ' Cone or Pyramid: ' + bw() + '</p></div></div>'
return page(22, "Thursday", "3D Shapes in the Real World",
f'''{sec(1, "Warm-up: Solid Math", s1)}
{sec(2, "Real-World Solids", s2)}
{sec(3, "Compare 2D and 3D", s3)}
{sec(4, "Number Talk: Reason About Solids", s4)}
{sec(5, "Word Problem & Shape Hunt", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# FRIDAY โ Review & Self-Check
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def friday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Go fast!</p>'\
'<div class="mgrid c2">'
s1 += f'<div class="abox"><p>Faces on a cube: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>A ball is shaped like a: {b("6em")}</p></div>'
s1 += f'<div class="abox"><p>Edges on a cube: {b("3em")}</p></div>'
s1 += f'<div class="abox"><p>Vertices on a pyramid: {b("3em")}</p></div>'
s1 += '</div></div>'
# 2: Estimate First! review
s2 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> A rectangular prism and a cube are glued together side by side. '\
'Guess how many faces you could touch on the outside, then talk it through with your teacher.</p>'\
'<p>My guess: ' + b("4em") + ' After discussing: ' + b("4em") + '</p></div>'
# 3: Mixed review table (reduced from 6 to 3)
s3 = '<p class="note">Review: fill in the table. Use a real object if it helps!</p>'
s3 += '<table class="tbl"><tr><th>Solid</th><th>Picture</th><th>Faces</th><th>Edges</th><th>Vertices</th><th>Real-world example</th></tr>'
for label, key in [("Cube", "cube"), ("Pyramid", "pyramid"), ("Cylinder", "cylinder")]:
s3 += f'<tr><td>{label}</td><td style="text-align:center;">{SOLIDS[key](size=34)}</td>'\
f'<td>{b("2.5em")}</td><td>{b("2.5em")}</td><td>{b("2.5em")}</td><td>{b("6em")}</td></tr>'
s3 += '</table>'
s3 += '<p style="font-size:11px; color:#666;">Hint for the cylinder: count only the FLAT faces.</p>'
# 4: Word problem review
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Show your work.</p>'\
'<div class="abox"><p>Milo builds a tower with 3 cubes stacked on top of each other. '\
'He wants to put a sticker on every face he can still SEE (the bottom of the tower and '\
'the hidden faces between cubes don\'t count). How many stickers does he need?</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>' + b("3em") + ' stickers</p></div></div>'
# 5: Self-check with emoji reflection
s5 = '<div class="selfcheck">'\
'<p><b>Self-Check: How do you feel about 3D shapes?</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>Naming Solids</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>Counting Faces, Edges & Vertices</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>Matching Nets to Solids</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>My favorite solid and where I saw one in real life:</b> ' + bl() + '</p>'\
'</div>'
return page(22, "Friday", "Week 22 Review & Self-Check",
f'''{sec(1, "Warm-up: Solid Facts", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "Faces, Edges & Vertices Review", s3)}
{sec(4, "Word Problem", s4)}
{sec(5, "Self-Check & Reflection", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TEACHER GUIDE
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def teacher_guide():
return tg_page_multi(
"Week 22", "3D Shapes โ Teacher Guide",
tg_section_title("Monday: Meet the 3D Shapes") +
tg_sec(1, "Warm-up 2D Review", ["4, 3, 6, pentagon"]) +
tg_sec(2, "The Six Solids", ["Vocabulary intro โ no answers needed"]) +
tg_sec(3, "Name That Solid", ["cone, cube, sphere, pyramid, cylinder"]) +
tg_sec(4, "Number Talk", ["Sphere is curved all over; cube has flat faces that stop it", "Circle is flat (2D); sphere is solid (3D)"]) +
tg_sec(5, "Word Problem", ["Cylinders and cones roll: 3+2 = 5"]) +
tg_note("Page break"),
tg_section_title("Tuesday: Faces, Edges & Vertices") +
tg_sec(1, "Warm-up Riddles", ["sphere, cube, cylinder, cone"]) +
tg_sec(2, "New Words", ["Cube: 6 faces, 12 edges, 8 vertices"]) +
tg_sec(3, "Estimate First", ["Rect. prism: 6 faces; pyramid: 5 faces"]) +
tg_sec(4, "Count Table", ["Cube 6/12/8; Rect prism 6/12/8; Pyramid 5/8/5; Sphere 0/0/0"]) +
tg_sec(5, "Word Problem", ["6 faces รท 4 per pack โ 2 packs, 2 stickers left over"]) +
tg_note("Page break"),
tg_section_title("Wednesday: Nets") +
tg_sec(1, "Warm-up", ["6, 8, 0, 1"]) +
tg_sec(2, "Match Nets", ["Cross net โ cube; circles+rectangle โ cylinder; square+4 triangles โ pyramid"]) +
tg_sec(3, "Two Ways", ["6 faces, not 5; all faces are squares, not triangles"]) +
tg_sec(4, "Word Problems", ["6 rectangle faces", "4ร3 = 12 triangles"]) +
tg_sec(5, "Create Own Net", ["Any valid 6-square arrangement; encourage cut-and-fold test"]) +
tg_note("Page break"),
tg_section_title("Thursday: Real World") +
tg_sec(1, "Warm-up Solid Math", ["12, 10, 11, 12โ8=4"]) +
tg_sec(2, "Real-World", ["sphere, cylinder, cone, rectangular prism, pyramid"]) +
tg_sec(3, "2D and 3D", ["square, circle, square + triangles, circle"]) +
tg_sec(4, "Number Talk", ["Same structure โ prism is a stretched cube", "Cans โ flat circle faces stack; spheres roll away"]) +
tg_sec(5, "Word Problem & Hunt", ["5ร2 = 10 circle faces; accept any correct household objects"]) +
tg_note("Page break"),
tg_section_title("Friday: Review & Self-Check") +
tg_sec(1, "Warm-up", ["6, sphere, 12, 5"]) +
tg_sec(2, "Estimate First", ["Discussion question โ glued pair shows 10 outside faces"]) +
tg_sec(3, "Review Table", ["Cube 6/12/8; Pyramid 5/8/5; Cylinder 2 flat faces, 0 edges/vertices (2nd-grade convention); examples vary"]) +
tg_sec(4, "Word Problem", ["Tower of 3 cubes: 4 sides ร 3 + 1 top = 13 stickers"]) +
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", "Meet the 3D Shapes"),
(tuesday, "Tuesday", "Faces, Edges & Vertices"),
(wednesday, "Wednesday", "Nets: Unfolding Solids"),
(thursday, "Thursday", "3D Shapes in the Real World"),
(friday, "Friday", "Week 22 Review & Self-Check"),
]
for lesson_func, day, title in days:
html = lesson_func()
fname = f"Week_22_{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_22_Teacher_Guide.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, "Week_22_Teacher_Guide.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
print("\nWeek 22 (new standard) complete!")