Add three lesson structure to remaining Early Beginner levels
This commit is contained in:
1 parent
3fdce23929
commit
e868e2a2e7
1 file changed
+133
-146
+133
-146
@@ -1,11 +1,9 @@
|
||||
/**
|
||||
* The DrawIt curriculum. Levels describe the learner; each level has numbered sub-levels (lessons).
|
||||
* Draw lessons: SVG fragments STACK (steps 1..n = full picture). Shade lessons (mode "shade"):
|
||||
* each step's svg is a full guide (light source + zone hints), not cumulative.
|
||||
* 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." },
|
||||
@@ -13,183 +11,172 @@ export const LEVELS: LevelMeta[] = [
|
||||
{ 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";
|
||||
export type Phase = "outline" | "detail" | "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; steps: LessonStep[];
|
||||
}
|
||||
|
||||
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; steps: LessonStep[]; }
|
||||
|
||||
|
||||
// Fish is the pilot for the 3-lesson model: Outline → Detail → Color it.
|
||||
// Outline/Detail use per-step `lines` (coloring-book strokes drawn one at a time).
|
||||
const LN = (d: string) => `<path d="${d}" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`;
|
||||
|
||||
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: [LN("M85 150 C 95 95, 180 78, 252 96 C 292 107, 306 128, 306 150 C 306 172, 292 193, 252 204 C 180 222, 95 205, 85 150 Z")] },
|
||||
{ n: 2, title: "The tail", instruction: "Add the fan-shaped tail at the back.",
|
||||
lines: [LN("M300 150 C 332 130, 360 112, 390 100 C 374 130, 374 170, 390 200 C 360 188, 332 170, 300 150 Z")] },
|
||||
{ n: 3, title: "The fins", instruction: "Draw a fin on the back, then one under the belly.",
|
||||
lines: [LN("M150 92 C 168 62, 212 60, 240 84"), LN("M150 178 C 168 208, 206 210, 228 196")] },
|
||||
{ n: 1, title: "The body", instruction: "Draw the big rounded body — loop all the way around.", tip: "Slow and smooth, like an egg.", lines: [`<path d="M85 150 C 95 95, 180 78, 252 96 C 292 107, 306 128, 306 150 C 306 172, 292 193, 252 204 C 180 222, 95 205, 85 150 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 2, title: "The tail", instruction: "Add the fan-shaped tail at the back.", lines: [`<path d="M300 150 C 332 130, 360 112, 390 100 C 374 130, 374 170, 390 200 C 360 188, 332 170, 300 150 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The fins", instruction: "Draw a fin on the back, then one under the belly.", lines: [`<path d="M150 92 C 168 62, 212 60, 240 84" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M150 178 C 168 208, 206 210, 228 196" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
const FISH_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "The eye", instruction: "Draw a round eye, then a little dot inside.",
|
||||
lines: [LN("M147 134 a15 15 0 1 0 0.1 0"), `<circle cx="129" cy="136" r="6" fill="#2b2440"/>`] },
|
||||
{ n: 2, title: "The mouth", instruction: "Add a small smile at the front.",
|
||||
lines: [LN("M90 162 q15 13 32 4")] },
|
||||
{ n: 3, title: "The gill", instruction: "Add a curved gill line behind the head.",
|
||||
lines: [LN("M160 104 q-16 46 0 92")] },
|
||||
{ n: 4, title: "Stripes", instruction: "Add a couple of curved stripes across the body.", tip: "Now it's ready to color!",
|
||||
lines: [LN("M205 96 q-20 54 4 110"), LN("M240 100 q-16 50 4 100")] },
|
||||
{ n: 1, title: "The eye", instruction: "Draw a round eye, then a little dot inside.", lines: [`<path d="M147 134 a15 15 0 1 0 0.1 0" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<circle cx="129" cy="136" r="6" fill="#2b2440"/>`] },
|
||||
{ n: 2, title: "The mouth", instruction: "Add a small smile at the front.", lines: [`<path d="M90 162 q15 13 32 4" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The gill", instruction: "Add a curved gill line behind the head.", lines: [`<path d="M160 104 q-16 46 0 92" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 4, title: "Stripes", instruction: "Add a couple of curved stripes across the body.", tip: "Now it's ready to color!", lines: [`<path d="M205 96 q-20 54 4 110" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M240 100 q-16 50 4 100" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
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 · Outline", subject: "a fish outline", emoji: "🐟", intro: "Let's draw the outline of a fish, 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 · Details", subject: "fish details", emoji: "🐟", intro: "Now add the details that make it a fish — the eye, mouth, gill, and stripes.", 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 · Color it!", subject: "color the fish", emoji: "🎨", 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: [] };
|
||||
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 };
|
||||
|
||||
const PANDA_STEPS: LessonStep[] = [
|
||||
{ n: 1, kind: "construct", title: "The head", instruction: "Draw one big round face.",
|
||||
tip: "Nice and round.",
|
||||
svg: `<ellipse cx="200" cy="162" rx="92" ry="84" fill="#fff" stroke="#2b2440" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "outline", title: "The ears", instruction: "Add two round ears in the top corners.",
|
||||
svg: `<circle cx="142" cy="92" r="30" fill="#2b2440"/><circle cx="258" cy="92" r="30" fill="#2b2440"/><circle cx="142" cy="92" r="14" fill="#5a5470"/><circle cx="258" cy="92" r="14" fill="#5a5470"/>` },
|
||||
{ n: 3, kind: "outline", title: "Eye patches", instruction: "Draw a dark leaf-shaped patch where each eye will go.",
|
||||
tip: "Pandas have big patches around their eyes.",
|
||||
svg: `<path d="M150 132 C 136 148, 140 178, 164 184 C 186 188, 196 166, 189 146 C 183 132, 164 124, 150 132 Z" fill="#2b2440"/><path d="M250 132 C 264 148, 260 178, 236 184 C 214 188, 204 166, 211 146 C 217 132, 236 124, 250 132 Z" fill="#2b2440"/>` },
|
||||
{ n: 4, kind: "detail", title: "The eyes", instruction: "Add a white circle, a pupil, and a sparkle inside each patch.",
|
||||
svg: `<circle cx="168" cy="158" r="9" fill="#fff"/><circle cx="170" cy="160" r="5" fill="#2b2440"/><circle cx="166" cy="156" r="2" fill="#fff"/><circle cx="232" cy="158" r="9" fill="#fff"/><circle cx="230" cy="160" r="5" fill="#2b2440"/><circle cx="228" cy="156" r="2" fill="#fff"/>` },
|
||||
{ n: 5, kind: "detail", title: "Nose and mouth", instruction: "Draw a rounded nose, a short line down, and two little smile curves.",
|
||||
svg: `<path d="M186 186 Q200 180 214 186 Q208 200 200 202 Q192 200 186 186 Z" fill="#2b2440"/><path d="M200 202 L200 212" stroke="#2b2440" stroke-width="3"/><path d="M200 212 q-13 12 -26 5 M200 212 q13 12 26 5" fill="none" stroke="#2b2440" stroke-width="3.5" stroke-linecap="round"/>` },
|
||||
{ n: 6, kind: "detail", title: "Rosy cheeks", instruction: "Add soft pink cheeks. Your panda is done!",
|
||||
tip: "🎉",
|
||||
svg: `<ellipse cx="150" cy="186" rx="15" ry="9" fill="#ffb6cf"/><ellipse cx="250" cy="186" rx="15" ry="9" fill="#ffb6cf"/>` },
|
||||
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: [`<ellipse cx="200" cy="162" rx="92" ry="84" fill="none" stroke="#2b2440" stroke-width="4"/>`] },
|
||||
{ n: 2, title: "The ears", instruction: "Add two round ears on top.", lines: [`<circle cx="142" cy="92" r="30" fill="none" stroke="#2b2440" stroke-width="4"/>`, `<circle cx="258" cy="92" r="30" fill="none" stroke="#2b2440" stroke-width="4"/>`] },
|
||||
{ n: 3, title: "Eye patches", instruction: "Draw a leaf-shaped patch for each eye.", lines: [`<path d="M150 132 C 136 148, 140 178, 164 184 C 186 188, 196 166, 189 146 C 183 132, 164 124, 150 132 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M250 132 C 264 148, 260 178, 236 184 C 214 188, 204 166, 211 146 C 217 132, 236 124, 250 132 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
export const PANDA_LESSON: Lesson = { level: "early-beginner", sublevel: 2, slug: "panda", title: "Draw a Panda", subject: "a cuddly panda", emoji: "🐼", intro: "A panda is just circles and ovals. Let's make a cuddly friend!", badgeKey: "early-beginner-2-panda", badgeName: "Panda Pal", mode: "draw", steps: PANDA_STEPS };
|
||||
|
||||
const FLOWER_STEPS: LessonStep[] = [
|
||||
{ n: 1, kind: "construct", title: "The middle", instruction: "Draw a circle in the center of the page.",
|
||||
tip: "Leave room all around for petals.",
|
||||
svg: `<circle cx="200" cy="118" r="34" fill="#ffd45e" stroke="#e0a92f" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "outline", title: "First petals", instruction: "Add four petals: one on top, bottom, left, and right.",
|
||||
tip: "Petals are like rounded raindrops.",
|
||||
svg: `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff7eb6" stroke="#e0699b" stroke-width="3" transform="rotate(0 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff7eb6" stroke="#e0699b" stroke-width="3" transform="rotate(90 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff7eb6" stroke="#e0699b" stroke-width="3" transform="rotate(180 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff7eb6" stroke="#e0699b" stroke-width="3" transform="rotate(270 200 118)"/>` },
|
||||
{ n: 3, kind: "outline", title: "More petals", instruction: "Tuck four more petals into the gaps so the flower is full.",
|
||||
svg: `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff9ec4" stroke="#e0699b" stroke-width="3" transform="rotate(45 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff9ec4" stroke="#e0699b" stroke-width="3" transform="rotate(135 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff9ec4" stroke="#e0699b" stroke-width="3" transform="rotate(225 200 118)"/><path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="#ff9ec4" stroke="#e0699b" stroke-width="3" transform="rotate(315 200 118)"/>` },
|
||||
{ n: 4, kind: "outline", title: "The stem", instruction: "Draw a curvy green stem going down from the flower.",
|
||||
svg: `<path d="M200 150 C 196 185, 210 214, 200 256" fill="none" stroke="#58c777" stroke-width="11" stroke-linecap="round"/>` },
|
||||
{ n: 5, kind: "outline", title: "The leaves", instruction: "Add a leaf on each side of the stem.",
|
||||
svg: `<path d="M200 198 C 168 184, 138 192, 150 218 C 162 240, 196 226, 200 198 Z" fill="#58c777" stroke="#3a9b57" stroke-width="3"/><path d="M200 226 C 232 214, 262 222, 250 246 C 238 266, 204 252, 200 226 Z" fill="#58c777" stroke="#3a9b57" stroke-width="3"/>` },
|
||||
{ n: 6, kind: "detail", title: "Seeds", instruction: "Dot some little seeds in the middle.",
|
||||
svg: `<circle cx="192" cy="112" r="4" fill="#e0a92f"/><circle cx="208" cy="114" r="4" fill="#e0a92f"/><circle cx="200" cy="124" r="4" fill="#e0a92f"/><circle cx="190" cy="126" r="3.5" fill="#e0a92f"/><circle cx="210" cy="126" r="3.5" fill="#e0a92f"/>` },
|
||||
{ n: 7, kind: "detail", title: "Leaf veins", instruction: "Add a line down each leaf, then color your flower!",
|
||||
tip: "🌸",
|
||||
svg: `<path d="M168 210 q22 4 30 16 M232 238 q-20 4 -30 -8" fill="none" stroke="#3a9b57" stroke-width="2.5"/>` },
|
||||
const PANDA_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "The eyes", instruction: "Add a circle and a dot inside each patch.", lines: [`<circle cx="168" cy="156" r="9" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="170" cy="158" r="4" fill="#2b2440"/>`, `<circle cx="232" cy="156" r="9" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="230" cy="158" r="4" fill="#2b2440"/>`] },
|
||||
{ n: 2, title: "The nose", instruction: "Draw a little rounded nose.", lines: [`<path d="M186 184 Q200 178 214 184 Q208 198 200 200 Q192 198 186 184 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The mouth", instruction: "Add a line down and two smile curves.", lines: [`<path d="M200 200 L200 210" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M200 210 q-13 12 -26 5" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M200 210 q13 12 26 5" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
export const FLOWER_LESSON: Lesson = { level: "early-beginner", sublevel: 3, slug: "flower", title: "Draw a Flower", subject: "a cheerful flower", emoji: "🌸", intro: "A circle in the middle and petals all around — then a stem and leaves.", badgeKey: "early-beginner-3-flower", badgeName: "Flower Power", mode: "draw", steps: FLOWER_STEPS };
|
||||
const PANDA_OUTLINE_SVG = PANDA_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n");
|
||||
|
||||
const UNICORN_STEPS: LessonStep[] = [
|
||||
{ n: 1, kind: "construct", title: "The head", instruction: "Draw a rounded head that's a little narrower at the chin.",
|
||||
svg: `<path d="M120 152 C 120 96, 165 72, 200 72 C 235 72, 280 96, 280 152 C 280 202, 246 236, 200 240 C 154 236, 120 202, 120 152 Z" fill="#fff" stroke="#2b2440" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "outline", title: "The ears", instruction: "Add a pointy ear on each side with a pink inside.",
|
||||
svg: `<path d="M150 98 C 138 72, 132 58, 150 60 C 166 64, 174 84, 180 96 Z" fill="#fff" stroke="#2b2440" stroke-width="4" stroke-linejoin="round"/><path d="M250 98 C 262 72, 268 58, 250 60 C 234 64, 226 84, 220 96 Z" fill="#fff" stroke="#2b2440" stroke-width="4" stroke-linejoin="round"/><path d="M156 84 q-6 12 0 22 M244 84 q6 12 0 22" fill="#ffd1e3"/>` },
|
||||
{ n: 3, kind: "outline", title: "The magic horn", instruction: "Draw a tall horn in the middle with little swirl lines.",
|
||||
svg: `<polygon points="200,80 188,18 212,80" fill="#ffd45e" stroke="#e0a92f" stroke-width="3" stroke-linejoin="round"/><path d="M193 66 l14 -5 M196 50 l11 -4 M199 36 l8 -3" stroke="#e0a92f" stroke-width="2.5" fill="none" stroke-linecap="round"/>` },
|
||||
{ n: 4, kind: "detail", title: "Eyes and cheeks", instruction: "Add two big eyes with sparkles and soft rosy cheeks.",
|
||||
svg: `<ellipse cx="172" cy="158" rx="8" ry="11" fill="#2b2440"/><circle cx="169" cy="153" r="3" fill="#fff"/><ellipse cx="228" cy="158" rx="8" ry="11" fill="#2b2440"/><circle cx="225" cy="153" r="3" fill="#fff"/><ellipse cx="150" cy="190" rx="13" ry="8" fill="#ffd1e3"/><ellipse cx="250" cy="190" rx="13" ry="8" fill="#ffd1e3"/>` },
|
||||
{ n: 5, kind: "detail", title: "Nose and smile", instruction: "Add two tiny nostril dots and a friendly smile.",
|
||||
svg: `<circle cx="188" cy="210" r="3.5" fill="#2b2440"/><circle cx="212" cy="210" r="3.5" fill="#2b2440"/><path d="M186 222 q14 12 28 0" fill="none" stroke="#2b2440" stroke-width="3" stroke-linecap="round"/>` },
|
||||
{ n: 6, kind: "color", title: "The rainbow mane", instruction: "Add flowing locks of color down one side of the head.",
|
||||
tip: "Use lots of colors!",
|
||||
svg: `<path d="M256 118 C 300 130, 300 175, 282 210 C 292 178, 276 150, 256 140 Z" fill="#c79bff"/><path d="M262 140 C 305 160, 300 205, 276 236 C 290 200, 272 168, 252 158 Z" fill="#8ec9ff"/><path d="M252 170 C 292 196, 280 236, 252 258 C 270 224, 248 192, 238 184 Z" fill="#ff9ec4"/>` },
|
||||
{ n: 7, kind: "detail", title: "Forelock and sparkles", instruction: "Add a curl between the ears and a few sparkles. 🦄",
|
||||
svg: `<path d="M176 92 C 160 110, 168 140, 190 132 C 176 120, 182 104, 196 96 Z" fill="#c79bff"/><path d="M200 88 C 196 120, 214 122, 214 96 Z" fill="#8ec9ff"/><g stroke="#ffd45e" stroke-width="3" fill="none" stroke-linecap="round"><path d="M300 95 l0 14 M293 102 l14 0"/><path d="M120 110 l0 10 M115 115 l10 0"/></g>` },
|
||||
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: [`<circle cx="200" cy="118" r="34" fill="none" stroke="#2b2440" stroke-width="4"/>`] },
|
||||
{ n: 2, title: "Petals", instruction: "Add petals on top, bottom, left, and right.", lines: [`<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(0 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(90 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(180 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(270 200 118)"/>`] },
|
||||
{ n: 3, title: "More petals", instruction: "Tuck four more petals into the gaps.", lines: [`<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(45 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(135 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(225 200 118)"/>`, `<path d="M200 86 C 180 78, 176 52, 200 40 C 224 52, 220 78, 200 86 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linejoin="round" transform="rotate(315 200 118)"/>`] },
|
||||
{ n: 4, title: "The stem", instruction: "Draw a stem going down from the flower.", lines: [`<path d="M195 152 C 191 186, 205 214, 197 256 L203 256 C 211 214, 199 186, 205 152 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 5, title: "The leaves", instruction: "Add a leaf on each side of the stem.", lines: [`<path d="M200 198 C 168 184, 138 192, 150 218 C 162 240, 196 226, 200 198 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M200 226 C 232 214, 262 222, 250 246 C 238 266, 204 252, 200 226 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
export const UNICORN_LESSON: Lesson = { level: "early-beginner", sublevel: 4, slug: "unicorn", title: "Draw a Unicorn", subject: "a magical unicorn", emoji: "🦄", intro: "A rounded head, a sparkly horn, and a rainbow mane. Let's make magic!", badgeKey: "early-beginner-4-unicorn", badgeName: "Unicorn Magic", mode: "draw", steps: UNICORN_STEPS };
|
||||
|
||||
const TREE_STEPS: LessonStep[] = [
|
||||
{ n: 1, kind: "construct", title: "The trunk", instruction: "Draw a trunk that's a little wider at the bottom.",
|
||||
tip: "Stand it up tall in the middle.",
|
||||
svg: `<path d="M178 262 C 176 222, 184 200, 190 176 L210 176 C 216 200, 224 222, 222 262 C 214 266, 186 266, 178 262 Z" fill="#b5793f" stroke="#8a5a2b" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "outline", title: "The branches", instruction: "Add two branches reaching up from the trunk.",
|
||||
svg: `<path d="M198 180 C 190 152, 166 142, 150 132" fill="none" stroke="#8a5a2b" stroke-width="12" stroke-linecap="round"/><path d="M204 180 C 214 152, 238 144, 254 134" fill="none" stroke="#8a5a2b" stroke-width="12" stroke-linecap="round"/>` },
|
||||
{ n: 3, kind: "outline", title: "Leafy clumps", instruction: "Draw a big round clump of leaves up top and one on the left.",
|
||||
tip: "Treetops are nice and lumpy.",
|
||||
svg: `<circle cx="150" cy="120" r="54" fill="#62c178" stroke="#3a9b57" stroke-width="4"/><circle cx="205" cy="86" r="60" fill="#62c178" stroke="#3a9b57" stroke-width="4"/>` },
|
||||
{ n: 4, kind: "outline", title: "More leaves", instruction: "Add clumps on the right and middle to fill out the top.",
|
||||
svg: `<circle cx="258" cy="120" r="50" fill="#62c178" stroke="#3a9b57" stroke-width="4"/><circle cx="200" cy="135" r="56" fill="#62c178" stroke="#3a9b57" stroke-width="4"/>` },
|
||||
{ n: 5, kind: "detail", title: "Apples", instruction: "Dot a few red apples in the leaves.",
|
||||
svg: `<circle cx="160" cy="120" r="8" fill="#e8554e"/><circle cx="232" cy="100" r="8" fill="#e8554e"/><circle cx="205" cy="150" r="8" fill="#e8554e"/><circle cx="255" cy="140" r="8" fill="#e8554e"/>` },
|
||||
{ n: 6, kind: "detail", title: "Grass", instruction: "Add a wavy line of grass along the bottom.",
|
||||
svg: `<path d="M120 262 q14 -18 28 0 q14 -18 28 0 q14 -18 28 0 q14 -18 28 0 q14 -18 28 0" fill="none" stroke="#58c777" stroke-width="4" stroke-linecap="round"/>` },
|
||||
{ n: 7, kind: "detail", title: "Bark", instruction: "Add a couple of bark lines on the trunk, then color your tree!",
|
||||
tip: "🌳",
|
||||
svg: `<path d="M194 198 q4 24 0 56 M206 198 q-3 24 0 54" fill="none" stroke="#8a5a2b" stroke-width="2.5"/>` },
|
||||
const FLOWER_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "Seeds", instruction: "Dot some seeds in the middle.", lines: [`<circle cx="192" cy="112" r="4" fill="#2b2440"/>`, `<circle cx="208" cy="114" r="4" fill="#2b2440"/>`, `<circle cx="200" cy="124" r="4" fill="#2b2440"/>`, `<circle cx="190" cy="126" r="3" fill="#2b2440"/>`, `<circle cx="210" cy="126" r="3" fill="#2b2440"/>`] },
|
||||
{ n: 2, title: "Leaf veins", instruction: "Add a line down each leaf.", lines: [`<path d="M170 210 q20 4 28 14" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M232 240 q-18 2 -28 -10" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "Center ring", instruction: "Draw a little ring inside the middle.", lines: [`<circle cx="200" cy="118" r="18" fill="none" stroke="#2b2440" stroke-width="3"/>`] },
|
||||
];
|
||||
|
||||
export const TREE_LESSON: Lesson = { level: "early-beginner", sublevel: 5, slug: "tree", title: "Draw a Tree", subject: "a leafy tree", emoji: "🌳", intro: "A trunk, some branches, and big clumps of leaves make a leafy tree.", badgeKey: "early-beginner-5-tree", badgeName: "Tree Top", mode: "draw", steps: TREE_STEPS };
|
||||
const FLOWER_OUTLINE_SVG = FLOWER_OUTLINE_STEPS.flatMap((s) => s.lines || []).join("\n");
|
||||
|
||||
const DINO_STEPS: LessonStep[] = [
|
||||
{ n: 1, kind: "construct", title: "The body", instruction: "Draw a big rounded body.",
|
||||
tip: "A long-neck dino is nice and round.",
|
||||
svg: `<path d="M118 200 C 118 166, 160 150, 210 150 C 270 150, 302 170, 302 200 C 302 230, 262 246, 205 246 C 155 246, 118 230, 118 200 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "outline", title: "The long neck", instruction: "Sweep a long neck up from the left of the body.",
|
||||
tip: "Curve it gently.",
|
||||
svg: `<path d="M150 168 C 122 122, 112 80, 124 55 C 130 44, 148 46, 152 58 C 146 86, 162 124, 180 160 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4" stroke-linejoin="round"/>` },
|
||||
{ n: 3, kind: "detail", title: "The head", instruction: "Add a small rounded head on top with a dot for the eye.",
|
||||
svg: `<path d="M100 46 C 100 32, 120 28, 138 34 C 152 39, 154 56, 142 64 C 126 72, 104 64, 98 54 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4" stroke-linejoin="round"/><circle cx="118" cy="46" r="4" fill="#2b2440"/>` },
|
||||
{ n: 4, kind: "outline", title: "The tail", instruction: "Draw a long tail swooping out to the right.",
|
||||
svg: `<path d="M298 198 C 338 184, 372 176, 398 168 C 380 192, 360 206, 304 220 C 300 213, 298 206, 298 198 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4" stroke-linejoin="round"/>` },
|
||||
{ n: 5, kind: "outline", title: "The legs", instruction: "Add two sturdy legs underneath.",
|
||||
svg: `<path d="M168 242 C 165 264, 166 278, 180 280 C 193 280, 192 264, 190 242 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4" stroke-linejoin="round"/><path d="M232 244 C 229 266, 230 280, 244 282 C 257 282, 256 266, 254 244 Z" fill="#7ec86a" stroke="#4f9b46" stroke-width="4" stroke-linejoin="round"/>` },
|
||||
{ n: 6, kind: "detail", title: "Back plates", instruction: "Add little triangle plates along the back.",
|
||||
svg: `<path d="M150 150 l10 -16 l12 16 Z" fill="#4f9b46"/><path d="M186 146 l11 -17 l12 17 Z" fill="#4f9b46"/><path d="M224 147 l11 -16 l12 16 Z" fill="#4f9b46"/><path d="M262 152 l10 -15 l12 16 Z" fill="#4f9b46"/>` },
|
||||
{ n: 7, kind: "detail", title: "Spots", instruction: "Dot a few spots on the body.",
|
||||
svg: `<circle cx="205" cy="188" r="9" fill="#4f9b46"/><circle cx="240" cy="200" r="7" fill="#4f9b46"/><circle cx="180" cy="210" r="6" fill="#4f9b46"/>` },
|
||||
{ n: 8, kind: "detail", title: "Smile", instruction: "Add a friendly smile, then color your dino any color you like!",
|
||||
tip: "🦕",
|
||||
svg: `<path d="M108 56 q12 10 24 3" fill="none" stroke="#2b2440" stroke-width="2.5" stroke-linecap="round"/>` },
|
||||
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: [`<path d="M120 152 C 120 96, 165 72, 200 72 C 235 72, 280 96, 280 152 C 280 202, 246 236, 200 240 C 154 236, 120 202, 120 152 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 2, title: "The ears", instruction: "Add a pointy ear on each side.", lines: [`<path d="M150 98 C 138 72, 132 58, 150 60 C 166 64, 174 84, 180 96 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M250 98 C 262 72, 268 58, 250 60 C 234 64, 226 84, 220 96 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The horn", instruction: "Draw a tall horn on top.", lines: [`<path d="M200 80 L188 18 L212 80 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 4, title: "The mane", instruction: "Draw the flowing mane and a curl on the forehead.", lines: [`<path d="M256 112 C 320 122, 320 200, 268 250 C 292 196, 280 150, 250 142 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M176 92 C 165 110, 175 135, 196 130 C 184 118, 188 102, 200 96 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
export const DINO_LESSON: Lesson = { level: "early-beginner", sublevel: 6, slug: "dinosaur", title: "Draw a Dinosaur", subject: "a friendly dinosaur", emoji: "🦕", intro: "A round body, a long neck, a small head, and a swooshy tail!", badgeKey: "early-beginner-6-dinosaur", badgeName: "Dino Master", mode: "draw", steps: DINO_STEPS };
|
||||
const UNICORN_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "The eyes", instruction: "Add two big eyes.", lines: [`<ellipse cx="172" cy="158" rx="7" ry="10" fill="none" stroke="#2b2440" stroke-width="4"/>`, `<ellipse cx="228" cy="158" rx="7" ry="10" fill="none" stroke="#2b2440" stroke-width="4"/>`] },
|
||||
{ n: 2, title: "Nose & mouth", instruction: "Add two nostril dots and a smile.", lines: [`<circle cx="188" cy="210" r="3" fill="#2b2440"/>`, `<circle cx="214" cy="210" r="3" fill="#2b2440"/>`, `<path d="M186 224 q14 12 28 0" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "Horn swirls", instruction: "Add little swirl lines on the horn.", lines: [`<path d="M193 66 l14 -5" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M196 50 l11 -4" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M199 36 l8 -3" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 4, title: "Mane lines", instruction: "Add flowing lines in the mane.", lines: [`<path d="M268 130 C 300 150, 296 200, 262 232" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M258 140 C 286 160, 282 200, 256 226" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
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: [`<path d="M178 262 C 176 222, 184 200, 190 176 L210 176 C 216 200, 224 222, 222 262 C 214 266, 186 266, 178 262 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 2, title: "Branches", instruction: "Add two branches reaching up.", lines: [`<path d="M198 180 C 190 152, 168 144, 152 134" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M204 180 C 214 152, 236 146, 252 136" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The treetop", instruction: "Draw a big bumpy treetop.", tip: "Nice and lumpy!", lines: [`<path d="M120 150 C 100 122, 122 96, 150 100 C 152 74, 200 62, 216 88 C 246 72, 286 92, 274 122 C 300 134, 292 168, 262 166 C 250 188, 150 188, 138 166 C 110 170, 104 152, 120 150 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
const TREE_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "Apples", instruction: "Add a few round apples in the leaves.", lines: [`<circle cx="168" cy="118" r="7" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="228" cy="104" r="7" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="204" cy="150" r="7" fill="none" stroke="#2b2440" stroke-width="3"/>`] },
|
||||
{ n: 2, title: "Grass", instruction: "Add wavy grass along the bottom.", lines: [`<path d="M120 262 q14 -16 28 0 q14 -16 28 0 q14 -16 28 0 q14 -16 28 0 q14 -16 28 0" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "Bark", instruction: "Add a couple of bark lines on the trunk.", lines: [`<path d="M194 200 q4 24 0 56" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M206 200 q-3 24 0 54" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
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: [`<path d="M118 200 C 118 166, 160 150, 210 150 C 270 150, 302 170, 302 200 C 302 230, 262 246, 205 246 C 155 246, 118 230, 118 200 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 2, title: "The neck", instruction: "Sweep a long neck up from the left.", lines: [`<path d="M150 168 C 122 122, 112 80, 124 55 C 130 44, 148 46, 152 58 C 146 86, 162 124, 180 160 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 3, title: "The head", instruction: "Add a small head on top of the neck.", lines: [`<path d="M100 46 C 100 32, 120 28, 138 34 C 152 39, 154 56, 142 64 C 126 72, 104 64, 98 54 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 4, title: "The tail", instruction: "Draw a long tail swooping to the right.", lines: [`<path d="M298 198 C 338 184, 372 176, 398 168 C 380 192, 360 206, 304 220 C 300 213, 298 206, 298 198 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 5, title: "The legs", instruction: "Add two sturdy legs underneath.", lines: [`<path d="M168 242 C 165 264, 166 278, 180 280 C 193 280, 192 264, 190 242 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M232 244 C 229 266, 230 280, 244 282 C 257 282, 256 266, 254 244 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
const DINO_DETAIL_STEPS: LessonStep[] = [
|
||||
{ n: 1, title: "Back plates", instruction: "Add triangle plates along the back.", lines: [`<path d="M150 150 l10 -16 l12 16 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M186 146 l11 -17 l12 17 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M224 147 l11 -16 l12 16 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`, `<path d="M262 152 l10 -15 l12 16 Z" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
{ n: 2, title: "Spots", instruction: "Add a few spots on the body.", lines: [`<circle cx="205" cy="188" r="9" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="240" cy="200" r="7" fill="none" stroke="#2b2440" stroke-width="3"/>`, `<circle cx="180" cy="212" r="6" fill="none" stroke="#2b2440" stroke-width="3"/>`] },
|
||||
{ n: 3, title: "The face", instruction: "Add an eye and a friendly smile.", lines: [`<circle cx="118" cy="46" r="4" fill="#2b2440"/>`, `<path d="M108 56 q12 10 24 3" fill="none" stroke="#2b2440" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>`] },
|
||||
];
|
||||
|
||||
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. Holding near the tip and pressing hard makes DARK shades; holding high up and pressing soft makes LIGHT shades.",
|
||||
tip: "Try it in the air first!",
|
||||
svg: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/>` },
|
||||
{ n: 2, kind: "shade", title: "Find the light", instruction: "The sun is up and to the left. The side of the ball facing the sun stays the brightest. That bright spot is the highlight.",
|
||||
svg: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><circle cx="178" cy="118" r="22" fill="none" stroke="#4f7cff" stroke-width="3" stroke-dasharray="6 6"/>` },
|
||||
{ n: 3, kind: "shade", title: "Soft shade all over", instruction: "Pick a light tone and, with soft gentle passes, shade the whole ball — but leave the bright highlight spot white.",
|
||||
tip: "Hold high and go easy.",
|
||||
svg: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><circle cx="178" cy="118" r="22" fill="none" stroke="#4f7cff" stroke-width="3" stroke-dasharray="6 6"/>` },
|
||||
{ n: 4, kind: "shade", title: "Build up the shadow", instruction: "Pick a darker tone and press a little harder on the side AWAY from the sun. Go over it a few times to build it up slowly.",
|
||||
tip: "More passes = darker.",
|
||||
svg: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><path d="M250 96 A84 84 0 0 1 250 204 A60 70 0 0 0 250 96 Z" fill="#2b2440" opacity="0.18"/>` },
|
||||
{ n: 5, kind: "shade", title: "Cast shadow & finish", instruction: "Shade the ground just under the ball on the shadow side. Keep that highlight bright and clean. You did it!",
|
||||
tip: "🌗",
|
||||
svg: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><path d="M250 96 A84 84 0 0 1 250 204 A60 70 0 0 0 250 96 Z" fill="#2b2440" opacity="0.18"/><ellipse cx="262" cy="236" rx="78" ry="15" fill="#2b2440" opacity="0.18"/>` },
|
||||
{ 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: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/>` },
|
||||
{ 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: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><circle cx="178" cy="118" r="22" fill="none" stroke="#4f7cff" stroke-width="3" stroke-dasharray="6 6"/>` },
|
||||
{ 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: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><circle cx="178" cy="118" r="22" fill="none" stroke="#4f7cff" stroke-width="3" stroke-dasharray="6 6"/>` },
|
||||
{ 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: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><path d="M250 96 A84 84 0 0 1 250 204 A60 70 0 0 0 250 96 Z" fill="#2b2440" opacity="0.18"/>` },
|
||||
{ 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: `<g><circle cx="62" cy="46" r="20" fill="#ffd45e"/><g stroke="#ffd45e" stroke-width="4" stroke-linecap="round"><path d="M62 14v-8M62 86v8M30 46h-8M94 46h8M39 23l-6-6M85 23l6-6M39 69l-6 6M85 69l6 6"/></g></g><line x1="40" y1="234" x2="370" y2="234" stroke="#c9c4d6" stroke-width="3"/><circle cx="210" cy="150" r="84" fill="#f1f1f4" stroke="#2b2440" stroke-width="4"/><path d="M250 96 A84 84 0 0 1 250 204 A60 70 0 0 0 250 96 Z" fill="#2b2440" opacity="0.18"/><ellipse cx="262" cy="236" rx="78" ry="15" fill="#2b2440" opacity="0.18"/>` },
|
||||
];
|
||||
|
||||
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: "Time to make a flat circle look like a round ball — using light and shadow! First, learn how to hold your pencil.", badgeKey: "learner-1-shading", badgeName: "Shading Star", mode: "shade", steps: SHADE_STEPS };
|
||||
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 };
|
||||
|
||||
export const LESSONS: Lesson[] = [FISH_OUTLINE_LESSON, FISH_DETAIL_LESSON, FISH_EXTRA_LESSON, PANDA_LESSON, FLOWER_LESSON, UNICORN_LESSON, TREE_LESSON, DINO_LESSON, SHADE_BALL_LESSON];
|
||||
export const 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, 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"); }
|
||||
|
||||
/** Subjects in a level, in order, each with its phase lessons (or a single legacy lesson). */
|
||||
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<string, { key: string; name: string; emoji: string; order: number; lessons: Lesson[] }>();
|
||||
@@ -198,7 +185,7 @@ export function getSubjects(level: string): { key: string; name: string; emoji:
|
||||
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);
|
||||
}
|
||||
const phaseRank: Record<string, number> = { outline: 0, detail: 1, extra: 2 };
|
||||
for (const s of map.values()) s.lessons.sort((a, b) => (phaseRank[a.phase ?? ""] ?? 0) - (phaseRank[b.phase ?? ""] ?? 0));
|
||||
const rank: Record<string, number> = { outline: 0, detail: 1, extra: 2 };
|
||||
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);
|
||||
}
|
||||
Reference in new issue
Block a user