diff --git a/src/app/learn/page.tsx b/src/app/learn/page.tsx index caabdbf..6f2684e 100644 --- a/src/app/learn/page.tsx +++ b/src/app/learn/page.tsx @@ -1,167 +1,186 @@ -import Link from "next/link"; -import SiteNav from "@/components/SiteNav"; -import { LEVELS, getSubjects, BEGINNER_PACKS, lessonStepCount, type Lesson } from "@/lib/curriculum"; -import { getCurrentUser } from "@/lib/session"; -import { getCompletedSteps, hasBadge } from "@/lib/progress"; -import { isLevelUnlocked, countCompletedLessons, isPackComplete, BEGINNER_UNLOCK_THRESHOLD } from "@/lib/gating"; - -export const metadata = { title: "Learn Β· DrawIt" }; -export const dynamic = "force-dynamic"; - -const PHASE_LABEL: Record = { - construct: "Shapes", outline: "Outline", detail: "Details", color: "Color", light: "Light & shadow", extra: "Color it!", -}; -const OPTIONAL_PHASES = new Set(["extra"]); - -type Subject = ReturnType[number]; - -export default async function LearnPage() { - const user = await getCurrentUser(); - - const doneCount = (l: Lesson) => (user ? getCompletedSteps(user.id, l.level, l.sublevel).length : 0); - const isDone = (l: Lesson) => { - if (!user) return false; - if (l.badgeKey && hasBadge(user.id, l.badgeKey)) return true; - return doneCount(l) >= lessonStepCount(l); - }; - const subjectComplete = (s: Subject) => s.lessons.every((l) => isDone(l)); - - // One card per phase, each gated behind the previous phase in the subject. - const phaseCard = (l: Lesson, locked: boolean) => { - const optional = OPTIONAL_PHASES.has(l.phase ?? ""); - const done = isDone(l); - const inProg = !done && !locked && doneCount(l) > 0; - const inner = ( -
- {PHASE_LABEL[l.phase ?? ""] ?? l.title}{optional ? " (optional)" : ""} - - {locked ? "πŸ”’ Locked" : done ? "βœ“ Done" : inProg ? `Step ${Math.min(doneCount(l) + 1, lessonStepCount(l))}/${lessonStepCount(l)}` : l.steps.length === 0 ? "Tap to start" : `${lessonStepCount(l)} steps`} - -
- ); - return locked ? ( -
{inner}
- ) : ( - {inner} - ); - }; - - const subjectAccordion = (subj: Subject, open: boolean) => { - const complete = subjectComplete(subj); - const anyStarted = subj.lessons.some((l) => doneCount(l) > 0); - // gate each phase behind the previous one being done - let prevDone = true; - const cards = subj.lessons.map((l) => { - const locked = !prevDone; - const card = phaseCard(l, locked); - prevDone = isDone(l); - return card; - }); - return ( -
- - {subj.emoji} {subj.name} - {complete ? βœ“ Done : anyStarted ? In progress : null} - -
- {cards} -
-
- ); - }; - - return ( - <> - -
-

Learn to draw 🎨

-

- Each picture is built up in steps. Finish the lessons to earn badges and fill your gallery. - {!user && " Log in to track your progress and earn badges."} -

- -
- {LEVELS.map((lvl, idx) => { - const subjects = getSubjects(lvl.key); - const unlocked = isLevelUnlocked(user?.id ?? null, lvl.key); - const firstIncomplete = subjects.find((s) => !subjectComplete(s))?.key; - - return ( -
-
-

{lvl.emoji} {idx + 1}. {lvl.name}

- {subjects.length === 0 && Coming soon} - {subjects.length > 0 && !unlocked && πŸ”’ Locked} -
-

{lvl.blurb}

- - {/* Locked level: show how to unlock */} - {subjects.length > 0 && !unlocked ? ( -
- {!user ? ( -

- Sign up and finish {BEGINNER_UNLOCK_THRESHOLD} Early Beginner drawings to unlock this level. -

- ) : ( - <> -

πŸ”’ Finish {BEGINNER_UNLOCK_THRESHOLD} Early Beginner lessons to unlock the {lvl.name} level.

-

- You've done {Math.min(countCompletedLessons(user.id, "early-beginner"), BEGINNER_UNLOCK_THRESHOLD)} of {BEGINNER_UNLOCK_THRESHOLD}. Keep going! -

- Practice Early Beginner - - )} -
- ) : lvl.key === "beginner" ? ( - // Beginner: group subjects into packs, each with a per-pack badge. -
- {BEGINNER_PACKS.map((pack) => { - const packSubjects = subjects.filter((s) => pack.subjectKeys.includes(s.key)); - const packDone = !!user && isPackComplete(user.id, pack); - return ( -
-
- {pack.emoji} {pack.name} - {packDone ? πŸ… {pack.badgeName} : Finish all {pack.subjectKeys.length} to earn {pack.badgeName}} -
-

{pack.blurb}

-
- {packSubjects.map((subj) => subjectAccordion(subj, subj.key === firstIncomplete))} -
-
- ); - })} -
- ) : ( - // Early Beginner (and any future flat levels) -
- {subjects.map((subj) => { - const phased = subj.lessons.length > 1 || !!subj.lessons[0].phase; - if (!phased) { - const l = subj.lessons[0]; - const done = isDone(l); - const inProg = !done && doneCount(l) > 0; - return ( - -
- {subj.emoji} {l.title} - {done ? βœ“ Done : inProg ? Step {Math.min(doneCount(l) + 1, lessonStepCount(l))}/{lessonStepCount(l)} : {lessonStepCount(l)} steps} -
- - ); - } - return subjectAccordion(subj, subj.key === firstIncomplete); - })} -
- )} -
- ); - })} -
-
- - ); -} - -const subCard = (done: boolean): React.CSSProperties => ({ textDecoration: "none", color: "inherit", border: done ? "2px solid var(--leaf)" : "2px solid var(--line)", boxShadow: "none", padding: 14 }); -const phaseBox: React.CSSProperties = { display: "block", border: "2px solid var(--line)", borderRadius: 12, padding: "12px 14px", background: "var(--surface)" }; +import Link from "next/link"; +import SiteNav from "@/components/SiteNav"; +import { LEVELS, getSubjects, getGroupedSubjects, BEGINNER_PACKS, lessonStepCount, type Lesson } from "@/lib/curriculum"; +import { getCurrentUser } from "@/lib/session"; +import { getCompletedSteps, hasBadge } from "@/lib/progress"; +import { isLevelUnlocked, countCompletedLessons, isPackComplete, BEGINNER_UNLOCK_THRESHOLD } from "@/lib/gating"; + +export const metadata = { title: "Learn Β· DrawIt" }; +export const dynamic = "force-dynamic"; + +const PHASE_LABEL: Record = { + construct: "Shapes", outline: "Outline", detail: "Details", color: "Color", light: "Light & shadow", extra: "Color it!", +}; +const OPTIONAL_PHASES = new Set(["extra"]); + +type Subject = ReturnType[number]; + +export default async function LearnPage() { + const user = await getCurrentUser(); + + const doneCount = (l: Lesson) => (user ? getCompletedSteps(user.id, l.level, l.sublevel).length : 0); + const isDone = (l: Lesson) => { + if (!user) return false; + if (l.badgeKey && hasBadge(user.id, l.badgeKey)) return true; + return doneCount(l) >= lessonStepCount(l); + }; + const subjectComplete = (s: Subject) => s.lessons.every((l) => isDone(l)); + + // One card per phase, each gated behind the previous phase in the subject. + const phaseCard = (l: Lesson, locked: boolean) => { + const optional = OPTIONAL_PHASES.has(l.phase ?? ""); + const done = isDone(l); + const inProg = !done && !locked && doneCount(l) > 0; + const inner = ( +
+ {PHASE_LABEL[l.phase ?? ""] ?? l.title}{optional ? " (optional)" : ""} + + {locked ? "πŸ”’ Locked" : done ? "βœ“ Done" : inProg ? `Step ${Math.min(doneCount(l) + 1, lessonStepCount(l))}/${lessonStepCount(l)}` : l.steps.length === 0 ? "Tap to start" : `${lessonStepCount(l)} steps`} + +
+ ); + return locked ? ( +
{inner}
+ ) : ( + {inner} + ); + }; + + const subjectAccordion = (subj: Subject, open: boolean) => { + const complete = subjectComplete(subj); + const anyStarted = subj.lessons.some((l) => doneCount(l) > 0); + // gate each phase behind the previous one being done + let prevDone = true; + const cards = subj.lessons.map((l) => { + const locked = !prevDone; + const card = phaseCard(l, locked); + prevDone = isDone(l); + return card; + }); + return ( +
+ + {subj.emoji} {subj.name} + {complete ? βœ“ Done : anyStarted ? In progress : null} + +
+ {cards} +
+
+ ); + }; + + return ( + <> + +
+

Learn to draw 🎨

+

+ Each picture is built up in steps. Finish the lessons to earn badges and fill your gallery. + {!user && " Log in to track your progress and earn badges."} +

+ +
+ {LEVELS.map((lvl, idx) => { + const subjects = getSubjects(lvl.key); + const unlocked = isLevelUnlocked(user?.id ?? null, lvl.key); + const orderedSubjects = lvl.key === "early-beginner" ? getGroupedSubjects(lvl.key).flatMap((g) => g.subjects) : subjects; + const firstIncomplete = orderedSubjects.find((s) => !subjectComplete(s))?.key; + + return ( +
+
+

{lvl.emoji} {idx + 1}. {lvl.name}

+ {subjects.length === 0 && Coming soon} + {subjects.length > 0 && !unlocked && πŸ”’ Locked} +
+

{lvl.blurb}

+ + {/* Locked level: show how to unlock */} + {subjects.length > 0 && !unlocked ? ( +
+ {!user ? ( +

+ Sign up and finish {BEGINNER_UNLOCK_THRESHOLD} Early Beginner drawings to unlock this level. +

+ ) : ( + <> +

πŸ”’ Finish {BEGINNER_UNLOCK_THRESHOLD} Early Beginner lessons to unlock the {lvl.name} level.

+

+ You've done {Math.min(countCompletedLessons(user.id, "early-beginner"), BEGINNER_UNLOCK_THRESHOLD)} of {BEGINNER_UNLOCK_THRESHOLD}. Keep going! +

+ Practice Early Beginner + + )} +
+ ) : lvl.key === "beginner" ? ( + // Beginner: group subjects into packs, each with a per-pack badge. +
+ {BEGINNER_PACKS.map((pack) => { + const packSubjects = subjects.filter((s) => pack.subjectKeys.includes(s.key)); + const packDone = !!user && isPackComplete(user.id, pack); + return ( +
+
+ {pack.emoji} {pack.name} + {packDone ? πŸ… {pack.badgeName} : Finish all {pack.subjectKeys.length} to earn {pack.badgeName}} +
+

{pack.blurb}

+
+ {packSubjects.map((subj) => subjectAccordion(subj, subj.key === firstIncomplete))} +
+
+ ); + })} +
+ ) : lvl.key === "early-beginner" ? ( + // Early Beginner: themed groups, each holding its subjects. +
+ {getGroupedSubjects(lvl.key).map((group) => { + const groupDone = group.subjects.every((s) => subjectComplete(s)); + return ( +
+
+ {group.emoji} {group.name} + {group.subjects.filter((s) => subjectComplete(s)).length}/{group.subjects.length} done +
+
+ {group.subjects.map((subj) => subjectAccordion(subj, subj.key === firstIncomplete))} +
+
+ ); + })} +
+ ) : ( + // Any future flat level +
+ {subjects.map((subj) => { + const phased = subj.lessons.length > 1 || !!subj.lessons[0].phase; + if (!phased) { + const l = subj.lessons[0]; + const done = isDone(l); + const inProg = !done && doneCount(l) > 0; + return ( + +
+ {subj.emoji} {l.title} + {done ? βœ“ Done : inProg ? Step {Math.min(doneCount(l) + 1, lessonStepCount(l))}/{lessonStepCount(l)} : {lessonStepCount(l)} steps} +
+ + ); + } + return subjectAccordion(subj, subj.key === firstIncomplete); + })} +
+ )} +
+ ); + })} +
+
+ + ); +} + +const subCard = (done: boolean): React.CSSProperties => ({ textDecoration: "none", color: "inherit", border: done ? "2px solid var(--leaf)" : "2px solid var(--line)", boxShadow: "none", padding: 14 }); +const phaseBox: React.CSSProperties = { display: "block", border: "2px solid var(--line)", borderRadius: 12, padding: "12px 14px", background: "var(--surface)" }; diff --git a/src/app/page.tsx b/src/app/page.tsx index e68e0ad..e0fa990 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,121 +1,124 @@ -import Link from "next/link"; -import SiteNav from "@/components/SiteNav"; -import FishSlideshow from "@/components/FishSlideshow"; -import { LEVELS, getSubjects, FISH_OUTLINE_LESSON, FISH_DETAIL_LESSON } from "@/lib/curriculum"; - -const FREE_SLUG = "fish-outline"; - -export default function Home() { - // Build a coloring-book "video" preview from the fish outline + detail lines - const fishSteps = [...FISH_OUTLINE_LESSON.steps, ...FISH_DETAIL_LESSON.steps]; - let cum = ""; - const slides = fishSteps.map((s, i) => { - cum += (s.lines || []).join("\n") + "\n"; - return { n: i + 1, title: s.title, instruction: s.instruction, cumulativeSvg: cum }; - }); - - return ( - <> - -
-
-
-
πŸ†“ Free & open source Β· πŸ”’ No data collected, ever
-

Learn to draw, one line at a time

-

- DrawIt teaches kids to draw with simple, friendly steps β€” built for iPads and tablets. Each - picture has an Outline lesson, a Details lesson, and a fun - Color it! lesson. The first lesson is free β€” create an account to unlock the rest. -

-
- 🐟 Try the first lesson free - Create a free account -
-
-
- -
-
-

Watch it drawn, line by line 🐟

-

- Lessons draw each line slowly so kids can follow along, like a coloring book that builds itself. -

- -
-
- -
-
-

Start free β€” unlock everything with an account

-

- The first lesson (Fish β†’ Outline) is free to try. A free account unlocks the rest, saves your - progress, and lets you earn badges and keep your drawings. -

-
- {LEVELS.map((lvl, idx) => { - const subjects = getSubjects(lvl.key); - const isFirst = lvl.key === "early-beginner"; - return ( -
-
-

{lvl.emoji} {idx + 1}. {lvl.name}

- {!isFirst && πŸ”’ Account needed} -
-

{lvl.blurb}

- {isFirst && subjects.length > 0 && ( -
- {subjects.map((subj) => { - const first = subj.lessons[0]; - const free = first.slug === FREE_SLUG; - return ( - - {free ? "Free" : "πŸ”’"} -
{subj.emoji}
- {subj.name} -

- {free ? "Outline Β· free to try" : "Create an account to unlock"} -

- - ); - })} -
- )} - {!isFirst && ( - - πŸ”’ - Unlock {lvl.name} -

Create a free account to explore.

- - )} -
- ); - })} -
-
- Create a free account -
-
-
- -
-
-

How DrawIt works

-
-

✏️ Outline β†’ Details

Trace the coloring-book outline, then add the details that bring it to life.

-

🎨 Color it in

Finish with the coloring studio β€” color, shade, and make it your own.

-

πŸ”’ Private by design

No analytics, no trackers, no data sold or shared. Just drawing.

-
-
-
-
-
DrawIt · Free & open source · No data collected. Made for young artists. 🎨
- - ); -} - -function card(locked: boolean): React.CSSProperties { - return { position: "relative", textDecoration: "none", color: "inherit", background: "var(--surface)", borderRadius: "var(--radius)", border: "2px solid var(--line)", padding: 18, opacity: locked ? 0.6 : 1, filter: locked ? "grayscale(0.7)" : "none" }; -} -function tag(free: boolean): React.CSSProperties { - return { position: "absolute", top: 12, right: 12, fontWeight: 800, fontSize: "0.8rem", padding: "3px 10px", borderRadius: 999, background: free ? "#e8f7ee" : "#f0ebf7", color: free ? "#1f7a45" : "var(--ink-soft)" }; -} +import Link from "next/link"; +import SiteNav from "@/components/SiteNav"; +import FishSlideshow from "@/components/FishSlideshow"; +import { LEVELS, getSubjects, FISH_OUTLINE_LESSON, FISH_DETAIL_LESSON } from "@/lib/curriculum"; + +const FREE_SLUG = "fish-outline"; + +export default function Home() { + // Build a coloring-book "video" preview from the fish outline + detail lines + const fishSteps = [...FISH_OUTLINE_LESSON.steps, ...FISH_DETAIL_LESSON.steps]; + let cum = ""; + const slides = fishSteps.map((s, i) => { + cum += (s.lines || []).join("\n") + "\n"; + return { n: i + 1, title: s.title, instruction: s.instruction, cumulativeSvg: cum }; + }); + + return ( + <> + +
+
+
+
πŸ†“ Free & open source Β· πŸ”’ No data collected, ever
+

Learn to draw, one line at a time

+

+ DrawIt teaches kids to draw with simple, friendly steps β€” built for iPads and tablets. Each + picture has an Outline lesson, a Details lesson, and a fun + Color it! lesson. The first lesson is free β€” create an account to unlock the rest. +

+
+ 🐟 Try the first lesson free + Create a free account +
+
+
+ +
+
+

Watch it drawn, line by line 🐟

+

+ Lessons draw each line slowly so kids can follow along, like a coloring book that builds itself. +

+ +
+
+ +
+
+

Start free β€” unlock everything with an account

+

+ The first lesson (Fish β†’ Outline) is free to try. A free account unlocks the rest, saves your + progress, and lets you earn badges and keep your drawings. +

+
+ {LEVELS.map((lvl, idx) => { + const subjects = getSubjects(lvl.key); + const isFirst = lvl.key === "early-beginner"; + return ( +
+
+

{lvl.emoji} {idx + 1}. {lvl.name}

+ {!isFirst && πŸ”’ Account needed} +
+

{lvl.blurb}

+ {isFirst && subjects.length > 0 && ( +
+ {subjects.slice(0, 6).map((subj) => { + const first = subj.lessons[0]; + const free = first.slug === FREE_SLUG; + return ( + + {free ? "Free" : "πŸ”’"} +
{subj.emoji}
+ {subj.name} +

+ {free ? "Outline Β· free to try" : "Create an account to unlock"} +

+ + ); + })} +
+ )} + {isFirst && subjects.length > 6 && ( +

…and lots more β€” shapes, animals, clothes, faces and more inside.

+ )} + {!isFirst && ( + + πŸ”’ + Unlock {lvl.name} +

Create a free account to explore.

+ + )} +
+ ); + })} +
+
+ Create a free account +
+
+
+ +
+
+

How DrawIt works

+
+

✏️ Outline β†’ Details

Trace the coloring-book outline, then add the details that bring it to life.

+

🎨 Color it in

Finish with the coloring studio β€” color, shade, and make it your own.

+

πŸ”’ Private by design

No analytics, no trackers, no data sold or shared. Just drawing.

+
+
+
+
+
DrawIt · Free & open source · No data collected. Made for young artists. 🎨
+ + ); +} + +function card(locked: boolean): React.CSSProperties { + return { position: "relative", textDecoration: "none", color: "inherit", background: "var(--surface)", borderRadius: "var(--radius)", border: "2px solid var(--line)", padding: 18, opacity: locked ? 0.6 : 1, filter: locked ? "grayscale(0.7)" : "none" }; +} +function tag(free: boolean): React.CSSProperties { + return { position: "absolute", top: 12, right: 12, fontWeight: 800, fontSize: "0.8rem", padding: "3px 10px", borderRadius: 999, background: free ? "#e8f7ee" : "#f0ebf7", color: free ? "#1f7a45" : "var(--ink-soft)" }; +} diff --git a/src/lib/curriculum.animals.ts b/src/lib/curriculum.animals.ts new file mode 100644 index 0000000..f210b58 --- /dev/null +++ b/src/lib/curriculum.animals.ts @@ -0,0 +1,405 @@ +/* AUTO-GENERATED by gen_animals.py β€” Early Beginner animals (original cute doodles). */ +import type { Lesson, LessonStep } from "./curriculum"; + +const LION_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The mane`, instruction:`Draw a big circle for the fluffy mane.`, lines:[``] }, + { n:2, title:`The face`, instruction:`Draw a round face inside.`, lines:[``] }, + { n:3, title:`The ears`, instruction:`Add two little ears.`, lines:[``,``] }, +]; + +const LION_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Eyes & nose`, instruction:`Add eyes and a nose.`, lines:[``,``,``] }, + { n:2, title:`Big smile`, instruction:`Add the mouth.`, lines:[``,``,``] }, + { n:3, title:`Mane fluff`, instruction:`Add fluffy lines around the mane.`, lines:[``,``,``,``,``,``,``,``] }, +]; + +const LION_OUTLINE_SVG = LION_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const LION_DETAIL_SVG = LION_OUTLINE_SVG + "\n" + LION_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const LION_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"lion", subjectName:`Lion`, subjectEmoji:`🦁`, emoji:`🦁`, order:20, sublevel:201, slug:"lion-outline", title:`Lion \u00b7 Outline`, subject:`lion outline`, intro:`Let\u2019s draw Lion\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Lion Legend`, phase:"outline", steps:LION_OUTLINE_STEPS }; +export const LION_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"lion", subjectName:`Lion`, subjectEmoji:`🦁`, emoji:`🦁`, order:20, sublevel:202, slug:"lion-detail", title:`Lion \u00b7 Details`, subject:`lion details`, intro:`Now add the details that bring your lion to life.`, badgeKey:"early-beginner-20-lion", badgeName:`Lion Legend`, phase:"detail", baseSvg:LION_OUTLINE_SVG, steps:LION_DETAIL_STEPS }; +export const LION_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"lion", subjectName:`Lion`, subjectEmoji:`🦁`, emoji:`🦁`, order:20, sublevel:203, slug:"lion-extra", title:`Lion \u00b7 Color it!`, subject:`color the lion`, intro:`Bring your lion to life! Color it in.`, badgeKey:"", badgeName:`Lion Legend`, phase:"extra", baseSvg:LION_DETAIL_SVG, steps:[] }; + +const ELEPHANT_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a big round body.`, lines:[``] }, + { n:2, title:`The head`, instruction:`Add a round head on the left.`, lines:[``] }, + { n:3, title:`The trunk`, instruction:`Curl a trunk down from the head.`, lines:[``] }, + { n:4, title:`The legs`, instruction:`Add chunky legs.`, lines:[``,``,``] }, +]; + +const ELEPHANT_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The ear`, instruction:`Add a big floppy ear.`, lines:[``] }, + { n:2, title:`Eye & tusk`, instruction:`Add an eye and a tusk.`, lines:[``,``] }, + { n:3, title:`The tail`, instruction:`Add a little tail.`, lines:[``] }, +]; + +const ELEPHANT_OUTLINE_SVG = ELEPHANT_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const ELEPHANT_DETAIL_SVG = ELEPHANT_OUTLINE_SVG + "\n" + ELEPHANT_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const ELEPHANT_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"elephant", subjectName:`Elephant`, subjectEmoji:`🐘`, emoji:`🐘`, order:21, sublevel:211, slug:"elephant-outline", title:`Elephant \u00b7 Outline`, subject:`elephant outline`, intro:`Let\u2019s draw Elephant\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Elephant Pal`, phase:"outline", steps:ELEPHANT_OUTLINE_STEPS }; +export const ELEPHANT_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"elephant", subjectName:`Elephant`, subjectEmoji:`🐘`, emoji:`🐘`, order:21, sublevel:212, slug:"elephant-detail", title:`Elephant \u00b7 Details`, subject:`elephant details`, intro:`Now add the details that bring your elephant to life.`, badgeKey:"early-beginner-21-elephant", badgeName:`Elephant Pal`, phase:"detail", baseSvg:ELEPHANT_OUTLINE_SVG, steps:ELEPHANT_DETAIL_STEPS }; +export const ELEPHANT_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"elephant", subjectName:`Elephant`, subjectEmoji:`🐘`, emoji:`🐘`, order:21, sublevel:213, slug:"elephant-extra", title:`Elephant \u00b7 Color it!`, subject:`color the elephant`, intro:`Bring your elephant to life! Color it in.`, badgeKey:"", badgeName:`Elephant Pal`, phase:"extra", baseSvg:ELEPHANT_DETAIL_SVG, steps:[] }; + +const GIRAFFE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw an oval body.`, lines:[``] }, + { n:2, title:`The neck`, instruction:`Draw a long tall neck.`, lines:[``] }, + { n:3, title:`The head`, instruction:`Add a small head on top.`, lines:[``] }, + { n:4, title:`The legs`, instruction:`Add four long legs.`, lines:[``,``,``,``] }, +]; + +const GIRAFFE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Horns & ear`, instruction:`Add little horns and an ear.`, lines:[``,``,``,``,``] }, + { n:2, title:`The face`, instruction:`Add an eye and a snout.`, lines:[``,``] }, + { n:3, title:`Spots`, instruction:`Add some spots.`, lines:[``,``,``,``,``] }, +]; + +const GIRAFFE_OUTLINE_SVG = GIRAFFE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const GIRAFFE_DETAIL_SVG = GIRAFFE_OUTLINE_SVG + "\n" + GIRAFFE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const GIRAFFE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"giraffe", subjectName:`Giraffe`, subjectEmoji:`πŸ¦’`, emoji:`πŸ¦’`, order:22, sublevel:221, slug:"giraffe-outline", title:`Giraffe \u00b7 Outline`, subject:`giraffe outline`, intro:`Let\u2019s draw Giraffe\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Tall Giraffe`, phase:"outline", steps:GIRAFFE_OUTLINE_STEPS }; +export const GIRAFFE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"giraffe", subjectName:`Giraffe`, subjectEmoji:`πŸ¦’`, emoji:`πŸ¦’`, order:22, sublevel:222, slug:"giraffe-detail", title:`Giraffe \u00b7 Details`, subject:`giraffe details`, intro:`Now add the details that bring your giraffe to life.`, badgeKey:"early-beginner-22-giraffe", badgeName:`Tall Giraffe`, phase:"detail", baseSvg:GIRAFFE_OUTLINE_SVG, steps:GIRAFFE_DETAIL_STEPS }; +export const GIRAFFE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"giraffe", subjectName:`Giraffe`, subjectEmoji:`πŸ¦’`, emoji:`πŸ¦’`, order:22, sublevel:223, slug:"giraffe-extra", title:`Giraffe \u00b7 Color it!`, subject:`color the giraffe`, intro:`Bring your giraffe to life! Color it in.`, badgeKey:"", badgeName:`Tall Giraffe`, phase:"extra", baseSvg:GIRAFFE_DETAIL_SVG, steps:[] }; + +const ZEBRA_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw an oval body.`, lines:[``] }, + { n:2, title:`The head`, instruction:`Add a head up to the left.`, lines:[``] }, + { n:3, title:`The neck`, instruction:`Join the head to the body.`, lines:[``] }, + { n:4, title:`The legs`, instruction:`Add four legs.`, lines:[``,``,``,``] }, +]; + +const ZEBRA_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add an eye, snout and ear.`, lines:[``,``,``] }, + { n:2, title:`Mane & tail`, instruction:`Add a spiky mane and a tail.`, lines:[``,``,``] }, + { n:3, title:`Stripes`, instruction:`Add bold stripes.`, lines:[``,``,``] }, +]; + +const ZEBRA_OUTLINE_SVG = ZEBRA_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const ZEBRA_DETAIL_SVG = ZEBRA_OUTLINE_SVG + "\n" + ZEBRA_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const ZEBRA_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"zebra", subjectName:`Zebra`, subjectEmoji:`πŸ¦“`, emoji:`πŸ¦“`, order:23, sublevel:231, slug:"zebra-outline", title:`Zebra \u00b7 Outline`, subject:`zebra outline`, intro:`Let\u2019s draw Zebra\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Stripe Star`, phase:"outline", steps:ZEBRA_OUTLINE_STEPS }; +export const ZEBRA_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"zebra", subjectName:`Zebra`, subjectEmoji:`πŸ¦“`, emoji:`πŸ¦“`, order:23, sublevel:232, slug:"zebra-detail", title:`Zebra \u00b7 Details`, subject:`zebra details`, intro:`Now add the details that bring your zebra to life.`, badgeKey:"early-beginner-23-zebra", badgeName:`Stripe Star`, phase:"detail", baseSvg:ZEBRA_OUTLINE_SVG, steps:ZEBRA_DETAIL_STEPS }; +export const ZEBRA_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"zebra", subjectName:`Zebra`, subjectEmoji:`πŸ¦“`, emoji:`πŸ¦“`, order:23, sublevel:233, slug:"zebra-extra", title:`Zebra \u00b7 Color it!`, subject:`color the zebra`, intro:`Bring your zebra to life! Color it in.`, badgeKey:"", badgeName:`Stripe Star`, phase:"extra", baseSvg:ZEBRA_DETAIL_SVG, steps:[] }; + +const RHINO_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a big oval body.`, lines:[``] }, + { n:2, title:`The head`, instruction:`Add a big head on the left.`, lines:[``] }, + { n:3, title:`The horn`, instruction:`Add a pointy horn.`, lines:[``] }, + { n:4, title:`The legs`, instruction:`Add sturdy legs.`, lines:[``,``,``] }, +]; + +const RHINO_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Eye & ear`, instruction:`Add an eye and an ear.`, lines:[``,``] }, + { n:2, title:`Small horn & mouth`, instruction:`Add a second horn and mouth.`, lines:[``,``] }, + { n:3, title:`The tail`, instruction:`Add a little tail.`, lines:[``] }, +]; + +const RHINO_OUTLINE_SVG = RHINO_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const RHINO_DETAIL_SVG = RHINO_OUTLINE_SVG + "\n" + RHINO_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const RHINO_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"rhino", subjectName:`Rhino`, subjectEmoji:`🦏`, emoji:`🦏`, order:24, sublevel:241, slug:"rhino-outline", title:`Rhino \u00b7 Outline`, subject:`rhino outline`, intro:`Let\u2019s draw Rhino\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Rhino Rumble`, phase:"outline", steps:RHINO_OUTLINE_STEPS }; +export const RHINO_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"rhino", subjectName:`Rhino`, subjectEmoji:`🦏`, emoji:`🦏`, order:24, sublevel:242, slug:"rhino-detail", title:`Rhino \u00b7 Details`, subject:`rhino details`, intro:`Now add the details that bring your rhino to life.`, badgeKey:"early-beginner-24-rhino", badgeName:`Rhino Rumble`, phase:"detail", baseSvg:RHINO_OUTLINE_SVG, steps:RHINO_DETAIL_STEPS }; +export const RHINO_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"rhino", subjectName:`Rhino`, subjectEmoji:`🦏`, emoji:`🦏`, order:24, sublevel:243, slug:"rhino-extra", title:`Rhino \u00b7 Color it!`, subject:`color the rhino`, intro:`Bring your rhino to life! Color it in.`, badgeKey:"", badgeName:`Rhino Rumble`, phase:"extra", baseSvg:RHINO_DETAIL_SVG, steps:[] }; + +const LEOPARD_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a sitting body.`, lines:[``] }, + { n:4, title:`The paws`, instruction:`Add two front paws.`, lines:[``,``] }, +]; + +const LEOPARD_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes, nose and mouth.`, lines:[``,``,``,``] }, + { n:2, title:`Whiskers & tail`, instruction:`Add whiskers and a curvy tail.`, lines:[``,``,``] }, + { n:3, title:`Spots`, instruction:`Add leopard spots.`, lines:[``,``,``,``,``] }, +]; + +const LEOPARD_OUTLINE_SVG = LEOPARD_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const LEOPARD_DETAIL_SVG = LEOPARD_OUTLINE_SVG + "\n" + LEOPARD_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const LEOPARD_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"leopard", subjectName:`Leopard`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:25, sublevel:251, slug:"leopard-outline", title:`Leopard \u00b7 Outline`, subject:`leopard outline`, intro:`Let\u2019s draw Leopard\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Spotty Leopard`, phase:"outline", steps:LEOPARD_OUTLINE_STEPS }; +export const LEOPARD_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"leopard", subjectName:`Leopard`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:25, sublevel:252, slug:"leopard-detail", title:`Leopard \u00b7 Details`, subject:`leopard details`, intro:`Now add the details that bring your leopard to life.`, badgeKey:"early-beginner-25-leopard", badgeName:`Spotty Leopard`, phase:"detail", baseSvg:LEOPARD_OUTLINE_SVG, steps:LEOPARD_DETAIL_STEPS }; +export const LEOPARD_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"leopard", subjectName:`Leopard`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:25, sublevel:253, slug:"leopard-extra", title:`Leopard \u00b7 Color it!`, subject:`color the leopard`, intro:`Bring your leopard to life! Color it in.`, badgeKey:"", badgeName:`Spotty Leopard`, phase:"extra", baseSvg:LEOPARD_DETAIL_SVG, steps:[] }; + +const TIGER_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a sitting body.`, lines:[``] }, +]; + +const TIGER_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes, nose and mouth.`, lines:[``,``,``,``,``,``] }, + { n:2, title:`Cheeks`, instruction:`Add fluffy cheeks.`, lines:[``,``] }, + { n:3, title:`Stripes`, instruction:`Add tiger stripes.`, lines:[``,``,``,``,``] }, +]; + +const TIGER_OUTLINE_SVG = TIGER_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const TIGER_DETAIL_SVG = TIGER_OUTLINE_SVG + "\n" + TIGER_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const TIGER_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"tiger", subjectName:`Tiger`, subjectEmoji:`🐯`, emoji:`🐯`, order:26, sublevel:261, slug:"tiger-outline", title:`Tiger \u00b7 Outline`, subject:`tiger outline`, intro:`Let\u2019s draw Tiger\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Tiger Power`, phase:"outline", steps:TIGER_OUTLINE_STEPS }; +export const TIGER_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"tiger", subjectName:`Tiger`, subjectEmoji:`🐯`, emoji:`🐯`, order:26, sublevel:262, slug:"tiger-detail", title:`Tiger \u00b7 Details`, subject:`tiger details`, intro:`Now add the details that bring your tiger to life.`, badgeKey:"early-beginner-26-tiger", badgeName:`Tiger Power`, phase:"detail", baseSvg:TIGER_OUTLINE_SVG, steps:TIGER_DETAIL_STEPS }; +export const TIGER_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"tiger", subjectName:`Tiger`, subjectEmoji:`🐯`, emoji:`🐯`, order:26, sublevel:263, slug:"tiger-extra", title:`Tiger \u00b7 Color it!`, subject:`color the tiger`, intro:`Bring your tiger to life! Color it in.`, badgeKey:"", badgeName:`Tiger Power`, phase:"extra", baseSvg:TIGER_DETAIL_SVG, steps:[] }; + +const MONKEY_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two big round ears.`, lines:[``,``] }, + { n:3, title:`The face`, instruction:`Add a face patch.`, lines:[``] }, +]; + +const MONKEY_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The eyes`, instruction:`Add two eyes.`, lines:[``,``,``,``] }, + { n:2, title:`Nose & mouth`, instruction:`Add a nose and a smile.`, lines:[``,``,``] }, + { n:3, title:`Ear insides`, instruction:`Add the inside of the ears.`, lines:[``,``] }, +]; + +const MONKEY_OUTLINE_SVG = MONKEY_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const MONKEY_DETAIL_SVG = MONKEY_OUTLINE_SVG + "\n" + MONKEY_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const MONKEY_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"monkey", subjectName:`Monkey`, subjectEmoji:`🐡`, emoji:`🐡`, order:27, sublevel:271, slug:"monkey-outline", title:`Monkey \u00b7 Outline`, subject:`monkey outline`, intro:`Let\u2019s draw Monkey\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Cheeky Monkey`, phase:"outline", steps:MONKEY_OUTLINE_STEPS }; +export const MONKEY_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"monkey", subjectName:`Monkey`, subjectEmoji:`🐡`, emoji:`🐡`, order:27, sublevel:272, slug:"monkey-detail", title:`Monkey \u00b7 Details`, subject:`monkey details`, intro:`Now add the details that bring your monkey to life.`, badgeKey:"early-beginner-27-monkey", badgeName:`Cheeky Monkey`, phase:"detail", baseSvg:MONKEY_OUTLINE_SVG, steps:MONKEY_DETAIL_STEPS }; +export const MONKEY_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"monkey", subjectName:`Monkey`, subjectEmoji:`🐡`, emoji:`🐡`, order:27, sublevel:273, slug:"monkey-extra", title:`Monkey \u00b7 Color it!`, subject:`color the monkey`, intro:`Bring your monkey to life! Color it in.`, badgeKey:"", badgeName:`Cheeky Monkey`, phase:"extra", baseSvg:MONKEY_DETAIL_SVG, steps:[] }; + +const CROCODILE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a long body and snout.`, lines:[``] }, + { n:2, title:`The legs`, instruction:`Add short legs.`, lines:[``,``] }, + { n:3, title:`The tail tip`, instruction:`Point the tail.`, lines:[``] }, +]; + +const CROCODILE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The eye`, instruction:`Add a bumpy eye.`, lines:[``,``] }, + { n:2, title:`Teeth`, instruction:`Add a toothy grin.`, lines:[``,``,``,``] }, + { n:3, title:`Back ridges`, instruction:`Add spikes on the back.`, lines:[``,``,``] }, +]; + +const CROCODILE_OUTLINE_SVG = CROCODILE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const CROCODILE_DETAIL_SVG = CROCODILE_OUTLINE_SVG + "\n" + CROCODILE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const CROCODILE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"crocodile", subjectName:`Crocodile`, subjectEmoji:`🐊`, emoji:`🐊`, order:28, sublevel:281, slug:"crocodile-outline", title:`Crocodile \u00b7 Outline`, subject:`crocodile outline`, intro:`Let\u2019s draw Crocodile\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Snappy Croc`, phase:"outline", steps:CROCODILE_OUTLINE_STEPS }; +export const CROCODILE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"crocodile", subjectName:`Crocodile`, subjectEmoji:`🐊`, emoji:`🐊`, order:28, sublevel:282, slug:"crocodile-detail", title:`Crocodile \u00b7 Details`, subject:`crocodile details`, intro:`Now add the details that bring your crocodile to life.`, badgeKey:"early-beginner-28-crocodile", badgeName:`Snappy Croc`, phase:"detail", baseSvg:CROCODILE_OUTLINE_SVG, steps:CROCODILE_DETAIL_STEPS }; +export const CROCODILE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"crocodile", subjectName:`Crocodile`, subjectEmoji:`🐊`, emoji:`🐊`, order:28, sublevel:283, slug:"crocodile-extra", title:`Crocodile \u00b7 Color it!`, subject:`color the crocodile`, intro:`Bring your crocodile to life! Color it in.`, badgeKey:"", badgeName:`Snappy Croc`, phase:"extra", baseSvg:CROCODILE_DETAIL_SVG, steps:[] }; + +const FOX_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Draw a pointy fox face.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two pointy ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a sitting body.`, lines:[``] }, + { n:4, title:`The tail`, instruction:`Add a bushy tail.`, lines:[``] }, +]; + +const FOX_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes and a nose.`, lines:[``,``,``] }, + { n:2, title:`Cheeks`, instruction:`Add fluffy cheeks.`, lines:[``,``] }, + { n:3, title:`Ear insides`, instruction:`Color the ears.`, lines:[``,``] }, +]; + +const FOX_OUTLINE_SVG = FOX_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const FOX_DETAIL_SVG = FOX_OUTLINE_SVG + "\n" + FOX_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const FOX_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"fox", subjectName:`Fox`, subjectEmoji:`🦊`, emoji:`🦊`, order:29, sublevel:291, slug:"fox-outline", title:`Fox \u00b7 Outline`, subject:`fox outline`, intro:`Let\u2019s draw Fox\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Foxy Friend`, phase:"outline", steps:FOX_OUTLINE_STEPS }; +export const FOX_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"fox", subjectName:`Fox`, subjectEmoji:`🦊`, emoji:`🦊`, order:29, sublevel:292, slug:"fox-detail", title:`Fox \u00b7 Details`, subject:`fox details`, intro:`Now add the details that bring your fox to life.`, badgeKey:"early-beginner-29-fox", badgeName:`Foxy Friend`, phase:"detail", baseSvg:FOX_OUTLINE_SVG, steps:FOX_DETAIL_STEPS }; +export const FOX_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"fox", subjectName:`Fox`, subjectEmoji:`🦊`, emoji:`🦊`, order:29, sublevel:293, slug:"fox-extra", title:`Fox \u00b7 Color it!`, subject:`color the fox`, intro:`Bring your fox to life! Color it in.`, badgeKey:"", badgeName:`Foxy Friend`, phase:"extra", baseSvg:FOX_DETAIL_SVG, steps:[] }; + +const BEAR_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two round ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a cuddly body.`, lines:[``] }, +]; + +const BEAR_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The snout`, instruction:`Add a snout and nose.`, lines:[``,``] }, + { n:2, title:`The eyes`, instruction:`Add two eyes.`, lines:[``,``] }, + { n:3, title:`Ear insides & tummy`, instruction:`Add details.`, lines:[``,``,``] }, +]; + +const BEAR_OUTLINE_SVG = BEAR_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const BEAR_DETAIL_SVG = BEAR_OUTLINE_SVG + "\n" + BEAR_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const BEAR_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"bear", subjectName:`Bear`, subjectEmoji:`🐻`, emoji:`🐻`, order:30, sublevel:301, slug:"bear-outline", title:`Bear \u00b7 Outline`, subject:`bear outline`, intro:`Let\u2019s draw Bear\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Bear Hug`, phase:"outline", steps:BEAR_OUTLINE_STEPS }; +export const BEAR_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"bear", subjectName:`Bear`, subjectEmoji:`🐻`, emoji:`🐻`, order:30, sublevel:302, slug:"bear-detail", title:`Bear \u00b7 Details`, subject:`bear details`, intro:`Now add the details that bring your bear to life.`, badgeKey:"early-beginner-30-bear", badgeName:`Bear Hug`, phase:"detail", baseSvg:BEAR_OUTLINE_SVG, steps:BEAR_DETAIL_STEPS }; +export const BEAR_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"bear", subjectName:`Bear`, subjectEmoji:`🐻`, emoji:`🐻`, order:30, sublevel:303, slug:"bear-extra", title:`Bear \u00b7 Color it!`, subject:`color the bear`, intro:`Bring your bear to life! Color it in.`, badgeKey:"", badgeName:`Bear Hug`, phase:"extra", baseSvg:BEAR_DETAIL_SVG, steps:[] }; + +const DEER_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw an oval head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two ears.`, lines:[``,``] }, + { n:3, title:`The antlers`, instruction:`Add branchy antlers.`, lines:[``,``,``,``] }, + { n:4, title:`The body`, instruction:`Add a small body.`, lines:[``] }, +]; + +const DEER_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes and a nose.`, lines:[``,``,``] }, + { n:2, title:`The snout`, instruction:`Add the snout line.`, lines:[``] }, +]; + +const DEER_OUTLINE_SVG = DEER_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const DEER_DETAIL_SVG = DEER_OUTLINE_SVG + "\n" + DEER_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const DEER_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"deer", subjectName:`Deer`, subjectEmoji:`🦌`, emoji:`🦌`, order:31, sublevel:311, slug:"deer-outline", title:`Deer \u00b7 Outline`, subject:`deer outline`, intro:`Let\u2019s draw Deer\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Deer Dear`, phase:"outline", steps:DEER_OUTLINE_STEPS }; +export const DEER_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"deer", subjectName:`Deer`, subjectEmoji:`🦌`, emoji:`🦌`, order:31, sublevel:312, slug:"deer-detail", title:`Deer \u00b7 Details`, subject:`deer details`, intro:`Now add the details that bring your deer to life.`, badgeKey:"early-beginner-31-deer", badgeName:`Deer Dear`, phase:"detail", baseSvg:DEER_OUTLINE_SVG, steps:DEER_DETAIL_STEPS }; +export const DEER_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"deer", subjectName:`Deer`, subjectEmoji:`🦌`, emoji:`🦌`, order:31, sublevel:313, slug:"deer-extra", title:`Deer \u00b7 Color it!`, subject:`color the deer`, intro:`Bring your deer to life! Color it in.`, badgeKey:"", badgeName:`Deer Dear`, phase:"extra", baseSvg:DEER_DETAIL_SVG, steps:[] }; + +const RABBIT_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two tall ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a round body.`, lines:[``] }, +]; + +const RABBIT_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes, nose and mouth.`, lines:[``,``,``,``] }, + { n:2, title:`Ears & whiskers`, instruction:`Add ear insides and whiskers.`, lines:[``,``,``,``] }, +]; + +const RABBIT_OUTLINE_SVG = RABBIT_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const RABBIT_DETAIL_SVG = RABBIT_OUTLINE_SVG + "\n" + RABBIT_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const RABBIT_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"rabbit", subjectName:`Rabbit`, subjectEmoji:`🐰`, emoji:`🐰`, order:32, sublevel:321, slug:"rabbit-outline", title:`Rabbit \u00b7 Outline`, subject:`rabbit outline`, intro:`Let\u2019s draw Rabbit\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Hoppy Rabbit`, phase:"outline", steps:RABBIT_OUTLINE_STEPS }; +export const RABBIT_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"rabbit", subjectName:`Rabbit`, subjectEmoji:`🐰`, emoji:`🐰`, order:32, sublevel:322, slug:"rabbit-detail", title:`Rabbit \u00b7 Details`, subject:`rabbit details`, intro:`Now add the details that bring your rabbit to life.`, badgeKey:"early-beginner-32-rabbit", badgeName:`Hoppy Rabbit`, phase:"detail", baseSvg:RABBIT_OUTLINE_SVG, steps:RABBIT_DETAIL_STEPS }; +export const RABBIT_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"rabbit", subjectName:`Rabbit`, subjectEmoji:`🐰`, emoji:`🐰`, order:32, sublevel:323, slug:"rabbit-extra", title:`Rabbit \u00b7 Color it!`, subject:`color the rabbit`, intro:`Bring your rabbit to life! Color it in.`, badgeKey:"", badgeName:`Hoppy Rabbit`, phase:"extra", baseSvg:RABBIT_DETAIL_SVG, steps:[] }; + +const HEDGEHOG_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a round spiky body.`, lines:[``] }, + { n:2, title:`The snout`, instruction:`Add a pointy snout.`, lines:[``] }, +]; + +const HEDGEHOG_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The spikes`, instruction:`Add zig-zag spikes.`, lines:[``,``,``,``] }, + { n:2, title:`The face`, instruction:`Add an eye and a nose.`, lines:[``,``] }, + { n:3, title:`The feet`, instruction:`Add little feet.`, lines:[``,``,``] }, +]; + +const HEDGEHOG_OUTLINE_SVG = HEDGEHOG_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const HEDGEHOG_DETAIL_SVG = HEDGEHOG_OUTLINE_SVG + "\n" + HEDGEHOG_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const HEDGEHOG_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"hedgehog", subjectName:`Hedgehog`, subjectEmoji:`πŸ¦”`, emoji:`πŸ¦”`, order:33, sublevel:331, slug:"hedgehog-outline", title:`Hedgehog \u00b7 Outline`, subject:`hedgehog outline`, intro:`Let\u2019s draw Hedgehog\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Prickly Pal`, phase:"outline", steps:HEDGEHOG_OUTLINE_STEPS }; +export const HEDGEHOG_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"hedgehog", subjectName:`Hedgehog`, subjectEmoji:`πŸ¦”`, emoji:`πŸ¦”`, order:33, sublevel:332, slug:"hedgehog-detail", title:`Hedgehog \u00b7 Details`, subject:`hedgehog details`, intro:`Now add the details that bring your hedgehog to life.`, badgeKey:"early-beginner-33-hedgehog", badgeName:`Prickly Pal`, phase:"detail", baseSvg:HEDGEHOG_OUTLINE_SVG, steps:HEDGEHOG_DETAIL_STEPS }; +export const HEDGEHOG_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"hedgehog", subjectName:`Hedgehog`, subjectEmoji:`πŸ¦”`, emoji:`πŸ¦”`, order:33, sublevel:333, slug:"hedgehog-extra", title:`Hedgehog \u00b7 Color it!`, subject:`color the hedgehog`, intro:`Bring your hedgehog to life! Color it in.`, badgeKey:"", badgeName:`Prickly Pal`, phase:"extra", baseSvg:HEDGEHOG_DETAIL_SVG, steps:[] }; + +const OWL_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a rounded owl body.`, lines:[``] }, + { n:2, title:`Ear tufts`, instruction:`Add two ear tufts.`, lines:[``,``] }, + { n:3, title:`The wings`, instruction:`Add two wings.`, lines:[``,``] }, +]; + +const OWL_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Big eyes`, instruction:`Add two big eyes.`, lines:[``,``,``,``] }, + { n:2, title:`Beak & feet`, instruction:`Add a beak and feet.`, lines:[``,``,``,``,``] }, + { n:3, title:`The tummy`, instruction:`Add a tummy curve.`, lines:[``] }, +]; + +const OWL_OUTLINE_SVG = OWL_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const OWL_DETAIL_SVG = OWL_OUTLINE_SVG + "\n" + OWL_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const OWL_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"owl", subjectName:`Owl`, subjectEmoji:`πŸ¦‰`, emoji:`πŸ¦‰`, order:34, sublevel:341, slug:"owl-outline", title:`Owl \u00b7 Outline`, subject:`owl outline`, intro:`Let\u2019s draw Owl\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Wise Owl`, phase:"outline", steps:OWL_OUTLINE_STEPS }; +export const OWL_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"owl", subjectName:`Owl`, subjectEmoji:`πŸ¦‰`, emoji:`πŸ¦‰`, order:34, sublevel:342, slug:"owl-detail", title:`Owl \u00b7 Details`, subject:`owl details`, intro:`Now add the details that bring your owl to life.`, badgeKey:"early-beginner-34-owl", badgeName:`Wise Owl`, phase:"detail", baseSvg:OWL_OUTLINE_SVG, steps:OWL_DETAIL_STEPS }; +export const OWL_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"owl", subjectName:`Owl`, subjectEmoji:`πŸ¦‰`, emoji:`πŸ¦‰`, order:34, sublevel:343, slug:"owl-extra", title:`Owl \u00b7 Color it!`, subject:`color the owl`, intro:`Bring your owl to life! Color it in.`, badgeKey:"", badgeName:`Wise Owl`, phase:"extra", baseSvg:OWL_DETAIL_SVG, steps:[] }; + +const CAT_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add two pointy ears.`, lines:[``,``] }, + { n:3, title:`The body`, instruction:`Add a sitting body.`, lines:[``] }, + { n:4, title:`The tail`, instruction:`Add a curvy tail.`, lines:[``] }, +]; + +const CAT_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The face`, instruction:`Add eyes, nose and mouth.`, lines:[``,``,``,``] }, + { n:2, title:`Whiskers`, instruction:`Add whiskers.`, lines:[``,``,``,``] }, +]; + +const CAT_OUTLINE_SVG = CAT_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const CAT_DETAIL_SVG = CAT_OUTLINE_SVG + "\n" + CAT_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const CAT_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"cat", subjectName:`Cat`, subjectEmoji:`🐱`, emoji:`🐱`, order:35, sublevel:351, slug:"cat-outline", title:`Cat \u00b7 Outline`, subject:`cat outline`, intro:`Let\u2019s draw Cat\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Cool Cat`, phase:"outline", steps:CAT_OUTLINE_STEPS }; +export const CAT_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"cat", subjectName:`Cat`, subjectEmoji:`🐱`, emoji:`🐱`, order:35, sublevel:352, slug:"cat-detail", title:`Cat \u00b7 Details`, subject:`cat details`, intro:`Now add the details that bring your cat to life.`, badgeKey:"early-beginner-35-cat", badgeName:`Cool Cat`, phase:"detail", baseSvg:CAT_OUTLINE_SVG, steps:CAT_DETAIL_STEPS }; +export const CAT_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"cat", subjectName:`Cat`, subjectEmoji:`🐱`, emoji:`🐱`, order:35, sublevel:353, slug:"cat-extra", title:`Cat \u00b7 Color it!`, subject:`color the cat`, intro:`Bring your cat to life! Color it in.`, badgeKey:"", badgeName:`Cool Cat`, phase:"extra", baseSvg:CAT_DETAIL_SVG, steps:[] }; + +const TURTLE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The shell`, instruction:`Draw a dome shell.`, lines:[``] }, + { n:2, title:`Head & legs`, instruction:`Add a head, legs and tail.`, lines:[``,``,``,``] }, +]; + +const TURTLE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Shell pattern`, instruction:`Add a shell pattern.`, lines:[``,``,``] }, + { n:2, title:`The eye`, instruction:`Add a friendly eye.`, lines:[``] }, +]; + +const TURTLE_OUTLINE_SVG = TURTLE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const TURTLE_DETAIL_SVG = TURTLE_OUTLINE_SVG + "\n" + TURTLE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const TURTLE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"turtle", subjectName:`Turtle`, subjectEmoji:`🐒`, emoji:`🐒`, order:36, sublevel:361, slug:"turtle-outline", title:`Turtle \u00b7 Outline`, subject:`turtle outline`, intro:`Let\u2019s draw Turtle\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Turtle Buddy`, phase:"outline", steps:TURTLE_OUTLINE_STEPS }; +export const TURTLE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"turtle", subjectName:`Turtle`, subjectEmoji:`🐒`, emoji:`🐒`, order:36, sublevel:362, slug:"turtle-detail", title:`Turtle \u00b7 Details`, subject:`turtle details`, intro:`Now add the details that bring your turtle to life.`, badgeKey:"early-beginner-36-turtle", badgeName:`Turtle Buddy`, phase:"detail", baseSvg:TURTLE_OUTLINE_SVG, steps:TURTLE_DETAIL_STEPS }; +export const TURTLE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"turtle", subjectName:`Turtle`, subjectEmoji:`🐒`, emoji:`🐒`, order:36, sublevel:363, slug:"turtle-extra", title:`Turtle \u00b7 Color it!`, subject:`color the turtle`, intro:`Bring your turtle to life! Color it in.`, badgeKey:"", badgeName:`Turtle Buddy`, phase:"extra", baseSvg:TURTLE_DETAIL_SVG, steps:[] }; + +const BIRD_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw an egg-shaped body.`, lines:[``] }, + { n:2, title:`The head`, instruction:`Add a round head.`, lines:[``] }, + { n:3, title:`The tail`, instruction:`Add a pointy tail.`, lines:[``] }, + { n:4, title:`The wing`, instruction:`Add a wing.`, lines:[``] }, +]; + +const BIRD_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Beak & eye`, instruction:`Add a beak and an eye.`, lines:[``,``] }, + { n:2, title:`The legs`, instruction:`Add two legs.`, lines:[``,``] }, +]; + +const BIRD_OUTLINE_SVG = BIRD_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const BIRD_DETAIL_SVG = BIRD_OUTLINE_SVG + "\n" + BIRD_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const BIRD_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"bird", subjectName:`Bird`, subjectEmoji:`🐦`, emoji:`🐦`, order:37, sublevel:371, slug:"bird-outline", title:`Bird \u00b7 Outline`, subject:`bird outline`, intro:`Let\u2019s draw Bird\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Little Birdie`, phase:"outline", steps:BIRD_OUTLINE_STEPS }; +export const BIRD_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"bird", subjectName:`Bird`, subjectEmoji:`🐦`, emoji:`🐦`, order:37, sublevel:372, slug:"bird-detail", title:`Bird \u00b7 Details`, subject:`bird details`, intro:`Now add the details that bring your bird to life.`, badgeKey:"early-beginner-37-bird", badgeName:`Little Birdie`, phase:"detail", baseSvg:BIRD_OUTLINE_SVG, steps:BIRD_DETAIL_STEPS }; +export const BIRD_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"bird", subjectName:`Bird`, subjectEmoji:`🐦`, emoji:`🐦`, order:37, sublevel:373, slug:"bird-extra", title:`Bird \u00b7 Color it!`, subject:`color the bird`, intro:`Bring your bird to life! Color it in.`, badgeKey:"", badgeName:`Little Birdie`, phase:"extra", baseSvg:BIRD_DETAIL_SVG, steps:[] }; + +const BUTTERFLY_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw a thin body.`, lines:[``] }, + { n:2, title:`Top wings`, instruction:`Add two big top wings.`, lines:[``,``] }, + { n:3, title:`Bottom wings`, instruction:`Add two bottom wings.`, lines:[``,``] }, +]; + +const BUTTERFLY_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Antennae`, instruction:`Add two antennae.`, lines:[``,``] }, + { n:2, title:`Wing dots`, instruction:`Add pretty dots.`, lines:[``,``,``,``] }, +]; + +const BUTTERFLY_OUTLINE_SVG = BUTTERFLY_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const BUTTERFLY_DETAIL_SVG = BUTTERFLY_OUTLINE_SVG + "\n" + BUTTERFLY_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const BUTTERFLY_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"butterfly", subjectName:`Butterfly`, subjectEmoji:`πŸ¦‹`, emoji:`πŸ¦‹`, order:38, sublevel:381, slug:"butterfly-outline", title:`Butterfly \u00b7 Outline`, subject:`butterfly outline`, intro:`Let\u2019s draw Butterfly\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Flutter By`, phase:"outline", steps:BUTTERFLY_OUTLINE_STEPS }; +export const BUTTERFLY_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"butterfly", subjectName:`Butterfly`, subjectEmoji:`πŸ¦‹`, emoji:`πŸ¦‹`, order:38, sublevel:382, slug:"butterfly-detail", title:`Butterfly \u00b7 Details`, subject:`butterfly details`, intro:`Now add the details that bring your butterfly to life.`, badgeKey:"early-beginner-38-butterfly", badgeName:`Flutter By`, phase:"detail", baseSvg:BUTTERFLY_OUTLINE_SVG, steps:BUTTERFLY_DETAIL_STEPS }; +export const BUTTERFLY_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"butterfly", subjectName:`Butterfly`, subjectEmoji:`πŸ¦‹`, emoji:`πŸ¦‹`, order:38, sublevel:383, slug:"butterfly-extra", title:`Butterfly \u00b7 Color it!`, subject:`color the butterfly`, intro:`Bring your butterfly to life! Color it in.`, badgeKey:"", badgeName:`Flutter By`, phase:"extra", baseSvg:BUTTERFLY_DETAIL_SVG, steps:[] }; + +export const ANIMAL_LESSONS: Lesson[] = [ + LION_OUTLINE_LESSON, + LION_DETAIL_LESSON, + LION_EXTRA_LESSON, + ELEPHANT_OUTLINE_LESSON, + ELEPHANT_DETAIL_LESSON, + ELEPHANT_EXTRA_LESSON, + GIRAFFE_OUTLINE_LESSON, + GIRAFFE_DETAIL_LESSON, + GIRAFFE_EXTRA_LESSON, + ZEBRA_OUTLINE_LESSON, + ZEBRA_DETAIL_LESSON, + ZEBRA_EXTRA_LESSON, + RHINO_OUTLINE_LESSON, + RHINO_DETAIL_LESSON, + RHINO_EXTRA_LESSON, + LEOPARD_OUTLINE_LESSON, + LEOPARD_DETAIL_LESSON, + LEOPARD_EXTRA_LESSON, + TIGER_OUTLINE_LESSON, + TIGER_DETAIL_LESSON, + TIGER_EXTRA_LESSON, + MONKEY_OUTLINE_LESSON, + MONKEY_DETAIL_LESSON, + MONKEY_EXTRA_LESSON, + CROCODILE_OUTLINE_LESSON, + CROCODILE_DETAIL_LESSON, + CROCODILE_EXTRA_LESSON, + FOX_OUTLINE_LESSON, + FOX_DETAIL_LESSON, + FOX_EXTRA_LESSON, + BEAR_OUTLINE_LESSON, + BEAR_DETAIL_LESSON, + BEAR_EXTRA_LESSON, + DEER_OUTLINE_LESSON, + DEER_DETAIL_LESSON, + DEER_EXTRA_LESSON, + RABBIT_OUTLINE_LESSON, + RABBIT_DETAIL_LESSON, + RABBIT_EXTRA_LESSON, + HEDGEHOG_OUTLINE_LESSON, + HEDGEHOG_DETAIL_LESSON, + HEDGEHOG_EXTRA_LESSON, + OWL_OUTLINE_LESSON, + OWL_DETAIL_LESSON, + OWL_EXTRA_LESSON, + CAT_OUTLINE_LESSON, + CAT_DETAIL_LESSON, + CAT_EXTRA_LESSON, + TURTLE_OUTLINE_LESSON, + TURTLE_DETAIL_LESSON, + TURTLE_EXTRA_LESSON, + BIRD_OUTLINE_LESSON, + BIRD_DETAIL_LESSON, + BIRD_EXTRA_LESSON, + BUTTERFLY_OUTLINE_LESSON, + BUTTERFLY_DETAIL_LESSON, + BUTTERFLY_EXTRA_LESSON +]; diff --git a/src/lib/curriculum.eb2.ts b/src/lib/curriculum.eb2.ts new file mode 100644 index 0000000..ad8e469 --- /dev/null +++ b/src/lib/curriculum.eb2.ts @@ -0,0 +1,234 @@ +/* AUTO-GENERATED by gen_eb2.py β€” Early Beginner geometric subjects (Simple Shapes, Fun Things, Clothes, Faces). */ +import type { Lesson, LessonStep } from "./curriculum"; + +const SQUARE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The square`, instruction:`Draw four straight sides to make a square.`, tip:`Keep the corners square!`, lines:[``] }, +]; + +const SQUARE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Happy face`, instruction:`Add two eyes and a big smile.`, tip:`Now it's a friendly square!`, lines:[``,``,``] }, +]; + +const SQUARE_OUTLINE_SVG = SQUARE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const SQUARE_DETAIL_SVG = SQUARE_OUTLINE_SVG + "\n" + SQUARE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const SQUARE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"square", subjectName:`Square`, subjectEmoji:`🟦`, emoji:`🟦`, order:7, sublevel:71, slug:"square-outline", title:`Square \u00b7 Outline`, subject:`square outline`, intro:`Let\u2019s draw Square\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Square Star`, phase:"outline", steps:SQUARE_OUTLINE_STEPS }; +export const SQUARE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"square", subjectName:`Square`, subjectEmoji:`🟦`, emoji:`🟦`, order:7, sublevel:72, slug:"square-detail", title:`Square \u00b7 Details`, subject:`square details`, intro:`Now add the details that make your square fun.`, badgeKey:"early-beginner-7-square", badgeName:`Square Star`, phase:"detail", baseSvg:SQUARE_OUTLINE_SVG, steps:SQUARE_DETAIL_STEPS }; +export const SQUARE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"square", subjectName:`Square`, subjectEmoji:`🟦`, emoji:`🟦`, order:7, sublevel:73, slug:"square-extra", title:`Square \u00b7 Color it!`, subject:`color the square`, intro:`Bring your square to life! Color it in.`, badgeKey:"", badgeName:`Square Star`, phase:"extra", baseSvg:SQUARE_DETAIL_SVG, steps:[] }; + +const TRIANGLE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The triangle`, instruction:`Draw three straight sides that meet at a point.`, lines:[``] }, +]; + +const TRIANGLE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Happy face`, instruction:`Add a cute face near the bottom.`, lines:[``,``,``] }, +]; + +const TRIANGLE_OUTLINE_SVG = TRIANGLE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const TRIANGLE_DETAIL_SVG = TRIANGLE_OUTLINE_SVG + "\n" + TRIANGLE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const TRIANGLE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"triangle", subjectName:`Triangle`, subjectEmoji:`πŸ”Ί`, emoji:`πŸ”Ί`, order:8, sublevel:81, slug:"triangle-outline", title:`Triangle \u00b7 Outline`, subject:`triangle outline`, intro:`Let\u2019s draw Triangle\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Triangle Ace`, phase:"outline", steps:TRIANGLE_OUTLINE_STEPS }; +export const TRIANGLE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"triangle", subjectName:`Triangle`, subjectEmoji:`πŸ”Ί`, emoji:`πŸ”Ί`, order:8, sublevel:82, slug:"triangle-detail", title:`Triangle \u00b7 Details`, subject:`triangle details`, intro:`Now add the details that make your triangle fun.`, badgeKey:"early-beginner-8-triangle", badgeName:`Triangle Ace`, phase:"detail", baseSvg:TRIANGLE_OUTLINE_SVG, steps:TRIANGLE_DETAIL_STEPS }; +export const TRIANGLE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"triangle", subjectName:`Triangle`, subjectEmoji:`πŸ”Ί`, emoji:`πŸ”Ί`, order:8, sublevel:83, slug:"triangle-extra", title:`Triangle \u00b7 Color it!`, subject:`color the triangle`, intro:`Bring your triangle to life! Color it in.`, badgeKey:"", badgeName:`Triangle Ace`, phase:"extra", baseSvg:TRIANGLE_DETAIL_SVG, steps:[] }; + +const HEART_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The heart`, instruction:`Draw two bumps on top that swoop to a point.`, tip:`Slow on the bumps!`, lines:[``] }, +]; + +const HEART_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Shine & smile`, instruction:`Add a shine line and a little smile.`, lines:[``,``] }, +]; + +const HEART_OUTLINE_SVG = HEART_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const HEART_DETAIL_SVG = HEART_OUTLINE_SVG + "\n" + HEART_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const HEART_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"heart", subjectName:`Heart`, subjectEmoji:`❀️`, emoji:`❀️`, order:9, sublevel:91, slug:"heart-outline", title:`Heart \u00b7 Outline`, subject:`heart outline`, intro:`Let\u2019s draw Heart\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Heart Hero`, phase:"outline", steps:HEART_OUTLINE_STEPS }; +export const HEART_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"heart", subjectName:`Heart`, subjectEmoji:`❀️`, emoji:`❀️`, order:9, sublevel:92, slug:"heart-detail", title:`Heart \u00b7 Details`, subject:`heart details`, intro:`Now add the details that make your heart fun.`, badgeKey:"early-beginner-9-heart", badgeName:`Heart Hero`, phase:"detail", baseSvg:HEART_OUTLINE_SVG, steps:HEART_DETAIL_STEPS }; +export const HEART_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"heart", subjectName:`Heart`, subjectEmoji:`❀️`, emoji:`❀️`, order:9, sublevel:93, slug:"heart-extra", title:`Heart \u00b7 Color it!`, subject:`color the heart`, intro:`Bring your heart to life! Color it in.`, badgeKey:"", badgeName:`Heart Hero`, phase:"extra", baseSvg:HEART_DETAIL_SVG, steps:[] }; + +const BOW_TIE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The two wings`, instruction:`Draw a triangle on each side meeting in the middle.`, lines:[``,``] }, + { n:2, title:`The knot`, instruction:`Add a little square knot in the middle.`, lines:[``] }, +]; + +const BOW_TIE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Polka dots`, instruction:`Add fold lines and some dots.`, lines:[``,``,``,``,``,``] }, +]; + +const BOW_TIE_OUTLINE_SVG = BOW_TIE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const BOW_TIE_DETAIL_SVG = BOW_TIE_OUTLINE_SVG + "\n" + BOW_TIE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const BOW_TIE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"bow-tie", subjectName:`Bow Tie`, subjectEmoji:`πŸŽ€`, emoji:`πŸŽ€`, order:10, sublevel:101, slug:"bow-tie-outline", title:`Bow Tie \u00b7 Outline`, subject:`bow tie outline`, intro:`Let\u2019s draw Bow Tie\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Dapper Bow`, phase:"outline", steps:BOW_TIE_OUTLINE_STEPS }; +export const BOW_TIE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"bow-tie", subjectName:`Bow Tie`, subjectEmoji:`πŸŽ€`, emoji:`πŸŽ€`, order:10, sublevel:102, slug:"bow-tie-detail", title:`Bow Tie \u00b7 Details`, subject:`bow tie details`, intro:`Now add the details that make your bow tie fun.`, badgeKey:"early-beginner-10-bow-tie", badgeName:`Dapper Bow`, phase:"detail", baseSvg:BOW_TIE_OUTLINE_SVG, steps:BOW_TIE_DETAIL_STEPS }; +export const BOW_TIE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"bow-tie", subjectName:`Bow Tie`, subjectEmoji:`πŸŽ€`, emoji:`πŸŽ€`, order:10, sublevel:103, slug:"bow-tie-extra", title:`Bow Tie \u00b7 Color it!`, subject:`color the bow tie`, intro:`Bring your bow tie to life! Color it in.`, badgeKey:"", badgeName:`Dapper Bow`, phase:"extra", baseSvg:BOW_TIE_DETAIL_SVG, steps:[] }; + +const FOOTBALL_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The ball`, instruction:`Draw a pointed oval.`, tip:`Pointy on each end.`, lines:[``] }, +]; + +const FOOTBALL_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Laces`, instruction:`Add the laces and stitches.`, lines:[``,``,``,``,``,``] }, +]; + +const FOOTBALL_OUTLINE_SVG = FOOTBALL_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const FOOTBALL_DETAIL_SVG = FOOTBALL_OUTLINE_SVG + "\n" + FOOTBALL_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const FOOTBALL_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"football", subjectName:`Football`, subjectEmoji:`🏈`, emoji:`🏈`, order:11, sublevel:111, slug:"football-outline", title:`Football \u00b7 Outline`, subject:`football outline`, intro:`Let\u2019s draw Football\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Touchdown`, phase:"outline", steps:FOOTBALL_OUTLINE_STEPS }; +export const FOOTBALL_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"football", subjectName:`Football`, subjectEmoji:`🏈`, emoji:`🏈`, order:11, sublevel:112, slug:"football-detail", title:`Football \u00b7 Details`, subject:`football details`, intro:`Now add the details that make your football fun.`, badgeKey:"early-beginner-11-football", badgeName:`Touchdown`, phase:"detail", baseSvg:FOOTBALL_OUTLINE_SVG, steps:FOOTBALL_DETAIL_STEPS }; +export const FOOTBALL_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"football", subjectName:`Football`, subjectEmoji:`🏈`, emoji:`🏈`, order:11, sublevel:113, slug:"football-extra", title:`Football \u00b7 Color it!`, subject:`color the football`, intro:`Bring your football to life! Color it in.`, badgeKey:"", badgeName:`Touchdown`, phase:"extra", baseSvg:FOOTBALL_DETAIL_SVG, steps:[] }; + +const BASKETBALL_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The ball`, instruction:`Draw one big round circle.`, lines:[``] }, +]; + +const BASKETBALL_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`The seams`, instruction:`Add the lines across the ball.`, lines:[``,``,``,``] }, +]; + +const BASKETBALL_OUTLINE_SVG = BASKETBALL_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const BASKETBALL_DETAIL_SVG = BASKETBALL_OUTLINE_SVG + "\n" + BASKETBALL_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const BASKETBALL_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"basketball", subjectName:`Basketball`, subjectEmoji:`πŸ€`, emoji:`πŸ€`, order:12, sublevel:121, slug:"basketball-outline", title:`Basketball \u00b7 Outline`, subject:`basketball outline`, intro:`Let\u2019s draw Basketball\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Hoop Star`, phase:"outline", steps:BASKETBALL_OUTLINE_STEPS }; +export const BASKETBALL_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"basketball", subjectName:`Basketball`, subjectEmoji:`πŸ€`, emoji:`πŸ€`, order:12, sublevel:122, slug:"basketball-detail", title:`Basketball \u00b7 Details`, subject:`basketball details`, intro:`Now add the details that make your basketball fun.`, badgeKey:"early-beginner-12-basketball", badgeName:`Hoop Star`, phase:"detail", baseSvg:BASKETBALL_OUTLINE_SVG, steps:BASKETBALL_DETAIL_STEPS }; +export const BASKETBALL_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"basketball", subjectName:`Basketball`, subjectEmoji:`πŸ€`, emoji:`πŸ€`, order:12, sublevel:123, slug:"basketball-extra", title:`Basketball \u00b7 Color it!`, subject:`color the basketball`, intro:`Bring your basketball to life! Color it in.`, badgeKey:"", badgeName:`Hoop Star`, phase:"extra", baseSvg:BASKETBALL_DETAIL_SVG, steps:[] }; + +const CUP_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The cup`, instruction:`Draw a cup that is wider at the top.`, tip:`Flat top β€” no oval yet!`, lines:[``] }, + { n:2, title:`The lid`, instruction:`Add a lid on top.`, lines:[``] }, +]; + +const CUP_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Straw & stripe`, instruction:`Add a straw and a wavy stripe.`, lines:[``,``] }, +]; + +const CUP_OUTLINE_SVG = CUP_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const CUP_DETAIL_SVG = CUP_OUTLINE_SVG + "\n" + CUP_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const CUP_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"cup", subjectName:`Cup`, subjectEmoji:`πŸ₯€`, emoji:`πŸ₯€`, order:13, sublevel:131, slug:"cup-outline", title:`Cup \u00b7 Outline`, subject:`cup outline`, intro:`Let\u2019s draw Cup\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Cup Champ`, phase:"outline", steps:CUP_OUTLINE_STEPS }; +export const CUP_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"cup", subjectName:`Cup`, subjectEmoji:`πŸ₯€`, emoji:`πŸ₯€`, order:13, sublevel:132, slug:"cup-detail", title:`Cup \u00b7 Details`, subject:`cup details`, intro:`Now add the details that make your cup fun.`, badgeKey:"early-beginner-13-cup", badgeName:`Cup Champ`, phase:"detail", baseSvg:CUP_OUTLINE_SVG, steps:CUP_DETAIL_STEPS }; +export const CUP_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"cup", subjectName:`Cup`, subjectEmoji:`πŸ₯€`, emoji:`πŸ₯€`, order:13, sublevel:133, slug:"cup-extra", title:`Cup \u00b7 Color it!`, subject:`color the cup`, intro:`Bring your cup to life! Color it in.`, badgeKey:"", badgeName:`Cup Champ`, phase:"extra", baseSvg:CUP_DETAIL_SVG, steps:[] }; + +const TROPHY_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The cup`, instruction:`Draw the trophy bowl.`, lines:[``] }, + { n:2, title:`Stem & base`, instruction:`Add the stem and a base.`, lines:[``,``] }, +]; + +const TROPHY_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Handles & star`, instruction:`Add two handles and a number 1.`, tip:`You're a winner!`, lines:[``,``,``,``] }, +]; + +const TROPHY_OUTLINE_SVG = TROPHY_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const TROPHY_DETAIL_SVG = TROPHY_OUTLINE_SVG + "\n" + TROPHY_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const TROPHY_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"trophy", subjectName:`Trophy`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:14, sublevel:141, slug:"trophy-outline", title:`Trophy \u00b7 Outline`, subject:`trophy outline`, intro:`Let\u2019s draw Trophy\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Trophy Winner`, phase:"outline", steps:TROPHY_OUTLINE_STEPS }; +export const TROPHY_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"trophy", subjectName:`Trophy`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:14, sublevel:142, slug:"trophy-detail", title:`Trophy \u00b7 Details`, subject:`trophy details`, intro:`Now add the details that make your trophy fun.`, badgeKey:"early-beginner-14-trophy", badgeName:`Trophy Winner`, phase:"detail", baseSvg:TROPHY_OUTLINE_SVG, steps:TROPHY_DETAIL_STEPS }; +export const TROPHY_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"trophy", subjectName:`Trophy`, subjectEmoji:`πŸ†`, emoji:`πŸ†`, order:14, sublevel:143, slug:"trophy-extra", title:`Trophy \u00b7 Color it!`, subject:`color the trophy`, intro:`Bring your trophy to life! Color it in.`, badgeKey:"", badgeName:`Trophy Winner`, phase:"extra", baseSvg:TROPHY_DETAIL_SVG, steps:[] }; + +const SHIRT_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The body`, instruction:`Draw the shirt body with sleeves.`, lines:[``] }, + { n:2, title:`The neck`, instruction:`Add a round neckline.`, lines:[``] }, +]; + +const SHIRT_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Collar & pocket`, instruction:`Add a collar and a little pocket.`, lines:[``,``] }, +]; + +const SHIRT_OUTLINE_SVG = SHIRT_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const SHIRT_DETAIL_SVG = SHIRT_OUTLINE_SVG + "\n" + SHIRT_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const SHIRT_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"shirt", subjectName:`Shirt`, subjectEmoji:`πŸ‘•`, emoji:`πŸ‘•`, order:15, sublevel:151, slug:"shirt-outline", title:`Shirt \u00b7 Outline`, subject:`shirt outline`, intro:`Let\u2019s draw Shirt\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Cool Shirt`, phase:"outline", steps:SHIRT_OUTLINE_STEPS }; +export const SHIRT_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"shirt", subjectName:`Shirt`, subjectEmoji:`πŸ‘•`, emoji:`πŸ‘•`, order:15, sublevel:152, slug:"shirt-detail", title:`Shirt \u00b7 Details`, subject:`shirt details`, intro:`Now add the details that make your shirt fun.`, badgeKey:"early-beginner-15-shirt", badgeName:`Cool Shirt`, phase:"detail", baseSvg:SHIRT_OUTLINE_SVG, steps:SHIRT_DETAIL_STEPS }; +export const SHIRT_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"shirt", subjectName:`Shirt`, subjectEmoji:`πŸ‘•`, emoji:`πŸ‘•`, order:15, sublevel:153, slug:"shirt-extra", title:`Shirt \u00b7 Color it!`, subject:`color the shirt`, intro:`Bring your shirt to life! Color it in.`, badgeKey:"", badgeName:`Cool Shirt`, phase:"extra", baseSvg:SHIRT_DETAIL_SVG, steps:[] }; + +const DRESS_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The top`, instruction:`Draw the dress top.`, lines:[``] }, + { n:2, title:`The skirt`, instruction:`Add a flowy skirt.`, lines:[``] }, +]; + +const DRESS_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Straps & waist`, instruction:`Add straps and a waistline.`, lines:[``,``,``] }, +]; + +const DRESS_OUTLINE_SVG = DRESS_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const DRESS_DETAIL_SVG = DRESS_OUTLINE_SVG + "\n" + DRESS_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const DRESS_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"dress", subjectName:`Dress`, subjectEmoji:`πŸ‘—`, emoji:`πŸ‘—`, order:16, sublevel:161, slug:"dress-outline", title:`Dress \u00b7 Outline`, subject:`dress outline`, intro:`Let\u2019s draw Dress\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Pretty Dress`, phase:"outline", steps:DRESS_OUTLINE_STEPS }; +export const DRESS_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"dress", subjectName:`Dress`, subjectEmoji:`πŸ‘—`, emoji:`πŸ‘—`, order:16, sublevel:162, slug:"dress-detail", title:`Dress \u00b7 Details`, subject:`dress details`, intro:`Now add the details that make your dress fun.`, badgeKey:"early-beginner-16-dress", badgeName:`Pretty Dress`, phase:"detail", baseSvg:DRESS_OUTLINE_SVG, steps:DRESS_DETAIL_STEPS }; +export const DRESS_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"dress", subjectName:`Dress`, subjectEmoji:`πŸ‘—`, emoji:`πŸ‘—`, order:16, sublevel:163, slug:"dress-extra", title:`Dress \u00b7 Color it!`, subject:`color the dress`, intro:`Bring your dress to life! Color it in.`, badgeKey:"", badgeName:`Pretty Dress`, phase:"extra", baseSvg:DRESS_DETAIL_SVG, steps:[] }; + +const SOCKS_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The sock`, instruction:`Draw an L-shaped sock.`, lines:[``] }, +]; + +const SOCKS_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Cuff & stripes`, instruction:`Add a folded cuff and stripes.`, lines:[``,``,``,``] }, +]; + +const SOCKS_OUTLINE_SVG = SOCKS_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const SOCKS_DETAIL_SVG = SOCKS_OUTLINE_SVG + "\n" + SOCKS_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const SOCKS_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"socks", subjectName:`Socks`, subjectEmoji:`🧦`, emoji:`🧦`, order:17, sublevel:171, slug:"socks-outline", title:`Socks \u00b7 Outline`, subject:`socks outline`, intro:`Let\u2019s draw Socks\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Sock Star`, phase:"outline", steps:SOCKS_OUTLINE_STEPS }; +export const SOCKS_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"socks", subjectName:`Socks`, subjectEmoji:`🧦`, emoji:`🧦`, order:17, sublevel:172, slug:"socks-detail", title:`Socks \u00b7 Details`, subject:`socks details`, intro:`Now add the details that make your socks fun.`, badgeKey:"early-beginner-17-socks", badgeName:`Sock Star`, phase:"detail", baseSvg:SOCKS_OUTLINE_SVG, steps:SOCKS_DETAIL_STEPS }; +export const SOCKS_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"socks", subjectName:`Socks`, subjectEmoji:`🧦`, emoji:`🧦`, order:17, sublevel:173, slug:"socks-extra", title:`Socks \u00b7 Color it!`, subject:`color the socks`, intro:`Bring your socks to life! Color it in.`, badgeKey:"", badgeName:`Sock Star`, phase:"extra", baseSvg:SOCKS_DETAIL_SVG, steps:[] }; + +const EYES_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`Two eyes`, instruction:`Draw two almond shapes, one eye apart.`, lines:[``,``] }, +]; + +const EYES_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Look alive`, instruction:`Add round eyeballs and dots, plus eyebrows.`, tip:`Eyes sit halfway!`, lines:[``,``,``,``,``,``] }, +]; + +const EYES_OUTLINE_SVG = EYES_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const EYES_DETAIL_SVG = EYES_OUTLINE_SVG + "\n" + EYES_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const EYES_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"eyes", subjectName:`Eyes`, subjectEmoji:`πŸ‘€`, emoji:`πŸ‘€`, order:18, sublevel:181, slug:"eyes-outline", title:`Eyes \u00b7 Outline`, subject:`eyes outline`, intro:`Let\u2019s draw Eyes\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Bright Eyes`, phase:"outline", steps:EYES_OUTLINE_STEPS }; +export const EYES_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"eyes", subjectName:`Eyes`, subjectEmoji:`πŸ‘€`, emoji:`πŸ‘€`, order:18, sublevel:182, slug:"eyes-detail", title:`Eyes \u00b7 Details`, subject:`eyes details`, intro:`Now add the details that make your eyes fun.`, badgeKey:"early-beginner-18-eyes", badgeName:`Bright Eyes`, phase:"detail", baseSvg:EYES_OUTLINE_SVG, steps:EYES_DETAIL_STEPS }; +export const EYES_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"eyes", subjectName:`Eyes`, subjectEmoji:`πŸ‘€`, emoji:`πŸ‘€`, order:18, sublevel:183, slug:"eyes-extra", title:`Eyes \u00b7 Color it!`, subject:`color the eyes`, intro:`Bring your eyes to life! Color it in.`, badgeKey:"", badgeName:`Bright Eyes`, phase:"extra", baseSvg:EYES_DETAIL_SVG, steps:[] }; + +const FACE_OUTLINE_STEPS: LessonStep[] = [ + { n:1, title:`The head`, instruction:`Draw a big round head.`, lines:[``] }, + { n:2, title:`The ears`, instruction:`Add an ear on each side.`, lines:[``,``] }, +]; + +const FACE_DETAIL_STEPS: LessonStep[] = [ + { n:1, title:`Eyes & nose`, instruction:`Add two eyes and a little nose.`, tip:`Eyes in the middle!`, lines:[``,``,``,``,``] }, + { n:2, title:`Smile & hair`, instruction:`Add a big smile and some hair.`, lines:[``,``] }, +]; + +const FACE_OUTLINE_SVG = FACE_OUTLINE_STEPS.flatMap(x=>x.lines||[]).join("\n"); +const FACE_DETAIL_SVG = FACE_OUTLINE_SVG + "\n" + FACE_DETAIL_STEPS.flatMap(x=>x.lines||[]).join("\n"); +export const FACE_OUTLINE_LESSON: Lesson = { level:"early-beginner", subjectKey:"face", subjectName:`Face`, subjectEmoji:`πŸ™‚`, emoji:`πŸ™‚`, order:19, sublevel:191, slug:"face-outline", title:`Face \u00b7 Outline`, subject:`face outline`, intro:`Let\u2019s draw Face\u2019s outline, one line at a time. Watch each line, then trace it!`, badgeKey:"", badgeName:`Friendly Face`, phase:"outline", steps:FACE_OUTLINE_STEPS }; +export const FACE_DETAIL_LESSON: Lesson = { level:"early-beginner", subjectKey:"face", subjectName:`Face`, subjectEmoji:`πŸ™‚`, emoji:`πŸ™‚`, order:19, sublevel:192, slug:"face-detail", title:`Face \u00b7 Details`, subject:`face details`, intro:`Now add the details that make your face fun.`, badgeKey:"early-beginner-19-face", badgeName:`Friendly Face`, phase:"detail", baseSvg:FACE_OUTLINE_SVG, steps:FACE_DETAIL_STEPS }; +export const FACE_EXTRA_LESSON: Lesson = { level:"early-beginner", subjectKey:"face", subjectName:`Face`, subjectEmoji:`πŸ™‚`, emoji:`πŸ™‚`, order:19, sublevel:193, slug:"face-extra", title:`Face \u00b7 Color it!`, subject:`color the face`, intro:`Bring your face to life! Color it in.`, badgeKey:"", badgeName:`Friendly Face`, phase:"extra", baseSvg:FACE_DETAIL_SVG, steps:[] }; + +export const EB2_LESSONS: Lesson[] = [ + SQUARE_OUTLINE_LESSON, + SQUARE_DETAIL_LESSON, + SQUARE_EXTRA_LESSON, + TRIANGLE_OUTLINE_LESSON, + TRIANGLE_DETAIL_LESSON, + TRIANGLE_EXTRA_LESSON, + HEART_OUTLINE_LESSON, + HEART_DETAIL_LESSON, + HEART_EXTRA_LESSON, + BOW_TIE_OUTLINE_LESSON, + BOW_TIE_DETAIL_LESSON, + BOW_TIE_EXTRA_LESSON, + FOOTBALL_OUTLINE_LESSON, + FOOTBALL_DETAIL_LESSON, + FOOTBALL_EXTRA_LESSON, + BASKETBALL_OUTLINE_LESSON, + BASKETBALL_DETAIL_LESSON, + BASKETBALL_EXTRA_LESSON, + CUP_OUTLINE_LESSON, + CUP_DETAIL_LESSON, + CUP_EXTRA_LESSON, + TROPHY_OUTLINE_LESSON, + TROPHY_DETAIL_LESSON, + TROPHY_EXTRA_LESSON, + SHIRT_OUTLINE_LESSON, + SHIRT_DETAIL_LESSON, + SHIRT_EXTRA_LESSON, + DRESS_OUTLINE_LESSON, + DRESS_DETAIL_LESSON, + DRESS_EXTRA_LESSON, + SOCKS_OUTLINE_LESSON, + SOCKS_DETAIL_LESSON, + SOCKS_EXTRA_LESSON, + EYES_OUTLINE_LESSON, + EYES_DETAIL_LESSON, + EYES_EXTRA_LESSON, + FACE_OUTLINE_LESSON, + FACE_DETAIL_LESSON, + FACE_EXTRA_LESSON +]; + diff --git a/src/lib/curriculum.ts b/src/lib/curriculum.ts index e46c773..6c0539a 100644 --- a/src/lib/curriculum.ts +++ b/src/lib/curriculum.ts @@ -1,213 +1,247 @@ -/** - * DrawIt curriculum. Each Early Beginner subject is a 3-lesson set: Outline -> Details -> Color it. - * Outline/Detail steps use per-step `lines` (coloring-book strokes drawn one at a time). The Detail - * lesson awards the subject badge (it is gated behind Outline). `mode "shade"` = shading studio. - */ -export interface LevelMeta { key: string; name: string; emoji: string; blurb: string; } -export const LEVELS: LevelMeta[] = [ - { key: "early-beginner", name: "Early Beginner", emoji: "\u{1F331}", blurb: "First lines and simple shapes. Perfect for brand-new artists." }, - { key: "beginner", name: "Beginner", emoji: "\u270F\uFE0F", blurb: "Combine shapes into friendly characters and objects." }, - { key: "learner", name: "Learner", emoji: "\u{1F3A8}", blurb: "Add details, shading, and your own ideas." }, - { key: "advanced-learned", name: "Advanced Learner", emoji: "\u{1F680}", blurb: "Proportion, perspective, and more complex scenes." }, - { key: "superb", name: "Superb", emoji: "\u{1F31F}", blurb: "Confident, expressive drawing in your own style." }, -]; -export function getLevel(key: string): LevelMeta | undefined { return LEVELS.find((l) => l.key === key); } -export type StepKind = "construct" | "outline" | "color" | "shade" | "detail"; -// Early Beginner uses outline/detail/extra; Beginner uses construct/outline/color/light. -export type Phase = "construct" | "outline" | "detail" | "color" | "light" | "extra"; -export interface LessonStep { n: number; title: string; instruction: string; tip?: string; kind?: StepKind; svg?: string; lines?: string[]; } -export interface Lesson { - level: string; sublevel: number; slug: string; title: string; subject: string; emoji: string; intro: string; - badgeKey: string; badgeName: string; mode?: "draw" | "shade"; phase?: Phase; baseSvg?: string; - subjectKey?: string; subjectName?: string; subjectEmoji?: string; order?: number; packKey?: string; steps: LessonStep[]; -} - - -const FISH_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The body", instruction: "Draw the big rounded body β€” loop all the way around.", tip: "Slow and smooth, like an egg.", lines: [``] }, - { n: 2, title: "The tail", instruction: "Add the fan-shaped tail at the back.", lines: [``] }, - { n: 3, title: "The fins", instruction: "Draw a fin on the back, then one under the belly.", lines: [``, ``] }, -]; - -const FISH_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "The eye", instruction: "Draw a round eye, then a little dot inside.", lines: [``, ``] }, - { n: 2, title: "The mouth", instruction: "Add a small smile at the front.", lines: [``] }, - { n: 3, title: "The gill", instruction: "Add a curved gill line behind the head.", lines: [``] }, - { n: 4, title: "Stripes", instruction: "Add a couple of curved stripes across the body.", tip: "Now it's ready to color!", lines: [``, ``] }, -]; - -const FISH_OUTLINE_SVG = FISH_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const FISH_DETAIL_SVG = FISH_OUTLINE_SVG + "\n" + FISH_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const FISH_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:11, slug:"fish-outline", title:"Fish \u00b7 Outline", subject:"fish outline", emoji:"🐟", intro:"Let\u2019s draw Fish\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Fish Friend", phase:"outline", subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: FISH_OUTLINE_STEPS }; - -export const FISH_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:12, slug:"fish-detail", title:"Fish \u00b7 Details", subject:"fish details", emoji:"🐟", intro:"Now add the details that bring your fish to life.", badgeKey:"early-beginner-1-fish", badgeName:"Fish Friend", phase:"detail", baseSvg: FISH_OUTLINE_SVG, subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: FISH_DETAIL_STEPS }; - -export const FISH_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:13, slug:"fish-extra", title:"Fish \u00b7 Color it!", subject:"color the fish", emoji:"\u{1F3A8}", intro:"Bring your fish to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Fish Friend", phase:"extra", baseSvg: FISH_DETAIL_SVG, subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: [] }; - -const PANDA_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The head", instruction: "Draw one big round face.", tip: "Nice and round.", lines: [``] }, - { n: 2, title: "The ears", instruction: "Add two round ears on top.", lines: [``, ``] }, - { n: 3, title: "Eye patches", instruction: "Draw a leaf-shaped patch for each eye.", lines: [``, ``] }, -]; - -const PANDA_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "The eyes", instruction: "Add a circle and a dot inside each patch.", lines: [``, ``, ``, ``] }, - { n: 2, title: "The nose", instruction: "Draw a little rounded nose.", lines: [``] }, - { n: 3, title: "The mouth", instruction: "Add a line down and two smile curves.", lines: [``, ``, ``] }, -]; - -const PANDA_OUTLINE_SVG = PANDA_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const PANDA_DETAIL_SVG = PANDA_OUTLINE_SVG + "\n" + PANDA_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const PANDA_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:21, slug:"panda-outline", title:"Panda \u00b7 Outline", subject:"panda outline", emoji:"🐼", intro:"Let\u2019s draw Panda\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Panda Pal", phase:"outline", subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: PANDA_OUTLINE_STEPS }; - -export const PANDA_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:22, slug:"panda-detail", title:"Panda \u00b7 Details", subject:"panda details", emoji:"🐼", intro:"Now add the details that bring your panda to life.", badgeKey:"early-beginner-2-panda", badgeName:"Panda Pal", phase:"detail", baseSvg: PANDA_OUTLINE_SVG, subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: PANDA_DETAIL_STEPS }; - -export const PANDA_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:23, slug:"panda-extra", title:"Panda \u00b7 Color it!", subject:"color the panda", emoji:"\u{1F3A8}", intro:"Bring your panda to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Panda Pal", phase:"extra", baseSvg: PANDA_DETAIL_SVG, subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: [] }; - -const FLOWER_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The center", instruction: "Draw a circle in the middle.", tip: "Leave room for petals.", lines: [``] }, - { n: 2, title: "Petals", instruction: "Add petals on top, bottom, left, and right.", lines: [``, ``, ``, ``] }, - { n: 3, title: "More petals", instruction: "Tuck four more petals into the gaps.", lines: [``, ``, ``, ``] }, - { n: 4, title: "The stem", instruction: "Draw a stem going down from the flower.", lines: [``] }, - { n: 5, title: "The leaves", instruction: "Add a leaf on each side of the stem.", lines: [``, ``] }, -]; - -const FLOWER_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "Seeds", instruction: "Dot some seeds in the middle.", lines: [``, ``, ``, ``, ``] }, - { n: 2, title: "Leaf veins", instruction: "Add a line down each leaf.", lines: [``, ``] }, - { n: 3, title: "Center ring", instruction: "Draw a little ring inside the middle.", lines: [``] }, -]; - -const FLOWER_OUTLINE_SVG = FLOWER_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const FLOWER_DETAIL_SVG = FLOWER_OUTLINE_SVG + "\n" + FLOWER_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const FLOWER_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:31, slug:"flower-outline", title:"Flower \u00b7 Outline", subject:"flower outline", emoji:"🌸", intro:"Let\u2019s draw Flower\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Flower Power", phase:"outline", subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: FLOWER_OUTLINE_STEPS }; - -export const FLOWER_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:32, slug:"flower-detail", title:"Flower \u00b7 Details", subject:"flower details", emoji:"🌸", intro:"Now add the details that bring your flower to life.", badgeKey:"early-beginner-3-flower", badgeName:"Flower Power", phase:"detail", baseSvg: FLOWER_OUTLINE_SVG, subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: FLOWER_DETAIL_STEPS }; - -export const FLOWER_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:33, slug:"flower-extra", title:"Flower \u00b7 Color it!", subject:"color the flower", emoji:"\u{1F3A8}", intro:"Bring your flower to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Flower Power", phase:"extra", baseSvg: FLOWER_DETAIL_SVG, subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: [] }; - -const UNICORN_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The head", instruction: "Draw a rounded head.", lines: [``] }, - { n: 2, title: "The ears", instruction: "Add a pointy ear on each side.", lines: [``, ``] }, - { n: 3, title: "The horn", instruction: "Draw a tall horn on top.", lines: [``] }, - { n: 4, title: "The mane", instruction: "Draw the flowing mane and a curl on the forehead.", lines: [``, ``] }, -]; - -const UNICORN_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "The eyes", instruction: "Add two big eyes.", lines: [``, ``] }, - { n: 2, title: "Nose & mouth", instruction: "Add two nostril dots and a smile.", lines: [``, ``, ``] }, - { n: 3, title: "Horn swirls", instruction: "Add little swirl lines on the horn.", lines: [``, ``, ``] }, - { n: 4, title: "Mane lines", instruction: "Add flowing lines in the mane.", lines: [``, ``] }, -]; - -const UNICORN_OUTLINE_SVG = UNICORN_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const UNICORN_DETAIL_SVG = UNICORN_OUTLINE_SVG + "\n" + UNICORN_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const UNICORN_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:41, slug:"unicorn-outline", title:"Unicorn \u00b7 Outline", subject:"unicorn outline", emoji:"πŸ¦„", intro:"Let\u2019s draw Unicorn\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Unicorn Magic", phase:"outline", subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: UNICORN_OUTLINE_STEPS }; - -export const UNICORN_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:42, slug:"unicorn-detail", title:"Unicorn \u00b7 Details", subject:"unicorn details", emoji:"πŸ¦„", intro:"Now add the details that bring your unicorn to life.", badgeKey:"early-beginner-4-unicorn", badgeName:"Unicorn Magic", phase:"detail", baseSvg: UNICORN_OUTLINE_SVG, subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: UNICORN_DETAIL_STEPS }; - -export const UNICORN_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:43, slug:"unicorn-extra", title:"Unicorn \u00b7 Color it!", subject:"color the unicorn", emoji:"\u{1F3A8}", intro:"Bring your unicorn to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Unicorn Magic", phase:"extra", baseSvg: UNICORN_DETAIL_SVG, subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: [] }; - -const TREE_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The trunk", instruction: "Draw a tall trunk, wider at the bottom.", lines: [``] }, - { n: 2, title: "Branches", instruction: "Add two branches reaching up.", lines: [``, ``] }, - { n: 3, title: "The treetop", instruction: "Draw a big bumpy treetop.", tip: "Nice and lumpy!", lines: [``] }, -]; - -const TREE_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "Apples", instruction: "Add a few round apples in the leaves.", lines: [``, ``, ``] }, - { n: 2, title: "Grass", instruction: "Add wavy grass along the bottom.", lines: [``] }, - { n: 3, title: "Bark", instruction: "Add a couple of bark lines on the trunk.", lines: [``, ``] }, -]; - -const TREE_OUTLINE_SVG = TREE_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const TREE_DETAIL_SVG = TREE_OUTLINE_SVG + "\n" + TREE_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const TREE_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:51, slug:"tree-outline", title:"Tree \u00b7 Outline", subject:"tree outline", emoji:"🌳", intro:"Let\u2019s draw Tree\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Tree Top", phase:"outline", subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: TREE_OUTLINE_STEPS }; - -export const TREE_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:52, slug:"tree-detail", title:"Tree \u00b7 Details", subject:"tree details", emoji:"🌳", intro:"Now add the details that bring your tree to life.", badgeKey:"early-beginner-5-tree", badgeName:"Tree Top", phase:"detail", baseSvg: TREE_OUTLINE_SVG, subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: TREE_DETAIL_STEPS }; - -export const TREE_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:53, slug:"tree-extra", title:"Tree \u00b7 Color it!", subject:"color the tree", emoji:"\u{1F3A8}", intro:"Bring your tree to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Tree Top", phase:"extra", baseSvg: TREE_DETAIL_SVG, subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: [] }; - -const DINO_OUTLINE_STEPS: LessonStep[] = [ - { n: 1, title: "The body", instruction: "Draw a big round body.", lines: [``] }, - { n: 2, title: "The neck", instruction: "Sweep a long neck up from the left.", lines: [``] }, - { n: 3, title: "The head", instruction: "Add a small head on top of the neck.", lines: [``] }, - { n: 4, title: "The tail", instruction: "Draw a long tail swooping to the right.", lines: [``] }, - { n: 5, title: "The legs", instruction: "Add two sturdy legs underneath.", lines: [``, ``] }, -]; - -const DINO_DETAIL_STEPS: LessonStep[] = [ - { n: 1, title: "Back plates", instruction: "Add triangle plates along the back.", lines: [``, ``, ``, ``] }, - { n: 2, title: "Spots", instruction: "Add a few spots on the body.", lines: [``, ``, ``] }, - { n: 3, title: "The face", instruction: "Add an eye and a friendly smile.", lines: [``, ``] }, -]; - -const DINO_OUTLINE_SVG = DINO_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); - -const DINO_DETAIL_SVG = DINO_OUTLINE_SVG + "\n" + DINO_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); - -export const DINO_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:61, slug:"dinosaur-outline", title:"Dinosaur \u00b7 Outline", subject:"dinosaur outline", emoji:"πŸ¦•", intro:"Let\u2019s draw Dinosaur\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Dino Master", phase:"outline", subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: DINO_OUTLINE_STEPS }; - -export const DINO_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:62, slug:"dinosaur-detail", title:"Dinosaur \u00b7 Details", subject:"dinosaur details", emoji:"πŸ¦•", intro:"Now add the details that bring your dinosaur to life.", badgeKey:"early-beginner-6-dinosaur", badgeName:"Dino Master", phase:"detail", baseSvg: DINO_OUTLINE_SVG, subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: DINO_DETAIL_STEPS }; - -export const DINO_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:63, slug:"dinosaur-extra", title:"Dinosaur \u00b7 Color it!", subject:"color the dinosaur", emoji:"\u{1F3A8}", intro:"Bring your dinosaur to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Dino Master", phase:"extra", baseSvg: DINO_DETAIL_SVG, subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: [] }; - -const SHADE_STEPS: LessonStep[] = [ - { n: 1, kind: "shade", title: "How to hold your pencil", instruction: "Watch the demo above. Near the tip + press hard = DARK; high up + soft = LIGHT.", tip: "Try it in the air first!", svg: `` }, - { n: 2, kind: "shade", title: "Find the light", instruction: "The sun is up-left. The side facing it stays brightest β€” that bright spot is the highlight.", svg: `` }, - { n: 3, kind: "shade", title: "Soft shade all over", instruction: "Pick a light tone and softly shade the whole ball β€” leave the bright spot white.", tip: "Hold high and go easy.", svg: `` }, - { n: 4, kind: "shade", title: "Build up the shadow", instruction: "Pick a darker tone and press harder on the side away from the sun. Build it up slowly.", tip: "More passes = darker.", svg: `` }, - { n: 5, kind: "shade", title: "Cast shadow & finish", instruction: "Shade the ground under the ball on the shadow side. Keep the highlight clean!", tip: "πŸŒ—", svg: `` }, -]; - -export const SHADE_BALL_LESSON: Lesson = { level:"learner", sublevel:1, slug:"shade-ball", title:"Light & Shadow: Shade a Ball", subject:"a shaded ball", emoji:"\u{1F317}", intro:"Make a flat circle look like a round ball using light and shadow!", badgeKey:"learner-1-shading", badgeName:"Shading Star", mode:"shade", subjectKey:"shade-ball", subjectName:"Shade a Ball", subjectEmoji:"\u{1F317}", order:1, steps: SHADE_STEPS }; - -import { BEGINNER_LESSONS, BEGINNER_PACKS, type Pack } from "./curriculum.beginner"; -export { BEGINNER_PACKS, type Pack } from "./curriculum.beginner"; -export { LIGHT_HINT_SVG } from "./curriculum.beginner"; - -const EARLY_BEGINNER_LESSONS: Lesson[] = [FISH_OUTLINE_LESSON, FISH_DETAIL_LESSON, FISH_EXTRA_LESSON, PANDA_OUTLINE_LESSON, PANDA_DETAIL_LESSON, PANDA_EXTRA_LESSON, FLOWER_OUTLINE_LESSON, FLOWER_DETAIL_LESSON, FLOWER_EXTRA_LESSON, UNICORN_OUTLINE_LESSON, UNICORN_DETAIL_LESSON, UNICORN_EXTRA_LESSON, TREE_OUTLINE_LESSON, TREE_DETAIL_LESSON, TREE_EXTRA_LESSON, DINO_OUTLINE_LESSON, DINO_DETAIL_LESSON, DINO_EXTRA_LESSON]; -export const LESSONS: Lesson[] = [...EARLY_BEGINNER_LESSONS, ...BEGINNER_LESSONS, SHADE_BALL_LESSON]; - -export function getLesson(level: string, sublevel: number): Lesson | undefined { return LESSONS.find((l) => l.level === level && l.sublevel === sublevel); } -export function getLessonBySlug(slug: string): Lesson | undefined { return LESSONS.find((l) => l.slug === slug); } -export function cumulativeSvg(lesson: Lesson, upTo: number): string { return lesson.steps.filter((s) => s.n <= upTo).map((s) => s.svg || "").join("\n"); } -export function cumulativeLines(lesson: Lesson, upTo: number): string { return lesson.steps.filter((s) => s.n <= upTo).flatMap((s) => s.lines || []).join("\n"); } -export function getSubjects(level: string): { key: string; name: string; emoji: string; order: number; lessons: Lesson[] }[] { - const inLevel = LESSONS.filter((l) => l.level === level); - const map = new Map(); - for (const l of inLevel) { - const key = l.subjectKey || l.slug; - if (!map.has(key)) map.set(key, { key, name: l.subjectName || l.title, emoji: l.subjectEmoji || l.emoji, order: l.order ?? l.sublevel, lessons: [] }); - map.get(key)!.lessons.push(l); - } - // Covers both Early Beginner (outline/detail/extra) and Beginner (construct/outline/color/light). - const rank: Record = { construct: 0, outline: 1, detail: 2, color: 3, extra: 3, light: 4 }; - for (const s of map.values()) s.lessons.sort((a, b) => (rank[a.phase ?? ""] ?? 0) - (rank[b.phase ?? ""] ?? 0)); - return [...map.values()].sort((a, b) => a.order - b.order); -} - -/** All badge definitions: per-subject (Early Beginner) + per-pack (Beginner). */ -export interface BadgeDef { badgeKey: string; name: string; emoji: string; groupKey: string; } -export function badgeDefs(): BadgeDef[] { - const fromLessons = LESSONS.filter((l) => l.badgeKey).map((l) => ({ badgeKey: l.badgeKey, name: l.badgeName, emoji: l.emoji, groupKey: `${l.level}-${l.sublevel}` })); - const fromPacks = BEGINNER_PACKS.map((p) => ({ badgeKey: p.badgeKey, name: p.badgeName, emoji: p.emoji, groupKey: "" })); - return [...fromLessons, ...fromPacks]; -} -export function getPackByBadge(badgeKey: string): Pack | undefined { return BEGINNER_PACKS.find((p) => p.badgeKey === badgeKey); } -/** The pack a lesson belongs to (Beginner only), via its packKey. */ -export function getPackForLesson(lesson: Lesson): Pack | undefined { return lesson.packKey ? BEGINNER_PACKS.find((p) => p.key === lesson.packKey) : undefined; } -/** Every lesson that belongs to a pack (all phases of all its subjects). */ -export function lessonsInPack(pack: Pack): Lesson[] { return LESSONS.filter((l) => l.level === pack.level && l.subjectKey && pack.subjectKeys.includes(l.subjectKey)); } -/** Number of completed steps needed to count a lesson as done. */ -export function lessonStepCount(l: Lesson): number { return l.steps.length || 1; } +/** + * DrawIt curriculum. Each Early Beginner subject is a 3-lesson set: Outline -> Details -> Color it. + * Outline/Detail steps use per-step `lines` (coloring-book strokes drawn one at a time). The Detail + * lesson awards the subject badge (it is gated behind Outline). `mode "shade"` = shading studio. + */ +export interface LevelMeta { key: string; name: string; emoji: string; blurb: string; } +export const LEVELS: LevelMeta[] = [ + { key: "early-beginner", name: "Early Beginner", emoji: "\u{1F331}", blurb: "First lines and simple shapes. Perfect for brand-new artists." }, + { key: "beginner", name: "Beginner", emoji: "\u270F\uFE0F", blurb: "Combine shapes into friendly characters and objects." }, + { key: "learner", name: "Learner", emoji: "\u{1F3A8}", blurb: "Add details, shading, and your own ideas." }, + { key: "advanced-learned", name: "Advanced Learner", emoji: "\u{1F680}", blurb: "Proportion, perspective, and more complex scenes." }, + { key: "superb", name: "Superb", emoji: "\u{1F31F}", blurb: "Confident, expressive drawing in your own style." }, +]; +export function getLevel(key: string): LevelMeta | undefined { return LEVELS.find((l) => l.key === key); } +export type StepKind = "construct" | "outline" | "color" | "shade" | "detail"; +// Early Beginner uses outline/detail/extra; Beginner uses construct/outline/color/light. +export type Phase = "construct" | "outline" | "detail" | "color" | "light" | "extra"; +export interface LessonStep { n: number; title: string; instruction: string; tip?: string; kind?: StepKind; svg?: string; lines?: string[]; } +export interface Lesson { + level: string; sublevel: number; slug: string; title: string; subject: string; emoji: string; intro: string; + badgeKey: string; badgeName: string; mode?: "draw" | "shade"; phase?: Phase; baseSvg?: string; + subjectKey?: string; subjectName?: string; subjectEmoji?: string; order?: number; packKey?: string; steps: LessonStep[]; +} + + +const FISH_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The body", instruction: "Draw the big rounded body β€” loop all the way around.", tip: "Slow and smooth, like an egg.", lines: [``] }, + { n: 2, title: "The tail", instruction: "Add the fan-shaped tail at the back.", lines: [``] }, + { n: 3, title: "The fins", instruction: "Draw a fin on the back, then one under the belly.", lines: [``, ``] }, +]; + +const FISH_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "The eye", instruction: "Draw a round eye, then a little dot inside.", lines: [``, ``] }, + { n: 2, title: "The mouth", instruction: "Add a small smile at the front.", lines: [``] }, + { n: 3, title: "The gill", instruction: "Add a curved gill line behind the head.", lines: [``] }, + { n: 4, title: "Stripes", instruction: "Add a couple of curved stripes across the body.", tip: "Now it's ready to color!", lines: [``, ``] }, +]; + +const FISH_OUTLINE_SVG = FISH_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const FISH_DETAIL_SVG = FISH_OUTLINE_SVG + "\n" + FISH_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const FISH_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:11, slug:"fish-outline", title:"Fish \u00b7 Outline", subject:"fish outline", emoji:"🐟", intro:"Let\u2019s draw Fish\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Fish Friend", phase:"outline", subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: FISH_OUTLINE_STEPS }; + +export const FISH_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:12, slug:"fish-detail", title:"Fish \u00b7 Details", subject:"fish details", emoji:"🐟", intro:"Now add the details that bring your fish to life.", badgeKey:"early-beginner-1-fish", badgeName:"Fish Friend", phase:"detail", baseSvg: FISH_OUTLINE_SVG, subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: FISH_DETAIL_STEPS }; + +export const FISH_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:13, slug:"fish-extra", title:"Fish \u00b7 Color it!", subject:"color the fish", emoji:"\u{1F3A8}", intro:"Bring your fish to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Fish Friend", phase:"extra", baseSvg: FISH_DETAIL_SVG, subjectKey:"fish", subjectName:"Fish", subjectEmoji:"🐟", order:1, steps: [] }; + +const PANDA_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The head", instruction: "Draw one big round face.", tip: "Nice and round.", lines: [``] }, + { n: 2, title: "The ears", instruction: "Add two round ears on top.", lines: [``, ``] }, + { n: 3, title: "Eye patches", instruction: "Draw a leaf-shaped patch for each eye.", lines: [``, ``] }, +]; + +const PANDA_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "The eyes", instruction: "Add a circle and a dot inside each patch.", lines: [``, ``, ``, ``] }, + { n: 2, title: "The nose", instruction: "Draw a little rounded nose.", lines: [``] }, + { n: 3, title: "The mouth", instruction: "Add a line down and two smile curves.", lines: [``, ``, ``] }, +]; + +const PANDA_OUTLINE_SVG = PANDA_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const PANDA_DETAIL_SVG = PANDA_OUTLINE_SVG + "\n" + PANDA_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const PANDA_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:21, slug:"panda-outline", title:"Panda \u00b7 Outline", subject:"panda outline", emoji:"🐼", intro:"Let\u2019s draw Panda\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Panda Pal", phase:"outline", subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: PANDA_OUTLINE_STEPS }; + +export const PANDA_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:22, slug:"panda-detail", title:"Panda \u00b7 Details", subject:"panda details", emoji:"🐼", intro:"Now add the details that bring your panda to life.", badgeKey:"early-beginner-2-panda", badgeName:"Panda Pal", phase:"detail", baseSvg: PANDA_OUTLINE_SVG, subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: PANDA_DETAIL_STEPS }; + +export const PANDA_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:23, slug:"panda-extra", title:"Panda \u00b7 Color it!", subject:"color the panda", emoji:"\u{1F3A8}", intro:"Bring your panda to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Panda Pal", phase:"extra", baseSvg: PANDA_DETAIL_SVG, subjectKey:"panda", subjectName:"Panda", subjectEmoji:"🐼", order:2, steps: [] }; + +const FLOWER_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The center", instruction: "Draw a circle in the middle.", tip: "Leave room for petals.", lines: [``] }, + { n: 2, title: "Petals", instruction: "Add petals on top, bottom, left, and right.", lines: [``, ``, ``, ``] }, + { n: 3, title: "More petals", instruction: "Tuck four more petals into the gaps.", lines: [``, ``, ``, ``] }, + { n: 4, title: "The stem", instruction: "Draw a stem going down from the flower.", lines: [``] }, + { n: 5, title: "The leaves", instruction: "Add a leaf on each side of the stem.", lines: [``, ``] }, +]; + +const FLOWER_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "Seeds", instruction: "Dot some seeds in the middle.", lines: [``, ``, ``, ``, ``] }, + { n: 2, title: "Leaf veins", instruction: "Add a line down each leaf.", lines: [``, ``] }, + { n: 3, title: "Center ring", instruction: "Draw a little ring inside the middle.", lines: [``] }, +]; + +const FLOWER_OUTLINE_SVG = FLOWER_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const FLOWER_DETAIL_SVG = FLOWER_OUTLINE_SVG + "\n" + FLOWER_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const FLOWER_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:31, slug:"flower-outline", title:"Flower \u00b7 Outline", subject:"flower outline", emoji:"🌸", intro:"Let\u2019s draw Flower\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Flower Power", phase:"outline", subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: FLOWER_OUTLINE_STEPS }; + +export const FLOWER_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:32, slug:"flower-detail", title:"Flower \u00b7 Details", subject:"flower details", emoji:"🌸", intro:"Now add the details that bring your flower to life.", badgeKey:"early-beginner-3-flower", badgeName:"Flower Power", phase:"detail", baseSvg: FLOWER_OUTLINE_SVG, subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: FLOWER_DETAIL_STEPS }; + +export const FLOWER_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:33, slug:"flower-extra", title:"Flower \u00b7 Color it!", subject:"color the flower", emoji:"\u{1F3A8}", intro:"Bring your flower to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Flower Power", phase:"extra", baseSvg: FLOWER_DETAIL_SVG, subjectKey:"flower", subjectName:"Flower", subjectEmoji:"🌸", order:3, steps: [] }; + +const UNICORN_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The head", instruction: "Draw a rounded head.", lines: [``] }, + { n: 2, title: "The ears", instruction: "Add a pointy ear on each side.", lines: [``, ``] }, + { n: 3, title: "The horn", instruction: "Draw a tall horn on top.", lines: [``] }, + { n: 4, title: "The mane", instruction: "Draw the flowing mane and a curl on the forehead.", lines: [``, ``] }, +]; + +const UNICORN_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "The eyes", instruction: "Add two big eyes.", lines: [``, ``] }, + { n: 2, title: "Nose & mouth", instruction: "Add two nostril dots and a smile.", lines: [``, ``, ``] }, + { n: 3, title: "Horn swirls", instruction: "Add little swirl lines on the horn.", lines: [``, ``, ``] }, + { n: 4, title: "Mane lines", instruction: "Add flowing lines in the mane.", lines: [``, ``] }, +]; + +const UNICORN_OUTLINE_SVG = UNICORN_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const UNICORN_DETAIL_SVG = UNICORN_OUTLINE_SVG + "\n" + UNICORN_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const UNICORN_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:41, slug:"unicorn-outline", title:"Unicorn \u00b7 Outline", subject:"unicorn outline", emoji:"πŸ¦„", intro:"Let\u2019s draw Unicorn\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Unicorn Magic", phase:"outline", subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: UNICORN_OUTLINE_STEPS }; + +export const UNICORN_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:42, slug:"unicorn-detail", title:"Unicorn \u00b7 Details", subject:"unicorn details", emoji:"πŸ¦„", intro:"Now add the details that bring your unicorn to life.", badgeKey:"early-beginner-4-unicorn", badgeName:"Unicorn Magic", phase:"detail", baseSvg: UNICORN_OUTLINE_SVG, subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: UNICORN_DETAIL_STEPS }; + +export const UNICORN_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:43, slug:"unicorn-extra", title:"Unicorn \u00b7 Color it!", subject:"color the unicorn", emoji:"\u{1F3A8}", intro:"Bring your unicorn to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Unicorn Magic", phase:"extra", baseSvg: UNICORN_DETAIL_SVG, subjectKey:"unicorn", subjectName:"Unicorn", subjectEmoji:"πŸ¦„", order:4, steps: [] }; + +const TREE_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The trunk", instruction: "Draw a tall trunk, wider at the bottom.", lines: [``] }, + { n: 2, title: "Branches", instruction: "Add two branches reaching up.", lines: [``, ``] }, + { n: 3, title: "The treetop", instruction: "Draw a big bumpy treetop.", tip: "Nice and lumpy!", lines: [``] }, +]; + +const TREE_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "Apples", instruction: "Add a few round apples in the leaves.", lines: [``, ``, ``] }, + { n: 2, title: "Grass", instruction: "Add wavy grass along the bottom.", lines: [``] }, + { n: 3, title: "Bark", instruction: "Add a couple of bark lines on the trunk.", lines: [``, ``] }, +]; + +const TREE_OUTLINE_SVG = TREE_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const TREE_DETAIL_SVG = TREE_OUTLINE_SVG + "\n" + TREE_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const TREE_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:51, slug:"tree-outline", title:"Tree \u00b7 Outline", subject:"tree outline", emoji:"🌳", intro:"Let\u2019s draw Tree\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Tree Top", phase:"outline", subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: TREE_OUTLINE_STEPS }; + +export const TREE_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:52, slug:"tree-detail", title:"Tree \u00b7 Details", subject:"tree details", emoji:"🌳", intro:"Now add the details that bring your tree to life.", badgeKey:"early-beginner-5-tree", badgeName:"Tree Top", phase:"detail", baseSvg: TREE_OUTLINE_SVG, subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: TREE_DETAIL_STEPS }; + +export const TREE_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:53, slug:"tree-extra", title:"Tree \u00b7 Color it!", subject:"color the tree", emoji:"\u{1F3A8}", intro:"Bring your tree to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Tree Top", phase:"extra", baseSvg: TREE_DETAIL_SVG, subjectKey:"tree", subjectName:"Tree", subjectEmoji:"🌳", order:5, steps: [] }; + +const DINO_OUTLINE_STEPS: LessonStep[] = [ + { n: 1, title: "The body", instruction: "Draw a big round body.", lines: [``] }, + { n: 2, title: "The neck", instruction: "Sweep a long neck up from the left.", lines: [``] }, + { n: 3, title: "The head", instruction: "Add a small head on top of the neck.", lines: [``] }, + { n: 4, title: "The tail", instruction: "Draw a long tail swooping to the right.", lines: [``] }, + { n: 5, title: "The legs", instruction: "Add two sturdy legs underneath.", lines: [``, ``] }, +]; + +const DINO_DETAIL_STEPS: LessonStep[] = [ + { n: 1, title: "Back plates", instruction: "Add triangle plates along the back.", lines: [``, ``, ``, ``] }, + { n: 2, title: "Spots", instruction: "Add a few spots on the body.", lines: [``, ``, ``] }, + { n: 3, title: "The face", instruction: "Add an eye and a friendly smile.", lines: [``, ``] }, +]; + +const DINO_OUTLINE_SVG = DINO_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n"); + +const DINO_DETAIL_SVG = DINO_OUTLINE_SVG + "\n" + DINO_DETAIL_STEPS.flatMap((s) => s.lines || []).join("\n"); + +export const DINO_OUTLINE_LESSON: Lesson = { level:"early-beginner", sublevel:61, slug:"dinosaur-outline", title:"Dinosaur \u00b7 Outline", subject:"dinosaur outline", emoji:"πŸ¦•", intro:"Let\u2019s draw Dinosaur\u2019s outline, one line at a time. Watch each line, then trace it!", badgeKey:"", badgeName:"Dino Master", phase:"outline", subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: DINO_OUTLINE_STEPS }; + +export const DINO_DETAIL_LESSON: Lesson = { level:"early-beginner", sublevel:62, slug:"dinosaur-detail", title:"Dinosaur \u00b7 Details", subject:"dinosaur details", emoji:"πŸ¦•", intro:"Now add the details that bring your dinosaur to life.", badgeKey:"early-beginner-6-dinosaur", badgeName:"Dino Master", phase:"detail", baseSvg: DINO_OUTLINE_SVG, subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: DINO_DETAIL_STEPS }; + +export const DINO_EXTRA_LESSON: Lesson = { level:"early-beginner", sublevel:63, slug:"dinosaur-extra", title:"Dinosaur \u00b7 Color it!", subject:"color the dinosaur", emoji:"\u{1F3A8}", intro:"Bring your dinosaur to life! Color it in, and try shading and layering.", badgeKey:"", badgeName:"Dino Master", phase:"extra", baseSvg: DINO_DETAIL_SVG, subjectKey:"dinosaur", subjectName:"Dinosaur", subjectEmoji:"πŸ¦•", order:6, steps: [] }; + +const SHADE_STEPS: LessonStep[] = [ + { n: 1, kind: "shade", title: "How to hold your pencil", instruction: "Watch the demo above. Near the tip + press hard = DARK; high up + soft = LIGHT.", tip: "Try it in the air first!", svg: `` }, + { n: 2, kind: "shade", title: "Find the light", instruction: "The sun is up-left. The side facing it stays brightest β€” that bright spot is the highlight.", svg: `` }, + { n: 3, kind: "shade", title: "Soft shade all over", instruction: "Pick a light tone and softly shade the whole ball β€” leave the bright spot white.", tip: "Hold high and go easy.", svg: `` }, + { n: 4, kind: "shade", title: "Build up the shadow", instruction: "Pick a darker tone and press harder on the side away from the sun. Build it up slowly.", tip: "More passes = darker.", svg: `` }, + { n: 5, kind: "shade", title: "Cast shadow & finish", instruction: "Shade the ground under the ball on the shadow side. Keep the highlight clean!", tip: "πŸŒ—", svg: `` }, +]; + +export const SHADE_BALL_LESSON: Lesson = { level:"learner", sublevel:1, slug:"shade-ball", title:"Light & Shadow: Shade a Ball", subject:"a shaded ball", emoji:"\u{1F317}", intro:"Make a flat circle look like a round ball using light and shadow!", badgeKey:"learner-1-shading", badgeName:"Shading Star", mode:"shade", subjectKey:"shade-ball", subjectName:"Shade a Ball", subjectEmoji:"\u{1F317}", order:1, steps: SHADE_STEPS }; + +import { BEGINNER_LESSONS, BEGINNER_PACKS, type Pack } from "./curriculum.beginner"; +import { EB2_LESSONS } from "./curriculum.eb2"; +import { ANIMAL_LESSONS } from "./curriculum.animals"; +export { BEGINNER_PACKS, type Pack } from "./curriculum.beginner"; +export { LIGHT_HINT_SVG } from "./curriculum.beginner"; + +const EARLY_BEGINNER_LESSONS: Lesson[] = [FISH_OUTLINE_LESSON, FISH_DETAIL_LESSON, FISH_EXTRA_LESSON, PANDA_OUTLINE_LESSON, PANDA_DETAIL_LESSON, PANDA_EXTRA_LESSON, FLOWER_OUTLINE_LESSON, FLOWER_DETAIL_LESSON, FLOWER_EXTRA_LESSON, UNICORN_OUTLINE_LESSON, UNICORN_DETAIL_LESSON, UNICORN_EXTRA_LESSON, TREE_OUTLINE_LESSON, TREE_DETAIL_LESSON, TREE_EXTRA_LESSON, DINO_OUTLINE_LESSON, DINO_DETAIL_LESSON, DINO_EXTRA_LESSON, ...EB2_LESSONS, ...ANIMAL_LESSONS]; +export const LESSONS: Lesson[] = [...EARLY_BEGINNER_LESSONS, ...BEGINNER_LESSONS, SHADE_BALL_LESSON]; + +export function getLesson(level: string, sublevel: number): Lesson | undefined { return LESSONS.find((l) => l.level === level && l.sublevel === sublevel); } +export function getLessonBySlug(slug: string): Lesson | undefined { return LESSONS.find((l) => l.slug === slug); } +export function cumulativeSvg(lesson: Lesson, upTo: number): string { return lesson.steps.filter((s) => s.n <= upTo).map((s) => s.svg || "").join("\n"); } +export function cumulativeLines(lesson: Lesson, upTo: number): string { return lesson.steps.filter((s) => s.n <= upTo).flatMap((s) => s.lines || []).join("\n"); } +export function getSubjects(level: string): { key: string; name: string; emoji: string; order: number; lessons: Lesson[] }[] { + const inLevel = LESSONS.filter((l) => l.level === level); + const map = new Map(); + for (const l of inLevel) { + const key = l.subjectKey || l.slug; + if (!map.has(key)) map.set(key, { key, name: l.subjectName || l.title, emoji: l.subjectEmoji || l.emoji, order: l.order ?? l.sublevel, lessons: [] }); + map.get(key)!.lessons.push(l); + } + // Covers both Early Beginner (outline/detail/extra) and Beginner (construct/outline/color/light). + const rank: Record = { construct: 0, outline: 1, detail: 2, color: 3, extra: 3, light: 4 }; + for (const s of map.values()) s.lessons.sort((a, b) => (rank[a.phase ?? ""] ?? 0) - (rank[b.phase ?? ""] ?? 0)); + return [...map.values()].sort((a, b) => a.order - b.order); +} + +/** Themed groups for browsing a level's subjects (Early Beginner). Keyed by subjectKey. */ +export interface SubjectGroup { key: string; name: string; emoji: string; subjectKeys: string[]; } +export const EARLY_BEGINNER_GROUPS: SubjectGroup[] = [ + { key: "shapes", name: "Simple Shapes", emoji: "⭐", subjectKeys: ["square", "triangle", "heart"] }, + { key: "classics", name: "Animals & Nature", emoji: "\u{1F41F}", subjectKeys: ["fish", "panda", "flower", "unicorn", "tree", "dinosaur"] }, + { key: "safari", name: "Safari Animals", emoji: "\u{1F981}", subjectKeys: ["lion", "elephant", "giraffe", "zebra", "rhino", "leopard", "tiger", "monkey", "crocodile"] }, + { key: "woodland", name: "Woodland Critters", emoji: "\u{1F98A}", subjectKeys: ["fox", "bear", "deer", "rabbit", "hedgehog", "owl", "cat", "turtle"] }, + { key: "air", name: "Up in the Air", emoji: "\u{1F98B}", subjectKeys: ["bird", "butterfly"] }, + { key: "fun", name: "Fun Things", emoji: "\u{1F380}", subjectKeys: ["bow-tie", "football", "basketball", "cup", "trophy"] }, + { key: "wear", name: "Things to Wear", emoji: "\u{1F455}", subjectKeys: ["shirt", "dress", "socks"] }, + { key: "faces", name: "Faces & Features", emoji: "\u{1F642}", subjectKeys: ["eyes", "face"] }, +]; + +export type GroupedSubjects = { key: string; name: string; emoji: string; subjects: ReturnType }[]; +/** Bucket a level's subjects into ordered themed groups; anything unlisted falls into a "More" group. */ +export function getGroupedSubjects(level: string): GroupedSubjects { + const subjects = getSubjects(level); + const byKey = new Map(subjects.map((s) => [s.key, s])); + const used = new Set(); + const cfg = level === "early-beginner" ? EARLY_BEGINNER_GROUPS : []; + const groups: GroupedSubjects = cfg + .map((g) => { + const subs = g.subjectKeys.map((k) => byKey.get(k)).filter(Boolean) as ReturnType; + subs.forEach((s) => used.add(s.key)); + return { key: g.key, name: g.name, emoji: g.emoji, subjects: subs }; + }) + .filter((g) => g.subjects.length > 0); + const rest = subjects.filter((s) => !used.has(s.key)); + if (rest.length) groups.push({ key: "more", name: "More", emoji: "✨", subjects: rest }); + return groups; +} + +/** All badge definitions: per-subject (Early Beginner) + per-pack (Beginner). */ +export interface BadgeDef { badgeKey: string; name: string; emoji: string; groupKey: string; } +export function badgeDefs(): BadgeDef[] { + const fromLessons = LESSONS.filter((l) => l.badgeKey).map((l) => ({ badgeKey: l.badgeKey, name: l.badgeName, emoji: l.emoji, groupKey: `${l.level}-${l.sublevel}` })); + const fromPacks = BEGINNER_PACKS.map((p) => ({ badgeKey: p.badgeKey, name: p.badgeName, emoji: p.emoji, groupKey: "" })); + return [...fromLessons, ...fromPacks]; +} +export function getPackByBadge(badgeKey: string): Pack | undefined { return BEGINNER_PACKS.find((p) => p.badgeKey === badgeKey); } +/** The pack a lesson belongs to (Beginner only), via its packKey. */ +export function getPackForLesson(lesson: Lesson): Pack | undefined { return lesson.packKey ? BEGINNER_PACKS.find((p) => p.key === lesson.packKey) : undefined; } +/** Every lesson that belongs to a pack (all phases of all its subjects). */ +export function lessonsInPack(pack: Pack): Lesson[] { return LESSONS.filter((l) => l.level === pack.level && l.subjectKey && pack.subjectKeys.includes(l.subjectKey)); } +/** Number of completed steps needed to count a lesson as done. */ +export function lessonStepCount(l: Lesson): number { return l.steps.length || 1; }