wondersheets/server/prompts.js
2026-02-22 00:03:35 +01:00

313 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Activity-specific prompts for worksheet generation.
* Each prompt is tailored to produce optimal SVG output for its activity type.
*/
const baseRules = `
MANDATORY STYLE & QUALITY RULES — MUST FOLLOW EXACTLY:
- Depict the theme literally and recognizably using standard, cute children's illustration style (e.g. animals look like real animals with big eyes/smiles; no invented blobs, hybrids, pigtails/bows on wrong things, distorted proportions, extra random parts).
- Every visible element MUST be FULLY CLOSED paths (use Z/z to close <path>, or <circle>/<ellipse>/<polygon>/<rect>). NO open paths, NO <line>, NO <polyline> unless closed, NO stroke-only lines without enclosed fill regions.
- Forbidden forever: blobs, distorted/wrong anatomy, floating disconnected lines/parts, random dots/scribbles/noise/artifacts, self-intersecting paths making uncolorable slivers, cut-off/incomplete shapes, inconsistent stroke widths, tiny details, fill="none" on main objects (except holes), any greyscale/shading.
- Stroke: #000000 solid (no dasharray except for traceable writing). Fill: #ffffff on all colorable regions.
- ViewBox: exactly '0 0 500 500'. MAXIMIZE PAGE USAGE. Use the full 500x500 canvas with MINIMAL margins (10-20px). Make the main subject FILL the available space.
- Attributes: single quotes ' only for all XML.
- SECURITY INSTRUCTIONS — CRITICALLY IMPORTANT: DO NOT INCLUDE ANY \`<script>\`, \`<a>\`, \`<foreignObject>\`, \`<iframe>\`, \`<object>\`, or any other interactive or external elements in the SVG. The SVG must be purely static visuals (paths, circles, rects, lines, etc.). ANY text inside the SVG should be strictly limited to the necessary tracing letters/numbers (NO Javascript, NO links).
- SVG: complete valid XML — <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'> ... </svg>. Use smooth curves (C, Q, S) for natural shapes.
- High-quality kid style: bold thick outlines, big simple shapes, cute friendly expressions (big round eyes as circles/ovals, smiling curved mouth), balanced proportions (big head for cuteness), no complexity/noise.
`;
const ageRules = (age) => `
AGE-SPECIFIC RULES — STRICT:
${age <= 4 ?
`- For age ${age}: Ultra-simple (12 huge objects max), stroke width 610px, very large regions (410 total), cartoon-big features, no small details/textures/patterns inside.` :
`- For age ${age}: Slightly more complex (36 elements), stroke 35px, allow small closed interior shapes (e.g. spots as tiny circles), but still bold and clear.`
}
`;
const jsonStructure = (sectionType) => `
Return ONLY valid JSON. No other text, no explanations.
JSON exactly this structure:
{
"title": "Short fun title",
"subtitle": "Clear one-sentence kid instruction",
"sections": [
{
"id": "${sectionType}-main",
"type": "${sectionType}",
"content_svg": "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'>...FULL complete valid SVG code here...</svg>"
}
]
}
CRITICAL: content_svg MUST be a string with single quotes in SVG attributes. Paths smooth and 100% closed.
`;
export const activityPrompts = {
coloring: (theme, age) => `
You are a professional SVG illustrator creating REALISTIC, RECOGNIZABLE children's coloring pages.
Theme: ${theme}
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 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.
🚨 SVG REQUIREMENTS (CRITICAL):
- Background: <rect width="500" height="500" fill="#FFFFFF"/> (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: <path d="M..." fill="#FFFFFF" stroke="black" stroke-width="3"/>
- Example Open Line: <path d="M..." fill="none" stroke="black" stroke-width="2"/>
📐 STEP-BY-STEP CONSTRUCTION METHOD (Layer by Layer):
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 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
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"
🎨 SPECIFIC THEME GUIDES:
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
ROBOT:
- Use geometric shapes (rectangles, circles)
- Fill ALL shapes with #FFFFFF to look solid
- Add buttons/panels on top
🔍 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:
- fill="none" on main shapes (causes messy overlaps)
- Translucent/opacity effects
- Tiny dust/specks
- Disconnected lines that should be closed
${baseRules}
${ageRules(age)}
${jsonStructure('coloring')}
`,
writing: (theme, age) => `
You are an educational illustrator creating handwriting practice worksheets for young children.
Theme: ${theme}
Age: ${age} years old
YOUR MISSION: Create a clean, professional tracing practice worksheet.
IMPORTANT: Randomly choose ONE of these options for what to trace:
- Option A (50% chance): A short WORD related to the theme (2-4 letters, e.g., "SUN", "CAT", "STAR")
- Option B (50% chance): NUMBERS 1-5 (for ages 3-4) or 1-9 (for ages 5-7), showing 3-5 numbers to trace
⚠️ STRICT ACTIVITY RESTRICTION — THIS IS A TRACING WORKSHEET ONLY:
- DO NOT include any mazes, paths to follow, or puzzles
- DO NOT include any counting exercises with objects
- DO NOT include large coloring illustrations
- DO NOT include groups of objects to count
- DO NOT include any decorative shapes, swirls, or random elements
- The ONLY activity is tracing letters OR numbers along dotted lines
🔴 CRITICAL ALIGNMENT & QUALITY RULES — MUST FOLLOW EXACTLY:
BASELINE ALIGNMENT:
- ALL characters in a row MUST sit on the SAME horizontal baseline
- Use a consistent y-coordinate for the bottom of all characters in each row
- Characters must NOT float, sink, or be misaligned with each other
CHARACTER CONSTRUCTION (for both letters AND numbers):
- Use simple <path> elements with stroke-dasharray='8,8' for uniform dots
- Character stroke-width: 4px for clean, visible dots
- Character height: exactly 80px tall
- Character spacing: exactly 70px between character centers
- Use ONLY basic straight lines and simple curves — no fancy flourishes
DOT PATTERN RULES:
- stroke-dasharray='8,8' — uniform 8px dots with 8px gaps
- stroke='#000000' stroke-linecap='round' for round dots
- fill='none' — characters are outlines only, not filled
- Dots must be evenly spaced along the entire character path
FORBIDDEN ELEMENTS:
- Random decorative dots or shapes anywhere
- Swirls, flourishes, or artistic embellishments
- Uneven or inconsistent dot spacing
- Characters of different sizes in the same row
- Floating or disconnected character parts
- Any shapes not part of the traceable characters
- Background decorations or patterns
WORKSHEET STRUCTURE — CRITICAL SPACING:
- Title area (y=30-60): Small title as SOLID black text (NOT dotted), font-size 24px, centered at y=50
- For words: "Trace: [WORD]"
- For numbers: "Trace the Numbers"
- LEAVE EMPTY SPACE between y=60 and y=150 — NO content here!
- Row 1 (y=180-260): Full dotted characters to trace — tops at y=160, bottoms at y=260
- Row 2 (y=300-380): Same characters, slightly lighter (stroke='#888888')
- Row 3 (y=420-480): Empty baseline only (solid line at y=450, stroke-width='1', stroke='#CCCCCC')
- Baseline guides: Add thin gray lines under each character row
STYLE FOR NUMBERS (if tracing numbers):
- Simple, clear digit shapes: 1, 2, 3, 4, 5, 6, 7, 8, 9
- Consistent sizing and spacing
- School-style number forms
STYLE FOR LETTERS (if tracing words):
- Use basic school-style uppercase letters
- Simple straight lines and gentle curves
- Maximum 4 letters per word
${baseRules}
${ageRules(age)}
${jsonStructure('writing')}
`,
'find-way': (theme, age) => `
You are a puzzle designer creating fun maze worksheets for young children.
Theme: ${theme}
Age: ${age} years old
YOUR MISSION: Create a SIMPLE, LOGICAL, and clearly SOLVABLE maze for young children.
⚠️ STRICT ACTIVITY RESTRICTION — THIS IS A MAZE/PATH-FINDING WORKSHEET ONLY:
- DO NOT include any numbers, digits, or counting exercises
- DO NOT include any letters, words, or writing practice
- DO NOT include large coloring areas — the maze IS the main activity
- The ONLY activity is finding the path through the maze from start to finish
🔴 CRITICAL MAZE LOGIC RULES — MUST FOLLOW EXACTLY:
1. USE A SIMPLE GRID STRUCTURE: Build the maze on an invisible 5x5 or 6x6 grid
2. CORRIDORS MUST BE STRAIGHT: Only horizontal and vertical paths, meeting at 90° angles
3. PATH WIDTH: Exactly 40px wide corridors — consistent everywhere
4. WALLS: Solid filled rectangles (not lines), exactly 10px thick, black fill
5. ONE CLEAR SOLUTION: There must be exactly ONE path from start to finish — no alternate routes
6. DEAD ENDS: Maximum 2-3 short dead ends (1-2 cells deep only)
7. NO OVERLAPPING: Paths never cross or overlap — walls completely separate all corridors
8. NO AMBIGUITY: Every junction must have clear wall boundaries — no gaps or unclear areas
MAZE STRUCTURE (follow this pattern):
- Draw a rectangular outer border (10px thick black rectangle)
- Inside, create corridors by placing rectangular wall blocks
- Corridors are the WHITE SPACE between walls
- START: Top-left area with a small themed icon (arrow or character)
- FINISH: Bottom-right area with a themed goal icon (star, treasure, home)
- Solution path should have 4-6 turns maximum
SVG CONSTRUCTION METHOD:
1. Draw outer border: <rect x='10' y='10' width='480' height='480' fill='none' stroke='#000' stroke-width='10'/>
2. Add internal walls as filled black rectangles: <rect x='...' y='...' width='...' height='...' fill='#000'/>
3. Corridors are the remaining white space (no need to draw them)
4. Add START icon at entrance
5. Add FINISH icon at exit
FORBIDDEN IN MAZES:
- Curved or diagonal paths
- Walls that don't connect properly (gaps)
- Paths that seem to go through walls
- Multiple possible solutions
- Dead ends longer than 2 grid cells
- Unclear or ambiguous junctions
${baseRules}
${ageRules(age)}
${jsonStructure('find-the-way')}
`,
counting: (theme, age) => `
You are an educational illustrator creating counting practice worksheets for young children.
Theme: ${theme}
Age: ${age} years old
YOUR MISSION: Create a fun counting exercise where children count themed objects and write the number.
⚠️ STRICT ACTIVITY RESTRICTION — THIS IS A COUNTING WORKSHEET ONLY:
- DO NOT include any mazes, paths to follow, or puzzles
- DO NOT include any letters, words, or writing/tracing practice (except answer boxes)
- DO NOT include large coloring illustrations — only countable themed objects
- DO NOT show the answers/numbers already filled in — leave answer boxes EMPTY
- DO NOT include number recognition (showing big numbers) — this is COUNTING objects
- The ONLY activity is counting groups of objects and writing the total in empty boxes
- Focus EXCLUSIVELY on groups of themed objects to count with empty answer boxes
COUNTING WORKSHEET SPECIFIC RULES:
- Create 3-5 GROUPS of themed objects to count
- Each group should have a DIFFERENT quantity (e.g., 2, 4, 5, 7, 9)
- Quantities appropriate for age: 1-5 for age 3-4, 1-10 for age 5-7
- Objects within each group must be IDENTICAL and themed
- Add an EMPTY box or circle next to each group for writing the answer (no numbers inside!)
- Objects should be large enough to count easily with a finger point
LAYOUT:
- Use GRID LAYOUT: Groups in rows, empty answer boxes on the right
- Each row: [Group of objects] → [Empty answer box]
- Clear visual separation between different groups
COUNTING-FRIENDLY DESIGN:
- Space objects clearly within groups — no overlapping
- Use familiar arrangements (lines, dice patterns, pyramid stacks)
- Make objects touch-friendly for finger counting
- Vary positions slightly so kids must actually count (not memorize patterns)
${baseRules}
${ageRules(age)}
${jsonStructure('counting')}
`
};
/**
* Get the appropriate prompt for an activity type
*/
export function getPromptForActivity(activityType, theme, age) {
// Map internal IDs to prompt keys
const typeMap = {
'coloring': 'coloring',
'writing': 'writing',
'find-way': 'find-way',
'find-the-way': 'find-way',
'counting': 'counting'
};
const promptKey = typeMap[activityType] || 'writing';
const promptGenerator = activityPrompts[promptKey];
if (!promptGenerator) {
console.warn(`No prompt found for activity type: ${activityType}, falling back to writing`);
return activityPrompts.writing(theme, age);
}
return promptGenerator(theme, age);
}