diff --git a/server/gallery.json b/server/gallery.json
index 16a7d3c1..73e41eef 100644
--- a/server/gallery.json
+++ b/server/gallery.json
@@ -1,92 +1,92 @@
[
{
- "title": "Pirate Parrot's Treasure!",
- "subtitle": "Color the parrot and his hidden treasure!",
+ "title": "Friendly Turtle",
+ "subtitle": "Color the turtle and the sea!",
"sections": [
{
"id": "coloring-main",
"type": "coloring",
- "content_svg": ""
+ "content_svg": ""
}
],
- "age": 5,
+ "age": 10,
"activityType": "coloring",
- "id": 1770458040593,
- "createdAt": "2026-02-07T09:54:00.593Z"
+ "id": 1770474964556,
+ "createdAt": "2026-02-07T14:36:04.556Z"
},
{
- "title": "Parrot's Treasure!",
- "subtitle": "Color the parrot and his treasure hunt!",
+ "title": "Cool Robot!",
+ "subtitle": "Color the awesome robot with your favorite colors!",
"sections": [
{
"id": "coloring-main",
"type": "coloring",
- "content_svg": ""
+ "content_svg": ""
}
],
- "age": 5,
+ "age": 10,
"activityType": "coloring",
- "id": 1770458028752,
- "createdAt": "2026-02-07T09:53:48.752Z"
+ "id": 1770474951297,
+ "createdAt": "2026-02-07T14:35:51.297Z"
},
{
- "title": "Pirate Parrot's Treasure!",
- "subtitle": "Color the parrot and his treasure hunt!",
+ "title": "Trace: PLANETS",
+ "subtitle": "Practice writing letters!",
+ "sections": [
+ {
+ "id": "writing-main",
+ "type": "writing",
+ "content_svg": ""
+ }
+ ],
+ "age": 10,
+ "activityType": "writing",
+ "id": 1770474941876,
+ "createdAt": "2026-02-07T14:35:41.876Z"
+ },
+ {
+ "title": "Space Rocket Fun!",
+ "subtitle": "Color the awesome rocket ship zooming through space!",
"sections": [
{
"id": "coloring-main",
"type": "coloring",
- "content_svg": ""
+ "content_svg": ""
+ }
+ ],
+ "age": 10,
+ "activityType": "coloring",
+ "id": 1770474920894,
+ "createdAt": "2026-02-07T14:35:20.894Z"
+ },
+ {
+ "title": "Rocket Adventure!",
+ "subtitle": "Color the rocket and prepare for blastoff!",
+ "sections": [
+ {
+ "id": "coloring-main",
+ "type": "coloring",
+ "content_svg": ""
+ }
+ ],
+ "age": 10,
+ "activityType": "coloring",
+ "id": 1770474873872,
+ "createdAt": "2026-02-07T14:34:33.872Z"
+ },
+ {
+ "title": "Rocket Ride!",
+ "subtitle": "Color the rocket ship!",
+ "sections": [
+ {
+ "id": "coloring-main",
+ "type": "coloring",
+ "content_svg": ""
}
],
"age": 5,
"activityType": "coloring",
- "id": 1770457963325,
- "createdAt": "2026-02-07T09:52:43.325Z"
- },
- {
- "title": "Count the Stars!",
- "subtitle": "Count each group and write the number",
- "sections": [
- {
- "id": "counting-main",
- "type": "counting",
- "content_svg": ""
- }
- ],
- "age": 5,
- "activityType": "counting",
- "id": 1770457944132,
- "createdAt": "2026-02-07T09:52:24.132Z"
- },
- {
- "title": "Count the Fishs!",
- "subtitle": "Count each group and write the number",
- "sections": [
- {
- "id": "counting-main",
- "type": "counting",
- "content_svg": ""
- }
- ],
- "age": 5,
- "activityType": "counting",
- "id": 1770457941396,
- "createdAt": "2026-02-07T09:52:21.396Z"
- },
- {
- "title": "Pirate Unicorn Treasure Hunt Maze Adventure",
- "subtitle": "Find the path from start to finish!",
- "sections": [
- {
- "id": "find-the-way-main",
- "type": "find-the-way",
- "content_svg": ""
- }
- ],
- "age": 5,
- "activityType": "find-way",
- "id": 1770457938911,
- "createdAt": "2026-02-07T09:52:18.911Z"
+ "id": 1770474863832,
+ "createdAt": "2026-02-07T14:34:23.832Z"
}
]
\ No newline at end of file
diff --git a/server/generators/coloring.js b/server/generators/coloring.js
index f09c0729..5b9a3d12 100644
--- a/server/generators/coloring.js
+++ b/server/generators/coloring.js
@@ -120,7 +120,7 @@ const illustrations = {
-
+
diff --git a/server/generators/counting.js b/server/generators/counting.js
index ab5d7bab..88eee71c 100644
--- a/server/generators/counting.js
+++ b/server/generators/counting.js
@@ -19,6 +19,19 @@ const themedObjects = {
const objectNames = Object.keys(themedObjects);
+/**
+ * Pluralize object names correctly
+ */
+function pluralize(word) {
+ const irregulars = {
+ 'fish': 'Fish',
+ 'butterfly': 'Butterflies',
+ 'moon': 'Moons'
+ };
+ if (irregulars[word]) return irregulars[word];
+ return word.charAt(0).toUpperCase() + word.slice(1) + 's';
+}
+
/**
* Generate random quantities that are all different
*/
@@ -151,7 +164,16 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
const objectType = pickObjectForTheme(theme, shape);
// ALWAYS generate random quantities for variety (LLM is deterministic)
- const maxValue = age <= 4 ? 5 : 10;
+ let maxValue;
+ if (age <= 4) {
+ maxValue = 5;
+ } else if (age <= 6) {
+ maxValue = 10;
+ } else if (age <= 8) {
+ maxValue = 15;
+ } else {
+ maxValue = 20;
+ }
const rowCount = 8;
const finalQuantities = generateRandomQuantities(rowCount, maxValue);
@@ -169,7 +191,7 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
// Dotted separator line between rows (except first row)
if (i > 0) {
- objectRows += ``;
+ objectRows += ``;
}
// Row number indicator - vertically centered in row
@@ -191,7 +213,7 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
`;
return {
- title: `Count the ${objectType.charAt(0).toUpperCase() + objectType.slice(1)}s!`,
+ title: `Count the ${pluralize(objectType)}!`,
subtitle: 'Count each group and write the number',
sections: [{
id: 'counting-main',
diff --git a/server/generators/maze.js b/server/generators/maze.js
index 1da3ffa7..5abdfa7f 100644
--- a/server/generators/maze.js
+++ b/server/generators/maze.js
@@ -44,7 +44,7 @@ function generateMazeGrid(rows, cols, startEdge, endEdge) {
startRow = 0; startCol = 0;
break;
case 'bottom':
- startRow = rows - 1; startCol = rows - 1;
+ startRow = rows - 1; startCol = cols - 1;
break;
case 'left':
startRow = 0; startCol = 0;
@@ -169,9 +169,15 @@ export function generateMazeWorksheet({ theme, difficulty = 1, age }) {
} else if (age <= 5 || difficulty === 2) {
rows = 5;
cols = 5;
- } else {
+ } else if (age <= 7) {
rows = 6;
cols = 6;
+ } else if (age <= 9) {
+ rows = 7;
+ cols = 7;
+ } else {
+ rows = 8;
+ cols = 8;
}
// Randomly select start and end edges - favor opposite edges for better gameplay
diff --git a/server/generators/writing.js b/server/generators/writing.js
index 36251a5c..a350f844 100644
--- a/server/generators/writing.js
+++ b/server/generators/writing.js
@@ -96,7 +96,7 @@ function generateCharacterRow(text, y, baseScale = 1, color = '#000000') {
*/
function generateBaseline(y, width = 400) {
const startX = (500 - width) / 2;
- return ``;
+ return ``;
}
/**
diff --git a/server/index.js b/server/index.js
index 40314526..361511ca 100644
--- a/server/index.js
+++ b/server/index.js
@@ -10,8 +10,7 @@ import { GoogleGenerativeAI } from '@google/generative-ai';
import {
generateWritingWorksheet,
generateCountingWorksheet,
- generateMazeWorksheet,
- generateColoringPage
+ generateMazeWorksheet
} from './generators/index.js';
dotenv.config();
@@ -75,9 +74,9 @@ function addToGallery(item) {
const parameterPrompts = {
writing: (theme, age) => {
const randomSeed = Math.floor(Math.random() * 1000);
- const wordLength = `${age} letters`;
- const numberRange = age <= 4 ? '1-5' : '1-9';
- const numberCount = age <= 4 ? '3-4' : '4-5';
+ const wordLength = age <= 4 ? '3-4 letters' : age <= 6 ? '4-5 letters' : age <= 8 ? '5-6 letters' : '6-8 letters';
+ const numberRange = age <= 4 ? '1-5' : age <= 6 ? '1-9' : age <= 8 ? '1-15' : '1-20';
+ const numberCount = age <= 4 ? '3-4' : age <= 6 ? '4-5' : '5-6';
return `
Create a children's tracing worksheet for theme "${theme}".
@@ -109,7 +108,7 @@ CRITICAL: You MUST return JSON with BOTH "shape" AND "quantities":
{"shape": "star", "quantities": [3, 1, 5, 2, 7, 4, 8, 6]}
- "shape": Choose ONE shape that matches "${theme}". Use the random seed ${randomSeed} to vary your choice - don't always pick the same shape for this theme.
-- "quantities": Array of exactly 8 different numbers (1-${age <= 4 ? 5 : 10})
+- "quantities": Array of exactly 8 different numbers (1-${age <= 4 ? 5 : age <= 6 ? 10 : age <= 8 ? 15 : 20})
Return ONLY valid JSON. No explanation.
`;
@@ -126,7 +125,9 @@ Return ONLY a JSON object:
Rules:
- difficulty 1 = easy (4x4 grid) for age 3-4
- difficulty 2 = medium (5x5 grid) for age 5-6
-- difficulty 3 = hard (6x6 grid) for age 7+
+- difficulty 3 = hard (6x6 grid) for age 7-8
+- difficulty 4 = challenging (7x7 grid) for age 9
+- difficulty 5 = expert (8x8 grid) for age 10
Return ONLY valid JSON, no explanation.
`,
@@ -183,7 +184,7 @@ app.post('/api/surprise', async (req, res) => {
Current timestamp: ${timestamp}
Generate ONE creative, fun, specific theme for a children's worksheet (e.g. "Space-Rex Coding", "Underwater Hamster Tea Party").
- Pick a RANDOM age between 3 and 7.
+ Pick a RANDOM age between 3 and 10.
Pick a RANDOM activity type with EQUAL PROBABILITY from these 4 options:
1. "coloring" - coloring pages
diff --git a/server/prompts.js b/server/prompts.js
index 4c81d146..42a0c169 100644
--- a/server/prompts.js
+++ b/server/prompts.js
@@ -50,96 +50,69 @@ Age: ${age} years old
🎯 YOUR GOAL: Create a coloring page with ONE clear subject that a 3-year-old can immediately identify as "${theme}".
-🚨 ABSOLUTE SVG REQUIREMENTS (CRITICAL - NON-NEGOTIABLE):
-- EVERY single path MUST have fill="none"
-- EVERY single path MUST have stroke="black" or stroke="#000000"
-- Use stroke-width="2" or "3" for all outlines
-- NO filled shapes allowed - children need empty white areas to color
-- Example:
+🚨 ABSOLUTE QUALITY RULES (CRITICAL - NON-NEGOTIABLE):
+1. USE WHITE FILLS: Every closed shape (head, body, legs, eyes) MUST have fill="#FFFFFF". This hides lines behind it.
+2. DRAWING ORDER: Draw from BACK to FRONT. Background parts first (tail, back legs), then main body, then front details (eyes, nose).
+3. CLOSED PATHS: All shapes must be fully closed paths so they can be filled with white.
+4. NO OVERLAPPING MESS: White fills solve this. If you draw a leg over a body, the white fill of the leg must hide the body line behind it.
-📐 STEP-BY-STEP SVG CONSTRUCTION METHOD:
+🚨 SVG REQUIREMENTS (CRITICAL):
+- Background: (Start with white canvas)
+- Stroke: stroke="black" or stroke="#000000"
+- Stroke Width: stroke-width="2" for main outlines, "2" for details
+- Fill: fill="#FFFFFF" for all object parts (to block lines behind)
+- Fill: fill="none" ONLY for open paths like whiskers or smiles
+- Example Closed Shape:
+- Example Open Line:
-For ANIMALS (cat, dog, panda, unicorn, etc.):
-1. HEAD: Draw a large circle or oval for head (100-150px diameter), centered around x=250, y=200
-2. EARS: Add 2 rounded ears on top of head (circles, triangles, or ovals)
-3. EYES: 2 circles (30-40px diameter) positioned symmetrically
-4. NOSE: Small circle or triangle in center below eyes
-5. MOUTH: Simple curved line (smile) below nose
-6. BODY: Large oval or rounded rectangle below head (150-200px wide, 180-220px tall)
-7. LEGS: 4 rounded rectangles or ovals extending down from body
-8. TAIL: Curved path on one side
-9. DETAILS: Add characteristic features (whiskers, spots, horn, etc.)
+📐 STEP-BY-STEP CONSTRUCTION METHOD (Layer by Layer):
-For OBJECTS (car, rocket, house, etc.):
-1. MAIN BODY: Start with basic shape (rectangle for car/house, elongated triangle for rocket)
-2. MAJOR COMPONENTS: Add 2-4 large recognizable parts (wheels, windows, door, roof)
-3. DETAILS: Add smaller features that make it identifiable
+For ANIMALS (Draw in this order):
+1. BACK LEGS/TAIL (Furthest back): Draw simple shapes, fill="#FFFFFF", stroke="black"
+2. BODY (Middle): Large oval/shape, fill="#FFFFFF", stroke="black" (Hides the top of back legs)
+3. HEAD (Front): Large circle/shape, fill="#FFFFFF", stroke="black" (Hides neck/body connection)
+4. FRONT LEGS (Front): Shapes overlapping body, fill="#FFFFFF", stroke="black"
+5. FACE DETAILS (Topmost): Eyes, nose, mouth. Eyes can have black pupils.
-For PLANTS (flower, tree, etc.):
-1. CENTER/TRUNK: Main central element
-2. PETALS/LEAVES: 5-8 symmetrical rounded shapes around center
-3. STEM: Vertical line or path
-4. BASE: Ground line or pot
+For OBJECTS (Car, Rocket, etc):
+1. MAIN CHASSIS/BODY: Large filled shape (fill="#FFFFFF")
+2. WHEELS/WINGS: Draw on top or behind as needed
+3. WINDOWS/DOORS: Draw on top of body (fill="#FFFFFF")
+4. DETAILS: Lines, handles, bolts
-🎨 SPECIFIC THEME EXAMPLES:
+For PLANTS:
+1. STEM/BRANCHES: Main lines
+2. LEAVES BEHIND: Fill="#FFFFFF"
+3. FLOWER CENTER: Fill="#FFFFFF" (Draw last so it's on top)
+4. PETALS: Fill="#FFFFFF"
-UNICORN:
-- Circle head (cx="250" cy="180", r="70")
-- 2 triangle ears
-- HORN: Triangle pointing up from forehead (30-40px tall)
-- 2 circle eyes
-- Small nose circle
-- Curved smile
-- Oval body below head
-- 4 rounded rectangle legs
-- Flowing curved tail on right side
-- Mane: 3-4 curved strokes on neck
+🎨 SPECIFIC THEME GUIDES:
-PANDA:
-- Large circle head (r="80")
-- 2 small circle ears on top
-- 2 LARGE circle eye patches (r="25", OUTLINED not filled)
-- 2 smaller circle eyes inside patches
-- Small circle nose
-- Smile below nose
-- Large oval body
-- 4 thick rounded legs
-- Optional: bamboo stick to the side (2 parallel lines)
+UNICORN:
+- Body: Oval (fill="#FFFFFF")
+- Legs: 4 rectangles (fill="#FFFFFF") - make sure they attach naturally
+- Head: Oval/Horse shape (fill="#FFFFFF")
+- START with separate shapes, but ensure they LOOK connected
+- Horn: Triangle on forehead
+- Mane/Tail: Flowing shapes
-CAT:
-- Circle head (r="60")
-- 2 triangle ears pointing up
-- 2 circle eyes
-- Small triangle nose
-- Whiskers (3 lines each side)
-- Curved smile
-- Oval body
-- 4 legs
-- Curved S-shaped tail
+ROBOT:
+- Use geometric shapes (rectangles, circles)
+- Fill ALL shapes with #FFFFFF to look solid
+- Add buttons/panels on top
-FLOWER:
-- Center circle (r="40")
-- 6-8 rounded petal paths around center (use ellipses or bezier curves)
-- Straight stem line down from center
-- 2 leaf shapes on stem (ellipses at angle)
-- Simple ground line
-
-🔍 QUALITY CHECKLIST - YOUR SVG MUST:
-✓ Have 8-15 large closed shapes ready for coloring
-✓ Be IMMEDIATELY recognizable as "${theme}"
-✓ Use ONLY stroke outlines (fill="none" on ALL paths)
-✓ Have bold stroke-width="2" or "3"
-✓ Be 500x500 viewBox with subject centered
-✓ Include characteristic features (horn for unicorn, eye patches for panda, etc.)
-✓ Have simple, rounded, child-friendly shapes
-✓ Look like it came from a store-bought coloring book
+🔍 QUALITY CHECKLIST:
+✓ Is the main subject clearly visible?
+✓ Are lines hidden where shapes overlap? (e.g. body line not visible through arm)
+✓ Is everything filled with white (except open lines)?
+✓ Is the stroke width consistent (bold 3px)?
+✓ Is the image centered in 500x500?
❌ AVOID:
-- Abstract or geometric art
-- Filled/colored areas
-- Tiny details (too hard for kids)
-- Complex overlapping shapes
-- Unrecognizable forms
+- fill="none" on main shapes (causes messy overlaps)
+- Translucent/opacity effects
+- Tiny dust/specks
+- Disconnected lines that should be closed
${baseRules}
${ageRules(age)}
diff --git a/src/App.jsx b/src/App.jsx
index 2ebe4765..79ea669a 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -110,7 +110,10 @@ function App() {
{/* Footer */}
diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx
index c5aa1b31..a6c00235 100644
--- a/src/components/Hero.jsx
+++ b/src/components/Hero.jsx
@@ -135,6 +135,13 @@ export const Hero = ({ onGenerate, generatedSheet, isGenerating }) => {
const pdfHeight = (imgProperties.height * pdfWidth) / imgProperties.width;
pdf.addImage(data, 'PNG', 0, 0, pdfWidth, pdfHeight);
+
+ // Add watermark at bottom center
+ const pageHeight = pdf.internal.pageSize.getHeight();
+ pdf.setFontSize(10);
+ pdf.setTextColor(150, 150, 150); // Light gray
+ pdf.text('wondersheets.art', pdfWidth / 2, pageHeight - 5, { align: 'center' });
+
return pdf;
};
@@ -190,19 +197,19 @@ export const Hero = ({ onGenerate, generatedSheet, isGenerating }) => {
- 3 to 7 years
+ 3 to 10 years
setAge(parseInt(e.target.value))}
className="w-full h-3 bg-slate-100 rounded-lg appearance-none cursor-pointer accent-primary-600 disabled:opacity-50"
/>
- 34567
+ 345678910