feat(kids): Add new interactive elements for kids levels

This commit is contained in:
Fatih Kadir Akın
2026-01-13 00:33:34 +03:00
parent 5098bb8352
commit 1b710df7dc
129 changed files with 8967 additions and 726 deletions

View File

@@ -0,0 +1,201 @@
# New Interactive Elements for Kids Levels
Add 5 new interactive components to enhance kids learning, inspired by key concepts from the prompting book.
---
## Current State
### Existing Components
| Component | Purpose | Used In |
|-----------|---------|---------|
| `PromptVsMistake` | Choose between good/bad prompts | All worlds |
| `MagicWords` | Fill-in-the-blank prompts | All worlds |
| `DragDropPrompt` | Arrange prompt pieces in order | World 2-5 |
| `Panel/StoryScene` | Story dialogue with Promi | All worlds |
| `LevelComplete` | Celebration with stars | All worlds |
### Book Concepts Not Yet Covered for Kids
1. **Few-shot learning** - Teaching by example
2. **Iterative refinement** - Improving prompts step-by-step
3. **Prompt anatomy** - Understanding prompt parts (role, context, task, format)
4. **Common pitfalls** - Recognizing and avoiding mistakes
5. **Chain of thought** - Step-by-step reasoning
---
## Proposed New Components
### 1. `<PromptLab />` - Interactive Prompt Tester
**Concept**: Kids build a prompt and see a simulated AI response (pre-defined).
**Props**:
```tsx
<PromptLab
scenario="Ask about a pet"
basePrompt="Tell me about dogs"
improvements={[
{ add: "that are good with kids", effect: "Now mentions family-friendly breeds!" },
{ add: "in 3 sentences", effect: "Response is shorter and clearer!" }
]}
finalResponse="Golden Retrievers are great with kids because..."
/>
```
**UX**:
- Shows base prompt with "add detail" buttons
- Each addition shows immediate simulated response change
- Teaches iterative refinement concept
**Book Reference**: Chapter 8 (Iterative Refinement)
---
### 2. `<PromptParts />` - Anatomy Highlighter
**Concept**: Interactive visualization of prompt components.
**Props**:
```tsx
<PromptParts
prompt="You are a friendly teacher. Explain fractions to a 10-year-old using pizza examples. Keep it under 50 words."
parts={[
{ text: "You are a friendly teacher", type: "role", color: "purple" },
{ text: "Explain fractions to a 10-year-old", type: "task", color: "blue" },
{ text: "using pizza examples", type: "example", color: "green" },
{ text: "Keep it under 50 words", type: "constraint", color: "orange" }
]}
/>
```
**UX**:
- Colored highlights on prompt parts
- Tap a part to see explanation
- Legend shows what each color means
**Book Reference**: Chapter 2 (Anatomy of a Prompt)
---
### 3. `<ExampleMatcher />` - Few-Shot Learning Game
**Concept**: Match examples to teach AI patterns.
**Props**:
```tsx
<ExampleMatcher
title="Teach the Pattern!"
examples={[
{ input: "happy", output: "😊" },
{ input: "sad", output: "😢" },
{ input: "angry", output: "???" }
]}
correctAnswer="😠"
options={["😠", "😊", "🎉", "😴"]}
explanation="The AI learns: words → matching emoji!"
/>
```
**UX**:
- Shows pattern with examples
- Kids choose what comes next
- Teaches few-shot learning concept
**Book Reference**: Chapter 7 (Few-Shot Learning)
---
### 4. `<PromptDoctor />` - Fix the Prompt
**Concept**: Identify and fix problems in broken prompts.
**Props**:
```tsx
<PromptDoctor
brokenPrompt="Write something"
problems={[
{ issue: "Too vague", fix: "Write a poem" },
{ issue: "No topic", fix: "Write a poem about friendship" },
{ issue: "No length", fix: "Write a short poem about friendship" }
]}
healedPrompt="Write a short poem about friendship"
/>
```
**UX**:
- Shows "sick" prompt with symptoms
- Kids tap problems to apply fixes
- Prompt "heals" as problems are fixed
- Fun medical/doctor theme
**Book Reference**: Chapter 15 (Common Pitfalls)
---
### 5. `<StepByStep />` - Chain of Thought Builder
**Concept**: Teach kids to ask AI to show its work.
**Props**:
```tsx
<StepByStep
problem="How many legs do 3 dogs and 2 cats have?"
wrongAnswer="20 legs (AI just guessed!)"
steps={[
"Dogs have 4 legs each",
"3 dogs × 4 legs = 12 legs",
"Cats have 4 legs each",
"2 cats × 4 legs = 8 legs",
"12 + 8 = 20 legs total"
]}
rightAnswer="20 legs (and we can check the work!)"
magicWords="Let's think step by step"
/>
```
**UX**:
- Shows problem with wrong answer first
- Kids add "magic words" to unlock step-by-step
- Steps reveal one at a time
- Teaches chain of thought prompting
**Book Reference**: Chapter 6 (Chain of Thought)
---
## Implementation Priority
| Priority | Component | Complexity | Impact |
|----------|-----------|------------|--------|
| 1 | `PromptParts` | Medium | High - visual learning |
| 2 | `ExampleMatcher` | Low | High - gamification |
| 3 | `PromptDoctor` | Medium | High - error recognition |
| 4 | `StepByStep` | Low | Medium - advanced concept |
| 5 | `PromptLab` | High | Medium - complex interactions |
---
## Level Integration
### Where to Add Components
| World | Level | New Component | Concept |
|-------|-------|---------------|---------|
| 2 | 2-4 Detail Detective | `PromptParts` | See prompt anatomy |
| 3 | 3-2 Show Don't Tell | `ExampleMatcher` | Teach by example |
| 5 | 5-2 Fix It Up | `PromptDoctor` | Fix broken prompts |
| 5 | 5-1 Perfect Prompt | `StepByStep` | Complex reasoning |
| 5 | 5-3 Prompt Remix | `PromptLab` | Iterate and improve |
---
## Estimated Work
- **Component Development**: ~2-3 hours per component
- **Level Content Updates**: ~30 min per level
- **i18n**: Add translation keys for new component labels
- **Testing**: Visual review on mobile/desktop
---
## Questions for User
1. **Priority**: Should I implement all 5, or start with top 2-3?
2. **Theming**: Any specific visual style preferences (medical theme for PromptDoctor, etc.)?
3. **Complexity**: Is `PromptLab` too complex for MVP, or should it be simpler?

View File

@@ -1,7 +1,7 @@
import type { MDXComponents } from "mdx/types"; import type { MDXComponents } from "mdx/types";
import type { ComponentPropsWithoutRef } from "react"; import type { ComponentPropsWithoutRef } from "react";
import { BeforeAfterEditor, BookPartsNav, BREAKFramework, Callout, ChainErrorDemo, ChainExample, ChainFlowDemo, Checklist, CodeEditor, Collapsible, Compare, ContentPipelineDemo, ContextPlayground, ContextWindowDemo, CostCalculatorDemo, CRISPEFramework, DiffView, EmbeddingsDemo, FallbackDemo, FewShotDemo, FillInTheBlank, IconCheck, IconClipboard, IconLightbulb, IconLock, IconSettings, IconStar, IconTarget, IconUser, IconX, InfoGrid, InteractiveChecklist, IterativeRefinementDemo, JailbreakDemo, JsonYamlDemo, LLMCapabilitiesDemo, NavButton, NavFooter, PrinciplesSummary, PromptAnalyzer, PromptBreakdown, PromptBuilder, PromptChallenge, PromptDebugger, Quiz, RTFFramework, SpecificitySpectrum, StructuredOutputDemo, SummarizationDemo, TemperatureDemo, TextToImageDemo, TextToVideoDemo, TokenizerDemo, TokenPredictionDemo, TryIt, ValidationDemo, VersionDiff } from "@/components/book/interactive"; import { BeforeAfterEditor, BookPartsNav, BREAKFramework, Callout, ChainErrorDemo, ChainExample, ChainFlowDemo, Checklist, CodeEditor, Collapsible, Compare, ContentPipelineDemo, ContextPlayground, ContextWindowDemo, CostCalculatorDemo, CRISPEFramework, DiffView, EmbeddingsDemo, FallbackDemo, FewShotDemo, FillInTheBlank, IconCheck, IconClipboard, IconLightbulb, IconLock, IconSettings, IconStar, IconTarget, IconUser, IconX, InfoGrid, InteractiveChecklist, IterativeRefinementDemo, JailbreakDemo, JsonYamlDemo, LLMCapabilitiesDemo, NavButton, NavFooter, PrinciplesSummary, PromptAnalyzer, PromptBreakdown, PromptBuilder, PromptChallenge, PromptDebugger, Quiz, RTFFramework, SpecificitySpectrum, StructuredOutputDemo, SummarizationDemo, TemperatureDemo, TextToImageDemo, TextToVideoDemo, TokenizerDemo, TokenPredictionDemo, TryIt, ValidationDemo, VersionDiff } from "@/components/book/interactive";
import { PromiCharacter, PromiWithMessage, Panel, StoryScene, PromptVsMistake, MagicWords, DragDropPrompt, LevelComplete } from "@/components/kids/elements"; import { PromiCharacter, PromiWithMessage, Panel, StoryScene, PromptVsMistake, MagicWords, DragDropPrompt, LevelComplete, Section, PromptParts, ExampleMatcher, PromptDoctor, StepByStep, PromptLab, WordPredictor } from "@/components/kids/elements";
export function useMDXComponents(components: MDXComponents): MDXComponents { export function useMDXComponents(components: MDXComponents): MDXComponents {
return { return {
@@ -92,5 +92,12 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
MagicWords, MagicWords,
DragDropPrompt, DragDropPrompt,
LevelComplete, LevelComplete,
Section,
PromptParts,
ExampleMatcher,
PromptDoctor,
StepByStep,
PromptLab,
WordPredictor,
}; };
} }

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "اجمع النجوم", "description": "اجمع النجوم وافتح مستويات جديدة" } "stars": { "title": "اجمع النجوم", "description": "اجمع النجوم وافتح مستويات جديدة" }
}, },
"startButton": "ابدأ اللعب!", "startButton": "ابدأ اللعب!",
"ageNote": "الأفضل للأطفال من 8-14 سنة الذين يعرفون القراءة والكتابة" "ageNote": "الأفضل للأطفال من 8-14 سنة الذين يعرفون القراءة والكتابة",
"whatYouLearn": "ماذا ستتعلم",
"readyTitle": "مستعد للبدء؟",
"readyMessage": "لننطلق في مغامرة ونتعلم كيف نتحدث مع الذكاء الاصطناعي!"
},
"navigation": {
"back": "رجوع",
"next": "التالي"
}, },
"map": { "title": "خريطة العالم", "subtitle": "اختر مستوى وابدأ مغامرتك!", "worldLevels": "{count} مستويات", "levelNumber": "المستوى {number}", "locked": "أكمل المستوى السابق للفتح" }, "map": { "title": "خريطة العالم", "subtitle": "اختر مستوى وابدأ مغامرتك!", "worldLevels": "{count} مستويات", "levelNumber": "المستوى {number}", "locked": "أكمل المستوى السابق للفتح" },
"worlds": { "1": { "title": "قرية البداية" }, "2": { "title": "قلعة الوضوح" }, "3": { "title": "كهوف السياق" }, "4": { "title": "وادي الإبداع" }, "5": { "title": "جبل الإتقان" } }, "worlds": { "1": { "title": "قرية البداية" }, "2": { "title": "قلعة الوضوح" }, "3": { "title": "كهوف السياق" }, "4": { "title": "وادي الإبداع" }, "5": { "title": "جبل الإتقان" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Ulduz Qazan", "description": "Ulduzlar topla və yeni səviyyələri aç" } "stars": { "title": "Ulduz Qazan", "description": "Ulduzlar topla və yeni səviyyələri aç" }
}, },
"startButton": "Oynamağa Başla!", "startButton": "Oynamağa Başla!",
"ageNote": "Oxumaq və yazmaq bilən 8-14 yaşlı uşaqlar üçün ən uyğun" "ageNote": "Oxumaq və yazmaq bilən 8-14 yaşlı uşaqlar üçün ən uyğun",
"whatYouLearn": "Nə öyrənəcəksən",
"readyTitle": "Başlamağa hazırsan?",
"readyMessage": "Gəl macəraya çıxaq və AI ilə danışmağı öyrənək!"
},
"navigation": {
"back": "Geri",
"next": "İrəli"
}, },
"map": { "title": "Dünya Xəritəsi", "subtitle": "Bir səviyyə seç və macərana başla!", "worldLevels": "{count} səviyyə", "levelNumber": "Səviyyə {number}", "locked": "Açmaq üçün əvvəlki səviyyəni tamamla" }, "map": { "title": "Dünya Xəritəsi", "subtitle": "Bir səviyyə seç və macərana başla!", "worldLevels": "{count} səviyyə", "levelNumber": "Səviyyə {number}", "locked": "Açmaq üçün əvvəlki səviyyəni tamamla" },
"worlds": { "1": { "title": "Başlanğıc Kəndi" }, "2": { "title": "Aydınlıq Qalası" }, "3": { "title": "Kontekst Mağaraları" }, "4": { "title": "Yaradıcılıq Kanyonu" }, "5": { "title": "Ustad Dağı" } }, "worlds": { "1": { "title": "Başlanğıc Kəndi" }, "2": { "title": "Aydınlıq Qalası" }, "3": { "title": "Kontekst Mağaraları" }, "4": { "title": "Yaradıcılıq Kanyonu" }, "5": { "title": "Ustad Dağı" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Sterne sammeln", "description": "Sammle Sterne und schalte neue Level frei" } "stars": { "title": "Sterne sammeln", "description": "Sammle Sterne und schalte neue Level frei" }
}, },
"startButton": "Jetzt spielen!", "startButton": "Jetzt spielen!",
"ageNote": "Am besten für Kinder von 8-14 Jahren, die lesen und schreiben können" "ageNote": "Am besten für Kinder von 8-14 Jahren, die lesen und schreiben können",
"whatYouLearn": "Was du lernst",
"readyTitle": "Bereit zum Starten?",
"readyMessage": "Lass uns auf ein Abenteuer gehen und lernen, mit KI zu sprechen!"
},
"navigation": {
"back": "Zurück",
"next": "Weiter"
}, },
"map": { "title": "Weltkarte", "subtitle": "Wähle ein Level und starte dein Abenteuer!", "worldLevels": "{count} Level", "levelNumber": "Level {number}", "locked": "Schließe das vorherige Level ab zum Freischalten" }, "map": { "title": "Weltkarte", "subtitle": "Wähle ein Level und starte dein Abenteuer!", "worldLevels": "{count} Level", "levelNumber": "Level {number}", "locked": "Schließe das vorherige Level ab zum Freischalten" },
"worlds": { "1": { "title": "Startdorf" }, "2": { "title": "Klarheitsschloss" }, "3": { "title": "Kontext-Höhlen" }, "4": { "title": "Kreativ-Canyon" }, "5": { "title": "Meisterberg" } }, "worlds": { "1": { "title": "Startdorf" }, "2": { "title": "Klarheitsschloss" }, "3": { "title": "Kontext-Höhlen" }, "4": { "title": "Kreativ-Canyon" }, "5": { "title": "Meisterberg" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Κέρδισε Αστέρια", "description": "Συλλέξτε αστέρια και ξεκλειδώστε νέα επίπεδα" } "stars": { "title": "Κέρδισε Αστέρια", "description": "Συλλέξτε αστέρια και ξεκλειδώστε νέα επίπεδα" }
}, },
"startButton": "Ξεκίνα να Παίζεις!", "startButton": "Ξεκίνα να Παίζεις!",
"ageNote": "Ιδανικό για παιδιά 8-14 ετών που ξέρουν να διαβάζουν και να γράφουν" "ageNote": "Ιδανικό για παιδιά 8-14 ετών που ξέρουν να διαβάζουν και να γράφουν",
"whatYouLearn": "Τι θα μάθεις",
"readyTitle": "Έτοιμος να ξεκινήσεις;",
"readyMessage": "Πάμε σε μια περιπέτεια και μάθουμε να μιλάμε με την AI!"
},
"navigation": {
"back": "Πίσω",
"next": "Επόμενο"
}, },
"map": { "title": "Χάρτης Κόσμου", "subtitle": "Επέλεξε ένα επίπεδο και ξεκίνα την περιπέτειά σου!", "worldLevels": "{count} επίπεδα", "levelNumber": "Επίπεδο {number}", "locked": "Ολοκλήρωσε το προηγούμενο επίπεδο για ξεκλείδωμα" }, "map": { "title": "Χάρτης Κόσμου", "subtitle": "Επέλεξε ένα επίπεδο και ξεκίνα την περιπέτειά σου!", "worldLevels": "{count} επίπεδα", "levelNumber": "Επίπεδο {number}", "locked": "Ολοκλήρωσε το προηγούμενο επίπεδο για ξεκλείδωμα" },
"worlds": { "1": { "title": "Χωριό Εκκίνησης" }, "2": { "title": "Κάστρο Σαφήνειας" }, "3": { "title": "Σπηλιές Πλαισίου" }, "4": { "title": "Φαράγγι Δημιουργικότητας" }, "5": { "title": "Βουνό Μαεστρίας" } }, "worlds": { "1": { "title": "Χωριό Εκκίνησης" }, "2": { "title": "Κάστρο Σαφήνειας" }, "3": { "title": "Σπηλιές Πλαισίου" }, "4": { "title": "Φαράγγι Δημιουργικότητας" }, "5": { "title": "Βουνό Μαεστρίας" } },

View File

@@ -1417,7 +1417,14 @@
} }
}, },
"startButton": "Start Playing!", "startButton": "Start Playing!",
"ageNote": "Best for kids ages 8-14 who can read and write" "ageNote": "Best for kids ages 8-14 who can read and write",
"whatYouLearn": "What You'll Learn",
"readyTitle": "Ready to Start?",
"readyMessage": "Let's go on an adventure and learn how to talk to AI!"
},
"navigation": {
"back": "Back",
"next": "Next"
}, },
"map": { "map": {
"title": "World Map", "title": "World Map",
@@ -1455,6 +1462,70 @@
"1_3_being_clear": { "1_3_being_clear": {
"title": "Being Clear", "title": "Being Clear",
"description": "Learn why clear instructions work better" "description": "Learn why clear instructions work better"
},
"2_1_missing_details": {
"title": "The Missing Details",
"description": "Discover why details matter - vague vs specific prompts"
},
"2_2_who_and_what": {
"title": "Who & What",
"description": "Add characters and objects to make prompts come alive"
},
"2_3_when_and_where": {
"title": "When & Where",
"description": "Learn to add time and place to your prompts"
},
"2_4_detail_detective": {
"title": "The Detail Detective",
"description": "Become a master of adding all the right details"
},
"3_1_setting_the_scene": {
"title": "Setting the Scene",
"description": "Learn why background info helps AI understand you"
},
"3_2_show_dont_tell": {
"title": "Show, Don't Tell",
"description": "Use examples to show AI exactly what you want"
},
"3_3_format_finder": {
"title": "The Format Finder",
"description": "Ask for lists, stories, poems, and more!"
},
"3_4_context_champion": {
"title": "Context Champion",
"description": "Combine all context techniques like a pro"
},
"4_1_pretend_time": {
"title": "Pretend Time!",
"description": "Learn role-play prompts - 'Act as...'"
},
"4_2_story_starters": {
"title": "Story Starters",
"description": "Create amazing stories with AI as your co-author"
},
"4_3_character_creator": {
"title": "Character Creator",
"description": "Give AI a personality and watch it come alive"
},
"4_4_world_builder": {
"title": "World Builder",
"description": "Create imaginative worlds and scenarios"
},
"5_1_perfect_prompt": {
"title": "The Perfect Prompt",
"description": "Combine clarity, details, and context together"
},
"5_2_fix_it_up": {
"title": "Fix It Up!",
"description": "Find and improve weak prompts"
},
"5_3_prompt_remix": {
"title": "Prompt Remix",
"description": "Rewrite prompts for different outcomes"
},
"5_4_graduation_day": {
"title": "Graduation Day",
"description": "The final challenge - become a Prompt Master!"
} }
}, },
"level": { "level": {
@@ -1470,6 +1541,105 @@
"nextLevel": "Next Level", "nextLevel": "Next Level",
"backToMap": "Back to Map", "backToMap": "Back to Map",
"allDone": "Back to Map" "allDone": "Back to Map"
},
"quiz": {
"goodLabel": "Great prompt!",
"badLabel": "Not the best",
"correct": "You got it!",
"incorrect": "Good try!",
"tryAgain": "Try Again"
},
"magicWords": {
"title": "Drag the magic words! ✨",
"dragOrTap": "🎯 Drag or tap words:",
"check": "Check!",
"retry": "Retry",
"correct": "correct",
"tryAgain": "Try again!"
},
"dragDrop": {
"title": "Build the prompt!",
"instruction": "Use arrows to move pieces, or tap two pieces to swap!",
"result": "Result",
"check": "Check!",
"retry": "Retry",
"success": "Perfect! You built a great prompt!",
"almost": "Almost! Keep reordering.",
"tapToSwap": "Tap another piece to swap positions!"
},
"promptParts": {
"title": "Sort the Prompt Parts!",
"instruction": "Tap each piece, then pick which type it is!",
"score": "Score",
"pickCategory": "What type is this?",
"success": "You sorted all the parts correctly!",
"retry": "Try Again",
"types": {
"role": "Role",
"task": "Task",
"context": "Context",
"constraint": "Constraint"
}
},
"exampleMatcher": {
"title": "Pattern Matcher",
"instruction": "Look at the pattern and pick what comes next!",
"pattern": "The Pattern:",
"check": "Check!",
"retry": "Try Again",
"correct": "You got it! 🎉",
"tryAgain": "Not quite - look at the pattern again!"
},
"promptDoctor": {
"title": "Prompt Doctor",
"health": "Prompt Health",
"sick": "Sick Prompt",
"healthy": "Healthy Prompt!",
"diagnose": "Click a problem to fix it:",
"success": "The prompt is all better now!",
"retry": "Start Over"
},
"stepByStep": {
"title": "Think Step by Step",
"problem": "The Problem:",
"withoutMagic": "Without magic words:",
"addMagicWords": "Add the Magic Words!",
"magicWordsActive": "Magic words added!",
"nextStep": "Reveal Next Step",
"withMagic": "With step-by-step thinking:",
"retry": "Try Again"
},
"promptLab": {
"title": "Prompt Lab",
"progress": "Improvements",
"yourPrompt": "Your Prompt:",
"aiSays": "AI Response:",
"addDetails": "Add improvements:",
"success": "Your prompt is now super specific!",
"retry": "Start Over"
},
"wordPredictor": {
"title": "How AI Thinks",
"instruction": "AI guesses the most likely next word. Can you think like AI?",
"aiThinks": "AI is reading:",
"thinkingDefault": "Hmm, what word would make the most sense here?",
"check": "Check My Guess!",
"correct": "You think like AI!",
"tryAgain": "Not quite! AI picks the most likely word.",
"retry": "Try Again"
},
"settings": {
"title": "Settings",
"language": "Language",
"progress": "Your Progress",
"stars": "Stars",
"completed": "Completed",
"resetTitle": "Reset Progress",
"resetButton": "Reset All Progress",
"resetWarning": "This will delete all your stars and progress. Are you sure?",
"resetConfirm": "Yes, Reset Everything",
"resetComplete": "Progress reset! Reloading...",
"cancel": "Cancel"
} }
} }
} }

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Gana Estrellas", "description": "Colecciona estrellas y desbloquea nuevos niveles" } "stars": { "title": "Gana Estrellas", "description": "Colecciona estrellas y desbloquea nuevos niveles" }
}, },
"startButton": "¡Empezar a Jugar!", "startButton": "¡Empezar a Jugar!",
"ageNote": "Ideal para niños de 8-14 años que saben leer y escribir" "ageNote": "Ideal para niños de 8-14 años que saben leer y escribir",
"whatYouLearn": "Lo Que Aprenderás",
"readyTitle": "¿Listo para Empezar?",
"readyMessage": "¡Vamos a una aventura y aprendamos a hablar con la IA!"
},
"navigation": {
"back": "Atrás",
"next": "Siguiente"
}, },
"map": { "title": "Mapa del Mundo", "subtitle": "¡Elige un nivel y comienza tu aventura!", "worldLevels": "{count} niveles", "levelNumber": "Nivel {number}", "locked": "Completa el nivel anterior para desbloquear" }, "map": { "title": "Mapa del Mundo", "subtitle": "¡Elige un nivel y comienza tu aventura!", "worldLevels": "{count} niveles", "levelNumber": "Nivel {number}", "locked": "Completa el nivel anterior para desbloquear" },
"worlds": { "1": { "title": "Aldea Inicial" }, "2": { "title": "Castillo de Claridad" }, "3": { "title": "Cuevas de Contexto" }, "4": { "title": "Cañón Creativo" }, "5": { "title": "Montaña Maestra" } }, "worlds": { "1": { "title": "Aldea Inicial" }, "2": { "title": "Castillo de Claridad" }, "3": { "title": "Cuevas de Contexto" }, "4": { "title": "Cañón Creativo" }, "5": { "title": "Montaña Maestra" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "ستاره جمع کن", "description": "ستاره جمع کن و مراحل جدید را باز کن" } "stars": { "title": "ستاره جمع کن", "description": "ستاره جمع کن و مراحل جدید را باز کن" }
}, },
"startButton": "شروع بازی!", "startButton": "شروع بازی!",
"ageNote": "مناسب برای کودکان ۸-۱۴ ساله که می‌توانند بخوانند و بنویسند" "ageNote": "مناسب برای کودکان ۸-۱۴ ساله که می‌توانند بخوانند و بنویسند",
"whatYouLearn": "چه چیزی یاد می‌گیری",
"readyTitle": "آماده شروع هستی؟",
"readyMessage": "بیا به ماجراجویی برویم و یاد بگیریم چطور با هوش مصنوعی صحبت کنیم!"
},
"navigation": {
"back": "برگشت",
"next": "بعدی"
}, },
"map": { "title": "نقشه جهان", "subtitle": "یک مرحله انتخاب کن و ماجراجویی‌ات را شروع کن!", "worldLevels": "{count} مرحله", "levelNumber": "مرحله {number}", "locked": "برای باز کردن، مرحله قبلی را کامل کن" }, "map": { "title": "نقشه جهان", "subtitle": "یک مرحله انتخاب کن و ماجراجویی‌ات را شروع کن!", "worldLevels": "{count} مرحله", "levelNumber": "مرحله {number}", "locked": "برای باز کردن، مرحله قبلی را کامل کن" },
"worlds": { "1": { "title": "دهکده شروع" }, "2": { "title": "قلعه شفافیت" }, "3": { "title": "غارهای زمینه" }, "4": { "title": "دره خلاقیت" }, "5": { "title": "کوه استادی" } }, "worlds": { "1": { "title": "دهکده شروع" }, "2": { "title": "قلعه شفافیت" }, "3": { "title": "غارهای زمینه" }, "4": { "title": "دره خلاقیت" }, "5": { "title": "کوه استادی" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Gagne des Étoiles", "description": "Collectionne des étoiles et débloque de nouveaux niveaux" } "stars": { "title": "Gagne des Étoiles", "description": "Collectionne des étoiles et débloque de nouveaux niveaux" }
}, },
"startButton": "Commencer à Jouer !", "startButton": "Commencer à Jouer !",
"ageNote": "Idéal pour les enfants de 8-14 ans qui savent lire et écrire" "ageNote": "Idéal pour les enfants de 8-14 ans qui savent lire et écrire",
"whatYouLearn": "Ce que tu vas apprendre",
"readyTitle": "Prêt à commencer ?",
"readyMessage": "Partons à l'aventure et apprenons à parler avec l'IA !"
},
"navigation": {
"back": "Retour",
"next": "Suivant"
}, },
"map": { "title": "Carte du Monde", "subtitle": "Choisis un niveau et commence ton aventure !", "worldLevels": "{count} niveaux", "levelNumber": "Niveau {number}", "locked": "Termine le niveau précédent pour débloquer" }, "map": { "title": "Carte du Monde", "subtitle": "Choisis un niveau et commence ton aventure !", "worldLevels": "{count} niveaux", "levelNumber": "Niveau {number}", "locked": "Termine le niveau précédent pour débloquer" },
"worlds": { "1": { "title": "Village de Départ" }, "2": { "title": "Château de la Clarté" }, "3": { "title": "Grottes du Contexte" }, "4": { "title": "Canyon Créatif" }, "5": { "title": "Montagne du Maître" } }, "worlds": { "1": { "title": "Village de Départ" }, "2": { "title": "Château de la Clarté" }, "3": { "title": "Grottes du Contexte" }, "4": { "title": "Canyon Créatif" }, "5": { "title": "Montagne du Maître" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "אסוף כוכבים", "description": "אסוף כוכבים ופתח שלבים חדשים" } "stars": { "title": "אסוף כוכבים", "description": "אסוף כוכבים ופתח שלבים חדשים" }
}, },
"startButton": "התחל לשחק!", "startButton": "התחל לשחק!",
"ageNote": "מתאים לילדים בגילאי 8-14 שיודעים לקרוא ולכתוב" "ageNote": "מתאים לילדים בגילאי 8-14 שיודעים לקרוא ולכתוב",
"whatYouLearn": "מה תלמד",
"readyTitle": "מוכן להתחיל?",
"readyMessage": "בוא נצא להרפתקה ונלמד איך לדבר עם AI!"
},
"navigation": {
"back": "אחורה",
"next": "הבא"
}, },
"map": { "title": "מפת העולם", "subtitle": "בחר שלב והתחל את ההרפתקה שלך!", "worldLevels": "{count} שלבים", "levelNumber": "שלב {number}", "locked": "השלם את השלב הקודם לפתיחה" }, "map": { "title": "מפת העולם", "subtitle": "בחר שלב והתחל את ההרפתקה שלך!", "worldLevels": "{count} שלבים", "levelNumber": "שלב {number}", "locked": "השלם את השלב הקודם לפתיחה" },
"worlds": { "1": { "title": "כפר ההתחלה" }, "2": { "title": "טירת הבהירות" }, "3": { "title": "מערות ההקשר" }, "4": { "title": "קניון היצירתיות" }, "5": { "title": "הר המומחיות" } }, "worlds": { "1": { "title": "כפר ההתחלה" }, "2": { "title": "טירת הבהירות" }, "3": { "title": "מערות ההקשר" }, "4": { "title": "קניון היצירתיות" }, "5": { "title": "הר המומחיות" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Guadagna Stelle", "description": "Raccogli stelle e sblocca nuovi livelli" } "stars": { "title": "Guadagna Stelle", "description": "Raccogli stelle e sblocca nuovi livelli" }
}, },
"startButton": "Inizia a Giocare!", "startButton": "Inizia a Giocare!",
"ageNote": "Ideale per bambini di 8-14 anni che sanno leggere e scrivere" "ageNote": "Ideale per bambini di 8-14 anni che sanno leggere e scrivere",
"whatYouLearn": "Cosa imparerai",
"readyTitle": "Pronto per iniziare?",
"readyMessage": "Andiamo all'avventura e impariamo a parlare con l'IA!"
},
"navigation": {
"back": "Indietro",
"next": "Avanti"
}, },
"map": { "title": "Mappa del Mondo", "subtitle": "Scegli un livello e inizia la tua avventura!", "worldLevels": "{count} livelli", "levelNumber": "Livello {number}", "locked": "Completa il livello precedente per sbloccare" }, "map": { "title": "Mappa del Mondo", "subtitle": "Scegli un livello e inizia la tua avventura!", "worldLevels": "{count} livelli", "levelNumber": "Livello {number}", "locked": "Completa il livello precedente per sbloccare" },
"worlds": { "1": { "title": "Villaggio Iniziale" }, "2": { "title": "Castello della Chiarezza" }, "3": { "title": "Caverne del Contesto" }, "4": { "title": "Canyon Creativo" }, "5": { "title": "Montagna del Maestro" } }, "worlds": { "1": { "title": "Villaggio Iniziale" }, "2": { "title": "Castello della Chiarezza" }, "3": { "title": "Caverne del Contesto" }, "4": { "title": "Canyon Creativo" }, "5": { "title": "Montagna del Maestro" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "スターを集めよう", "description": "スターを集めて新しいレベルをアンロック" } "stars": { "title": "スターを集めよう", "description": "スターを集めて新しいレベルをアンロック" }
}, },
"startButton": "遊び始めよう!", "startButton": "遊び始めよう!",
"ageNote": "読み書きができる8〜14歳のお子様に最適" "ageNote": "読み書きができる8〜14歳のお子様に最適",
"whatYouLearn": "学べること",
"readyTitle": "始める準備はできた?",
"readyMessage": "冒険に出かけて、AIと話す方法を学ぼう"
},
"navigation": {
"back": "戻る",
"next": "次へ"
}, },
"map": { "title": "ワールドマップ", "subtitle": "レベルを選んで冒険を始めよう!", "worldLevels": "{count}レベル", "levelNumber": "レベル{number}", "locked": "前のレベルをクリアしてアンロック" }, "map": { "title": "ワールドマップ", "subtitle": "レベルを選んで冒険を始めよう!", "worldLevels": "{count}レベル", "levelNumber": "レベル{number}", "locked": "前のレベルをクリアしてアンロック" },
"worlds": { "1": { "title": "はじまりの村" }, "2": { "title": "明確城" }, "3": { "title": "コンテキスト洞窟" }, "4": { "title": "クリエイティブ渓谷" }, "5": { "title": "マスター山" } }, "worlds": { "1": { "title": "はじまりの村" }, "2": { "title": "明確城" }, "3": { "title": "コンテキスト洞窟" }, "4": { "title": "クリエイティブ渓谷" }, "5": { "title": "マスター山" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "별 모으기", "description": "별을 모아 새로운 레벨을 열어요" } "stars": { "title": "별 모으기", "description": "별을 모아 새로운 레벨을 열어요" }
}, },
"startButton": "게임 시작!", "startButton": "게임 시작!",
"ageNote": "읽고 쓸 수 있는 8-14세 어린이에게 적합해요" "ageNote": "읽고 쓸 수 있는 8-14세 어린이에게 적합해요",
"whatYouLearn": "배울 내용",
"readyTitle": "시작할 준비됐어?",
"readyMessage": "모험을 떠나 AI와 대화하는 법을 배워보자!"
},
"navigation": {
"back": "뒤로",
"next": "다음"
}, },
"map": { "title": "세계 지도", "subtitle": "레벨을 선택하고 모험을 시작하세요!", "worldLevels": "{count}개 레벨", "levelNumber": "레벨 {number}", "locked": "이전 레벨을 완료하면 열립니다" }, "map": { "title": "세계 지도", "subtitle": "레벨을 선택하고 모험을 시작하세요!", "worldLevels": "{count}개 레벨", "levelNumber": "레벨 {number}", "locked": "이전 레벨을 완료하면 열립니다" },
"worlds": { "1": { "title": "시작 마을" }, "2": { "title": "명확성의 성" }, "3": { "title": "맥락 동굴" }, "4": { "title": "창의력 협곡" }, "5": { "title": "마스터 산" } }, "worlds": { "1": { "title": "시작 마을" }, "2": { "title": "명확성의 성" }, "3": { "title": "맥락 동굴" }, "4": { "title": "창의력 협곡" }, "5": { "title": "마스터 산" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Ganhe Estrelas", "description": "Colete estrelas e desbloqueie novos níveis" } "stars": { "title": "Ganhe Estrelas", "description": "Colete estrelas e desbloqueie novos níveis" }
}, },
"startButton": "Começar a Jogar!", "startButton": "Começar a Jogar!",
"ageNote": "Ideal para crianças de 8-14 anos que sabem ler e escrever" "ageNote": "Ideal para crianças de 8-14 anos que sabem ler e escrever",
"whatYouLearn": "O que você vai aprender",
"readyTitle": "Pronto para começar?",
"readyMessage": "Vamos em uma aventura e aprender a falar com a IA!"
},
"navigation": {
"back": "Voltar",
"next": "Próximo"
}, },
"map": { "title": "Mapa do Mundo", "subtitle": "Escolha um nível e comece sua aventura!", "worldLevels": "{count} níveis", "levelNumber": "Nível {number}", "locked": "Complete o nível anterior para desbloquear" }, "map": { "title": "Mapa do Mundo", "subtitle": "Escolha um nível e comece sua aventura!", "worldLevels": "{count} níveis", "levelNumber": "Nível {number}", "locked": "Complete o nível anterior para desbloquear" },
"worlds": { "1": { "title": "Vila Inicial" }, "2": { "title": "Castelo da Clareza" }, "3": { "title": "Cavernas de Contexto" }, "4": { "title": "Cânion Criativo" }, "5": { "title": "Montanha Mestre" } }, "worlds": { "1": { "title": "Vila Inicial" }, "2": { "title": "Castelo da Clareza" }, "3": { "title": "Cavernas de Contexto" }, "4": { "title": "Cânion Criativo" }, "5": { "title": "Montanha Mestre" } },

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "Собирай звёзды", "description": "Собирай звёзды и открывай новые уровни" } "stars": { "title": "Собирай звёзды", "description": "Собирай звёзды и открывай новые уровни" }
}, },
"startButton": "Начать играть!", "startButton": "Начать играть!",
"ageNote": "Лучше всего подходит для детей 8-14 лет, умеющих читать и писать" "ageNote": "Лучше всего подходит для детей 8-14 лет, умеющих читать и писать",
"whatYouLearn": "Что ты узнаешь",
"readyTitle": "Готов начать?",
"readyMessage": "Отправимся в приключение и научимся разговаривать с ИИ!"
},
"navigation": {
"back": "Назад",
"next": "Далее"
}, },
"map": { "title": "Карта мира", "subtitle": "Выбери уровень и начни своё приключение!", "worldLevels": "{count} уровней", "levelNumber": "Уровень {number}", "locked": "Пройди предыдущий уровень для разблокировки" }, "map": { "title": "Карта мира", "subtitle": "Выбери уровень и начни своё приключение!", "worldLevels": "{count} уровней", "levelNumber": "Уровень {number}", "locked": "Пройди предыдущий уровень для разблокировки" },
"worlds": { "1": { "title": "Стартовая деревня" }, "2": { "title": "Замок ясности" }, "3": { "title": "Пещеры контекста" }, "4": { "title": "Каньон творчества" }, "5": { "title": "Гора мастерства" } }, "worlds": { "1": { "title": "Стартовая деревня" }, "2": { "title": "Замок ясности" }, "3": { "title": "Пещеры контекста" }, "4": { "title": "Каньон творчества" }, "5": { "title": "Гора мастерства" } },

View File

@@ -1417,7 +1417,14 @@
} }
}, },
"startButton": "Oynamaya Başla!", "startButton": "Oynamaya Başla!",
"ageNote": "Okuma yazma bilen 8-14 yaş çocuklar için en uygun" "ageNote": "Okuma yazma bilen 8-14 yaş çocuklar için en uygun",
"whatYouLearn": "Ne Öğreneceksin",
"readyTitle": "Başlamaya Hazır mısın?",
"readyMessage": "Haydi bir maceraya çıkalım ve yapay zeka ile nasıl konuşulacağını öğrenelim!"
},
"navigation": {
"back": "Geri",
"next": "İleri"
}, },
"map": { "map": {
"title": "Dünya Haritası", "title": "Dünya Haritası",
@@ -1436,7 +1443,23 @@
"levels": { "levels": {
"1_1_meet_promi": { "title": "Promi ile Tanış!", "description": "Robot arkadaşınla tanış ve yapay zekanın ne olduğunu öğren" }, "1_1_meet_promi": { "title": "Promi ile Tanış!", "description": "Robot arkadaşınla tanış ve yapay zekanın ne olduğunu öğren" },
"1_2_first_words": { "title": "Promi'in İlk Sözleri", "description": "İlk promptunu yazarak Promi'in anlamasına yardım et" }, "1_2_first_words": { "title": "Promi'in İlk Sözleri", "description": "İlk promptunu yazarak Promi'in anlamasına yardım et" },
"1_3_being_clear": { "title": "Net Olmak", "description": "Net talimatların neden daha iyi çalıştığını öğren" } "1_3_being_clear": { "title": "Net Olmak", "description": "Net talimatların neden daha iyi çalıştığını öğren" },
"2_1_missing_details": { "title": "Eksik Detaylar", "description": "Detayların neden önemli olduğunu keşfet" },
"2_2_who_and_what": { "title": "Kim ve Ne", "description": "Promptlarına karakter ve nesne ekle" },
"2_3_when_and_where": { "title": "Ne Zaman ve Nerede", "description": "Promptlarına zaman ve yer eklemeyi öğren" },
"2_4_detail_detective": { "title": "Detay Dedektifi", "description": "Doğru detayları ekleme ustası ol" },
"3_1_setting_the_scene": { "title": "Sahneyi Hazırlamak", "description": "Arka plan bilgisinin yapay zekaya nasıl yardımcı olduğunu öğren" },
"3_2_show_dont_tell": { "title": "Göster, Anlatma", "description": "Örnekler kullanarak tam olarak ne istediğini göster" },
"3_3_format_finder": { "title": "Format Bulucu", "description": "Liste, hikaye, şiir ve daha fazlasını iste!" },
"3_4_context_champion": { "title": "Bağlam Şampiyonu", "description": "Tüm bağlam tekniklerini bir profesyonel gibi birleştir" },
"4_1_pretend_time": { "title": "Hayal Zamanı!", "description": "Rol yapma promptlarını öğren" },
"4_2_story_starters": { "title": "Hikaye Başlatıcılar", "description": "Yapay zeka ile harika hikayeler oluştur" },
"4_3_character_creator": { "title": "Karakter Yaratıcı", "description": "Yapay zekaya kişilik ver" },
"4_4_world_builder": { "title": "Dünya Oluşturucu", "description": "Hayal gücüyle dolu dünyalar yarat" },
"5_1_perfect_prompt": { "title": "Mükemmel Prompt", "description": "Netlik, detay ve bağlamı birleştir" },
"5_2_fix_it_up": { "title": "Düzelt!", "description": "Zayıf promptları bul ve geliştir" },
"5_3_prompt_remix": { "title": "Prompt Remix", "description": "Farklı sonuçlar için promptları yeniden yaz" },
"5_4_graduation_day": { "title": "Mezuniyet Günü", "description": "Son mücadele - Prompt Ustası ol!" }
}, },
"level": { "level": {
"backToMap": "Haritaya Dön", "backToMap": "Haritaya Dön",
@@ -1451,6 +1474,105 @@
"nextLevel": "Sonraki Seviye", "nextLevel": "Sonraki Seviye",
"backToMap": "Haritaya Dön", "backToMap": "Haritaya Dön",
"allDone": "Haritaya Dön" "allDone": "Haritaya Dön"
},
"quiz": {
"goodLabel": "Harika prompt!",
"badLabel": "Pek iyi değil",
"correct": "Doğru bildin!",
"incorrect": "İyi deneme!",
"tryAgain": "Tekrar Dene"
},
"magicWords": {
"title": "Sihirli kelimeleri sürükle! ✨",
"dragOrTap": "🎯 Kelimeleri sürükle veya tıkla:",
"check": "Kontrol Et!",
"retry": "Tekrar Dene",
"correct": "doğru",
"tryAgain": "Tekrar dene!"
},
"dragDrop": {
"title": "Promptu oluştur!",
"instruction": "Okları kullanarak taşı veya iki parçaya tıklayarak yer değiştir!",
"result": "Sonuç",
"check": "Kontrol Et!",
"retry": "Tekrar Dene",
"success": "Mükemmel! Harika bir prompt oluşturdun!",
"almost": "Neredeyse! Sıralamaya devam et.",
"tapToSwap": "Yer değiştirmek için başka bir parçaya tıkla!"
},
"promptParts": {
"title": "Prompt Parçalarını Sırala!",
"instruction": "Her parçaya tıkla, sonra türünü seç!",
"score": "Puan",
"pickCategory": "Bu ne türü?",
"success": "Tüm parçaları doğru sıraladın!",
"retry": "Tekrar Dene",
"types": {
"role": "Rol",
"task": "Görev",
"context": "Bağlam",
"constraint": "Kısıtlama"
}
},
"exampleMatcher": {
"title": "Desen Eşleştirici",
"instruction": "Desene bak ve sıradaki ne olmalı seç!",
"pattern": "Desen:",
"check": "Kontrol Et!",
"retry": "Tekrar Dene",
"correct": "Doğru bildin! 🎉",
"tryAgain": "Tam değil - desene tekrar bak!"
},
"promptDoctor": {
"title": "Prompt Doktoru",
"health": "Prompt Sağlığı",
"sick": "Hasta Prompt",
"healthy": "Sağlıklı Prompt!",
"diagnose": "Düzeltmek için bir soruna tıkla:",
"success": "Prompt artık tamamen iyileşti!",
"retry": "Baştan Başla"
},
"stepByStep": {
"title": "Adım Adım Düşün",
"problem": "Problem:",
"withoutMagic": "Sihirli kelimeler olmadan:",
"addMagicWords": "Sihirli Kelimeleri Ekle!",
"magicWordsActive": "Sihirli kelimeler eklendi!",
"nextStep": "Sonraki Adımı Göster",
"withMagic": "Adım adım düşünme ile:",
"retry": "Tekrar Dene"
},
"promptLab": {
"title": "Prompt Laboratuvarı",
"progress": "İyileştirmeler",
"yourPrompt": "Promptun:",
"aiSays": "Yapay Zeka Yanıtı:",
"addDetails": "İyileştirme ekle:",
"success": "Promptun artık süper detaylı!",
"retry": "Baştan Başla"
},
"wordPredictor": {
"title": "Yapay Zeka Nasıl Düşünür",
"instruction": "Yapay zeka en mantıklı kelimeyi tahmin eder. Sen de yapay zeka gibi düşünebilir misin?",
"aiThinks": "Yapay zeka okuyor:",
"thinkingDefault": "Hmm, buraya hangi kelime en çok uyar?",
"check": "Tahminimi Kontrol Et!",
"correct": "Yapay zeka gibi düşünüyorsun!",
"tryAgain": "Tam değil! Yapay zeka en olası kelimeyi seçer.",
"retry": "Tekrar Dene"
},
"settings": {
"title": "Ayarlar",
"language": "Dil",
"progress": "İlerlemeniz",
"stars": "Yıldız",
"completed": "Tamamlanan",
"resetTitle": "İlerlemeyi Sıfırla",
"resetButton": "Tüm İlerlemeyi Sıfırla",
"resetWarning": "Bu tüm yıldızlarını ve ilerlemenizi silecek. Emin misiniz?",
"resetConfirm": "Evet, Her Şeyi Sıfırla",
"resetComplete": "İlerleme sıfırlandı! Yeniden yükleniyor...",
"cancel": "İptal"
} }
} }
} }

View File

@@ -1399,7 +1399,14 @@
"stars": { "title": "赚取星星", "description": "收集星星,解锁新关卡" } "stars": { "title": "赚取星星", "description": "收集星星,解锁新关卡" }
}, },
"startButton": "开始游戏!", "startButton": "开始游戏!",
"ageNote": "适合8-14岁会读写的儿童" "ageNote": "适合8-14岁会读写的儿童",
"whatYouLearn": "你将学到什么",
"readyTitle": "准备好开始了吗?",
"readyMessage": "让我们踏上冒险学习如何与AI对话"
},
"navigation": {
"back": "返回",
"next": "下一步"
}, },
"map": { "title": "世界地图", "subtitle": "选择一个关卡,开始你的冒险!", "worldLevels": "{count}个关卡", "levelNumber": "关卡{number}", "locked": "完成上一关以解锁" }, "map": { "title": "世界地图", "subtitle": "选择一个关卡,开始你的冒险!", "worldLevels": "{count}个关卡", "levelNumber": "关卡{number}", "locked": "完成上一关以解锁" },
"worlds": { "1": { "title": "新手村" }, "2": { "title": "清晰城堡" }, "3": { "title": "上下文洞穴" }, "4": { "title": "创意峡谷" }, "5": { "title": "大师山" } }, "worlds": { "1": { "title": "新手村" }, "2": { "title": "清晰城堡" }, "3": { "title": "上下文洞穴" }, "4": { "title": "创意峡谷" }, "5": { "title": "大师山" } },

16
public/sounds/README.md Normal file
View File

@@ -0,0 +1,16 @@
# Kids Game Background Music
Add an 8-bit dubstep/chiptune music file here named `8bit-game-music.mp3`.
## Recommended Sources (Royalty-Free)
- [OpenGameArt.org](https://opengameart.org/) - Free game assets including music
- [FreeMusicArchive.org](https://freemusicarchive.org/) - CC-licensed music
- [Incompetech.com](https://incompetech.com/) - Royalty-free music by Kevin MacLeod
## File Requirements
- **Filename:** `8bit-game-music.mp3`
- **Format:** MP3
- **Style:** 8-bit / Chiptune / Retro game music
- **Loop-friendly:** Ideally seamless loop for background music

View File

@@ -452,3 +452,260 @@
margin: 1rem 0; margin: 1rem 0;
} }
/* Kids Map Animations */
@keyframes bounce-slow {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
}
@keyframes draw-path {
from {
stroke-dashoffset: 200;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes float {
0%, 100% {
transform: translateY(0) rotate(0deg);
}
25% {
transform: translateY(-5px) rotate(2deg);
}
75% {
transform: translateY(3px) rotate(-2deg);
}
}
.animate-bounce-slow {
animation: bounce-slow 3s ease-in-out infinite;
}
.animate-draw-path {
animation: draw-path 2s ease-out forwards;
}
.animate-float {
animation: float 4s ease-in-out infinite;
}
/* Cloud animations for kids background */
@keyframes cloud-drift {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100vw);
}
}
.animate-cloud-slow {
animation: cloud-drift 45s linear infinite;
}
.animate-cloud-medium {
animation: cloud-drift 30s linear infinite;
}
.animate-cloud-fast {
animation: cloud-drift 20s linear infinite;
}
.animation-delay-500 {
animation-delay: 500ms;
}
.animation-delay-1000 {
animation-delay: 1000ms;
}
.animation-delay-1500 {
animation-delay: 1500ms;
}
/* Pixel Art Styles for Kids Game */
.pixel-font {
font-family: 'Courier New', Courier, monospace;
font-weight: bold;
letter-spacing: 0.5px;
}
.pixel-border {
clip-path: polygon(
0 4px, 4px 4px, 4px 0,
calc(100% - 4px) 0, calc(100% - 4px) 4px, 100% 4px,
100% calc(100% - 4px), calc(100% - 4px) calc(100% - 4px), calc(100% - 4px) 100%,
4px 100%, 4px calc(100% - 4px), 0 calc(100% - 4px)
);
}
.pixel-border-sm {
clip-path: polygon(
0 2px, 2px 2px, 2px 0,
calc(100% - 2px) 0, calc(100% - 2px) 2px, 100% 2px,
100% calc(100% - 2px), calc(100% - 2px) calc(100% - 2px), calc(100% - 2px) 100%,
2px 100%, 2px calc(100% - 2px), 0 calc(100% - 2px)
);
}
.pixel-btn {
position: relative;
border: none;
background: linear-gradient(180deg, #4A90D9 0%, #357ABD 100%);
color: white !important;
text-decoration: none !important;
color: white;
font-weight: bold;
padding: 8px 16px;
clip-path: polygon(
0 4px, 4px 4px, 4px 0,
calc(100% - 4px) 0, calc(100% - 4px) 4px, 100% 4px,
100% calc(100% - 4px), calc(100% - 4px) calc(100% - 4px), calc(100% - 4px) 100%,
4px 100%, 4px calc(100% - 4px), 0 calc(100% - 4px)
);
box-shadow: 0 4px 0 #2563EB;
transition: all 0.1s;
}
.pixel-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 0 #2563EB;
}
.pixel-btn:active {
transform: translateY(2px);
box-shadow: 0 2px 0 #2563EB;
}
.pixel-btn-green {
background: linear-gradient(180deg, #22C55E 0%, #16A34A 100%);
box-shadow: 0 4px 0 #15803D;
}
.pixel-btn-green:hover {
box-shadow: 0 6px 0 #15803D;
}
.pixel-btn-green:active {
box-shadow: 0 2px 0 #15803D;
}
.pixel-btn-amber {
background: linear-gradient(180deg, #F59E0B 0%, #D97706 100%);
box-shadow: 0 4px 0 #B45309;
}
.pixel-btn-amber:hover {
box-shadow: 0 6px 0 #B45309;
}
.pixel-btn-amber:active {
box-shadow: 0 2px 0 #B45309;
}
.pixel-panel {
background: linear-gradient(180deg, #FEF3C7 0%, #FDE68A 100%);
border: 4px solid #D97706;
clip-path: polygon(
0 8px, 8px 8px, 8px 0,
calc(100% - 8px) 0, calc(100% - 8px) 8px, 100% 8px,
100% calc(100% - 8px), calc(100% - 8px) calc(100% - 8px), calc(100% - 8px) 100%,
8px 100%, 8px calc(100% - 8px), 0 calc(100% - 8px)
);
}
.pixel-panel-blue {
background: linear-gradient(180deg, #DBEAFE 0%, #BFDBFE 100%);
border-color: #2563EB;
}
.pixel-panel-green {
background: linear-gradient(180deg, #DCFCE7 0%, #BBF7D0 100%);
border-color: #16A34A;
}
.pixel-panel-red {
background: linear-gradient(180deg, #FEE2E2 0%, #FECACA 100%);
border-color: #DC2626;
}
.pixel-text-shadow {
text-shadow: 2px 2px 0 rgba(0,0,0,0.3);
}
/* Pixelated image rendering */
.pixel-render {
image-rendering: pixelated;
image-rendering: crisp-edges;
}
/* Pixel art prose styles for kids levels */
.kids-prose-pixel {
color: #2C1810;
font-size: 1.5rem;
}
.kids-prose-pixel h1,
.kids-prose-pixel h2,
.kids-prose-pixel h3 {
color: #2C1810;
text-shadow: 2px 2px 0 rgba(0,0,0,0.2);
margin-bottom: 1rem;
border-bottom: none;
padding-bottom: 0;
}
.kids-prose-pixel h1 {
font-size: 2.75rem;
}
.kids-prose-pixel h2 {
font-size: 2.25rem;
}
.kids-prose-pixel h3 {
font-size: 1.875rem;
}
.kids-prose-pixel p {
color: #5D4037;
margin-bottom: 1.25rem;
line-height: 1.8;
font-size: 1.5rem;
}
.kids-prose-pixel ul,
.kids-prose-pixel ol {
color: #5D4037;
margin-bottom: 1.25rem;
padding-left: 2rem;
font-size: 1.5rem;
}
.kids-prose-pixel li {
margin-bottom: 0.75rem;
}
.kids-prose-pixel strong {
color: #2C1810;
font-weight: bold;
}
.kids-prose-pixel em {
color: #8B4513;
}
/* Reset margins for p tags inside interactive kids components */
.kids-prose-pixel [class*="rounded-xl"] p,
.kids-prose-pixel [class*="rounded-lg"] p,
.kids-prose-pixel .pixel-panel p {
margin: 0;
padding: 0;
}

View File

@@ -1,4 +1,31 @@
import { Schoolbell } from "next/font/google";
import { KidsHeader } from "@/components/kids/layout/kids-header"; import { KidsHeader } from "@/components/kids/layout/kids-header";
import { BackgroundMusic } from "@/components/kids/layout/background-music";
import { LevelProvider } from "@/components/kids/providers/level-context";
const kidsFont = Schoolbell({
subsets: ["latin"],
weight: "400",
variable: "--font-kids",
});
// Pixel art cloud component for background
function PixelCloudBg({ className, style }: { className?: string; style?: React.CSSProperties }) {
return (
<svg
viewBox="0 0 32 16"
className={className}
style={{ imageRendering: "pixelated", ...style }}
>
<rect x="8" y="8" width="16" height="8" fill="white" />
<rect x="4" y="12" width="8" height="4" fill="white" />
<rect x="20" y="12" width="8" height="4" fill="white" />
<rect x="12" y="4" width="8" height="4" fill="white" />
<rect x="6" y="8" width="4" height="4" fill="white" />
<rect x="22" y="8" width="4" height="4" fill="white" />
</svg>
);
}
export default function KidsLayout({ export default function KidsLayout({
children, children,
@@ -6,11 +33,50 @@ export default function KidsLayout({
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<div className="min-h-screen bg-gradient-to-b from-sky-50 via-white to-emerald-50 dark:from-sky-950 dark:via-background dark:to-emerald-950"> <LevelProvider>
<div className={`fixed inset-0 flex flex-col text-xl light ${kidsFont.className}`} data-theme="light" style={{ colorScheme: "light" }}>
{/* Smooth gradient sky background */}
<div
className="absolute inset-0 -z-10"
style={{
background: "linear-gradient(180deg, #4A90D9 0%, #87CEEB 30%, #98D8F0 60%, #B8E8F8 100%)"
}}
/>
{/* Animated pixel clouds - drift from left to right */}
<div className="absolute inset-0 -z-5 overflow-hidden pointer-events-none">
<PixelCloudBg
className="absolute w-24 h-12 opacity-90 animate-cloud-slow"
style={{ top: "8%", left: 0, animationDelay: "0s" }}
/>
<PixelCloudBg
className="absolute w-32 h-16 opacity-80 animate-cloud-medium"
style={{ top: "15%", left: 0, animationDelay: "-10s" }}
/>
<PixelCloudBg
className="absolute w-20 h-10 opacity-85 animate-cloud-fast"
style={{ top: "5%", left: 0, animationDelay: "-5s" }}
/>
<PixelCloudBg
className="absolute w-28 h-14 opacity-75 animate-cloud-slow"
style={{ top: "22%", left: 0, animationDelay: "-20s" }}
/>
<PixelCloudBg
className="absolute w-16 h-8 opacity-70 animate-cloud-medium"
style={{ top: "12%", left: 0, animationDelay: "-15s" }}
/>
<PixelCloudBg
className="absolute w-36 h-18 opacity-60 animate-cloud-fast"
style={{ top: "28%", left: 0, animationDelay: "-8s" }}
/>
</div>
<KidsHeader /> <KidsHeader />
<main className="container py-6"> <main className="flex-1 min-h-0 overflow-hidden">
{children} {children}
</main> </main>
<BackgroundMusic />
</div> </div>
</LevelProvider>
); );
} }

View File

@@ -1,9 +1,7 @@
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import Link from "next/link"; import { getLocale } from "next-intl/server";
import { getTranslations, getLocale } from "next-intl/server"; import { getLevelBySlug, getAllLevels } from "@/lib/kids/levels";
import { getLevelBySlug, getAdjacentLevels, getAllLevels } from "@/lib/kids/levels"; import { LevelContentWrapper } from "@/components/kids/layout/level-content-wrapper";
import { ChevronLeft, ChevronRight, Map } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { Metadata } from "next"; import type { Metadata } from "next";
interface LevelPageProps { interface LevelPageProps {
@@ -33,15 +31,12 @@ export async function generateMetadata({ params }: LevelPageProps): Promise<Meta
export default async function LevelPage({ params }: LevelPageProps) { export default async function LevelPage({ params }: LevelPageProps) {
const { slug } = await params; const { slug } = await params;
const level = getLevelBySlug(slug); const level = getLevelBySlug(slug);
const t = await getTranslations("kids");
const locale = await getLocale(); const locale = await getLocale();
if (!level) { if (!level) {
notFound(); notFound();
} }
const { prev, next } = getAdjacentLevels(slug);
// Try to load locale-specific content, fall back to English // Try to load locale-specific content, fall back to English
let Content; let Content;
try { try {
@@ -50,80 +45,13 @@ export default async function LevelPage({ params }: LevelPageProps) {
try { try {
Content = (await import(`@/content/kids/en/${slug}.mdx`)).default; Content = (await import(`@/content/kids/en/${slug}.mdx`)).default;
} catch { } catch {
Content = () => ( Content = null;
<div className="text-center py-12">
<p className="text-muted-foreground">
{t("level.comingSoon")}
</p>
</div>
);
} }
} }
return ( return (
<div className="max-w-2xl mx-auto"> <LevelContentWrapper levelSlug={slug} levelNumber={`${level.world}-${level.levelNumber}`}>
{/* Level Header */} {Content ? <Content /> : null}
<header className="mb-8"> </LevelContentWrapper>
<Link
href="/kids/map"
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-primary mb-4"
>
<Map className="h-4 w-4" />
{t("level.backToMap")}
</Link>
<div className="flex items-center gap-3 mb-2">
<span className="px-3 py-1 bg-primary/10 text-primary rounded-full text-sm font-medium">
{t("level.levelLabel", { number: `${level.world}-${level.levelNumber}` })}
</span>
</div>
<h1 className="text-3xl font-bold tracking-tight mb-2">
{level.title}
</h1>
<p className="text-muted-foreground">
{level.description}
</p>
</header>
{/* Level Content */}
<div className="prose max-w-none kids-prose">
<Content />
</div>
{/* Navigation */}
<nav className="flex items-center justify-between mt-12 pt-6 border-t">
{prev ? (
<Button variant="outline" asChild className="gap-2 rounded-xl">
<Link href={`/kids/level/${prev.slug}`}>
<ChevronLeft className="h-4 w-4" />
<span className="hidden sm:inline">{prev.title}</span>
<span className="sm:hidden">{t("level.previous")}</span>
</Link>
</Button>
) : (
<div />
)}
<Button variant="ghost" asChild>
<Link href="/kids/map">
<Map className="h-4 w-4 mr-2" />
{t("level.map")}
</Link>
</Button>
{next ? (
<Button variant="outline" asChild className="gap-2 rounded-xl">
<Link href={`/kids/level/${next.slug}`}>
<span className="hidden sm:inline">{next.title}</span>
<span className="sm:hidden">{t("level.next")}</span>
<ChevronRight className="h-4 w-4" />
</Link>
</Button>
) : (
<div />
)}
</nav>
</div>
); );
} }

View File

@@ -11,12 +11,7 @@ export default async function KidsMapPage() {
const t = await getTranslations("kids"); const t = await getTranslations("kids");
return ( return (
<div className="max-w-4xl mx-auto"> <div className="h-full flex flex-col overflow-hidden">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold mb-2">{t("map.title")}</h1>
<p className="text-muted-foreground">{t("map.subtitle")}</p>
</div>
<ProgressMap /> <ProgressMap />
</div> </div>
); );

View File

@@ -1,84 +1,11 @@
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { Play, Sparkles, Star, Bot } from "lucide-react";
import { Button } from "@/components/ui/button";
import { PromiCharacter } from "@/components/kids/elements/character-guide";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { KidsHomeContent } from "@/components/kids/layout/kids-home-content";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Learn Prompting for Kids | prompts.chat", title: "Learn Prompting for Kids | prompts.chat",
description: "A fun, game-based way for kids to learn how to talk to AI. Join Promi the robot on an adventure through Prompt Land!", description: "A fun, game-based way for kids to learn how to talk to AI. Join Promi the robot on an adventure through Prompt Land!",
}; };
export default async function KidsHomePage() { export default function KidsHomePage() {
const t = await getTranslations("kids"); return <KidsHomeContent />;
return (
<div className="max-w-2xl mx-auto text-center">
{/* Hero */}
<div className="mb-8">
<div className="inline-flex items-center gap-2 px-4 py-2 bg-primary/10 rounded-full text-primary text-sm font-medium mb-6">
<Sparkles className="h-4 w-4" />
{t("home.badge")}
</div>
<h1 className="text-4xl md:text-5xl font-bold tracking-tight mb-4 bg-gradient-to-r from-primary via-purple-500 to-pink-500 bg-clip-text text-transparent">
{t("home.title")}
</h1>
<p className="text-xl text-muted-foreground mb-8">
{t("home.subtitle")}
</p>
</div>
{/* Promi Introduction */}
<div className="mb-10 p-6 bg-white dark:bg-card rounded-2xl shadow-lg border-2 border-primary/20">
<div className="flex flex-col sm:flex-row items-center gap-6">
<div className="shrink-0">
<PromiCharacter mood="happy" size="lg" />
</div>
<div className="text-left">
<p className="text-lg font-medium mb-2">{t("home.promiIntro.greeting")}</p>
<p className="text-muted-foreground">
{t("home.promiIntro.message")}
</p>
</div>
</div>
</div>
{/* Features */}
<div className="grid sm:grid-cols-3 gap-4 mb-10">
<div className="p-4 bg-emerald-50 dark:bg-emerald-950/30 rounded-xl border border-emerald-200 dark:border-emerald-800">
<div className="text-3xl mb-2">🎮</div>
<h3 className="font-semibold mb-1">{t("home.features.games.title")}</h3>
<p className="text-sm text-muted-foreground">{t("home.features.games.description")}</p>
</div>
<div className="p-4 bg-blue-50 dark:bg-blue-950/30 rounded-xl border border-blue-200 dark:border-blue-800">
<div className="text-3xl mb-2">📖</div>
<h3 className="font-semibold mb-1">{t("home.features.stories.title")}</h3>
<p className="text-sm text-muted-foreground">{t("home.features.stories.description")}</p>
</div>
<div className="p-4 bg-purple-50 dark:bg-purple-950/30 rounded-xl border border-purple-200 dark:border-purple-800">
<div className="text-3xl mb-2"></div>
<h3 className="font-semibold mb-1">{t("home.features.stars.title")}</h3>
<p className="text-sm text-muted-foreground">{t("home.features.stars.description")}</p>
</div>
</div>
{/* CTA */}
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button asChild size="lg" className="text-lg px-8 py-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow">
<Link href="/kids/map">
<Play className="h-5 w-5 mr-2" />
{t("home.startButton")}
</Link>
</Button>
</div>
{/* Age note */}
<p className="mt-8 text-sm text-muted-foreground">
{t("home.ageNote")}
</p>
</div>
);
} }

View File

@@ -150,6 +150,7 @@ export default async function RootLayout({
const headersList = await headers(); const headersList = await headers();
const pathname = headersList.get("x-pathname") || headersList.get("x-invoke-path") || ""; const pathname = headersList.get("x-pathname") || headersList.get("x-invoke-path") || "";
const isEmbedRoute = pathname.startsWith("/embed"); const isEmbedRoute = pathname.startsWith("/embed");
const isKidsRoute = pathname.startsWith("/kids");
const locale = await getLocale(); const locale = await getLocale();
const messages = await getMessages(); const messages = await getMessages();
@@ -198,7 +199,7 @@ export default async function RootLayout({
</> </>
)} )}
<Providers locale={locale} messages={messages} theme={config.theme} branding={{ ...config.branding, useCloneBranding: config.homepage?.useCloneBranding }}> <Providers locale={locale} messages={messages} theme={config.theme} branding={{ ...config.branding, useCloneBranding: config.homepage?.useCloneBranding }}>
{isEmbedRoute ? ( {isEmbedRoute || isKidsRoute ? (
children children
) : ( ) : (
<> <>

View File

@@ -1,189 +1,290 @@
"use client"; "use client";
import { useState, useCallback } from "react"; import { useState, useCallback, useEffect, useId } from "react";
import { Check, RefreshCw, GripVertical } from "lucide-react"; import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button"; import { ChevronLeft, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface DragDropPromptProps { interface DragDropPromptProps {
title?: string; title?: string;
instruction?: string; instruction?: string;
pieces: string[]; pieces: string[];
correctOrder: number[]; // Indices of pieces in correct order correctOrder: number[];
successMessage?: string; successMessage?: string;
} }
interface SavedState {
currentOrder: number[];
submitted: boolean;
shuffledPieces: number[];
}
export function DragDropPrompt({ export function DragDropPrompt({
title = "Build the prompt! 🧩", title,
instruction = "Drag the pieces into the right order to make a good prompt.", instruction,
pieces, pieces,
correctOrder, correctOrder,
successMessage = "Perfect! You built a great prompt!", successMessage,
}: DragDropPromptProps) { }: DragDropPromptProps) {
const [shuffledPieces] = useState(() => { const t = useTranslations("kids.dragDrop");
// Create array of indices and shuffle const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const displayInstruction = instruction || t("instruction");
const [shuffledPieces, setShuffledPieces] = useState<number[]>([]);
const [currentOrder, setCurrentOrder] = useState<number[]>([]);
const [submitted, setSubmitted] = useState(false);
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state on mount
useEffect(() => {
const shuffle = () => {
const indices = pieces.map((_, i) => i); const indices = pieces.map((_, i) => i);
for (let i = indices.length - 1; i > 0; i--) { for (let i = indices.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); const j = Math.floor(Math.random() * (i + 1));
[indices[i], indices[j]] = [indices[j], indices[i]]; [indices[i], indices[j]] = [indices[j], indices[i]];
} }
return indices; return indices;
};
if (!levelSlug) {
const shuffled = shuffle();
setShuffledPieces(shuffled);
setCurrentOrder(shuffled);
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && saved.shuffledPieces && saved.shuffledPieces.length > 0 && saved.currentOrder) {
setShuffledPieces(saved.shuffledPieces);
setCurrentOrder(saved.currentOrder);
setSubmitted(saved.submitted || false);
} else {
const shuffled = shuffle();
setShuffledPieces(shuffled);
setCurrentOrder(shuffled);
}
setIsLoaded(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [levelSlug, componentId]);
// Save state when it changes
useEffect(() => {
if (!levelSlug || !isLoaded || currentOrder.length === 0) return;
saveComponentState<SavedState>(levelSlug, componentId, {
currentOrder,
submitted,
shuffledPieces,
}); });
}, [levelSlug, componentId, currentOrder, submitted, shuffledPieces, isLoaded]);
const [currentOrder, setCurrentOrder] = useState<number[]>(shuffledPieces); // Don't render until loaded to prevent hydration mismatch
const [submitted, setSubmitted] = useState(false); if (!isLoaded) return null;
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
const isCorrect = useCallback(() => { const isCorrect = () => {
return currentOrder.every((pieceIndex, position) => pieceIndex === correctOrder[position]); return currentOrder.every((pieceIndex, position) => pieceIndex === correctOrder[position]);
}, [currentOrder, correctOrder]);
const handleDragStart = (index: number) => {
setDraggedIndex(index);
}; };
const handleDragOver = (e: React.DragEvent, index: number) => { // Move piece left (swap with previous)
e.preventDefault(); const moveLeft = (position: number) => {
if (draggedIndex === null || draggedIndex === index) return; if (submitted || position === 0) return;
const newOrder = [...currentOrder]; const newOrder = [...currentOrder];
const draggedItem = newOrder[draggedIndex]; [newOrder[position - 1], newOrder[position]] = [newOrder[position], newOrder[position - 1]];
newOrder.splice(draggedIndex, 1);
newOrder.splice(index, 0, draggedItem);
setCurrentOrder(newOrder); setCurrentOrder(newOrder);
setDraggedIndex(index);
}; };
const handleDragEnd = () => { // Move piece right (swap with next)
setDraggedIndex(null); const moveRight = (position: number) => {
}; if (submitted || position === currentOrder.length - 1) return;
const moveItem = (fromIndex: number, direction: "up" | "down") => {
const toIndex = direction === "up" ? fromIndex - 1 : fromIndex + 1;
if (toIndex < 0 || toIndex >= currentOrder.length) return;
const newOrder = [...currentOrder]; const newOrder = [...currentOrder];
[newOrder[fromIndex], newOrder[toIndex]] = [newOrder[toIndex], newOrder[fromIndex]]; [newOrder[position], newOrder[position + 1]] = [newOrder[position + 1], newOrder[position]];
setCurrentOrder(newOrder); setCurrentOrder(newOrder);
}; };
// Tap to select, tap another to swap
const handleTap = (position: number) => {
if (submitted) return;
if (selectedIndex === null) {
// Select this piece
setSelectedIndex(position);
} else if (selectedIndex === position) {
// Deselect
setSelectedIndex(null);
} else {
// Swap with selected piece
const newOrder = [...currentOrder];
[newOrder[selectedIndex], newOrder[position]] = [newOrder[position], newOrder[selectedIndex]];
setCurrentOrder(newOrder);
setSelectedIndex(null);
}
};
const handleSubmit = () => { const handleSubmit = () => {
setSubmitted(true); setSubmitted(true);
setSelectedIndex(null);
}; };
const handleReset = () => { const handleReset = () => {
setCurrentOrder(shuffledPieces); setCurrentOrder(shuffledPieces);
setSubmitted(false); setSubmitted(false);
setSelectedIndex(null);
}; };
const correct = isCorrect(); const correct = isCorrect();
return ( return (
<div className="my-6 rounded-2xl border-2 border-blue-200 dark:border-blue-800 overflow-hidden"> <div className="my-4 p-4 bg-white rounded-xl border-4 border-[#D97706]">
{/* Header */} {/* Header */}
<div className="px-4 py-3 bg-gradient-to-r from-blue-100 to-cyan-100 dark:from-blue-950/50 dark:to-cyan-950/50 border-b border-blue-200 dark:border-blue-800"> <div className="flex items-center gap-3 mb-3">
<p className="font-semibold m-0">{title}</p> <PixelPuzzleIcon />
<p className="text-sm text-muted-foreground m-0">{instruction}</p> <span className="font-bold text-2xl text-[#2C1810]">{displayTitle}</span>
</div> </div>
<p className="text-lg text-[#8B7355] mb-4 m-0">{displayInstruction}</p>
<div className="p-4 space-y-4"> {/* Pieces with arrow controls */}
{/* Draggable pieces */} <div className="space-y-2 mb-4">
<div className="space-y-2"> {currentOrder.map((pieceIndex, position) => {
{currentOrder.map((pieceIndex, position) => ( const isSelected = selectedIndex === position;
const isCorrectPiece = submitted && pieceIndex === correctOrder[position];
const isWrongPiece = submitted && pieceIndex !== correctOrder[position];
return (
<div <div
key={`${pieceIndex}-${position}`} key={`${pieceIndex}-${position}`}
draggable={!submitted}
onDragStart={() => handleDragStart(position)}
onDragOver={(e) => handleDragOver(e, position)}
onDragEnd={handleDragEnd}
className={cn( className={cn(
"flex items-center gap-3 p-3 rounded-xl border-2 transition-all", "flex items-center gap-2 p-2 rounded-lg border-2 transition-all",
!submitted && "cursor-grab active:cursor-grabbing hover:border-primary hover:shadow-md", !submitted && !isSelected && "bg-white border-[#D97706] hover:bg-[#FEF3C7]",
submitted && pieceIndex === correctOrder[position] && "border-green-500 bg-green-50 dark:bg-green-950/30", !submitted && isSelected && "bg-[#DBEAFE] border-[#3B82F6] ring-2 ring-[#3B82F6] scale-[1.02]",
submitted && pieceIndex !== correctOrder[position] && "border-red-400 bg-red-50 dark:bg-red-950/30", isCorrectPiece && "bg-[#DCFCE7] border-[#16A34A]",
!submitted && "border-muted-foreground/20 bg-white dark:bg-card", isWrongPiece && "bg-[#FEE2E2] border-[#DC2626]"
draggedIndex === position && "opacity-50 scale-95"
)} )}
> >
{!submitted && ( {/* Position number */}
<div className="flex flex-col gap-0.5"> <span className="w-8 h-8 flex items-center justify-center bg-[#D97706] text-white font-bold rounded-md text-lg">
<button
onClick={() => moveItem(position, "up")}
disabled={position === 0}
className="p-0.5 hover:text-primary disabled:opacity-30"
>
</button>
<button
onClick={() => moveItem(position, "down")}
disabled={position === currentOrder.length - 1}
className="p-0.5 hover:text-primary disabled:opacity-30"
>
</button>
</div>
)}
<GripVertical className={cn("h-5 w-5 text-muted-foreground shrink-0", submitted && "opacity-0")} />
<span className="flex-1 font-mono text-sm">{pieces[pieceIndex]}</span>
<span className="w-6 h-6 rounded-full bg-muted flex items-center justify-center text-xs font-bold">
{position + 1} {position + 1}
</span> </span>
</div>
))}
</div>
{/* Preview */} {/* Left arrow */}
<div className="p-3 bg-muted/30 rounded-xl"> <button
<p className="text-xs text-muted-foreground mb-2 m-0">Your prompt will look like:</p> onClick={() => moveLeft(position)}
<pre className="whitespace-pre-wrap text-sm font-mono m-0"> disabled={submitted || position === 0}
{currentOrder.map((i) => pieces[i]).join(" ")}
</pre>
</div>
{/* Result */}
{submitted && (
<div
className={cn( className={cn(
"p-4 rounded-xl text-center", "w-10 h-10 flex items-center justify-center rounded-lg border-2 transition-all",
correct position === 0 || submitted
? "bg-green-100 dark:bg-green-950/50 border border-green-300 dark:border-green-800" ? "bg-gray-100 border-gray-200 text-gray-300 cursor-not-allowed"
: "bg-amber-100 dark:bg-amber-950/50 border border-amber-300 dark:border-amber-800" : "bg-[#FEF3C7] border-[#D97706] text-[#D97706] hover:bg-[#D97706] hover:text-white active:scale-95"
)} )}
> >
{correct ? ( <ChevronLeft className="w-6 h-6" />
<> </button>
<p className="text-2xl mb-2">🎉</p>
<p className="font-semibold text-lg m-0">{successMessage}</p> {/* Piece content - tappable */}
</> <button
) : ( onClick={() => handleTap(position)}
<> disabled={submitted}
<p className="font-semibold m-0">Almost there!</p> className={cn(
<p className="text-sm text-muted-foreground m-0 mt-1"> "flex-1 px-4 py-3 text-xl font-medium text-left rounded-lg transition-all",
Try moving the pieces around to find the best order. !submitted && "hover:bg-[#FEF3C7] cursor-pointer",
submitted && "cursor-default"
)}
>
<span className="text-[#2C1810]">{pieces[pieceIndex]}</span>
</button>
{/* Right arrow */}
<button
onClick={() => moveRight(position)}
disabled={submitted || position === currentOrder.length - 1}
className={cn(
"w-10 h-10 flex items-center justify-center rounded-lg border-2 transition-all",
position === currentOrder.length - 1 || submitted
? "bg-gray-100 border-gray-200 text-gray-300 cursor-not-allowed"
: "bg-[#FEF3C7] border-[#D97706] text-[#D97706] hover:bg-[#D97706] hover:text-white active:scale-95"
)}
>
<ChevronRight className="w-6 h-6" />
</button>
{/* Status indicator */}
{submitted && (
<span className="w-8 h-8 flex items-center justify-center text-xl">
{isCorrectPiece ? "✓" : "✗"}
</span>
)}
</div>
);
})}
</div>
{/* Hint for tap-to-swap */}
{selectedIndex !== null && (
<div className="bg-[#DBEAFE] border-2 border-[#3B82F6] rounded-lg p-3 mb-4 text-center">
<p className="text-lg text-[#1E40AF] font-medium m-0">
👆 {t("tapToSwap")}
</p> </p>
</> </div>
)}
{/* Preview */}
<div className="bg-[#FEF3C7]/50 rounded-lg p-4 mb-4 border-2 border-[#D97706]/30">
<span className="text-lg text-[#8B7355]">{t("result")}: </span>
<span className="text-xl text-[#2C1810]">
{currentOrder.map((i) => pieces[i]).join(" ")}
</span>
</div>
{/* Result feedback */}
{submitted && (
<div className={cn(
"rounded-lg p-4 mt-4 mb-4 text-center",
correct ? "bg-[#DCFCE7] border-2 border-[#16A34A]" : "bg-[#FEF3C7] border-2 border-[#D97706]"
)}>
{correct ? (
<p className="font-bold text-xl m-0 text-[#16A34A]">🎉 {successMessage || t("success")}</p>
) : (
<p className="font-bold text-lg m-0 text-[#D97706]">{t("almost")}</p>
)} )}
</div> </div>
)} )}
{/* Actions */} {/* Actions */}
<div className="flex gap-2"> <div className="flex gap-3">
{!submitted ? ( {!submitted ? (
<Button onClick={handleSubmit} className="rounded-full"> <button
<Check className="h-4 w-4 mr-1" /> onClick={handleSubmit}
Check my prompt! className="px-6 py-3 bg-[#22C55E] hover:bg-[#16A34A] text-white font-bold rounded-lg text-xl transition-colors"
</Button> >
{t("check")}
</button>
) : ( ) : (
<Button onClick={handleReset} variant="outline" className="rounded-full"> <button
<RefreshCw className="h-4 w-4 mr-1" /> onClick={handleReset}
Try again className="px-6 py-3 bg-[#8B4513] hover:bg-[#A0522D] text-white font-bold rounded-lg text-xl transition-colors"
</Button> >
{t("retry")}
</button>
)} )}
</div> </div>
</div> </div>
</div> );
}
function PixelPuzzleIcon() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5 inline-block text-[#3B82F6]" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="2" width="5" height="5" fill="currentColor" />
<rect x="9" y="2" width="5" height="5" fill="currentColor" />
<rect x="2" y="9" width="5" height="5" fill="currentColor" />
<rect x="9" y="9" width="5" height="5" fill="currentColor" />
<rect x="7" y="4" width="2" height="2" fill="currentColor" />
<rect x="4" y="7" width="2" height="2" fill="currentColor" />
</svg>
); );
} }

View File

@@ -0,0 +1,196 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface Example {
input: string;
output: string;
}
interface ExampleMatcherProps {
title?: string;
instruction?: string;
examples: Example[];
question: string;
options: string[];
correctAnswer: string;
explanation?: string;
}
interface SavedState {
selectedAnswer: string | null;
submitted: boolean;
}
export function ExampleMatcher({
title,
instruction,
examples,
question,
options,
correctAnswer,
explanation,
}: ExampleMatcherProps) {
const t = useTranslations("kids.exampleMatcher");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const displayInstruction = instruction || t("instruction");
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null);
const [submitted, setSubmitted] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved) {
setSelectedAnswer(saved.selectedAnswer);
setSubmitted(saved.submitted);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
selectedAnswer,
submitted,
});
}, [levelSlug, componentId, selectedAnswer, submitted, isLoaded]);
if (!isLoaded) return null;
const isCorrect = selectedAnswer === correctAnswer;
const handleSelect = (option: string) => {
if (submitted) return;
setSelectedAnswer(option);
};
const handleSubmit = () => {
if (!selectedAnswer) return;
setSubmitted(true);
};
const handleReset = () => {
setSelectedAnswer(null);
setSubmitted(false);
};
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#E0E7FF] to-[#C7D2FE] border-4 border-[#6366F1] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#4338CA] mb-2 flex items-center gap-2">
🧩 {displayTitle}
</h3>
<p className="text-[#5D4037] mb-4 m-0">{displayInstruction}</p>
{/* Examples Pattern */}
<div className="bg-white/80 rounded-lg p-4 mb-4 border-2 border-[#6366F1]">
<div className="text-sm font-medium text-[#4338CA] mb-2">{t("pattern")}</div>
<div className="space-y-2">
{examples.map((example, index) => (
<div key={index} className="flex items-center gap-3 text-lg">
<span className="px-3 py-1 bg-[#E0E7FF] rounded-lg font-medium">{example.input}</span>
<span className="text-[#6366F1] font-bold"></span>
<span className="px-3 py-1 bg-[#C7D2FE] rounded-lg font-medium">{example.output}</span>
</div>
))}
{/* Question row */}
<div className="flex items-center gap-3 text-lg pt-2 border-t-2 border-dashed border-[#6366F1]">
<span className="px-3 py-1 bg-[#FEF3C7] border-2 border-[#F59E0B] rounded-lg font-medium">
{question}
</span>
<span className="text-[#6366F1] font-bold"></span>
<span className="px-3 py-1 bg-gray-100 rounded-lg font-medium text-gray-400">
{submitted ? (isCorrect ? selectedAnswer : `${selectedAnswer}`) : "???"}
</span>
</div>
</div>
</div>
{/* Options */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2 mb-4">
{options.map((option) => {
const isSelected = selectedAnswer === option;
const showCorrect = submitted && option === correctAnswer;
const showWrong = submitted && isSelected && !isCorrect;
return (
<button
key={option}
onClick={() => handleSelect(option)}
disabled={submitted}
className={cn(
"px-4 py-3 rounded-lg border-2 text-xl font-bold transition-all",
!submitted && !isSelected && "bg-white border-gray-300 hover:border-[#6366F1] hover:bg-[#E0E7FF]",
!submitted && isSelected && "bg-[#C7D2FE] border-[#6366F1] scale-105",
showCorrect && "bg-green-100 border-green-500 text-green-700",
showWrong && "bg-red-100 border-red-400 text-red-600",
submitted && !showCorrect && !showWrong && "opacity-50"
)}
>
{option}
</button>
);
})}
</div>
{/* Submit/Reset buttons */}
<div className="flex gap-2">
{!submitted ? (
<button
onClick={handleSubmit}
disabled={!selectedAnswer}
className={cn(
"px-6 py-2 rounded-lg font-bold text-white transition-all",
selectedAnswer
? "bg-[#6366F1] hover:bg-[#4F46E5]"
: "bg-gray-300 cursor-not-allowed"
)}
>
{t("check")}
</button>
) : (
<button
onClick={handleReset}
className="px-6 py-2 rounded-lg font-bold bg-[#6366F1] hover:bg-[#4F46E5] text-white"
>
{t("retry")}
</button>
)}
</div>
{/* Result feedback */}
{submitted && (
<div className={cn(
"mt-4 p-4 rounded-lg border-2 animate-in fade-in zoom-in-95 duration-300",
isCorrect
? "bg-green-100 border-green-500"
: "bg-amber-100 border-amber-500"
)}>
<p className={cn(
"font-bold text-lg m-0",
isCorrect ? "text-green-700" : "text-amber-700"
)}>
{isCorrect ? t("correct") : t("tryAgain")}
</p>
{explanation && (
<p className="text-[#5D4037] mt-2 m-0">{explanation}</p>
)}
</div>
)}
</div>
);
}

View File

@@ -1,7 +1,14 @@
export { PromiCharacter, SpeechBubble, PromiWithMessage } from "./character-guide"; export { PromiCharacter, PromiWithMessage } from './character-guide';
export { Section, LevelSlides } from './level-slides';
export { StoryScene, Panel } from "./story-scene"; export { StoryScene, Panel } from "./story-scene";
export { ProgressMap } from "./progress-map"; export { ProgressMap } from "./progress-map";
export { PromptVsMistake } from "./prompt-vs-mistake"; export { PromptVsMistake } from "./prompt-vs-mistake";
export { MagicWords } from "./magic-words"; export { MagicWords } from "./magic-words";
export { DragDropPrompt } from "./drag-drop-prompt"; export { DragDropPrompt } from "./drag-drop-prompt";
export { LevelComplete } from "./level-complete"; export { LevelComplete } from "./level-complete";
export { PromptParts } from "./prompt-parts";
export { ExampleMatcher } from "./example-matcher";
export { PromptDoctor } from "./prompt-doctor";
export { StepByStep } from "./step-by-step";
export { PromptLab } from "./prompt-lab";
export { WordPredictor } from "./word-predictor";

View File

@@ -3,16 +3,15 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { Star, ArrowRight, Map, RotateCcw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { completeLevel, getLevelProgress } from "@/lib/kids/progress"; import { completeLevel, getLevelProgress } from "@/lib/kids/progress";
import { getAdjacentLevels } from "@/lib/kids/levels"; import { getAdjacentLevels, getLevelBySlug } from "@/lib/kids/levels";
import { PromiCharacter } from "./character-guide"; import { analyticsKids } from "@/lib/analytics";
import { PixelRobot, PixelStar } from "./pixel-art";
interface LevelCompleteProps { interface LevelCompleteProps {
levelSlug: string; levelSlug: string;
stars?: number; // 1-3, calculated based on performance stars?: number;
message?: string; message?: string;
} }
@@ -27,58 +26,63 @@ export function LevelComplete({
const { next } = getAdjacentLevels(levelSlug); const { next } = getAdjacentLevels(levelSlug);
useEffect(() => { useEffect(() => {
// Check if already completed with higher stars
const existingProgress = getLevelProgress(levelSlug); const existingProgress = getLevelProgress(levelSlug);
const existingStars = existingProgress?.stars || 0; const existingStars = existingProgress?.stars || 0;
if (stars > existingStars) { if (stars > existingStars) {
// Save progress
completeLevel(levelSlug, stars); completeLevel(levelSlug, stars);
setShowConfetti(true); setShowConfetti(true);
// Track level completion
const level = getLevelBySlug(levelSlug);
if (level) {
analyticsKids.completeLevel(levelSlug, level.world, stars);
}
} }
setSavedStars(Math.max(stars, existingStars)); setSavedStars(Math.max(stars, existingStars));
// Hide confetti after animation
const timer = setTimeout(() => setShowConfetti(false), 3000); const timer = setTimeout(() => setShowConfetti(false), 3000);
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [levelSlug, stars]); }, [levelSlug, stars]);
return ( return (
<div className="my-8 relative"> <div className="my-8 relative">
{/* Confetti effect */} {/* Pixel confetti effect */}
{showConfetti && ( {showConfetti && (
<div className="absolute inset-0 pointer-events-none overflow-hidden"> <div className="absolute inset-0 pointer-events-none overflow-hidden">
{Array.from({ length: 20 }).map((_, i) => ( {Array.from({ length: 15 }).map((_, i) => (
<div <div
key={i} key={i}
className="absolute animate-bounce" className="absolute animate-bounce"
style={{ style={{
left: `${Math.random() * 100}%`, left: `${10 + (i * 6)}%`,
top: `${Math.random() * 50}%`, top: `${10 + (i % 4) * 15}%`,
animationDelay: `${Math.random() * 0.5}s`, animationDelay: `${i * 0.1}s`,
animationDuration: `${0.5 + Math.random() * 0.5}s`, animationDuration: `${0.5 + (i % 3) * 0.2}s`,
}} }}
> >
{["🎉", "⭐", "🌟", "✨", "🎊"][Math.floor(Math.random() * 5)]} <PixelStar filled className="w-6 h-6" />
</div> </div>
))} ))}
</div> </div>
)} )}
<div className="rounded-2xl border-4 border-green-400 dark:border-green-600 bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-950/50 dark:to-emerald-950/50 overflow-hidden"> <div className="pixel-panel pixel-panel-green overflow-hidden">
{/* Header */} {/* Header */}
<div className="p-6 text-center"> <div className="p-6 text-center">
<div className="flex justify-center mb-4"> <div className="flex justify-center mb-4">
<PromiCharacter mood="celebrating" size="lg" /> <PixelRobot className="w-16 h-20 animate-bounce-slow" />
</div> </div>
<h2 className="text-3xl font-bold mb-2">🎉 {t("levelComplete.title")}</h2> <h2 className="text-4xl font-bold mb-3 text-[#2C1810] pixel-text-shadow">
<p className="text-lg text-muted-foreground">{message}</p> {t("levelComplete.title")}
</h2>
<p className="text-xl text-[#5D4037] m-0">{message}</p>
</div> </div>
{/* Stars */} {/* Pixel Stars */}
<div className="flex justify-center gap-2 pb-6"> <div className="flex justify-center gap-3 pb-6">
{[1, 2, 3].map((star) => ( {[1, 2, 3].map((star) => (
<div <div
key={star} key={star}
@@ -86,48 +90,74 @@ export function LevelComplete({
"transition-all duration-500", "transition-all duration-500",
star <= savedStars ? "scale-100" : "scale-75 opacity-30" star <= savedStars ? "scale-100" : "scale-75 opacity-30"
)} )}
style={{ style={{ animationDelay: `${star * 0.2}s` }}
animationDelay: `${star * 0.2}s`,
}}
> >
<Star <PixelStar filled={star <= savedStars} className="w-10 h-10" />
className={cn(
"h-12 w-12",
star <= savedStars
? "fill-amber-400 text-amber-400 drop-shadow-lg"
: "text-muted-foreground/30"
)}
/>
</div> </div>
))} ))}
</div> </div>
{/* Actions */} {/* Actions - pixel style */}
<div className="flex flex-col sm:flex-row gap-3 justify-center p-6 bg-white/50 dark:bg-card/50 border-t"> <div className="flex flex-col sm:flex-row gap-3 justify-center p-4 bg-[#4A3728] border-t-4 border-[#8B4513]">
{next ? ( {next ? (
<Button asChild size="lg" className="rounded-full gap-2"> <Link
<Link href={`/kids/level/${next.slug}`}> href={`/kids/level/${next.slug}`}
className="pixel-btn pixel-btn-green px-8 py-3 text-xl text-center"
>
<span className="flex items-center justify-center gap-2">
{t("levelComplete.nextLevel")} {t("levelComplete.nextLevel")}
<ArrowRight className="h-5 w-5" /> <PixelArrowRight />
</span>
</Link> </Link>
</Button>
) : ( ) : (
<Button asChild size="lg" className="rounded-full gap-2"> <Link
<Link href="/kids/map"> href="/kids/map"
className="pixel-btn pixel-btn-green px-8 py-3 text-xl text-center"
>
{t("levelComplete.allDone")} {t("levelComplete.allDone")}
<Map className="h-5 w-5" />
</Link> </Link>
</Button>
)} )}
<Button variant="outline" asChild size="lg" className="rounded-full gap-2"> <Link
<Link href="/kids/map"> href="/kids/map"
<Map className="h-5 w-5" /> className="pixel-btn pixel-btn-amber px-8 py-3 text-xl text-center"
>
<span className="flex items-center justify-center gap-2">
<PixelMapIcon />
{t("levelComplete.backToMap")} {t("levelComplete.backToMap")}
</span>
</Link> </Link>
</Button>
</div> </div>
</div> </div>
</div> </div>
); );
} }
function PixelArrowRight() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="5" width="6" height="2" fill="currentColor" />
<rect x="8" y="5" width="2" height="2" fill="currentColor" />
<rect x="6" y="3" width="2" height="2" fill="currentColor" />
<rect x="6" y="7" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelMapIcon() {
return (
<svg viewBox="0 0 16 16" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
{/* Pin head - circle */}
<rect x="5" y="1" width="6" height="2" fill="currentColor" />
<rect x="4" y="2" width="8" height="2" fill="currentColor" />
<rect x="3" y="3" width="10" height="4" fill="currentColor" />
<rect x="4" y="7" width="8" height="2" fill="currentColor" />
<rect x="5" y="9" width="6" height="2" fill="currentColor" />
{/* Pin point */}
<rect x="6" y="11" width="4" height="2" fill="currentColor" />
<rect x="7" y="13" width="2" height="2" fill="currentColor" />
{/* Inner highlight */}
<rect x="5" y="4" width="2" height="2" fill="rgba(255,255,255,0.4)" />
</svg>
);
}

View File

@@ -0,0 +1,134 @@
"use client";
import { useState, Children, isValidElement, ReactNode, ReactElement } from "react";
import { ChevronLeft, ChevronRight, Map } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { useTranslations } from "next-intl";
interface SectionProps {
children: ReactNode;
}
export function Section({ children }: SectionProps) {
return <>{children}</>;
}
interface LevelSlidesProps {
children: ReactNode;
levelSlug: string;
}
export function LevelSlides({ children, levelSlug }: LevelSlidesProps) {
const t = useTranslations("kids");
const [currentSection, setCurrentSection] = useState(0);
// Extract Section components from children
const sections: ReactElement[] = [];
Children.forEach(children, (child) => {
if (isValidElement(child) && child.type === Section) {
sections.push(child);
}
});
// If no sections found, wrap all content in one section
if (sections.length === 0) {
sections.push(<Section key="default">{children}</Section>);
}
const totalSections = sections.length;
const isFirstSection = currentSection === 0;
const isLastSection = currentSection === totalSections - 1;
const goToNext = () => {
if (!isLastSection) {
setCurrentSection((prev) => prev + 1);
}
};
const goToPrev = () => {
if (!isFirstSection) {
setCurrentSection((prev) => prev - 1);
}
};
return (
<div className="h-full flex flex-col">
{/* Content area */}
<div className="flex-1 overflow-hidden flex items-center justify-center p-4">
<div className="w-full max-w-2xl h-full flex flex-col justify-center">
<div
key={currentSection}
className="animate-in fade-in slide-in-from-right-4 duration-300 prose max-w-none kids-prose"
>
{sections[currentSection]}
</div>
</div>
</div>
{/* Navigation footer */}
<div className="shrink-0 border-t bg-white/50 dark:bg-background/50 backdrop-blur">
<div className="container py-4 flex items-center justify-between">
{/* Back button */}
<Button
variant="ghost"
size="lg"
onClick={goToPrev}
disabled={isFirstSection}
className={cn(
"rounded-full px-6 transition-opacity",
isFirstSection && "opacity-0 pointer-events-none"
)}
>
<ChevronLeft className="h-5 w-5 mr-1" />
{t("navigation.back")}
</Button>
{/* Progress indicators */}
<div className="flex items-center gap-2">
{Array.from({ length: totalSections }).map((_, i) => (
<button
key={i}
onClick={() => setCurrentSection(i)}
className={cn(
"w-3 h-3 rounded-full transition-all",
i === currentSection
? "bg-primary w-8"
: i < currentSection
? "bg-primary/50"
: "bg-muted-foreground/30 hover:bg-muted-foreground/50"
)}
aria-label={`Go to section ${i + 1}`}
/>
))}
</div>
{/* Next button or Map link */}
{!isLastSection ? (
<Button
size="lg"
onClick={goToNext}
className="rounded-full px-6"
>
{t("navigation.next")}
<ChevronRight className="h-5 w-5 ml-1" />
</Button>
) : (
<Button
asChild
variant="outline"
size="lg"
className="rounded-full px-6"
>
<Link href="/kids/map">
<Map className="h-5 w-5 mr-1" />
{t("level.map")}
</Link>
</Button>
)}
</div>
</div>
</div>
);
}

View File

@@ -1,55 +1,111 @@
"use client"; "use client";
import { useState, useCallback } from "react"; import { useState, useCallback, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { Check, RefreshCw, Sparkles, GripVertical } from "lucide-react"; import { Check, RefreshCw, Sparkles, GripVertical } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface BlankConfig { interface BlankConfig {
id: string; id?: string;
hint: string; hint: string;
answers: string[]; // Words to choose from (first one is correct) answers: string[]; // Words to choose from (all are correct)
emoji?: string; emoji?: string;
} }
interface MagicWordsProps { interface MagicWordsProps {
title?: string; title?: string;
sentence: string; // Use {{id}} for blanks sentence: string; // Use _ for blanks
blanks: BlankConfig[]; blanks: BlankConfig[];
successMessage?: string; successMessage?: string;
} }
interface SavedState {
placements: Record<string, string>;
submitted: boolean;
availableWords: { word: string; blankId: string }[];
}
export function MagicWords({ export function MagicWords({
title = "Drag the magic words! ✨", title,
sentence, sentence,
blanks, blanks,
successMessage = "Amazing! You created a great prompt!", successMessage,
}: MagicWordsProps) { }: MagicWordsProps) {
const t = useTranslations("kids.magicWords");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const [placements, setPlacements] = useState<Record<string, string>>({}); const [placements, setPlacements] = useState<Record<string, string>>({});
const [submitted, setSubmitted] = useState(false); const [submitted, setSubmitted] = useState(false);
const [draggedWord, setDraggedWord] = useState<string | null>(null); const [draggedWord, setDraggedWord] = useState<string | null>(null);
const [availableWords, setAvailableWords] = useState<{ word: string; blankId: string }[]>([]);
const [isLoaded, setIsLoaded] = useState(false);
// Get all available words from blanks (shuffled) // Generate IDs for blanks if not provided
const [availableWords] = useState(() => { const blanksWithIds = blanks.map((blank, index) => ({
const words = blanks.flatMap((blank) => ...blank,
blank.answers.map((answer) => ({ word: answer, blankId: blank.id })) id: blank.id || `blank-${index}`,
}));
// Load saved state on mount
useEffect(() => {
const shuffleWords = () => {
const words = blanksWithIds.flatMap((blank) =>
blank.answers.map((answer) => ({ word: answer, blankId: blank.id! }))
); );
// Shuffle
for (let i = words.length - 1; i > 0; i--) { for (let i = words.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); const j = Math.floor(Math.random() * (i + 1));
[words[i], words[j]] = [words[j], words[i]]; [words[i], words[j]] = [words[j], words[i]];
} }
return words; return words;
};
if (!levelSlug) {
setPlacements({});
setAvailableWords(shuffleWords());
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && saved.placements && saved.availableWords && saved.availableWords.length > 0) {
setPlacements(saved.placements);
setSubmitted(saved.submitted || false);
setAvailableWords(saved.availableWords);
} else {
setPlacements({});
setAvailableWords(shuffleWords());
}
setIsLoaded(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [levelSlug, componentId]);
// Save state when it changes
useEffect(() => {
if (!levelSlug || !isLoaded || availableWords.length === 0) return;
saveComponentState<SavedState>(levelSlug, componentId, {
placements,
submitted,
availableWords,
}); });
}, [levelSlug, componentId, placements, submitted, availableWords, isLoaded]);
const checkAnswer = useCallback((blankId: string, value: string): boolean => { const checkAnswer = useCallback((blankId: string, value: string): boolean => {
const blank = blanks.find((b) => b.id === blankId); const blank = blanksWithIds.find((b) => b.id === blankId);
if (!blank) return false; if (!blank) return false;
return blank.answers.some((answer) => answer.toLowerCase() === value.toLowerCase()); return blank.answers.some((answer) => answer.toLowerCase() === value.toLowerCase());
}, [blanks]); }, [blanksWithIds]);
const allCorrect = submitted && blanks.every((blank) => checkAnswer(blank.id, placements[blank.id] || "")); // Don't render until loaded to prevent hydration mismatch
const score = blanks.filter((blank) => checkAnswer(blank.id, placements[blank.id] || "")).length; if (!isLoaded) return null;
const allCorrect = submitted && blanksWithIds.every((blank) => checkAnswer(blank.id, placements[blank.id] || ""));
const score = blanksWithIds.filter((blank) => checkAnswer(blank.id, placements[blank.id] || "")).length;
const usedWords = Object.values(placements); const usedWords = Object.values(placements);
@@ -80,7 +136,7 @@ export function MagicWords({
if (submitted) return; if (submitted) return;
// Find first empty blank // Find first empty blank
const emptyBlank = blanks.find((blank) => !placements[blank.id]); const emptyBlank = blanksWithIds.find((blank) => !placements[blank.id]);
if (emptyBlank) { if (emptyBlank) {
// Remove word from previous placement // Remove word from previous placement
const newPlacements = { ...placements }; const newPlacements = { ...placements };
@@ -113,36 +169,42 @@ export function MagicWords({
// Parse sentence and render with drop zones // Parse sentence and render with drop zones
const renderSentence = () => { const renderSentence = () => {
const parts = sentence.split(/(\{\{[^}]+\}\})/g); // Split by underscore placeholders
const parts = sentence.split(/(_+)/g);
let blankIndex = 0;
return parts.map((part, index) => { return parts.map((part, index) => {
const match = part.match(/\{\{([^}]+)\}\}/); // Check if this is a blank placeholder (one or more underscores)
if (match) { if (/^_+$/.test(part)) {
const blankId = match[1]; const blank = blanksWithIds[blankIndex];
const blank = blanks.find((b) => b.id === blankId); if (!blank) return <span key={index}>{part}</span>;
const blankId = blank.id;
const placedWord = placements[blankId]; const placedWord = placements[blankId];
const isCorrect = submitted && checkAnswer(blankId, placedWord || ""); const isCorrect = submitted && checkAnswer(blankId, placedWord || "");
const isWrong = submitted && !isCorrect; const isWrong = submitted && !isCorrect;
blankIndex++;
return ( return (
<span key={index} className="inline-flex items-center gap-1 mx-1 my-1"> <span key={index} className="inline-flex items-center gap-1 mx-1 my-1">
{blank?.emoji && <span className="text-lg">{blank.emoji}</span>}
<span <span
onClick={() => placedWord && handleClickBlank(blankId)} onClick={() => placedWord && handleClickBlank(blankId)}
onDragOver={(e) => e.preventDefault()} onDragOver={(e) => e.preventDefault()}
onDrop={() => handleDrop(blankId)} onDrop={() => handleDrop(blankId)}
className={cn( className={cn(
"px-3 py-2 border-2 border-dashed rounded-xl min-w-[100px] text-center font-medium transition-all cursor-pointer", "px-3 py-2 border-2 border-dashed rounded-lg min-w-[100px] text-xl text-center font-medium transition-all cursor-pointer text-[#2C1810]",
!placedWord && "bg-white dark:bg-card border-primary/50", !placedWord && "bg-white border-purple-400",
placedWord && !submitted && "bg-primary/10 border-primary border-solid", placedWord && !submitted && "bg-purple-100 border-purple-500 border-solid",
isCorrect && "border-green-500 border-solid bg-green-50 dark:bg-green-950/30", isCorrect && "border-green-500 border-solid bg-green-50",
isWrong && "border-red-400 border-solid bg-red-50 dark:bg-red-950/30", isWrong && "border-red-400 border-solid bg-red-50",
draggedWord && !placedWord && "border-primary bg-primary/5 scale-105" draggedWord && !placedWord && "border-purple-500 bg-purple-50 scale-105"
)} )}
title={blank.hint}
> >
{placedWord || "___"} {placedWord || blank.hint}
</span> </span>
{submitted && isCorrect && <Check className="h-5 w-5 text-green-500" />} {submitted && isCorrect && <Check className="h-6 w-6 text-green-500" />}
</span> </span>
); );
} }
@@ -151,25 +213,25 @@ export function MagicWords({
}; };
return ( return (
<div className="my-6 rounded-2xl border-2 border-purple-200 dark:border-purple-800 overflow-hidden"> <div className="my-4 rounded-xl border-4 border-purple-300 overflow-hidden bg-white">
{/* Header */} {/* Header */}
<div className="px-4 py-3 bg-gradient-to-r from-purple-100 to-pink-100 dark:from-purple-950/50 dark:to-pink-950/50 border-b border-purple-200 dark:border-purple-800"> <div className="px-4 py-3 bg-gradient-to-r from-purple-100 to-pink-100 border-b-2 border-purple-200">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Sparkles className="h-5 w-5 text-purple-500" /> <Sparkles className="h-6 w-6 text-purple-500" />
<span className="font-semibold">{title}</span> <span className="font-bold text-2xl text-[#2C1810]">{displayTitle}</span>
</div> </div>
</div> </div>
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Sentence with blanks */} {/* Sentence with blanks */}
<div className="text-lg leading-loose p-4 bg-muted/30 rounded-xl flex flex-wrap items-center"> <div className="text-xl leading-relaxed p-4 bg-purple-50 rounded-lg flex flex-wrap items-center text-[#2C1810]">
{renderSentence()} {renderSentence()}
</div> </div>
{/* Word bank */} {/* Word bank */}
<div className="p-4 bg-purple-50 dark:bg-purple-950/30 rounded-xl"> <div className="p-4 bg-purple-100 rounded-lg">
<p className="text-sm font-medium text-purple-700 dark:text-purple-300 mb-3"> <p className="text-lg font-medium text-purple-700 mb-3 m-0">
🎯 Drag or tap words to fill the blanks: {t("dragOrTap")}
</p> </p>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{availableWords.map(({ word }, index) => { {availableWords.map(({ word }, index) => {
@@ -180,16 +242,18 @@ export function MagicWords({
draggable={!submitted && !isUsed} draggable={!submitted && !isUsed}
onDragStart={() => handleDragStart(word)} onDragStart={() => handleDragStart(word)}
onDragEnd={handleDragEnd} onDragEnd={handleDragEnd}
onTouchStart={() => !isUsed && !submitted && handleDragStart(word)}
onTouchEnd={() => handleDragEnd()}
onClick={() => !isUsed && handleClickWord(word)} onClick={() => !isUsed && handleClickWord(word)}
disabled={submitted || isUsed} disabled={submitted || isUsed}
className={cn( className={cn(
"flex items-center gap-1 px-3 py-2 rounded-lg border-2 font-medium transition-all", "flex items-center gap-2 px-4 py-3 rounded-lg border-2 text-xl font-medium transition-all text-[#2C1810]",
!isUsed && !submitted && "bg-white dark:bg-card border-purple-300 hover:border-purple-500 hover:shadow-md cursor-grab active:cursor-grabbing", !isUsed && !submitted && "bg-white border-purple-300 hover:border-purple-500 hover:shadow-md cursor-grab active:cursor-grabbing",
isUsed && "bg-muted/50 border-muted text-muted-foreground opacity-50 cursor-not-allowed", isUsed && "bg-gray-100 border-gray-300 text-gray-400 opacity-50 cursor-not-allowed",
submitted && "cursor-default" submitted && "cursor-default"
)} )}
> >
{!submitted && !isUsed && <GripVertical className="h-4 w-4 text-muted-foreground" />} {!submitted && !isUsed && <GripVertical className="h-5 w-5 text-purple-400" />}
{word} {word}
</button> </button>
); );
@@ -201,45 +265,37 @@ export function MagicWords({
{submitted && ( {submitted && (
<div <div
className={cn( className={cn(
"p-4 rounded-xl text-center", "p-4 rounded-lg text-center",
allCorrect allCorrect
? "bg-green-100 dark:bg-green-950/50 border border-green-300 dark:border-green-800" ? "bg-green-100 border-2 border-green-300"
: "bg-amber-100 dark:bg-amber-950/50 border border-amber-300 dark:border-amber-800" : "bg-amber-100 border-2 border-amber-300"
)} )}
> >
{allCorrect ? ( {allCorrect ? (
<> <p className="font-bold text-xl m-0 text-green-800">🎉 {successMessage || "Amazing!"}</p>
<p className="text-2xl mb-2">🎉</p>
<p className="font-semibold text-lg m-0">{successMessage}</p>
</>
) : ( ) : (
<> <p className="font-bold text-lg m-0 text-amber-800">
<p className="font-semibold m-0"> {score} / {blanksWithIds.length} {t("correct")}! {t("tryAgain")}
{score} of {blanks.length} correct!
</p> </p>
<p className="text-sm text-muted-foreground m-0 mt-1">
Try different words!
</p>
</>
)} )}
</div> </div>
)} )}
{/* Actions */} {/* Actions */}
<div className="flex gap-2"> <div className="flex gap-3">
{!submitted ? ( {!submitted ? (
<Button <Button
onClick={handleSubmit} onClick={handleSubmit}
className="rounded-full" className="rounded-full h-12 text-xl px-6"
disabled={Object.keys(placements).length < blanks.length} disabled={Object.keys(placements).length < blanksWithIds.length}
> >
<Check className="h-4 w-4 mr-1" /> <Check className="h-5 w-5 mr-2" />
Check my words! {t("check")}
</Button> </Button>
) : ( ) : (
<Button onClick={handleReset} variant="outline" className="rounded-full"> <Button onClick={handleReset} variant="outline" className="rounded-full h-12 text-xl px-6">
<RefreshCw className="h-4 w-4 mr-1" /> <RefreshCw className="h-5 w-5 mr-2" />
Try again {t("retry")}
</Button> </Button>
)} )}
</div> </div>

View File

@@ -0,0 +1,287 @@
"use client";
import { cn } from "@/lib/utils";
// Pixel Art Tree (Pine)
export function PixelTree({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 16 24"
className={cn("w-8 h-12", className)}
style={{ imageRendering: "pixelated" }}
>
{/* Tree top */}
<rect x="6" y="0" width="4" height="2" fill="#228B22" />
<rect x="4" y="2" width="8" height="2" fill="#228B22" />
<rect x="2" y="4" width="12" height="2" fill="#2E8B2E" />
<rect x="4" y="6" width="8" height="2" fill="#228B22" />
<rect x="2" y="8" width="12" height="2" fill="#2E8B2E" />
<rect x="0" y="10" width="16" height="2" fill="#228B22" />
<rect x="2" y="12" width="12" height="2" fill="#2E8B2E" />
<rect x="0" y="14" width="16" height="2" fill="#1E6B1E" />
{/* Trunk */}
<rect x="6" y="16" width="4" height="8" fill="#8B4513" />
</svg>
);
}
// Pixel Art Bush
export function PixelBush({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 16 10"
className={cn("w-8 h-5", className)}
style={{ imageRendering: "pixelated" }}
>
<rect x="4" y="0" width="8" height="2" fill="#32CD32" />
<rect x="2" y="2" width="12" height="2" fill="#228B22" />
<rect x="0" y="4" width="16" height="4" fill="#2E8B2E" />
<rect x="2" y="8" width="12" height="2" fill="#1E6B1E" />
</svg>
);
}
// Pixel Art Cloud
export function PixelCloud({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 12"
className={cn("w-12 h-6", className)}
style={{ imageRendering: "pixelated" }}
>
<rect x="4" y="0" width="8" height="2" fill="white" />
<rect x="2" y="2" width="14" height="2" fill="white" />
<rect x="0" y="4" width="20" height="4" fill="white" />
<rect x="14" y="2" width="6" height="2" fill="white" />
<rect x="16" y="4" width="8" height="4" fill="white" />
<rect x="2" y="8" width="20" height="2" fill="#f0f0f0" />
<rect x="4" y="10" width="16" height="2" fill="#e8e8e8" />
</svg>
);
}
// Pixel Art Castle
export function PixelCastle({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 32 32"
className={cn("w-16 h-16", className)}
style={{ imageRendering: "pixelated" }}
>
{/* Towers */}
<rect x="0" y="4" width="6" height="4" fill="#808080" />
<rect x="0" y="0" width="2" height="4" fill="#696969" />
<rect x="4" y="0" width="2" height="4" fill="#696969" />
<rect x="26" y="4" width="6" height="4" fill="#808080" />
<rect x="26" y="0" width="2" height="4" fill="#696969" />
<rect x="30" y="0" width="2" height="4" fill="#696969" />
{/* Main body */}
<rect x="0" y="8" width="32" height="16" fill="#A0A0A0" />
<rect x="4" y="8" width="24" height="4" fill="#888888" />
{/* Windows */}
<rect x="6" y="14" width="4" height="4" fill="#4169E1" />
<rect x="22" y="14" width="4" height="4" fill="#4169E1" />
{/* Door */}
<rect x="12" y="16" width="8" height="8" fill="#8B4513" />
<rect x="14" y="18" width="4" height="6" fill="#654321" />
{/* Flag */}
<rect x="15" y="4" width="2" height="8" fill="#654321" />
<rect x="17" y="4" width="6" height="4" fill="#FF4444" />
{/* Base */}
<rect x="0" y="24" width="32" height="8" fill="#696969" />
</svg>
);
}
// Pixel Art Mountain
export function PixelMountain({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 16"
className={cn("w-12 h-8", className)}
style={{ imageRendering: "pixelated" }}
>
{/* Snow cap */}
<rect x="10" y="0" width="4" height="2" fill="white" />
<rect x="8" y="2" width="8" height="2" fill="white" />
{/* Mountain body */}
<rect x="6" y="4" width="12" height="2" fill="#808080" />
<rect x="4" y="6" width="16" height="2" fill="#696969" />
<rect x="2" y="8" width="20" height="2" fill="#606060" />
<rect x="0" y="10" width="24" height="6" fill="#505050" />
</svg>
);
}
// Pixel Art Flower
export function PixelFlower({ className, color = "#FF69B4" }: { className?: string; color?: string }) {
return (
<svg
viewBox="0 0 8 12"
className={cn("w-4 h-6", className)}
style={{ imageRendering: "pixelated" }}
>
{/* Petals */}
<rect x="2" y="0" width="4" height="2" fill={color} />
<rect x="0" y="2" width="2" height="4" fill={color} />
<rect x="6" y="2" width="2" height="4" fill={color} />
<rect x="2" y="6" width="4" height="2" fill={color} />
{/* Center */}
<rect x="2" y="2" width="4" height="4" fill="#FFD700" />
{/* Stem */}
<rect x="3" y="8" width="2" height="4" fill="#228B22" />
</svg>
);
}
// Pixel Art Star
export function PixelStar({ className, filled = false }: { className?: string; filled?: boolean }) {
const color = filled ? "#FFD700" : "#D3D3D3";
return (
<svg
viewBox="0 0 12 12"
className={cn("w-4 h-4", className)}
style={{ imageRendering: "pixelated" }}
>
<rect x="5" y="0" width="2" height="2" fill={color} />
<rect x="4" y="2" width="4" height="2" fill={color} />
<rect x="0" y="4" width="12" height="2" fill={color} />
<rect x="2" y="6" width="8" height="2" fill={color} />
<rect x="2" y="8" width="2" height="2" fill={color} />
<rect x="8" y="8" width="2" height="2" fill={color} />
<rect x="0" y="10" width="2" height="2" fill={color} />
<rect x="10" y="10" width="2" height="2" fill={color} />
</svg>
);
}
// Pixel Art Robot (Promi)
export function PixelRobot({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 16 20"
className={cn("w-8 h-10", className)}
style={{ imageRendering: "pixelated" }}
>
{/* Antenna */}
<rect x="7" y="0" width="2" height="2" fill="#FFD700" />
<rect x="6" y="2" width="4" height="2" fill="#C0C0C0" />
{/* Head */}
<rect x="2" y="4" width="12" height="8" fill="#4A90D9" />
<rect x="4" y="6" width="3" height="3" fill="white" />
<rect x="9" y="6" width="3" height="3" fill="white" />
<rect x="5" y="7" width="2" height="2" fill="#333" />
<rect x="10" y="7" width="2" height="2" fill="#333" />
<rect x="6" y="10" width="4" height="2" fill="#333" />
{/* Body */}
<rect x="4" y="12" width="8" height="6" fill="#4A90D9" />
<rect x="6" y="14" width="4" height="2" fill="#FFD700" />
{/* Arms */}
<rect x="0" y="12" width="4" height="2" fill="#4A90D9" />
<rect x="12" y="12" width="4" height="2" fill="#4A90D9" />
{/* Feet */}
<rect x="4" y="18" width="3" height="2" fill="#333" />
<rect x="9" y="18" width="3" height="2" fill="#333" />
</svg>
);
}
// Pixel Art Level Node
export function PixelLevelNode({
state,
levelNumber,
className
}: {
state: "locked" | "available" | "completed";
levelNumber: string;
className?: string;
}) {
const bgColor = state === "completed" ? "#22C55E" : state === "available" ? "#3B82F6" : "#6B7280";
const borderColor = state === "completed" ? "#16A34A" : state === "available" ? "#2563EB" : "#4B5563";
const glowColor = state === "available" ? "rgba(59, 130, 246, 0.4)" : state === "completed" ? "rgba(34, 197, 94, 0.3)" : "transparent";
return (
<div className={cn("relative", className)}>
{/* Glow effect */}
{state !== "locked" && (
<div
className="absolute inset-0 -m-2 rounded-lg animate-pulse"
style={{ backgroundColor: glowColor }}
/>
)}
<svg
viewBox="0 0 24 24"
className="w-16 h-16 md:w-20 md:h-20"
style={{ imageRendering: "pixelated" }}
>
{/* Outer border */}
<rect x="2" y="0" width="20" height="2" fill={borderColor} />
<rect x="0" y="2" width="2" height="20" fill={borderColor} />
<rect x="22" y="2" width="2" height="20" fill={borderColor} />
<rect x="2" y="22" width="20" height="2" fill={borderColor} />
{/* Inner fill */}
<rect x="2" y="2" width="20" height="20" fill={bgColor} />
{/* Icon based on state */}
{state === "locked" && (
<>
{/* Lock icon */}
<rect x="9" y="8" width="6" height="2" fill="#333" />
<rect x="8" y="10" width="8" height="8" fill="#333" />
<rect x="10" y="12" width="4" height="4" fill="#666" />
</>
)}
{state === "available" && (
<>
{/* Play icon */}
<rect x="9" y="7" width="2" height="10" fill="white" />
<rect x="11" y="9" width="2" height="6" fill="white" />
<rect x="13" y="11" width="2" height="2" fill="white" />
</>
)}
{state === "completed" && (
<>
{/* Checkmark */}
<rect x="6" y="12" width="2" height="4" fill="white" />
<rect x="8" y="14" width="2" height="2" fill="white" />
<rect x="10" y="12" width="2" height="4" fill="white" />
<rect x="12" y="10" width="2" height="4" fill="white" />
<rect x="14" y="8" width="2" height="4" fill="white" />
<rect x="16" y="6" width="2" height="4" fill="white" />
</>
)}
</svg>
{/* Level number badge */}
<div
className="absolute -top-2 -right-2 w-8 h-8 flex items-center justify-center text-sm font-bold bg-amber-400 text-amber-900 shadow-md"
style={{
clipPath: "polygon(10% 0%, 90% 0%, 100% 10%, 100% 90%, 90% 100%, 10% 100%, 0% 90%, 0% 10%)",
}}
>
{levelNumber}
</div>
</div>
);
}
// Pixel Art Path Segment
export function PixelPath({ width = 100, className }: { width?: number; className?: string }) {
const segments = Math.ceil(width / 8);
return (
<svg
viewBox={`0 0 ${width} 8`}
className={cn("h-2", className)}
style={{ width: `${width}px`, imageRendering: "pixelated" }}
>
{Array.from({ length: segments }).map((_, i) => (
<rect
key={i}
x={i * 8}
y="2"
width="6"
height="4"
fill={i % 2 === 0 ? "#D4A574" : "#C4956A"}
/>
))}
</svg>
);
}

View File

@@ -1,99 +1,266 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useState, useRef } from "react";
import Link from "next/link"; import Link from "next/link";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { Star, Lock, Check, Play } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { worlds, type Level } from "@/lib/kids/levels"; import { worlds, type Level, getAllLevels } from "@/lib/kids/levels";
import { getProgress, isLevelUnlocked, type KidsProgress } from "@/lib/kids/progress"; import { getProgress, isLevelUnlocked, type KidsProgress } from "@/lib/kids/progress";
import { analyticsKids } from "@/lib/analytics";
import { Button } from "@/components/ui/button";
import {
PixelTree,
PixelBush,
PixelCastle,
PixelMountain,
PixelFlower,
PixelStar,
PixelRobot,
PixelLevelNode
} from "./pixel-art";
export function ProgressMap() { export function ProgressMap() {
const t = useTranslations("kids"); const t = useTranslations("kids");
const [progress, setProgress] = useState<KidsProgress | null>(null); const [progress, setProgress] = useState<KidsProgress | null>(null);
const scrollRef = useRef<HTMLDivElement>(null);
const allLevels = getAllLevels();
useEffect(() => { useEffect(() => {
setProgress(getProgress()); setProgress(getProgress());
analyticsKids.viewMap();
}, []); }, []);
return ( // Calculate positions for all levels in a continuous horizontal path
<div className="space-y-8"> const levelPositions = allLevels.map((_, index) => {
{worlds.map((world) => ( const spacing = 200; // pixels between levels
<WorldSection key={world.number} world={world} progress={progress} t={t} /> const x = 120 + index * spacing;
))} // Create a gentle wave pattern - centered around 55%
</div> const y = 55 + Math.sin(index * 0.8) * 15;
); return { x, y };
} });
interface WorldSectionProps { // Calculate map width - ensure it fits content but also works on large screens
world: typeof worlds[0]; const calculatedWidth = (allLevels.length * 200) + 240;
progress: KidsProgress | null; const mapWidth = Math.max(calculatedWidth, 800);
t: ReturnType<typeof useTranslations>;
}
function WorldSection({ world, progress, t }: WorldSectionProps) { const scrollLeft = () => {
const colorClasses = { scrollRef.current?.scrollBy({ left: -300, behavior: "smooth" });
emerald: { };
bg: "bg-emerald-50 dark:bg-emerald-950/30",
border: "border-emerald-200 dark:border-emerald-800", const scrollRight = () => {
text: "text-emerald-700 dark:text-emerald-300", scrollRef.current?.scrollBy({ left: 300, behavior: "smooth" });
badge: "bg-emerald-100 dark:bg-emerald-900/50",
},
blue: {
bg: "bg-blue-50 dark:bg-blue-950/30",
border: "border-blue-200 dark:border-blue-800",
text: "text-blue-700 dark:text-blue-300",
badge: "bg-blue-100 dark:bg-blue-900/50",
},
}[world.color] || {
bg: "bg-gray-50 dark:bg-gray-950/30",
border: "border-gray-200 dark:border-gray-800",
text: "text-gray-700 dark:text-gray-300",
badge: "bg-gray-100 dark:bg-gray-900/50",
}; };
return ( return (
<div className={cn("rounded-2xl border-2 p-6", colorClasses.bg, colorClasses.border)}> <div className="relative h-full flex flex-col">
{/* World Header */} {/* Scroll controls for desktop */}
<div className="flex items-center gap-3 mb-6"> <div className="hidden md:flex absolute left-2 top-1/2 -translate-y-1/2 z-20">
<span className="text-4xl">{world.emoji}</span> <Button variant="secondary" size="icon" onClick={scrollLeft} className="rounded-full shadow-lg">
<div> <ChevronLeft className="h-5 w-5" />
<h2 className="text-xl font-bold">{t(`worlds.${world.number}.title`)}</h2> </Button>
<p className="text-sm text-muted-foreground">
{t("map.worldLevels", { count: world.levels.length })}
</p>
</div> </div>
<div className="hidden md:flex absolute right-2 top-1/2 -translate-y-1/2 z-20">
<Button variant="secondary" size="icon" onClick={scrollRight} className="rounded-full shadow-lg">
<ChevronRight className="h-5 w-5" />
</Button>
</div> </div>
{/* Levels */} {/* Horizontal scrolling map container */}
<div className="grid sm:grid-cols-3 gap-4"> <div
{world.levels.map((level) => ( ref={scrollRef}
<LevelCard className="flex-1 overflow-x-auto overflow-y-hidden scrollbar-hide flex justify-center"
style={{ scrollbarWidth: "none", msOverflowStyle: "none" }}
>
<div
className="relative h-full min-h-[400px] min-w-full"
style={{ width: `${mapWidth}px`, imageRendering: "pixelated" }}
>
{/* Sky is handled by kids layout - no additional background needed */}
{/* Pixel art ground layers - use full width (max of mapWidth or 100%) */}
<div className="absolute bottom-0 left-0 right-0 h-12 bg-[#8B5A2B]" style={{ minWidth: `${mapWidth}px` }} />
<div className="absolute bottom-12 left-0 right-0 h-4 bg-[#228B22]" style={{ minWidth: `${mapWidth}px` }} />
<div className="absolute bottom-16 left-0 right-0 h-2 bg-[#32CD32]" style={{ minWidth: `${mapWidth}px` }} />
{/* Pixel art path connecting all levels */}
<svg
className="absolute inset-0 w-full h-full pointer-events-none z-0"
style={{ width: `${mapWidth}px` }}
preserveAspectRatio="none"
>
{/* Draw dotted path between levels - pixel style */}
<path
d={generatePathD(levelPositions)}
fill="none"
stroke="#D4A574"
strokeWidth="12"
strokeLinecap="square"
strokeLinejoin="miter"
strokeDasharray="16 8"
/>
{/* Path border for depth */}
<path
d={generatePathD(levelPositions)}
fill="none"
stroke="#8B5A2B"
strokeWidth="16"
strokeLinecap="square"
strokeLinejoin="miter"
strokeDasharray="16 8"
className="opacity-30"
/>
</svg>
{/* Decorative elements - rendered after path so clouds appear on top */}
<MapDecorations mapWidth={mapWidth} />
{/* World labels - pixel art style */}
{worlds.map((world) => {
const firstLevelIndex = allLevels.findIndex(l => l.world === world.number);
if (firstLevelIndex === -1) return null;
const pos = levelPositions[firstLevelIndex];
return (
<div
key={world.number}
className="absolute z-10 pointer-events-none"
style={{ left: `${pos.x - 50}px`, top: "12px" }}
>
<div
className="px-4 py-2 bg-[#FFD700] border-3 border-[#DAA520] text-base font-bold text-[#8B4513] whitespace-nowrap"
style={{
clipPath: "polygon(4px 0%, calc(100% - 4px) 0%, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 0% calc(100% - 4px), 0% 4px)",
}}
>
{t(`worlds.${world.number}.title`)}
</div>
</div>
);
})}
{/* Level nodes */}
{allLevels.map((level, index) => (
<LevelNode
key={level.slug} key={level.slug}
level={level} level={level}
position={levelPositions[index]}
progress={progress} progress={progress}
colorClasses={colorClasses} index={index}
t={t} t={t}
/> />
))} ))}
</div> </div>
</div> </div>
{/* Progress bar at bottom - pixel art style */}
<div className="shrink-0 px-4 py-3 bg-[#2C1810] border-t-4 border-[#8B4513]">
<div className="max-w-md mx-auto">
<div className="flex items-center justify-between text-xl mb-2">
<span className="font-bold text-2xl text-[#FFD700]">{t("map.title")}</span>
<div className="flex items-center gap-2">
<PixelStar filled className="w-6 h-6" />
<span className="text-[#FFD700] font-bold text-xl">
{getCompletedCount(progress, allLevels)} / {allLevels.length}
</span>
</div>
</div>
{/* Pixel art progress bar */}
<div className="h-6 bg-[#4A3728] border-2 border-[#8B4513] relative overflow-hidden">
<div
className="h-full bg-[#22C55E] transition-all duration-500"
style={{
width: `${(getCompletedCount(progress, allLevels) / allLevels.length) * 100}%`,
}}
/>
{/* Pixel segments overlay */}
<div className="absolute inset-0 flex">
{Array.from({ length: allLevels.length }).map((_, i) => (
<div
key={i}
className="flex-1 border-r border-[#2C1810] last:border-r-0"
/>
))}
</div>
</div>
</div>
</div>
</div>
); );
} }
interface LevelCardProps { function generatePathD(positions: { x: number; y: number }[]): string {
if (positions.length === 0) return "";
let d = `M ${positions[0].x} ${positions[0].y}`;
for (let i = 1; i < positions.length; i++) {
const prev = positions[i - 1];
const curr = positions[i];
const midX = (prev.x + curr.x) / 2;
// Create smooth curves
d += ` Q ${midX} ${prev.y}, ${midX} ${(prev.y + curr.y) / 2}`;
d += ` Q ${midX} ${curr.y}, ${curr.x} ${curr.y}`;
}
return d;
}
function MapDecorations({ mapWidth }: { mapWidth: number }) {
// Generate decorations along the map - using seeded positions for consistency
const decorations = [];
const spacing = 100;
for (let i = 0; i < Math.floor(mapWidth / spacing); i++) {
const x = 50 + i * spacing;
const type = i % 5;
const yOffset = Math.sin(i * 0.8) * 10;
decorations.push(
<div
key={`deco-${i}`}
className="absolute pointer-events-none"
style={{
left: `${x + (i % 3) * 15}px`,
bottom: `${55 + yOffset + (i % 4) * 5}px`
}}
>
{type === 0 && <PixelTree />}
{type === 1 && <PixelBush />}
{type === 2 && <PixelFlower color={i % 2 === 0 ? "#FF69B4" : "#FF6347"} />}
{type === 3 && <PixelTree className="w-10 h-14" />}
{type === 4 && <PixelMountain />}
</div>
);
}
// Add castle at the end
decorations.push(
<div
key="castle"
className="absolute pointer-events-none"
style={{ left: `${mapWidth - 80}px`, bottom: "50px" }}
>
<PixelCastle />
</div>
);
return <>{decorations}</>;
}
function getCompletedCount(progress: KidsProgress | null, levels: Level[]): number {
if (!progress) return 0;
return levels.filter(l => progress.levels[l.slug]?.completed).length;
}
interface LevelNodeProps {
level: Level; level: Level;
position: { x: number; y: number };
progress: KidsProgress | null; progress: KidsProgress | null;
colorClasses: { index: number;
bg: string;
border: string;
text: string;
badge: string;
};
t: ReturnType<typeof useTranslations>; t: ReturnType<typeof useTranslations>;
} }
function LevelCard({ level, progress, colorClasses, t }: LevelCardProps) { function LevelNode({ level, position, progress, index, t }: LevelNodeProps) {
const [unlocked, setUnlocked] = useState(false); const [unlocked, setUnlocked] = useState(false);
const levelProgress = progress?.levels[level.slug]; const levelProgress = progress?.levels[level.slug];
const isCompleted = levelProgress?.completed; const isCompleted = levelProgress?.completed;
@@ -103,65 +270,56 @@ function LevelCard({ level, progress, colorClasses, t }: LevelCardProps) {
setUnlocked(isLevelUnlocked(level.slug)); setUnlocked(isLevelUnlocked(level.slug));
}, [level.slug, progress]); }, [level.slug, progress]);
if (!unlocked) { const state = !unlocked ? "locked" : isCompleted ? "completed" : "available";
return (
<div className="relative p-4 rounded-xl bg-muted/50 border-2 border-dashed border-muted-foreground/20 opacity-60"> const nodeContent = (
<div className="absolute top-2 right-2"> <div
<Lock className="h-5 w-5 text-muted-foreground" /> className={cn(
"absolute transform -translate-x-1/2 -translate-y-1/2 transition-all duration-300",
"animate-in fade-in zoom-in",
unlocked && !isCompleted && "hover:scale-110",
isCompleted && "hover:scale-110",
)}
style={{
left: `${position.x}px`,
top: `${position.y}%`,
animationDelay: `${index * 100}ms`,
}}
>
{/* Pixel art level node */}
<PixelLevelNode
state={state}
levelNumber={`${level.world}.${level.levelNumber}`}
/>
{/* Stars for completed levels */}
{isCompleted && (
<div className="absolute -bottom-1 left-1/2 -translate-x-1/2 flex gap-0">
{[1, 2, 3].map((star) => (
<PixelStar key={star} filled={star <= stars} />
))}
</div> </div>
<div className="text-center py-4"> )}
<p className="font-medium text-muted-foreground">{t(`levels.${level.slug.replace(/-/g, "_")}.title`)}</p>
<p className="text-xs text-muted-foreground mt-1">{t("map.locked")}</p> {/* Level title label - pixel style */}
<div
className="absolute top-full mt-6 left-1/2 -translate-x-1/2 whitespace-nowrap px-3 py-2 text-base font-bold bg-amber-100 dark:bg-amber-900 border-2 border-amber-400"
style={{
clipPath: "polygon(4px 0%, calc(100% - 4px) 0%, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 0% calc(100% - 4px), 0% 4px)",
}}
>
{t(`levels.${level.slug.replace(/-/g, "_")}.title`)}
</div> </div>
</div> </div>
); );
if (!unlocked) {
return <div className="group cursor-not-allowed">{nodeContent}</div>;
} }
return ( return (
<Link <Link href={`/kids/level/${level.slug}`} className="group cursor-pointer">
href={`/kids/level/${level.slug}`} {nodeContent}
className={cn(
"relative block p-4 rounded-xl bg-white dark:bg-card border-2 transition-all hover:scale-105 hover:shadow-lg",
isCompleted ? "border-green-400 dark:border-green-600" : "border-primary/30 hover:border-primary"
)}
>
{/* Status badge */}
<div className="absolute top-2 right-2">
{isCompleted ? (
<div className="flex items-center justify-center w-6 h-6 rounded-full bg-green-500 text-white">
<Check className="h-4 w-4" />
</div>
) : (
<div className="flex items-center justify-center w-6 h-6 rounded-full bg-primary text-primary-foreground">
<Play className="h-3 w-3" />
</div>
)}
</div>
{/* Level info */}
<div className="mb-3">
<span className={cn("text-xs font-medium px-2 py-0.5 rounded-full", colorClasses.badge, colorClasses.text)}>
{t("map.levelNumber", { number: `${level.world}-${level.levelNumber}` })}
</span>
</div>
<h3 className="font-semibold mb-1">{level.title}</h3>
<p className="text-xs text-muted-foreground line-clamp-2">{level.description}</p>
{/* Stars */}
<div className="flex items-center gap-1 mt-3">
{[1, 2, 3].map((star) => (
<Star
key={star}
className={cn(
"h-4 w-4",
star <= stars
? "fill-amber-400 text-amber-400"
: "text-muted-foreground/30"
)}
/>
))}
</div>
</Link> </Link>
); );
} }

View File

@@ -0,0 +1,208 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface Problem {
issue: string;
symptom: string;
fix: string;
}
interface PromptDoctorProps {
title?: string;
brokenPrompt: string;
problems: Problem[];
healedPrompt: string;
successMessage?: string;
}
interface SavedState {
fixedProblems: number[];
isHealed: boolean;
}
export function PromptDoctor({
title,
brokenPrompt,
problems,
healedPrompt,
successMessage,
}: PromptDoctorProps) {
const t = useTranslations("kids.promptDoctor");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const [fixedProblems, setFixedProblems] = useState<number[]>([]);
const [isHealed, setIsHealed] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && saved.fixedProblems) {
setFixedProblems(saved.fixedProblems);
setIsHealed(saved.isHealed || false);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
fixedProblems,
isHealed,
});
}, [levelSlug, componentId, fixedProblems, isHealed, isLoaded]);
if (!isLoaded) return null;
const handleFixProblem = (index: number) => {
if (fixedProblems.includes(index) || isHealed) return;
const newFixed = [...fixedProblems, index];
setFixedProblems(newFixed);
if (newFixed.length === problems.length) {
setIsHealed(true);
}
};
const handleReset = () => {
setFixedProblems([]);
setIsHealed(false);
};
// Calculate current prompt based on fixes applied
const getCurrentPrompt = () => {
if (isHealed) return healedPrompt;
let currentPrompt = brokenPrompt;
// Apply fixes in order
problems.forEach((problem, index) => {
if (fixedProblems.includes(index)) {
// This is simplified - in reality you'd need smarter text manipulation
currentPrompt = problem.fix;
}
});
// Return the last applied fix or broken prompt
if (fixedProblems.length > 0) {
return problems[fixedProblems[fixedProblems.length - 1]].fix;
}
return brokenPrompt;
};
const healthPercentage = (fixedProblems.length / problems.length) * 100;
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#FEE2E2] to-[#FECACA] border-4 border-[#EF4444] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#DC2626] mb-4 flex items-center gap-2">
🏥 {displayTitle}
</h3>
{/* Health bar */}
<div className="mb-4">
<div className="flex items-center justify-between mb-1">
<span className="text-sm font-medium text-[#DC2626]">{t("health")}</span>
<span className="text-sm font-medium text-[#DC2626]">{Math.round(healthPercentage)}%</span>
</div>
<div className="h-4 bg-red-200 rounded-full overflow-hidden border-2 border-[#EF4444]">
<div
className={cn(
"h-full transition-all duration-500",
healthPercentage < 50 ? "bg-red-500" : healthPercentage < 100 ? "bg-yellow-500" : "bg-green-500"
)}
style={{ width: `${healthPercentage}%` }}
/>
</div>
</div>
{/* Current prompt display */}
<div className={cn(
"p-4 rounded-lg border-4 mb-4 transition-all duration-300",
isHealed
? "bg-green-100 border-green-500"
: "bg-white border-red-300"
)}>
<div className="flex items-center gap-2 mb-2">
{isHealed ? (
<span className="text-2xl">💚</span>
) : (
<span className="text-2xl animate-pulse">🤒</span>
)}
<span className={cn(
"font-bold",
isHealed ? "text-green-700" : "text-red-600"
)}>
{isHealed ? t("healthy") : t("sick")}
</span>
</div>
<p className="text-lg font-medium text-[#2C1810] m-0">
"{getCurrentPrompt()}"
</p>
</div>
{/* Problems to fix */}
{!isHealed && (
<div className="space-y-2 mb-4">
<div className="text-sm font-medium text-[#DC2626] mb-2">{t("diagnose")}</div>
{problems.map((problem, index) => {
const isFixed = fixedProblems.includes(index);
return (
<button
key={index}
onClick={() => handleFixProblem(index)}
disabled={isFixed}
className={cn(
"w-full p-3 rounded-lg border-2 text-left transition-all",
isFixed
? "bg-green-100 border-green-400 opacity-60"
: "bg-white border-red-300 hover:border-red-500 hover:bg-red-50 cursor-pointer"
)}
>
<div className="flex items-center gap-2">
<span className="text-xl">{isFixed ? "✅" : "💊"}</span>
<div>
<div className="font-bold text-[#DC2626]">{problem.issue}</div>
<div className="text-sm text-[#5D4037]">{problem.symptom}</div>
</div>
</div>
</button>
);
})}
</div>
)}
{/* Success message */}
{isHealed && (
<div className="p-4 bg-green-100 border-2 border-green-500 rounded-lg mb-4 animate-in fade-in zoom-in-95 duration-300">
<p className="font-bold text-green-700 text-lg m-0">
{successMessage || t("success")}
</p>
</div>
)}
{/* Reset button */}
{(isHealed || fixedProblems.length > 0) && (
<button
onClick={handleReset}
className="px-6 py-2 rounded-lg font-bold bg-[#DC2626] hover:bg-[#B91C1C] text-white"
>
{t("retry")}
</button>
)}
</div>
);
}

View File

@@ -0,0 +1,203 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface Improvement {
label: string;
prompt: string;
response: string;
}
interface PromptLabProps {
title?: string;
scenario: string;
basePrompt: string;
baseResponse: string;
improvements: Improvement[];
successMessage?: string;
}
interface SavedState {
appliedImprovements: number[];
completed: boolean;
}
export function PromptLab({
title,
scenario,
basePrompt,
baseResponse,
improvements,
successMessage,
}: PromptLabProps) {
const t = useTranslations("kids.promptLab");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const [appliedImprovements, setAppliedImprovements] = useState<number[]>([]);
const [completed, setCompleted] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && saved.appliedImprovements && Array.isArray(saved.appliedImprovements)) {
setAppliedImprovements(saved.appliedImprovements);
setCompleted(saved.completed || false);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
appliedImprovements,
completed,
});
}, [levelSlug, componentId, appliedImprovements, completed, isLoaded]);
if (!isLoaded) return null;
const handleApplyImprovement = (index: number) => {
if (appliedImprovements.includes(index) || completed) return;
const newApplied = [...appliedImprovements, index];
setAppliedImprovements(newApplied);
if (newApplied.length === improvements.length) {
setCompleted(true);
}
};
const handleReset = () => {
setAppliedImprovements([]);
setCompleted(false);
};
// Get current prompt based on applied improvements
const getCurrentPrompt = () => {
if (appliedImprovements.length === 0) return basePrompt;
// Return the prompt from the highest applied improvement
const maxApplied = Math.max(...appliedImprovements);
return improvements[maxApplied].prompt;
};
// Get current response based on improvements
const getCurrentResponse = () => {
if (appliedImprovements.length === 0) return baseResponse;
// Return the response from the highest applied improvement
const maxApplied = Math.max(...appliedImprovements);
return improvements[maxApplied].response;
};
const progressPercentage = (appliedImprovements.length / improvements.length) * 100;
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#D1FAE5] to-[#A7F3D0] border-4 border-[#10B981] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#047857] mb-2 flex items-center gap-2">
🔬 {displayTitle}
</h3>
<p className="text-[#5D4037] mb-4 m-0">{scenario}</p>
{/* Progress bar */}
<div className="mb-4">
<div className="flex items-center justify-between mb-1">
<span className="text-sm font-medium text-[#047857]">{t("progress")}</span>
<span className="text-sm font-medium text-[#047857]">{appliedImprovements.length}/{improvements.length}</span>
</div>
<div className="h-3 bg-green-200 rounded-full overflow-hidden border-2 border-[#10B981]">
<div
className="h-full bg-[#10B981] transition-all duration-500"
style={{ width: `${progressPercentage}%` }}
/>
</div>
</div>
{/* Current prompt */}
<div className="bg-white/80 rounded-lg p-4 mb-4 border-2 border-[#10B981]">
<div className="text-sm font-medium text-[#047857] mb-2">{t("yourPrompt")}</div>
<p className="text-lg font-medium text-[#2C1810] m-0">
"{getCurrentPrompt()}"
</p>
</div>
{/* AI Response */}
<div className={cn(
"rounded-lg p-4 mb-4 border-2 transition-all duration-300",
completed
? "bg-green-100 border-green-500"
: "bg-gray-50 border-gray-300"
)}>
<div className="flex items-center gap-2 mb-2">
<span className="text-xl">🤖</span>
<span className={cn(
"font-medium text-sm",
completed ? "text-green-700" : "text-gray-600"
)}>
{t("aiSays")}
</span>
</div>
<p className="text-[#5D4037] m-0 italic">"{getCurrentResponse()}"</p>
</div>
{/* Improvement buttons */}
{!completed && (
<div className="space-y-2 mb-4">
<div className="text-sm font-medium text-[#047857]">{t("addDetails")}</div>
{improvements.map((improvement, index) => {
const isApplied = appliedImprovements.includes(index);
return (
<button
key={index}
onClick={() => handleApplyImprovement(index)}
disabled={isApplied}
className={cn(
"w-full p-3 rounded-lg border-2 text-left transition-all",
isApplied
? "bg-green-100 border-green-400 opacity-60"
: "bg-white border-[#10B981] hover:bg-green-50 cursor-pointer"
)}
>
<div className="flex items-center gap-2">
<span className="text-xl">{isApplied ? "✅" : ""}</span>
<div className="font-bold text-[#047857]">{improvement.label}</div>
</div>
</button>
);
})}
</div>
)}
{/* Success message */}
{completed && (
<div className="p-4 bg-green-100 border-2 border-green-500 rounded-lg mb-4 animate-in fade-in zoom-in-95 duration-300">
<p className="font-bold text-green-700 text-lg m-0">
🎉 {successMessage || t("success")}
</p>
</div>
)}
{/* Reset button */}
{(completed || appliedImprovements.length > 0) && (
<button
onClick={handleReset}
className="px-6 py-2 rounded-lg font-bold bg-[#047857] hover:bg-[#065F46] text-white"
>
{t("retry")}
</button>
)}
</div>
);
}

View File

@@ -0,0 +1,204 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
type PartType = "role" | "task" | "context" | "constraint";
interface PromptPart {
text: string;
type: PartType;
}
interface PromptPartsProps {
title?: string;
instruction?: string;
parts: PromptPart[];
successMessage?: string;
}
interface SavedState {
assignments: Record<number, PartType | null>;
completed: boolean;
}
const partColors: Record<PartType, { bg: string; border: string; text: string; emoji: string }> = {
role: { bg: "bg-purple-100", border: "border-purple-400", text: "text-purple-700", emoji: "🎭" },
task: { bg: "bg-blue-100", border: "border-blue-400", text: "text-blue-700", emoji: "✏️" },
context: { bg: "bg-green-100", border: "border-green-400", text: "text-green-700", emoji: "📖" },
constraint: { bg: "bg-orange-100", border: "border-orange-400", text: "text-orange-700", emoji: "📏" },
};
export function PromptParts({ title, instruction, parts, successMessage }: PromptPartsProps) {
const t = useTranslations("kids.promptParts");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const displayInstruction = instruction || t("instruction");
const [assignments, setAssignments] = useState<Record<number, PartType | null>>({});
const [selectedPart, setSelectedPart] = useState<number | null>(null);
const [completed, setCompleted] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved) {
setAssignments(saved.assignments || {});
setCompleted(saved.completed || false);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
assignments,
completed,
});
}, [levelSlug, componentId, assignments, completed, isLoaded]);
if (!isLoaded) return null;
// Check if all parts are correctly assigned
const checkCompletion = (newAssignments: Record<number, PartType | null>) => {
const allAssigned = parts.every((_, index) => newAssignments[index] !== undefined && newAssignments[index] !== null);
const allCorrect = parts.every((part, index) => newAssignments[index] === part.type);
if (allAssigned && allCorrect) {
setCompleted(true);
}
};
const handlePartClick = (index: number) => {
if (completed) return;
setSelectedPart(selectedPart === index ? null : index);
};
const handleCategoryClick = (category: PartType) => {
if (completed || selectedPart === null) return;
const newAssignments = { ...assignments, [selectedPart]: category };
setAssignments(newAssignments);
setSelectedPart(null);
checkCompletion(newAssignments);
};
const handleReset = () => {
setAssignments({});
setCompleted(false);
setSelectedPart(null);
};
const getAssignmentStatus = (index: number): "correct" | "wrong" | "pending" | null => {
const assigned = assignments[index];
if (assigned === undefined || assigned === null) return null;
return assigned === parts[index].type ? "correct" : "wrong";
};
const score = parts.filter((part, index) => assignments[index] === part.type).length;
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#FEF3C7] to-[#FDE68A] border-4 border-[#D97706] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#92400E] mb-2 flex items-center gap-2">
🧩 {displayTitle}
</h3>
<p className="text-[#92400E] mb-4 m-0">{displayInstruction}</p>
{/* Score */}
<div className="mb-4 text-sm font-medium text-[#92400E]">
{t("score")}: {score}/{parts.length}
</div>
{/* Prompt pieces to categorize */}
<div className="bg-white/80 rounded-lg p-4 mb-4 border-2 border-[#D97706]">
<div className="flex flex-wrap gap-2">
{parts.map((part, index) => {
const status = getAssignmentStatus(index);
const isSelected = selectedPart === index;
const assigned = assignments[index];
const colors = assigned ? partColors[assigned] : null;
return (
<button
key={index}
onClick={() => handlePartClick(index)}
disabled={completed}
className={cn(
"px-3 py-2 rounded-lg border-2 transition-all text-base font-medium",
!assigned && !isSelected && "bg-gray-100 border-gray-300 text-gray-700 hover:border-[#D97706]",
!assigned && isSelected && "bg-yellow-100 border-[#D97706] text-[#92400E] ring-2 ring-[#D97706] scale-105",
assigned && colors && `${colors.bg} ${colors.border} ${colors.text}`,
status === "correct" && "ring-2 ring-green-500",
status === "wrong" && "ring-2 ring-red-400",
!completed && "cursor-pointer"
)}
>
{status === "correct" && <span className="mr-1"></span>}
{status === "wrong" && <span className="mr-1"></span>}
{part.text}
</button>
);
})}
</div>
</div>
{/* Category buttons */}
{selectedPart !== null && !completed && (
<div className="mb-4 animate-in fade-in slide-in-from-top-2 duration-200">
<div className="text-sm font-medium text-[#92400E] mb-2">{t("pickCategory")}</div>
<div className="grid grid-cols-2 gap-2">
{(Object.keys(partColors) as PartType[]).map((type) => {
const colors = partColors[type];
return (
<button
key={type}
onClick={() => handleCategoryClick(type)}
className={cn(
"flex items-center justify-center gap-2 px-4 py-3 rounded-lg border-2 font-bold transition-all",
colors.bg,
colors.border,
colors.text,
"hover:scale-105 cursor-pointer"
)}
>
<span className="text-xl">{colors.emoji}</span>
<span>{t(`types.${type}`)}</span>
</button>
);
})}
</div>
</div>
)}
{/* Success message */}
{completed && (
<div className="p-4 bg-green-100 border-2 border-green-500 rounded-lg mb-4 animate-in fade-in zoom-in-95 duration-300">
<p className="font-bold text-green-700 text-lg m-0">
🎉 {successMessage || t("success")}
</p>
</div>
)}
{/* Reset button */}
{(Object.keys(assignments).length > 0 || completed) && (
<button
onClick={handleReset}
className="px-6 py-2 rounded-lg font-bold bg-[#D97706] hover:bg-[#B45309] text-white"
>
{t("retry")}
</button>
)}
</div>
);
}

View File

@@ -1,35 +1,73 @@
"use client"; "use client";
import { useState } from "react"; import { useState, useEffect, useId } from "react";
import { Check, X, RefreshCw } from "lucide-react"; import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { PromiWithMessage } from "./character-guide"; import { PixelRobot, PixelStar } from "./pixel-art";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface PromptVsMistakeProps { interface PromptVsMistakeProps {
question: string; question: string;
good: string; good: string;
bad: string; bad: string;
goodLabel?: string;
badLabel?: string;
explanation?: string; explanation?: string;
promiMessage?: string; promiMessage?: string;
} }
interface SavedState {
selected: "good" | "bad" | null;
showResult: boolean;
order: string[];
}
export function PromptVsMistake({ export function PromptVsMistake({
question, question,
good, good,
bad, bad,
goodLabel = "Good prompt ✓",
badLabel = "Not so good ✗",
explanation, explanation,
promiMessage, promiMessage,
}: PromptVsMistakeProps) { }: PromptVsMistakeProps) {
const t = useTranslations("kids.quiz");
const levelSlug = useLevelSlug();
const componentId = useId();
const [selected, setSelected] = useState<"good" | "bad" | null>(null); const [selected, setSelected] = useState<"good" | "bad" | null>(null);
const [showResult, setShowResult] = useState(false); const [showResult, setShowResult] = useState(false);
const [order, setOrder] = useState<string[]>([]);
const [isLoaded, setIsLoaded] = useState(false);
// Randomize order // Load saved state on mount
const [order] = useState(() => Math.random() > 0.5 ? ["good", "bad"] : ["bad", "good"]); useEffect(() => {
const randomOrder = Math.random() > 0.5 ? ["good", "bad"] : ["bad", "good"];
if (!levelSlug) {
setOrder(randomOrder);
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && saved.order && saved.order.length > 0) {
setSelected(saved.selected);
setShowResult(saved.showResult);
setOrder(saved.order);
} else {
setOrder(randomOrder);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state when it changes
useEffect(() => {
if (!levelSlug || !isLoaded || order.length === 0) return;
saveComponentState<SavedState>(levelSlug, componentId, {
selected,
showResult,
order,
});
}, [levelSlug, componentId, selected, showResult, order, isLoaded]);
const handleSelect = (choice: "good" | "bad") => { const handleSelect = (choice: "good" | "bad") => {
setSelected(choice); setSelected(choice);
@@ -41,6 +79,9 @@ export function PromptVsMistake({
setShowResult(false); setShowResult(false);
}; };
// Don't render until loaded to prevent hydration mismatch
if (!isLoaded) return null;
const isCorrect = selected === "good"; const isCorrect = selected === "good";
const options = order.map((type) => ({ const options = order.map((type) => ({
@@ -49,83 +90,193 @@ export function PromptVsMistake({
})); }));
return ( return (
<div className="my-6 rounded-2xl border-2 border-primary/20 overflow-hidden"> <div className="my-2">
{/* Question */} {/* Question card with Promi */}
<div className="px-4 py-3 bg-primary/10 border-b border-primary/20"> <div className="flex items-center gap-2 mb-2">
<p className="font-semibold text-lg m-0">🤔 {question}</p> <div className="shrink-0">
<PixelRobot className="w-8 h-10" />
</div>
<div className="flex-1 relative">
{/* Speech bubble */}
<div className="bg-white rounded-lg p-2 shadow-md border-2 border-[#8B4513] relative ml-2">
{/* Arrow pointing left */}
<div className="absolute -left-2 top-1/2 -translate-y-1/2 w-0 h-0 border-t-[6px] border-t-transparent border-r-[8px] border-r-[#8B4513] border-b-[6px] border-b-transparent" />
<div className="absolute -left-1 top-1/2 -translate-y-1/2 w-0 h-0 border-t-[5px] border-t-transparent border-r-[6px] border-r-white border-b-[5px] border-b-transparent" />
<p className="text-base font-bold text-[#2C1810] m-0">
{question}
</p>
</div>
</div>
</div> </div>
<div className="p-4 space-y-4"> {/* Choice cards - side by side for compact layout */}
{/* Options */} <div className="grid grid-cols-2 gap-2">
<div className="grid sm:grid-cols-2 gap-4"> {options.map(({ type, text }, index) => {
{options.map(({ type, text }) => ( const isGood = type === "good";
return (
<button <button
key={type} key={type}
onClick={() => handleSelect(type)} onClick={() => handleSelect(type)}
disabled={showResult} disabled={showResult}
className={cn( className={cn(
"p-4 rounded-xl border-2 text-left transition-all", "w-full h-full text-left transition-all duration-300 rounded-lg overflow-hidden",
!showResult && "hover:border-primary hover:shadow-md cursor-pointer", !showResult && "hover:scale-[1.01] hover:shadow-lg cursor-pointer",
showResult && type === "good" && "border-green-500 bg-green-50 dark:bg-green-950/30", showResult && "scale-100"
showResult && type === "bad" && "border-red-400 bg-red-50 dark:bg-red-950/30",
!showResult && "border-muted-foreground/20 bg-muted/30"
)} )}
> >
<pre className="whitespace-pre-wrap text-sm font-mono m-0">{text}</pre>
{showResult && (
<div className={cn( <div className={cn(
"flex items-center gap-2 mt-3 pt-3 border-t text-sm font-medium", "p-0.5 rounded-md transition-colors h-full",
type === "good" ? "text-green-600 border-green-200" : "text-red-500 border-red-200" !showResult && "bg-gradient-to-br from-[#FFB347] to-[#FF8C00]",
showResult && isGood && "bg-gradient-to-br from-[#4ADE80] to-[#16A34A]",
showResult && !isGood && "bg-gradient-to-br from-[#FB7185] to-[#E11D48]"
)}> )}>
{type === "good" ? ( <div className={cn(
<> "bg-white rounded-md p-2 transition-colors h-full flex flex-col",
<Check className="h-4 w-4" /> showResult && isGood && "bg-[#F0FDF4]",
{goodLabel} showResult && !isGood && "bg-[#FFF1F2]"
</> )}>
) : ( {/* Option label */}
<> <div className="flex items-center gap-1 mb-1">
<X className="h-4 w-4" /> <span className={cn(
{badLabel} "w-6 h-6 rounded-full flex items-center justify-center text-sm font-bold text-white",
</> !showResult && "bg-[#F59E0B]",
showResult && isGood && "bg-[#22C55E]",
showResult && !isGood && "bg-[#EF4444]"
)}>
{showResult ? (isGood ? <PixelCheckIcon /> : <PixelXIcon />) : (index === 0 ? "A" : "B")}
</span>
{showResult && (
<span className={cn(
"text-sm font-bold",
isGood ? "text-[#16A34A]" : "text-[#DC2626]"
)}>
{isGood ? t("goodLabel") : t("badLabel")}
</span>
)} )}
</div> </div>
)}
</button>
))}
</div>
{/* Result */} {/* Prompt text */}
{showResult && ( <div className="bg-[#FEF3C7] rounded p-1.5 border border-[#F59E0B]/30 flex-1 flex items-center">
<div className={cn( <p className="text-sm text-[#2C1810] m-0 whitespace-pre-wrap leading-tight">
"p-4 rounded-xl", "{text}"
isCorrect
? "bg-green-100 dark:bg-green-950/50 border border-green-300 dark:border-green-800"
: "bg-amber-100 dark:bg-amber-950/50 border border-amber-300 dark:border-amber-800"
)}>
<p className="font-semibold text-lg m-0 mb-2">
{isCorrect ? "🎉 Great job!" : "🤔 Not quite!"}
</p> </p>
{explanation && <p className="text-sm m-0">{explanation}</p>}
</div> </div>
)} </div>
</div>
</button>
);
})}
</div>
{/* Promi message */} {/* Result feedback */}
{showResult && promiMessage && (
<PromiWithMessage
message={promiMessage}
mood={isCorrect ? "celebrating" : "thinking"}
/>
)}
{/* Reset button */}
{showResult && ( {showResult && (
<Button onClick={handleReset} variant="outline" size="sm" className="rounded-full"> <div className={cn(
<RefreshCw className="h-4 w-4 mr-1" /> "mt-3 rounded-lg p-3 text-center animate-in fade-in zoom-in-95 duration-300",
Try again isCorrect
</Button> ? "bg-gradient-to-br from-[#BBF7D0] to-[#86EFAC] border-2 border-[#22C55E]"
: "bg-gradient-to-br from-[#FEF08A] to-[#FDE047] border-2 border-[#F59E0B]"
)}>
<p className="text-base font-bold text-[#2C1810] m-0">
{isCorrect ? (
<><PixelStar filled className="w-4 h-4 inline" /> {t("correct")} <PixelStar filled className="w-4 h-4 inline" /></>
) : t("incorrect")}
</p>
{explanation && (
<p className="text-sm text-[#5D4037] m-0 mt-2">{explanation}</p>
)} )}
{promiMessage && (
<div className="flex items-center justify-center gap-2 mt-3 bg-white/60 rounded-md p-2">
<PixelRobot className="w-6 h-7 shrink-0" />
<p className="text-sm text-[#5D4037] m-0">{promiMessage}</p>
</div> </div>
)}
<button
onClick={handleReset}
className="mt-3 inline-flex items-center gap-1 px-4 py-2 bg-[#8B4513] hover:bg-[#A0522D] text-white text-sm font-bold rounded-md transition-colors"
>
<PixelRefreshIcon />
{t("tryAgain")}
</button>
</div>
)}
</div> </div>
); );
} }
// Pixel art icons
function PixelCheckIcon() {
return (
<svg viewBox="0 0 12 12" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="6" width="2" height="2" fill="currentColor" />
<rect x="4" y="8" width="2" height="2" fill="currentColor" />
<rect x="6" y="6" width="2" height="2" fill="currentColor" />
<rect x="8" y="4" width="2" height="2" fill="currentColor" />
<rect x="10" y="2" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelXIcon() {
return (
<svg viewBox="0 0 12 12" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="2" width="2" height="2" fill="currentColor" />
<rect x="8" y="2" width="2" height="2" fill="currentColor" />
<rect x="4" y="4" width="2" height="2" fill="currentColor" />
<rect x="6" y="4" width="2" height="2" fill="currentColor" />
<rect x="4" y="6" width="2" height="2" fill="currentColor" />
<rect x="6" y="6" width="2" height="2" fill="currentColor" />
<rect x="2" y="8" width="2" height="2" fill="currentColor" />
<rect x="8" y="8" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelRefreshIcon() {
return (
<svg viewBox="0 0 16 16" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="6" y="1" width="4" height="2" fill="currentColor" />
<rect x="4" y="3" width="2" height="2" fill="currentColor" />
<rect x="10" y="3" width="2" height="2" fill="currentColor" />
<rect x="2" y="5" width="2" height="2" fill="currentColor" />
<rect x="12" y="5" width="2" height="4" fill="currentColor" />
<rect x="2" y="7" width="2" height="4" fill="currentColor" />
<rect x="12" y="9" width="2" height="2" fill="currentColor" />
<rect x="4" y="11" width="2" height="2" fill="currentColor" />
<rect x="10" y="11" width="2" height="2" fill="currentColor" />
<rect x="6" y="13" width="4" height="2" fill="currentColor" />
<rect x="12" y="3" width="3" height="2" fill="currentColor" />
<rect x="1" y="11" width="3" height="2" fill="currentColor" />
</svg>
);
}
function PixelThinkingIcon() {
return (
<svg viewBox="0 0 32 32" className="w-12 h-12" style={{ imageRendering: "pixelated" }}>
{/* Face circle */}
<rect x="10" y="4" width="12" height="2" fill="#F59E0B" />
<rect x="8" y="6" width="2" height="2" fill="#F59E0B" />
<rect x="22" y="6" width="2" height="2" fill="#F59E0B" />
<rect x="6" y="8" width="2" height="4" fill="#F59E0B" />
<rect x="24" y="8" width="2" height="4" fill="#F59E0B" />
<rect x="6" y="12" width="2" height="4" fill="#F59E0B" />
<rect x="24" y="12" width="2" height="4" fill="#F59E0B" />
<rect x="8" y="16" width="2" height="2" fill="#F59E0B" />
<rect x="22" y="16" width="2" height="2" fill="#F59E0B" />
<rect x="10" y="18" width="12" height="2" fill="#F59E0B" />
{/* Fill */}
<rect x="8" y="8" width="16" height="8" fill="#FEF3C7" />
<rect x="10" y="6" width="12" height="2" fill="#FEF3C7" />
<rect x="10" y="16" width="12" height="2" fill="#FEF3C7" />
{/* Eyes */}
<rect x="10" y="10" width="2" height="2" fill="#2C1810" />
<rect x="20" y="10" width="2" height="2" fill="#2C1810" />
{/* Thinking mouth */}
<rect x="14" y="14" width="4" height="2" fill="#2C1810" />
{/* Thought bubbles */}
<rect x="26" y="4" width="2" height="2" fill="#8B7355" />
<rect x="28" y="2" width="3" height="3" fill="#8B7355" />
</svg>
);
}

View File

@@ -0,0 +1,212 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface StepByStepProps {
title?: string;
problem: string;
wrongAnswer: string;
steps: string[];
rightAnswer: string;
magicWords?: string;
successMessage?: string;
}
interface SavedState {
magicWordsAdded: boolean;
revealedSteps: number;
completed: boolean;
}
export function StepByStep({
title,
problem,
wrongAnswer,
steps,
rightAnswer,
magicWords = "Let's think step by step",
successMessage,
}: StepByStepProps) {
const t = useTranslations("kids.stepByStep");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const [magicWordsAdded, setMagicWordsAdded] = useState(false);
const [revealedSteps, setRevealedSteps] = useState(0);
const [completed, setCompleted] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && typeof saved.magicWordsAdded === 'boolean') {
setMagicWordsAdded(saved.magicWordsAdded);
setRevealedSteps(saved.revealedSteps || 0);
setCompleted(saved.completed || false);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
magicWordsAdded,
revealedSteps,
completed,
});
}, [levelSlug, componentId, magicWordsAdded, revealedSteps, completed, isLoaded]);
if (!isLoaded) return null;
const handleAddMagicWords = () => {
setMagicWordsAdded(true);
};
const handleRevealNextStep = () => {
if (revealedSteps < steps.length) {
const newRevealed = revealedSteps + 1;
setRevealedSteps(newRevealed);
if (newRevealed === steps.length) {
setCompleted(true);
}
}
};
const handleReset = () => {
setMagicWordsAdded(false);
setRevealedSteps(0);
setCompleted(false);
};
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#DBEAFE] to-[#BFDBFE] border-4 border-[#3B82F6] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#1D4ED8] mb-4 flex items-center gap-2">
🧠 {displayTitle}
</h3>
{/* Problem */}
<div className="bg-white/80 rounded-lg p-4 mb-4 border-2 border-[#3B82F6]">
<div className="text-sm font-medium text-[#3B82F6] mb-2">{t("problem")}</div>
<p className="text-lg font-medium text-[#2C1810] m-0">{problem}</p>
</div>
{/* Wrong answer (before magic words) */}
{!magicWordsAdded && (
<div className="bg-red-50 rounded-lg p-4 mb-4 border-2 border-red-300">
<div className="flex items-center gap-2 mb-2">
<span className="text-xl">😕</span>
<span className="font-bold text-red-600">{t("withoutMagic")}</span>
</div>
<p className="text-[#5D4037] m-0">{wrongAnswer}</p>
</div>
)}
{/* Magic words button */}
{!magicWordsAdded && (
<button
onClick={handleAddMagicWords}
className="w-full p-4 mb-4 rounded-lg border-4 border-dashed border-[#8B5CF6] bg-purple-50 hover:bg-purple-100 transition-all cursor-pointer group"
>
<div className="flex items-center justify-center gap-2">
<span className="text-2xl group-hover:animate-bounce"></span>
<span className="text-lg font-bold text-[#7C3AED]">{t("addMagicWords")}</span>
<span className="text-2xl group-hover:animate-bounce"></span>
</div>
<div className="text-[#8B5CF6] font-medium mt-1">"{magicWords}"</div>
</button>
)}
{/* Steps revealed after magic words */}
{magicWordsAdded && (
<>
<div className="bg-purple-50 rounded-lg p-3 mb-4 border-2 border-[#8B5CF6]">
<div className="flex items-center gap-2">
<span className="text-xl"></span>
<span className="font-bold text-[#7C3AED]">{t("magicWordsActive")}</span>
</div>
<p className="text-[#8B5CF6] m-0">"{magicWords}"</p>
</div>
{/* Steps */}
<div className="space-y-2 mb-4">
{steps.map((step, index) => {
const isRevealed = index < revealedSteps;
return (
<div
key={index}
className={cn(
"p-3 rounded-lg border-2 transition-all duration-300",
isRevealed
? "bg-green-50 border-green-400 animate-in fade-in slide-in-from-left-4"
: "bg-gray-100 border-gray-300"
)}
>
<div className="flex items-center gap-2">
<span className={cn(
"w-6 h-6 rounded-full flex items-center justify-center text-sm font-bold",
isRevealed ? "bg-green-500 text-white" : "bg-gray-300 text-gray-500"
)}>
{isRevealed ? "✓" : index + 1}
</span>
<span className={cn(
"font-medium",
isRevealed ? "text-green-700" : "text-gray-400"
)}>
{isRevealed ? step : "???"}
</span>
</div>
</div>
);
})}
</div>
{/* Reveal next step button */}
{!completed && (
<button
onClick={handleRevealNextStep}
className="w-full p-3 rounded-lg font-bold bg-[#3B82F6] hover:bg-[#2563EB] text-white transition-all"
>
{t("nextStep")} ({revealedSteps + 1}/{steps.length})
</button>
)}
{/* Correct answer revealed */}
{completed && (
<div className="bg-green-100 rounded-lg p-4 border-2 border-green-500 animate-in fade-in zoom-in-95 duration-300">
<div className="flex items-center gap-2 mb-2">
<span className="text-2xl">🎉</span>
<span className="font-bold text-green-700">{t("withMagic")}</span>
</div>
<p className="text-green-700 font-medium m-0">{rightAnswer}</p>
{successMessage && (
<p className="text-[#5D4037] mt-2 m-0">{successMessage}</p>
)}
</div>
)}
</>
)}
{/* Reset button */}
{(magicWordsAdded || completed) && (
<button
onClick={handleReset}
className="mt-4 px-6 py-2 rounded-lg font-bold bg-gray-500 hover:bg-gray-600 text-white"
>
{t("retry")}
</button>
)}
</div>
);
}

View File

@@ -1,10 +1,8 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { PromiCharacter } from "./character-guide"; import { PixelRobot } from "./pixel-art";
type PromiMood = "happy" | "thinking" | "excited" | "confused" | "celebrating"; type PromiMood = "happy" | "thinking" | "excited" | "confused" | "celebrating";
@@ -27,66 +25,62 @@ export function StoryScene({ panels, className }: StorySceneProps) {
const isLast = currentPanel === panels.length - 1; const isLast = currentPanel === panels.length - 1;
return ( return (
<div className={cn("my-6 rounded-2xl border-2 border-primary/20 overflow-hidden", className)}> <div className={cn("my-6 pixel-panel overflow-hidden", className)}>
{/* Story panel */} {/* Story panel */}
<div className="p-6 bg-gradient-to-br from-primary/5 to-purple-500/5 min-h-[200px] flex items-center"> <div className="p-4 min-h-[180px] flex items-center">
<div className="flex items-start gap-4 w-full"> <div className="flex items-start gap-4 w-full">
{panel.character === "promi" && ( {panel.character === "promi" && (
<div className="shrink-0"> <div className="shrink-0">
<PromiCharacter mood={panel.mood || "happy"} size="md" /> <PixelRobot className="w-12 h-16" />
</div> </div>
)} )}
<div <div
className={cn( className={cn(
"flex-1 p-4 bg-white dark:bg-card rounded-xl shadow-md", "flex-1 p-4 bg-white/80 border-2 border-[#D97706]",
panel.highlight && "ring-2 ring-primary ring-offset-2" panel.highlight && "bg-[#FEF3C7]"
)} )}
style={{ clipPath: "polygon(4px 0, calc(100% - 4px) 0, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 0 calc(100% - 4px), 0 4px)" }}
> >
<p className="text-lg leading-relaxed m-0">{panel.text}</p> <p className="text-xl leading-relaxed m-0 text-[#2C1810]">{panel.text}</p>
</div> </div>
</div> </div>
</div> </div>
{/* Navigation */} {/* Navigation - pixel style */}
{panels.length > 1 && ( {panels.length > 1 && (
<div className="flex items-center justify-between px-4 py-3 bg-muted/30 border-t"> <div className="flex items-center justify-between px-4 py-2 bg-[#4A3728] border-t-2 border-[#8B4513]">
<Button <button
variant="ghost"
size="sm"
onClick={() => setCurrentPanel((p) => p - 1)} onClick={() => setCurrentPanel((p) => p - 1)}
disabled={isFirst} disabled={isFirst}
className="gap-1" className={cn("pixel-btn px-3 py-1 text-xs", isFirst && "opacity-40")}
> >
<ChevronLeft className="h-4 w-4" />
Back Back
</Button> </button>
{/* Progress dots */} {/* Progress dots - pixel style */}
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
{panels.map((_, i) => ( {panels.map((_, i) => (
<button <button
key={i} key={i}
onClick={() => setCurrentPanel(i)} onClick={() => setCurrentPanel(i)}
className={cn( className={cn(
"w-2 h-2 rounded-full transition-colors", "w-3 h-3 border-2",
i === currentPanel i === currentPanel
? "bg-primary" ? "bg-[#22C55E] border-[#16A34A]"
: "bg-muted-foreground/30 hover:bg-muted-foreground/50" : "bg-[#4A3728] border-[#8B4513] hover:bg-[#5D4037]"
)} )}
style={{ clipPath: "polygon(2px 0, calc(100% - 2px) 0, 100% 2px, 100% calc(100% - 2px), calc(100% - 2px) 100%, 2px 100%, 0 calc(100% - 2px), 0 2px)" }}
/> />
))} ))}
</div> </div>
<Button <button
variant="ghost"
size="sm"
onClick={() => setCurrentPanel((p) => p + 1)} onClick={() => setCurrentPanel((p) => p + 1)}
disabled={isLast} disabled={isLast}
className="gap-1" className={cn("pixel-btn pixel-btn-green px-3 py-1 text-xs", isLast && "opacity-40")}
> >
Next Next
<ChevronRight className="h-4 w-4" /> </button>
</Button>
</div> </div>
)} )}
</div> </div>
@@ -102,21 +96,22 @@ interface SinglePanelProps {
export function Panel({ character = "promi", mood = "happy", children, highlight }: SinglePanelProps) { export function Panel({ character = "promi", mood = "happy", children, highlight }: SinglePanelProps) {
return ( return (
<div className="my-6 rounded-2xl border-2 border-primary/20 overflow-hidden"> <div className="my-6 pixel-panel">
<div className="p-6 bg-gradient-to-br from-primary/5 to-purple-500/5"> <div className="p-4">
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
{character === "promi" && ( {character === "promi" && (
<div className="shrink-0"> <div className="shrink-0">
<PromiCharacter mood={mood} size="md" /> <PixelRobot className="w-12 h-16" />
</div> </div>
)} )}
<div <div
className={cn( className={cn(
"flex-1 p-4 bg-white dark:bg-card rounded-xl shadow-md", "flex-1 p-4 bg-white/80 border-2 border-[#D97706]",
highlight && "ring-2 ring-primary ring-offset-2" highlight && "bg-[#FEF3C7]"
)} )}
style={{ clipPath: "polygon(4px 0, calc(100% - 4px) 0, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 0 calc(100% - 4px), 0 4px)" }}
> >
<div className="text-lg leading-relaxed">{children}</div> <div className="text-xl leading-relaxed text-[#2C1810]">{children}</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,204 @@
"use client";
import { useState, useEffect, useId } from "react";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { useLevelSlug } from "@/components/kids/providers/level-context";
import { getComponentState, saveComponentState } from "@/lib/kids/progress";
interface WordPredictorProps {
title?: string;
instruction?: string;
sentence: string;
options: string[];
correctAnswer: string;
explanation: string;
aiThinking?: string;
successMessage?: string;
}
interface SavedState {
selectedAnswer: string | null;
submitted: boolean;
}
export function WordPredictor({
title,
instruction,
sentence,
options,
correctAnswer,
explanation,
aiThinking,
successMessage,
}: WordPredictorProps) {
const t = useTranslations("kids.wordPredictor");
const levelSlug = useLevelSlug();
const componentId = useId();
const displayTitle = title || t("title");
const displayInstruction = instruction || t("instruction");
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null);
const [submitted, setSubmitted] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
// Load saved state
useEffect(() => {
if (!levelSlug) {
setIsLoaded(true);
return;
}
const saved = getComponentState<SavedState>(levelSlug, componentId);
if (saved && typeof saved.submitted === "boolean") {
setSelectedAnswer(saved.selectedAnswer);
setSubmitted(saved.submitted);
}
setIsLoaded(true);
}, [levelSlug, componentId]);
// Save state
useEffect(() => {
if (!levelSlug || !isLoaded) return;
saveComponentState<SavedState>(levelSlug, componentId, {
selectedAnswer,
submitted,
});
}, [levelSlug, componentId, selectedAnswer, submitted, isLoaded]);
if (!isLoaded) return null;
const isCorrect = selectedAnswer === correctAnswer;
const handleSelect = (option: string) => {
if (submitted) return;
setSelectedAnswer(option);
};
const handleSubmit = () => {
if (!selectedAnswer) return;
setSubmitted(true);
};
const handleReset = () => {
setSelectedAnswer(null);
setSubmitted(false);
};
// Render sentence with blank
const renderSentence = () => {
const parts = sentence.split("___");
return (
<span>
{parts[0]}
<span className={cn(
"inline-block min-w-[80px] px-3 py-1 mx-1 rounded-lg border-2 border-dashed text-center font-bold",
!submitted && "bg-yellow-100 border-yellow-500 text-yellow-700",
submitted && isCorrect && "bg-green-100 border-green-500 text-green-700 border-solid",
submitted && !isCorrect && "bg-red-100 border-red-400 text-red-600 border-solid"
)}>
{selectedAnswer || "???"}
</span>
{parts[1]}
</span>
);
};
return (
<div className="my-4 p-4 bg-gradient-to-br from-[#E0E7FF] to-[#C7D2FE] border-4 border-[#6366F1] rounded-xl">
{/* Title */}
<h3 className="text-xl font-bold text-[#4338CA] mb-2 flex items-center gap-2">
🧠 {displayTitle}
</h3>
<p className="text-[#5D4037] mb-4 m-0">{displayInstruction}</p>
{/* AI Brain visualization */}
<div className="bg-white/80 rounded-lg p-4 mb-4 border-2 border-[#6366F1]">
<div className="flex items-center gap-2 mb-3">
<span className="text-2xl">🤖</span>
<span className="font-medium text-[#4338CA]">{t("aiThinks")}</span>
</div>
<p className="text-lg text-[#2C1810] m-0">
{renderSentence()}
</p>
</div>
{/* Thinking bubble */}
{!submitted && (
<div className="bg-[#F0F9FF] rounded-lg p-3 mb-4 border-2 border-[#0EA5E9] italic text-[#0369A1]">
💭 {aiThinking || t("thinkingDefault")}
</div>
)}
{/* Options */}
<div className="grid grid-cols-2 gap-2 mb-4">
{options.map((option, index) => {
const isSelected = selectedAnswer === option;
const showCorrect = submitted && option === correctAnswer;
const showWrong = submitted && isSelected && !isCorrect;
return (
<button
key={index}
onClick={() => handleSelect(option)}
disabled={submitted}
className={cn(
"p-3 rounded-lg border-2 font-bold text-lg transition-all",
!submitted && !isSelected && "bg-white border-[#6366F1] text-[#4338CA] hover:bg-indigo-50 cursor-pointer",
!submitted && isSelected && "bg-indigo-100 border-[#4338CA] text-[#4338CA] ring-2 ring-[#4338CA] scale-105",
showCorrect && "bg-green-100 border-green-500 text-green-700",
showWrong && "bg-red-100 border-red-400 text-red-600"
)}
>
{showCorrect && "✓ "}
{showWrong && "✗ "}
{option}
</button>
);
})}
</div>
{/* Submit button */}
{!submitted && (
<button
onClick={handleSubmit}
disabled={!selectedAnswer}
className={cn(
"w-full py-3 rounded-lg font-bold text-lg transition-all",
selectedAnswer
? "bg-[#6366F1] hover:bg-[#4F46E5] text-white cursor-pointer"
: "bg-gray-200 text-gray-400 cursor-not-allowed"
)}
>
{t("check")}
</button>
)}
{/* Result */}
{submitted && (
<div className={cn(
"p-4 rounded-lg border-2 mb-4 animate-in fade-in zoom-in-95 duration-300",
isCorrect ? "bg-green-100 border-green-500" : "bg-orange-100 border-orange-400"
)}>
<p className={cn(
"font-bold text-lg mb-2 m-0",
isCorrect ? "text-green-700" : "text-orange-700"
)}>
{isCorrect ? `🎉 ${successMessage || t("correct")}` : `🤔 ${t("tryAgain")}`}
</p>
<p className="text-[#5D4037] m-0">{explanation}</p>
</div>
)}
{/* Reset button */}
{submitted && (
<button
onClick={handleReset}
className="px-6 py-2 rounded-lg font-bold bg-[#6366F1] hover:bg-[#4F46E5] text-white"
>
{t("retry")}
</button>
)}
</div>
);
}

View File

@@ -0,0 +1,347 @@
"use client";
import { useState, useRef, useCallback } from "react";
// Pixel art speaker icons
function PixelSpeakerOn() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="5" width="3" height="6" fill="currentColor" />
<rect x="5" y="4" width="2" height="8" fill="currentColor" />
<rect x="7" y="3" width="2" height="10" fill="currentColor" />
<rect x="11" y="4" width="2" height="2" fill="currentColor" />
<rect x="11" y="10" width="2" height="2" fill="currentColor" />
<rect x="13" y="6" width="2" height="4" fill="currentColor" />
</svg>
);
}
function PixelSpeakerOff() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="5" width="3" height="6" fill="currentColor" />
<rect x="5" y="4" width="2" height="8" fill="currentColor" />
<rect x="7" y="3" width="2" height="10" fill="currentColor" />
<rect x="11" y="4" width="2" height="2" fill="currentColor" />
<rect x="13" y="6" width="2" height="2" fill="currentColor" />
<rect x="11" y="10" width="2" height="2" fill="currentColor" />
<rect x="13" y="10" width="2" height="2" fill="currentColor" />
</svg>
);
}
// 8-bit chiptune music generator using Web Audio API
class ChiptunePlayer {
private audioContext: AudioContext | null = null;
private masterGain: GainNode | null = null;
private isPlaying = false;
private intervalId: number | null = null;
private step = 0;
// Fun bouncy 8-bit melody - playful and catchy!
private melody = [
// Part 1: Bouncy intro
523.25, 0, 659.25, 0, 783.99, 0, 659.25, 0, // C5 - E5 - G5 - E5 (bouncy)
698.46, 0, 783.99, 0, 880.00, 783.99, 659.25, 0, // F5 - G5 - A5 G5 E5 (climb up!)
// Part 2: Silly descending
783.99, 698.46, 659.25, 587.33, 523.25, 0, 392.00, 0, // G5 F5 E5 D5 C5 - G4 (slide down)
440.00, 493.88, 523.25, 0, 659.25, 0, 523.25, 0, // A4 B4 C5 - E5 - C5 (pop back up)
// Part 3: Playful jumps
392.00, 523.25, 392.00, 523.25, 659.25, 783.99, 659.25, 0, // G4 C5 G4 C5 E5 G5 E5 (jumping!)
880.00, 0, 783.99, 0, 659.25, 523.25, 587.33, 659.25, // A5 - G5 - E5 C5 D5 E5
// Part 4: Fun ending
783.99, 0, 659.25, 0, 523.25, 587.33, 659.25, 783.99, // G5 - E5 - C5 D5 E5 G5
880.00, 783.99, 659.25, 523.25, 392.00, 0, 523.25, 0, // A5 G5 E5 C5 G4 - C5 (finish!)
];
// Funky bass line - groovy!
private bass = [
// Part 1
130.81, 0, 130.81, 164.81, 196.00, 0, 164.81, 0, // C3 - C3 E3 G3 - E3
174.61, 0, 196.00, 0, 220.00, 196.00, 164.81, 0, // F3 - G3 - A3 G3 E3
// Part 2
196.00, 174.61, 164.81, 146.83, 130.81, 0, 98.00, 0, // G3 F3 E3 D3 C3 - G2
110.00, 123.47, 130.81, 0, 164.81, 0, 130.81, 0, // A2 B2 C3 - E3 - C3
// Part 3
98.00, 130.81, 98.00, 130.81, 164.81, 196.00, 164.81, 0, // G2 C3 G2 C3 E3 G3 E3
220.00, 0, 196.00, 0, 164.81, 130.81, 146.83, 164.81, // A3 - G3 - E3 C3 D3 E3
// Part 4
196.00, 0, 164.81, 0, 130.81, 146.83, 164.81, 196.00, // G3 - E3 - C3 D3 E3 G3
220.00, 196.00, 164.81, 130.81, 98.00, 0, 130.81, 0, // A3 G3 E3 C3 G2 - C3
];
async start() {
if (this.isPlaying) return;
try {
this.audioContext = new (window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext)();
// Resume audio context if suspended (required by browsers)
if (this.audioContext.state === "suspended") {
await this.audioContext.resume();
}
this.masterGain = this.audioContext.createGain();
this.masterGain.gain.value = 0.2;
this.masterGain.connect(this.audioContext.destination);
this.isPlaying = true;
this.step = 0;
// Play notes at upbeat tempo
this.intervalId = window.setInterval(() => this.playStep(), 150);
} catch (error) {
console.error("Failed to start audio:", error);
}
}
private playStep() {
if (!this.audioContext || !this.masterGain) return;
const now = this.audioContext.currentTime;
const noteIndex = this.step % this.melody.length;
// Play melody (square wave for 8-bit sound) - skip if 0 (rest)
if (this.melody[noteIndex] > 0) {
this.playNote(this.melody[noteIndex], now, 0.12, "square", 0.12);
}
// Play bass (triangle wave) - louder and deeper, skip if 0
if (this.bass[noteIndex] > 0) {
this.playNote(this.bass[noteIndex], now, 0.14, "triangle", 0.15);
// Add sub-bass for extra punch
this.playNote(this.bass[noteIndex] / 2, now, 0.14, "sine", 0.08);
}
// Aggressive dubstep-style percussion
if (this.step % 8 === 0) {
this.playDrum(now, "kick");
this.playDrum(now + 0.15, "kick"); // Double kick
} else if (this.step % 8 === 4) {
this.playDrum(now, "snare");
} else if (this.step % 2 === 1) {
this.playDrum(now, "hihat");
}
// Wobble bass on every other beat for dubstep feel
if (this.step % 4 === 2) {
this.playWobble(now);
}
this.step++;
}
private playNote(freq: number, time: number, duration: number, type: OscillatorType, volume: number) {
if (!this.audioContext || !this.masterGain) return;
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
osc.type = type;
osc.frequency.value = freq;
gain.gain.setValueAtTime(volume, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + duration);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start(time);
osc.stop(time + duration);
}
private playDrum(time: number, type: "kick" | "hihat" | "snare" = "hihat") {
if (!this.audioContext || !this.masterGain) return;
if (type === "kick") {
// Heavy dubstep kick - deep and punchy
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
osc.type = "sine";
osc.frequency.setValueAtTime(180, time);
osc.frequency.exponentialRampToValueAtTime(30, time + 0.12);
gain.gain.setValueAtTime(0.5, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.2);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start(time);
osc.stop(time + 0.2);
// Add click for attack
const click = this.audioContext.createOscillator();
const clickGain = this.audioContext.createGain();
click.type = "square";
click.frequency.value = 800;
clickGain.gain.setValueAtTime(0.15, time);
clickGain.gain.exponentialRampToValueAtTime(0.001, time + 0.02);
click.connect(clickGain);
clickGain.connect(this.masterGain);
click.start(time);
click.stop(time + 0.02);
} else if (type === "snare") {
// Aggressive dubstep snare - noise + tone
const bufferSize = this.audioContext.sampleRate * 0.15;
const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = Math.random() * 2 - 1;
}
const noise = this.audioContext.createBufferSource();
noise.buffer = buffer;
const noiseGain = this.audioContext.createGain();
noiseGain.gain.setValueAtTime(0.3, time);
noiseGain.gain.exponentialRampToValueAtTime(0.001, time + 0.15);
const filter = this.audioContext.createBiquadFilter();
filter.type = "bandpass";
filter.frequency.value = 3000;
filter.Q.value = 1;
noise.connect(filter);
filter.connect(noiseGain);
noiseGain.connect(this.masterGain);
noise.start(time);
noise.stop(time + 0.15);
// Add tone body
const tone = this.audioContext.createOscillator();
const toneGain = this.audioContext.createGain();
tone.type = "triangle";
tone.frequency.setValueAtTime(200, time);
tone.frequency.exponentialRampToValueAtTime(100, time + 0.05);
toneGain.gain.setValueAtTime(0.2, time);
toneGain.gain.exponentialRampToValueAtTime(0.001, time + 0.08);
tone.connect(toneGain);
toneGain.connect(this.masterGain);
tone.start(time);
tone.stop(time + 0.08);
} else {
// Hi-hat - crispy noise
const bufferSize = this.audioContext.sampleRate * 0.04;
const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = Math.random() * 2 - 1;
}
const noise = this.audioContext.createBufferSource();
noise.buffer = buffer;
const gain = this.audioContext.createGain();
gain.gain.setValueAtTime(0.08, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.04);
const filter = this.audioContext.createBiquadFilter();
filter.type = "highpass";
filter.frequency.value = 9000;
noise.connect(filter);
filter.connect(gain);
gain.connect(this.masterGain);
noise.start(time);
noise.stop(time + 0.04);
}
}
private playWobble(time: number) {
if (!this.audioContext || !this.masterGain) return;
// Classic dubstep wobble bass
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
const lfo = this.audioContext.createOscillator();
const lfoGain = this.audioContext.createGain();
osc.type = "sawtooth";
osc.frequency.value = 55; // Low A
// LFO for wobble effect
lfo.type = "sine";
lfo.frequency.value = 8; // Wobble speed
lfoGain.gain.value = 400;
lfo.connect(lfoGain);
// Create filter for wobble
const filter = this.audioContext.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.value = 400;
filter.Q.value = 8;
lfoGain.connect(filter.frequency);
gain.gain.setValueAtTime(0.2, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.3);
osc.connect(filter);
filter.connect(gain);
gain.connect(this.masterGain);
lfo.start(time);
osc.start(time);
lfo.stop(time + 0.3);
osc.stop(time + 0.3);
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
if (this.audioContext) {
this.audioContext.close();
this.audioContext = null;
}
this.isPlaying = false;
}
getIsPlaying() {
return this.isPlaying;
}
}
export function MusicButton() {
const [isPlaying, setIsPlaying] = useState(false);
const playerRef = useRef<ChiptunePlayer | null>(null);
const toggleMusic = useCallback(async () => {
if (!playerRef.current) {
playerRef.current = new ChiptunePlayer();
}
if (isPlaying) {
playerRef.current.stop();
setIsPlaying(false);
} else {
await playerRef.current.start();
setIsPlaying(true);
}
}, [isPlaying]);
return (
<button
onClick={toggleMusic}
className="pixel-btn pixel-btn-amber px-2 py-1.5 h-8 flex items-center"
aria-label={isPlaying ? "Mute music" : "Play music"}
title={isPlaying ? "Mute music" : "Play music"}
>
{isPlaying ? <PixelSpeakerOn /> : <PixelSpeakerOff />}
</button>
);
}
// Legacy export for backwards compatibility
export function BackgroundMusic() {
return null;
}

View File

@@ -2,11 +2,13 @@
import Link from "next/link"; import Link from "next/link";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { Home, Map, Star } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { getTotalStars, getCompletedLevelsCount } from "@/lib/kids/progress"; import { getTotalStars, getCompletedLevelsCount } from "@/lib/kids/progress";
import { getTotalLevels } from "@/lib/kids/levels"; import { getTotalLevels, getLevelBySlug } from "@/lib/kids/levels";
import { PixelStar, PixelRobot } from "@/components/kids/elements/pixel-art";
import { MusicButton } from "./background-music";
import { SettingsButton } from "./settings-modal";
import { useLevelSlug } from "@/components/kids/providers/level-context";
export function KidsHeader() { export function KidsHeader() {
const t = useTranslations("kids"); const t = useTranslations("kids");
@@ -14,60 +16,108 @@ export function KidsHeader() {
const [completed, setCompleted] = useState(0); const [completed, setCompleted] = useState(0);
const total = getTotalLevels(); const total = getTotalLevels();
// Get current level from context (will be empty if not in a level)
const levelSlug = useLevelSlug();
const currentLevel = levelSlug ? getLevelBySlug(levelSlug) : null;
const levelNumber = currentLevel ? `${currentLevel.world}.${currentLevel.levelNumber}` : null;
useEffect(() => { useEffect(() => {
setStars(getTotalStars()); setStars(getTotalStars());
setCompleted(getCompletedLevelsCount()); setCompleted(getCompletedLevelsCount());
}, []); }, []);
return ( return (
<header className="sticky top-0 z-50 w-full border-b bg-white/80 dark:bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-white/60"> <header className="shrink-0 z-50 w-full bg-[#2C1810] border-b-4 border-[#8B4513]">
<div className="container flex h-16 items-center justify-between"> <div className="container flex h-14 items-center justify-between px-4">
{/* Logo */} {/* Logo */}
<Link href="/kids" className="flex items-center gap-2 font-bold text-xl"> <Link href="/kids" className="flex items-center gap-2">
<span className="text-2xl">🤖</span> <PixelRobot className="w-8 h-10" />
<span className="bg-gradient-to-r from-primary to-purple-500 bg-clip-text text-transparent"> <span className="text-[#FFD700] font-bold text-2xl pixel-text-shadow hidden sm:block">
{t("header.title")} {t("header.title")}
</span> </span>
</Link> </Link>
{/* Stats & Nav */} {/* Stats & Nav */}
<div className="flex items-center gap-4"> <div className="flex items-center gap-3">
{/* Current level indicator */}
{levelNumber && (
<div className="flex items-center gap-1 px-3 h-8 bg-[#FFD700] border-2 border-[#DAA520] pixel-border-sm">
<span className="text-[#8B4513] text-sm font-bold">
{t("level.levelLabel", { number: levelNumber })}
</span>
</div>
)}
{/* Stars counter */} {/* Stars counter */}
<div className="flex items-center gap-1 px-3 py-1.5 bg-amber-100 dark:bg-amber-900/30 rounded-full text-amber-700 dark:text-amber-300"> <div className="flex items-center gap-1 px-3 h-8 bg-[#4A3728] border-2 border-[#8B4513] pixel-border-sm">
<Star className="h-4 w-4 fill-current" /> <PixelStar filled className="w-4 h-4" />
<span className="font-semibold text-sm">{stars}</span> <span className="text-white text-sm">{stars}</span>
</div> </div>
{/* Progress */} {/* Progress */}
<div className="hidden sm:flex items-center gap-1 px-3 py-1.5 bg-emerald-100 dark:bg-emerald-900/30 rounded-full text-emerald-700 dark:text-emerald-300 text-sm"> <div className="hidden sm:flex items-center gap-1 px-3 h-8 bg-[#4A3728] border-2 border-[#8B4513] pixel-border-sm">
<span className="font-semibold">{completed}/{total}</span> <span className="text-[#22C55E] text-sm">{completed}/{total}</span>
<span className="text-emerald-600 dark:text-emerald-400">{t("header.levels")}</span>
</div> </div>
{/* Nav buttons */} {/* Nav buttons */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button variant="ghost" size="icon" asChild className="rounded-full"> <MusicButton />
<Link href="/kids"> <SettingsButton />
<Home className="h-5 w-5" /> <Link
<span className="sr-only">{t("header.home")}</span> href="/kids"
className="pixel-btn px-3 py-1.5 text-sm h-8 flex items-center"
>
<PixelHomeIcon />
</Link> </Link>
</Button> <Link
<Button variant="ghost" size="icon" asChild className="rounded-full"> href="/kids/map"
<Link href="/kids/map"> className="pixel-btn pixel-btn-green px-3 py-1.5 text-sm h-8 flex items-center"
<Map className="h-5 w-5" /> >
<span className="sr-only">{t("header.map")}</span> <PixelMapIcon />
</Link> </Link>
</Button>
</div>
{/* Back to main site */} {/* Back to main site */}
<Button variant="outline" size="sm" asChild className="hidden md:flex rounded-full"> <a
<Link href="/"> href="/"
className="hidden md:flex pixel-btn pixel-btn-amber px-3 py-1.5 text-sm h-8 items-center"
>
{t("header.mainSite")} {t("header.mainSite")}
</Link> </a>
</Button> </div>
</div> </div>
</div> </div>
</header> </header>
); );
} }
// Pixel art home icon
function PixelHomeIcon() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="7" y="1" width="2" height="2" fill="currentColor" />
<rect x="5" y="3" width="6" height="2" fill="currentColor" />
<rect x="3" y="5" width="10" height="2" fill="currentColor" />
<rect x="2" y="7" width="12" height="2" fill="currentColor" />
<rect x="3" y="9" width="10" height="6" fill="currentColor" />
<rect x="6" y="11" width="4" height="4" fill="#2C1810" />
</svg>
);
}
// Pixel art pin/location icon
function PixelMapIcon() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
{/* Pin head - circle */}
<rect x="5" y="1" width="6" height="2" fill="currentColor" />
<rect x="4" y="2" width="8" height="2" fill="currentColor" />
<rect x="3" y="3" width="10" height="4" fill="currentColor" />
<rect x="4" y="7" width="8" height="2" fill="currentColor" />
<rect x="5" y="9" width="6" height="2" fill="currentColor" />
{/* Pin point */}
<rect x="6" y="11" width="4" height="2" fill="currentColor" />
<rect x="7" y="13" width="2" height="2" fill="currentColor" />
{/* Inner highlight */}
<rect x="5" y="4" width="2" height="2" fill="rgba(255,255,255,0.4)" />
</svg>
);
}

View File

@@ -0,0 +1,252 @@
"use client";
import { useState } from "react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { analyticsKids } from "@/lib/analytics";
import { PixelRobot, PixelStar, PixelTree, PixelCastle } from "@/components/kids/elements/pixel-art";
export function KidsHomeContent() {
const t = useTranslations("kids");
const [step, setStep] = useState(0);
const totalSteps = 3;
const nextStep = () => setStep((prev) => Math.min(prev + 1, totalSteps - 1));
const prevStep = () => setStep((prev) => Math.max(prev - 1, 0));
return (
<div className="h-full flex flex-col">
{/* Main content area */}
<div className="flex-1 min-h-0 overflow-y-auto flex items-center justify-center p-4">
<div className="w-full max-w-2xl my-auto">
{/* Step 0: Welcome */}
{step === 0 && (
<div className="text-center animate-in fade-in slide-in-from-right-4 duration-300">
<div className="inline-flex items-center gap-2 px-4 py-2 bg-[#ffffff] border-2 border-[#DAA520] pixel-border-sm text-[#8B4513] text-lg mb-4">
<PixelStar filled className="w-4 h-4" />
{t("home.badge")}
</div>
<h1 className="text-5xl md:text-6xl font-bold tracking-tight mb-4 text-[#2C1810] pixel-text-shadow">
{t("home.title")}
</h1>
<p className="text-3xl md:text-4xl text-[#5D4037] mb-8">
{t("home.subtitle")}
</p>
<div className="pixel-panel p-4 md:p-6">
<div className="flex flex-col sm:flex-row items-center gap-4 md:gap-6">
<div className="shrink-0">
<PixelRobot className="w-16 h-20" />
</div>
<div className="text-center sm:text-left">
<p className="text-2xl md:text-3xl font-bold text-[#2C1810] mb-2">{t("home.promiIntro.greeting")}</p>
<p className="text-xl md:text-2xl text-[#5D4037]">
{t("home.promiIntro.message")}
</p>
</div>
</div>
</div>
</div>
)}
{/* Step 1: Features */}
{step === 1 && (
<div className="text-center animate-in fade-in slide-in-from-right-4 duration-300">
<h2 className="text-4xl md:text-5xl font-bold mb-6 text-[#2C1810] pixel-text-shadow">
{t("home.whatYouLearn")}
</h2>
<div className="grid gap-4">
<div className="pixel-panel pixel-panel-green p-4 flex items-center gap-4">
<PixelGamepad />
<div className="text-left">
<h3 className="font-bold text-2xl md:text-3xl text-[#2C1810]">{t("home.features.games.title")}</h3>
<p className="text-xl md:text-2xl text-[#5D4037]">{t("home.features.games.description")}</p>
</div>
</div>
<div className="pixel-panel pixel-panel-blue p-4 flex items-center gap-4">
<PixelBook />
<div className="text-left">
<h3 className="font-bold text-2xl md:text-3xl text-[#2C1810]">{t("home.features.stories.title")}</h3>
<p className="text-xl md:text-2xl text-[#5D4037]">{t("home.features.stories.description")}</p>
</div>
</div>
<div className="pixel-panel p-4 flex items-center gap-4">
<div className="flex">
<PixelStar filled className="w-8 h-8" />
<PixelStar filled className="w-8 h-8" />
<PixelStar filled className="w-8 h-8" />
</div>
<div className="text-left">
<h3 className="font-bold text-2xl md:text-3xl text-[#2C1810]">{t("home.features.stars.title")}</h3>
<p className="text-xl md:text-2xl text-[#5D4037]">{t("home.features.stars.description")}</p>
</div>
</div>
</div>
</div>
)}
{/* Step 2: Ready to start */}
{step === 2 && (
<div className="text-center animate-in fade-in slide-in-from-right-4 duration-300">
<div className="mb-6 flex justify-center items-end gap-4">
<PixelTree className="w-10 h-14" />
<PixelRobot className="w-16 h-20 animate-bounce-slow" />
<PixelCastle className="w-12 h-12" />
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-[#2C1810] pixel-text-shadow">
{t("home.readyTitle")}
</h2>
<p className="text-xl md:text-2xl text-[#5D4037] mb-8">
{t("home.readyMessage")}
</p>
<Link
href="/kids/map"
onClick={() => analyticsKids.startGame()}
className="inline-block pixel-btn pixel-btn-green text-xl md:text-2xl px-8 py-4"
>
<span className="flex items-center gap-2">
<PixelPlayIcon />
{t("home.startButton")}
</span>
</Link>
<p className="mt-6 text-lg text-[#8B7355]">
{t("home.ageNote")}
</p>
</div>
)}
</div>
</div>
{/* Navigation footer - pixel art style */}
<div className="shrink-0 bg-[#2C1810] border-t-4 border-[#8B4513]">
<div className="container py-3 flex items-center justify-between">
{/* Back button */}
<button
onClick={prevStep}
disabled={step === 0}
className={cn(
"pixel-btn px-6 py-3 text-lg",
step === 0 && "opacity-0 pointer-events-none"
)}
>
<span className="flex items-center gap-1">
<PixelArrowLeft />
{t("navigation.back")}
</span>
</button>
{/* Step indicators - pixel style */}
<div className="flex items-center gap-2">
{Array.from({ length: totalSteps }).map((_, i) => (
<button
key={i}
onClick={() => setStep(i)}
className={cn(
"w-4 h-4 border-2 transition-all",
i === step
? "bg-[#22C55E] border-[#16A34A]"
: "bg-[#4A3728] border-[#8B4513] hover:bg-[#5D4037]"
)}
style={{ clipPath: "polygon(2px 0, calc(100% - 2px) 0, 100% 2px, 100% calc(100% - 2px), calc(100% - 2px) 100%, 2px 100%, 0 calc(100% - 2px), 0 2px)" }}
aria-label={`Go to step ${i + 1}`}
/>
))}
</div>
{/* Next button */}
{step < totalSteps - 1 ? (
<button
onClick={nextStep}
className="pixel-btn pixel-btn-green px-6 py-3 text-lg"
>
<span className="flex items-center gap-1">
{t("navigation.next")}
<PixelArrowRight />
</span>
</button>
) : (
<Link
href="/kids/map"
className="pixel-btn pixel-btn-green px-6 py-3 text-lg"
>
<span className="flex items-center gap-1">
<PixelPlayIcon />
{t("home.startButton")}
</span>
</Link>
)}
</div>
</div>
</div>
);
}
// Pixel art icons
function PixelPlayIcon() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="1" width="2" height="10" fill="currentColor" />
<rect x="4" y="3" width="2" height="6" fill="currentColor" />
<rect x="6" y="4" width="2" height="4" fill="currentColor" />
<rect x="8" y="5" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelArrowLeft() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="4" y="5" width="6" height="2" fill="currentColor" />
<rect x="2" y="5" width="2" height="2" fill="currentColor" />
<rect x="4" y="3" width="2" height="2" fill="currentColor" />
<rect x="4" y="7" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelArrowRight() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="5" width="6" height="2" fill="currentColor" />
<rect x="8" y="5" width="2" height="2" fill="currentColor" />
<rect x="6" y="3" width="2" height="2" fill="currentColor" />
<rect x="6" y="7" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelGamepad() {
return (
<svg viewBox="0 0 24 16" className="w-10 h-7" style={{ imageRendering: "pixelated" }}>
<rect x="4" y="2" width="16" height="12" fill="#333" />
<rect x="2" y="4" width="4" height="8" fill="#333" />
<rect x="18" y="4" width="4" height="8" fill="#333" />
<rect x="6" y="6" width="2" height="4" fill="#22C55E" />
<rect x="4" y="7" width="6" height="2" fill="#22C55E" />
<rect x="16" y="6" width="2" height="2" fill="#EF4444" />
<rect x="18" y="8" width="2" height="2" fill="#3B82F6" />
</svg>
);
}
function PixelBook() {
return (
<svg viewBox="0 0 20 16" className="w-8 h-6" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="1" width="16" height="14" fill="#8B4513" />
<rect x="4" y="2" width="12" height="12" fill="#FEF3C7" />
<rect x="9" y="2" width="2" height="12" fill="#D97706" />
<rect x="5" y="4" width="3" height="1" fill="#333" />
<rect x="5" y="6" width="3" height="1" fill="#333" />
<rect x="12" y="4" width="3" height="1" fill="#333" />
<rect x="12" y="6" width="3" height="1" fill="#333" />
</svg>
);
}

View File

@@ -0,0 +1,217 @@
"use client";
import { useState, Children, isValidElement, ReactNode, ReactElement, useEffect } from "react";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { Section } from "@/components/kids/elements";
import { useSetLevelSlug } from "@/components/kids/providers/level-context";
import { getLevelBySlug } from "@/lib/kids/levels";
import { analyticsKids } from "@/lib/analytics";
interface LevelContentWrapperProps {
children: ReactNode;
levelSlug: string;
levelNumber: string;
}
export function LevelContentWrapper({ children, levelSlug, levelNumber }: LevelContentWrapperProps) {
const t = useTranslations("kids");
const [currentSection, setCurrentSection] = useState(0);
const setLevelSlug = useSetLevelSlug();
// Set the level slug in context when component mounts
useEffect(() => {
setLevelSlug(levelSlug);
// Track level view
const level = getLevelBySlug(levelSlug);
if (level) {
analyticsKids.viewLevel(levelSlug, level.world);
}
return () => setLevelSlug(""); // Clear when unmounting
}, [levelSlug, setLevelSlug]);
// Extract Section components from children
const sections: ReactElement[] = [];
let hasExplicitSections = false;
// First pass: check if there are explicit Section components
Children.forEach(children, (child) => {
if (isValidElement(child) && child.type === Section) {
hasExplicitSections = true;
}
});
// Second pass: collect sections
if (hasExplicitSections) {
Children.forEach(children, (child) => {
if (isValidElement(child) && child.type === Section) {
sections.push(child);
}
});
} else {
Children.forEach(children, (child) => {
if (isValidElement(child)) {
sections.push(<Section key={sections.length}>{child}</Section>);
}
});
}
// If no sections found, show coming soon
if (sections.length === 0) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center pixel-panel p-6">
<p className="text-[#5D4037] mb-4">{t("level.comingSoon")}</p>
<Link href="/kids/map" className="pixel-btn pixel-btn-green px-4 py-2 inline-flex items-center gap-2">
<PixelMapIcon />
{t("level.backToMap")}
</Link>
</div>
</div>
);
}
const totalSections = sections.length;
const isFirstSection = currentSection === 0;
const isLastSection = currentSection === totalSections - 1;
const goToNext = () => {
if (!isLastSection) {
setCurrentSection((prev) => prev + 1);
}
};
const goToPrev = () => {
if (!isFirstSection) {
setCurrentSection((prev) => prev - 1);
}
};
// Reset to first section when level changes
useEffect(() => {
setCurrentSection(0);
}, [levelSlug]);
return (
<div className="h-full flex flex-col">
{/* Content area */}
<div className="flex-1 min-h-0 overflow-y-auto flex items-center justify-center p-4">
<div className="w-full max-w-2xl my-auto">
<div
key={currentSection}
className="animate-in fade-in slide-in-from-right-4 duration-300 prose max-w-none kids-prose-pixel"
>
{sections[currentSection]}
</div>
</div>
</div>
{/* Navigation footer - pixel art style */}
<div className="shrink-0 bg-[#2C1810] border-t-4 border-[#8B4513]">
<div className="max-w-2xl mx-auto py-3 px-4 flex items-center justify-between">
{/* Back button */}
<button
onClick={goToPrev}
disabled={isFirstSection}
className={cn(
"pixel-btn px-6 py-3 text-xl",
isFirstSection && "opacity-0 pointer-events-none"
)}
>
<span className="flex items-center gap-1">
<PixelArrowLeft />
{t("navigation.back")}
</span>
</button>
{/* Progress indicators - pixel style */}
<div className="flex items-center gap-2">
{Array.from({ length: totalSections }).map((_, i) => (
<button
key={i}
onClick={() => setCurrentSection(i)}
className={cn(
"w-4 h-4 border-2 transition-all",
i === currentSection
? "bg-[#22C55E] border-[#16A34A]"
: i < currentSection
? "bg-[#3B82F6] border-[#2563EB]"
: "bg-[#4A3728] border-[#8B4513] hover:bg-[#5D4037]"
)}
style={{ clipPath: "polygon(2px 0, calc(100% - 2px) 0, 100% 2px, 100% calc(100% - 2px), calc(100% - 2px) 100%, 2px 100%, 0 calc(100% - 2px), 0 2px)" }}
aria-label={`Go to section ${i + 1}`}
/>
))}
</div>
{/* Next button or Map link */}
{!isLastSection ? (
<button
onClick={goToNext}
className="pixel-btn pixel-btn-green px-6 py-3 text-xl"
>
<span className="flex items-center gap-1">
{t("navigation.next")}
<PixelArrowRight />
</span>
</button>
) : (
<Link
href="/kids/map"
className="pixel-btn pixel-btn-amber px-6 py-3 text-xl"
>
<span className="flex items-center gap-1">
<PixelMapIcon />
{t("level.map")}
</span>
</Link>
)}
</div>
</div>
</div>
);
}
// Pixel art icons
function PixelArrowLeft() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="4" y="5" width="6" height="2" fill="currentColor" />
<rect x="2" y="5" width="2" height="2" fill="currentColor" />
<rect x="4" y="3" width="2" height="2" fill="currentColor" />
<rect x="4" y="7" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelArrowRight() {
return (
<svg viewBox="0 0 12 12" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
<rect x="2" y="5" width="6" height="2" fill="currentColor" />
<rect x="8" y="5" width="2" height="2" fill="currentColor" />
<rect x="6" y="3" width="2" height="2" fill="currentColor" />
<rect x="6" y="7" width="2" height="2" fill="currentColor" />
</svg>
);
}
function PixelMapIcon() {
return (
<svg viewBox="0 0 16 16" className="w-4 h-4" style={{ imageRendering: "pixelated" }}>
{/* Pin head - circle */}
<rect x="5" y="1" width="6" height="2" fill="currentColor" />
<rect x="4" y="2" width="8" height="2" fill="currentColor" />
<rect x="3" y="3" width="10" height="4" fill="currentColor" />
<rect x="4" y="7" width="8" height="2" fill="currentColor" />
<rect x="5" y="9" width="6" height="2" fill="currentColor" />
{/* Pin point */}
<rect x="6" y="11" width="4" height="2" fill="currentColor" />
<rect x="7" y="13" width="2" height="2" fill="currentColor" />
{/* Inner highlight */}
<rect x="5" y="4" width="2" height="2" fill="rgba(255,255,255,0.4)" />
</svg>
);
}

View File

@@ -0,0 +1,210 @@
"use client";
import { useState } from "react";
import { useTranslations, useLocale } from "next-intl";
import { cn } from "@/lib/utils";
import { clearAllProgress, getTotalStars, getCompletedLevelsCount } from "@/lib/kids/progress";
import { setLocale } from "@/lib/i18n/client";
import { analyticsKids } from "@/lib/analytics";
import { Settings, X, Globe, Trash2, Check } from "lucide-react";
const SUPPORTED_LOCALES = [
{ code: "en", label: "English", flag: "🇺🇸" },
{ code: "zh", label: "中文", flag: "🇨🇳" },
{ code: "es", label: "Español", flag: "🇪🇸" },
{ code: "pt", label: "Português", flag: "🇧🇷" },
{ code: "fr", label: "Français", flag: "🇫🇷" },
{ code: "de", label: "Deutsch", flag: "🇩🇪" },
{ code: "it", label: "Italiano", flag: "🇮🇹" },
{ code: "ja", label: "日本語", flag: "🇯🇵" },
{ code: "tr", label: "Türkçe", flag: "🇹🇷" },
{ code: "az", label: "Azərbaycan", flag: "🇦🇿" },
{ code: "ko", label: "한국어", flag: "🇰🇷" },
{ code: "ar", label: "العربية", flag: "🇸🇦" },
{ code: "fa", label: "فارسی", flag: "🇮🇷" },
{ code: "ru", label: "Русский", flag: "🇷🇺" },
{ code: "he", label: "עברית", flag: "🇮🇱" },
{ code: "el", label: "Ελληνικά", flag: "🇬🇷" },
];
export function SettingsButton() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button
onClick={() => {
setIsOpen(true);
analyticsKids.openSettings();
}}
className="pixel-btn pixel-btn-purple px-3 py-1.5 text-sm h-8 flex items-center"
aria-label="Settings"
>
<PixelSettingsIcon />
</button>
{isOpen && <SettingsModal onClose={() => setIsOpen(false)} />}
</>
);
}
function SettingsModal({ onClose }: { onClose: () => void }) {
const t = useTranslations("kids.settings");
const currentLocale = useLocale();
const [showResetConfirm, setShowResetConfirm] = useState(false);
const [resetComplete, setResetComplete] = useState(false);
const stars = getTotalStars();
const completed = getCompletedLevelsCount();
const handleLanguageChange = (locale: string) => {
analyticsKids.changeLanguage(locale);
setLocale(locale);
};
const handleResetProgress = () => {
if (!showResetConfirm) {
setShowResetConfirm(true);
return;
}
clearAllProgress();
analyticsKids.resetProgress();
setResetComplete(true);
setShowResetConfirm(false);
// Reload to reflect changes
setTimeout(() => {
window.location.reload();
}, 1000);
};
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
{/* Backdrop */}
<div
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
onClick={onClose}
/>
{/* Modal */}
<div className="relative bg-[#FEF3C7] border-4 border-[#8B4513] rounded-xl p-6 w-full max-w-md animate-in zoom-in-95 fade-in duration-200">
{/* Close button */}
<button
onClick={onClose}
className="absolute top-3 right-3 p-2 text-[#8B4513] hover:bg-[#8B4513]/10 rounded-lg"
>
<X className="w-5 h-5" />
</button>
{/* Title */}
<h2 className="text-2xl font-bold text-[#8B4513] mb-6 flex items-center gap-2">
<Settings className="w-6 h-6" />
{t("title")}
</h2>
{/* Language Section */}
<div className="mb-6">
<h3 className="text-lg font-bold text-[#5D4037] mb-3 flex items-center gap-2">
<Globe className="w-5 h-5" />
{t("language")}
</h3>
<div className="grid grid-cols-3 gap-2">
{SUPPORTED_LOCALES.map((locale) => (
<button
key={locale.code}
onClick={() => handleLanguageChange(locale.code)}
className={cn(
"p-2 rounded-lg border-2 text-sm font-medium transition-all",
currentLocale === locale.code
? "bg-[#8B4513] border-[#5D4037] text-white"
: "bg-white border-[#D4A574] text-[#5D4037] hover:border-[#8B4513]"
)}
>
<span className="text-lg">{locale.flag}</span>
<div className="text-xs mt-1">{locale.label}</div>
</button>
))}
</div>
</div>
{/* Progress Info */}
<div className="mb-6 p-4 bg-white/50 rounded-lg border-2 border-[#D4A574]">
<h3 className="text-lg font-bold text-[#5D4037] mb-2">
{t("progress")}
</h3>
<div className="flex gap-4 text-[#5D4037]">
<div>
<span className="text-2xl font-bold text-[#FFD700]"> {stars}</span>
<div className="text-xs">{t("stars")}</div>
</div>
<div>
<span className="text-2xl font-bold text-[#22C55E]"> {completed}</span>
<div className="text-xs">{t("completed")}</div>
</div>
</div>
</div>
{/* Reset Progress */}
<div className="border-t-2 border-[#D4A574] pt-4">
<h3 className="text-lg font-bold text-[#5D4037] mb-3 flex items-center gap-2">
<Trash2 className="w-5 h-5" />
{t("resetTitle")}
</h3>
{resetComplete ? (
<div className="p-3 bg-green-100 border-2 border-green-500 rounded-lg text-green-700 font-medium flex items-center gap-2">
<Check className="w-5 h-5" />
{t("resetComplete")}
</div>
) : showResetConfirm ? (
<div className="space-y-2">
<p className="text-red-600 font-medium text-sm">
{t("resetWarning")}
</p>
<div className="flex gap-2">
<button
onClick={handleResetProgress}
className="flex-1 py-2 px-4 bg-red-500 hover:bg-red-600 text-white font-bold rounded-lg"
>
{t("resetConfirm")}
</button>
<button
onClick={() => setShowResetConfirm(false)}
className="flex-1 py-2 px-4 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold rounded-lg"
>
{t("cancel")}
</button>
</div>
</div>
) : (
<button
onClick={handleResetProgress}
className="w-full py-2 px-4 bg-red-100 hover:bg-red-200 text-red-700 font-bold rounded-lg border-2 border-red-300"
>
{t("resetButton")}
</button>
)}
</div>
</div>
</div>
);
}
// Pixel art settings/gear icon
function PixelSettingsIcon() {
return (
<svg viewBox="0 0 16 16" className="w-5 h-5" style={{ imageRendering: "pixelated" }}>
<rect x="6" y="0" width="4" height="2" fill="currentColor" />
<rect x="6" y="14" width="4" height="2" fill="currentColor" />
<rect x="0" y="6" width="2" height="4" fill="currentColor" />
<rect x="14" y="6" width="2" height="4" fill="currentColor" />
<rect x="2" y="2" width="2" height="2" fill="currentColor" />
<rect x="12" y="2" width="2" height="2" fill="currentColor" />
<rect x="2" y="12" width="2" height="2" fill="currentColor" />
<rect x="12" y="12" width="2" height="2" fill="currentColor" />
<rect x="4" y="4" width="8" height="8" fill="currentColor" />
<rect x="6" y="6" width="4" height="4" fill="#2C1810" />
</svg>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
interface LevelContextType {
levelSlug: string;
setLevelSlug: (slug: string) => void;
}
const LevelContext = createContext<LevelContextType>({
levelSlug: "",
setLevelSlug: () => {},
});
export function LevelProvider({
children,
levelSlug: initialSlug = ""
}: {
children: ReactNode;
levelSlug?: string;
}) {
const [levelSlug, setLevelSlug] = useState(initialSlug);
// Update if initialSlug changes
useEffect(() => {
if (initialSlug) {
setLevelSlug(initialSlug);
}
}, [initialSlug]);
return (
<LevelContext.Provider value={{ levelSlug, setLevelSlug }}>
{children}
</LevelContext.Provider>
);
}
export function useLevelSlug(): string {
const context = useContext(LevelContext);
return context.levelSlug;
}
export function useSetLevelSlug(): (slug: string) => void {
const context = useContext(LevelContext);
return context.setLevelSlug;
}

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
مرحباً! أنا **Promi** 🤖، صديقك الروبوت! سعيد جداً بلقائك! مرحباً! أنا **Promi** 🤖، صديقك الروبوت! سعيد جداً بلقائك!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
أنا ذكاء اصطناعي! يمكنني قراءة رسائلك ومحاولة مساعدتك. لكن هناك سر... أحتاج **تعليمات جيدة** لأقوم بأفضل عمل! أنا ذكاء اصطناعي! يمكنني قراءة رسائلك ومحاولة مساعدتك. لكن هناك سر... أحتاج **تعليمات جيدة** لأقوم بأفضل عمل!
</Panel> </Panel>
</Section>
<Section>
## ما هو البرومبت؟ ## ما هو البرومبت؟
**البرومبت** هو كلمة راقية للرسالة التي ترسلها لذكاء اصطناعي مثلي. **البرومبت** هو كلمة راقية للرسالة التي ترسلها لذكاء اصطناعي مثلي.
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
عندما تكتب برومبت جيد، أستطيع فهم ما تريد ومساعدتك بشكل أفضل! هيا نتدرب! عندما تكتب برومبت جيد، أستطيع فهم ما تريد ومساعدتك بشكل أفضل! هيا نتدرب!
</Panel> </Panel>
</Section>
<Section>
## لنجرب! ## لنجرب!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="الرسالة الأولى تخبر Promi بالضبط أي نوع من القصص يكتب! الثانية قصيرة جداً - Promi لا يعرف أي نوع من القصص تريد." explanation="الرسالة الأولى تخبر Promi بالضبط أي نوع من القصص يكتب! الثانية قصيرة جداً - Promi لا يعرف أي نوع من القصص تريد."
promiMessage="رأيت؟ المزيد من التفاصيل يساعدني على فهم ما تريد!" promiMessage="رأيت؟ المزيد من التفاصيل يساعدني على فهم ما تريد!"
/> />
</Section>
<Section>
## اختبار سريع! ## اختبار سريع!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="البرومبت يستخدم الكلمات لإخبار الذكاء الاصطناعي ما تحتاجه. الإيموجي ممتعة لكنها لا تعطي معلومات كافية!" explanation="البرومبت يستخدم الكلمات لإخبار الذكاء الاصطناعي ما تحتاجه. الإيموجي ممتعة لكنها لا تعطي معلومات كافية!"
promiMessage="الكلمات هي قوتي الخارقة! كلما أخبرتني أكثر، استطعت المساعدة أفضل!" promiMessage="الكلمات هي قوتي الخارقة! كلما أخبرتني أكثر، استطعت المساعدة أفضل!"
/> />
</Section>
<Section>
## نجحت! 🎉 ## نجحت! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
عمل رائع! تعلمت ما هو الذكاء الاصطناعي وما هو البرومبت. أنت تصبح خبيراً في البرومبت! عمل رائع! تعلمت ما هو الذكاء الاصطناعي وما هو البرومبت. أنت تصبح خبيراً في البرومبت!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="تعلمت ما هو الذكاء الاصطناعي والبرومبت!" message="تعلمت ما هو الذكاء الاصطناعي والبرومبت!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
مرحباً بعودتك يا صديقي! مستعد لكتابة أول برومبت حقيقي؟ هيا بنا! 🚀 مرحباً بعودتك يا صديقي! مستعد لكتابة أول برومبت حقيقي؟ هيا بنا! 🚀
</Panel> </Panel>
</Section>
<Section>
## سحر الكلمات ## سحر الكلمات
عندما تتحدث مع الذكاء الاصطناعي، كل كلمة مهمة! دعنا نرى كيف إضافة المزيد من الكلمات تجعل البرومبت أفضل. عندما تتحدث مع الذكاء الاصطناعي، كل كلمة مهمة! دعنا نرى كيف إضافة المزيد من الكلمات تجعل البرومبت أفضل.
@@ -9,7 +12,9 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
انظر! إذا قال لي شخص فقط "قطة"، لا أعرف ماذا يريدون. هل يريدون صورة؟ قصة؟ حقائق عن القطط؟ أنا مرتبك! 😵‍💫 انظر! إذا قال لي شخص فقط "قطة"، لا أعرف ماذا يريدون. هل يريدون صورة؟ قصة؟ حقائق عن القطط؟ أنا مرتبك! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## بناء برومبت أفضل ## بناء برومبت أفضل
البرومبت الجيد له **ثلاثة أجزاء**: البرومبت الجيد له **ثلاثة أجزاء**:
@@ -21,7 +26,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
هيا نبني برومبت معاً! هيا نبني برومبت معاً!
</Panel> </Panel>
</Section>
<Section>
## اسحب القطع! ## اسحب القطع!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="ممتاز! هذا برومبت رائع!" successMessage="ممتاز! هذا برومبت رائع!"
/> />
</Section>
<Section>
## املأ الفراغات! ## املأ الفراغات!
الآن حاول صنع برومبتك بسحب الكلمات السحرية: الآن حاول صنع برومبتك بسحب الكلمات السحرية:
<MagicWords <MagicWords
title="أنشئ برومبتك! ✨" title="أنشئ برومبتك! ✨"
sentence="من فضلك اكتب {{type}} عن {{character}} الذي {{action}}" sentence="من فضلك اكتب {{type}} عن {{character}} الذي {{action}}"
@@ -51,7 +61,9 @@
]} ]}
successMessage="واو! صنعت برومبت رائع!" successMessage="واو! صنعت برومبت رائع!"
/> />
</Section>
<Section>
## دورك للاختيار! ## دورك للاختيار!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@
explanation="البرومبت الأول يخبرني أنها يجب أن تكون مضحكة، عن بطريق، وماذا يريد البطريق أن يفعل!" explanation="البرومبت الأول يخبرني أنها يجب أن تكون مضحكة، عن بطريق، وماذا يريد البطريق أن يفعل!"
promiMessage="التفاصيل تجعل كل شيء أفضل! أحب معرفة بالضبط ما تريد!" promiMessage="التفاصيل تجعل كل شيء أفضل! أحب معرفة بالضبط ما تريد!"
/> />
</Section>
<Section>
## عمل رائع! 🌟 ## عمل رائع! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
كتبت أول برومبت لك! تعلمت أن البرومبت الجيد يحتاج: ما تريد، موضوع، وتفاصيل. أنت تتحسن! كتبت أول برومبت لك! تعلمت أن البرومبت الجيد يحتاج: ما تريد، موضوع، وتفاصيل. أنت تتحسن!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="تعلمت كيف تكتب أول برومبت!" message="تعلمت كيف تكتب أول برومبت!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
مرحباً يا نجم! 🌟 اليوم سنتعلم أهم مهارة: أن تكون **واضحاً**! مرحباً يا نجم! 🌟 اليوم سنتعلم أهم مهارة: أن تكون **واضحاً**!
</Panel> </Panel>
</Section>
<Section>
## لماذا الوضوح مهم ## لماذا الوضوح مهم
تخيل أن تطلب من أمك "طعام" مقابل طلب "ساندويتش زبدة فول سوداني بدون قشرة." أيهما يعطيك بالضبط ما تريد؟ تخيل أن تطلب من أمك "طعام" مقابل طلب "ساندويتش زبدة فول سوداني بدون قشرة." أيهما يعطيك بالضبط ما تريد؟
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
معي نفس الشيء! عندما تكون واضحاً، أعرف بالضبط كيف أساعد. عندما تكون غامضاً، علي أن أخمن... وقد أخمن خطأ! معي نفس الشيء! عندما تكون واضحاً، أعرف بالضبط كيف أساعد. عندما تكون غامضاً، علي أن أخمن... وقد أخمن خطأ!
</Panel> </Panel>
</Section>
<Section>
## واضح مقابل غير واضح ## واضح مقابل غير واضح
هيا نتدرب على اكتشاف الفرق! هيا نتدرب على اكتشاف الفرق!
<PromptVsMistake <PromptVsMistake
question="أي برومبت أوضح؟" question="أي برومبت أوضح؟"
good="اكتب قصيدة من 4 أسطر عن الفراشات في حديقة، باستخدام كلمات مقفاة" good="اكتب قصيدة من 4 أسطر عن الفراشات في حديقة، باستخدام كلمات مقفاة"
@@ -22,6 +28,7 @@
promiMessage="برومبت واضح = نتائج أفضل! إنه مثل السحر!" promiMessage="برومبت واضح = نتائج أفضل! إنه مثل السحر!"
/> />
<PromptVsMistake <PromptVsMistake
question="أيهما يخبرني بالضبط ما تحتاج؟" question="أيهما يخبرني بالضبط ما تحتاج؟"
good="ساعدني في كتابة 3 حقائق ممتعة عن الدلافين يستمتع بها طفل عمره 10 سنوات" good="ساعدني في كتابة 3 حقائق ممتعة عن الدلافين يستمتع بها طفل عمره 10 سنوات"
@@ -29,11 +36,14 @@
explanation="البرومبت الأول يخبرني: كم حقيقة (3)، أي نوع (ممتعة)، ولمن (طفل 10 سنوات). هذا يساعد كثيراً!" explanation="البرومبت الأول يخبرني: كم حقيقة (3)، أي نوع (ممتعة)، ولمن (طفل 10 سنوات). هذا يساعد كثيراً!"
promiMessage="عندما تخبرني لمن، أستطيع جعله مثالياً لهم!" promiMessage="عندما تخبرني لمن، أستطيع جعله مثالياً لهم!"
/> />
</Section>
<Section>
## تحدي الوضوح ## تحدي الوضوح
هيا نبني أوضح برومبت على الإطلاق! هيا نبني أوضح برومبت على الإطلاق!
<DragDropPrompt <DragDropPrompt
title="اجعله واضحاً كالكريستال! 💎" title="اجعله واضحاً كالكريستال! 💎"
instruction="رتب هذه القطع لصنع برومبت واضح جداً" instruction="رتب هذه القطع لصنع برومبت واضح جداً"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="هذا أوضح برومبت على الإطلاق! مذهل!" successMessage="هذا أوضح برومبت على الإطلاق! مذهل!"
/> />
</Section>
<Section>
## أضف تفاصيل واضحة ## أضف تفاصيل واضحة
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="أضفت كل التفاصيل المهمة! عمل رائع!" successMessage="أضفت كل التفاصيل المهمة! عمل رائع!"
/> />
</Section>
<Section>
## القواعد الذهبية للوضوح ## القواعد الذهبية للوضوح
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **كيف** يجب أن يكون؟ (قصير، مضحك، بسيط) 2. **كيف** يجب أن يكون؟ (قصير، مضحك، بسيط)
3. **لمن** هو؟ (أنا، صديقي، صفي) 3. **لمن** هو؟ (أنا، صديقي، صفي)
<PromptVsMistake <PromptVsMistake
question="التحدي الأخير! أيهما يستخدم القواعد الثلاث كلها؟" question="التحدي الأخير! أيهما يستخدم القواعد الثلاث كلها؟"
good="اكتب نكتة قصيرة ومضحكة عن البيتزا يمكنني إخبارها لأصدقائي في الغداء" good="اكتب نكتة قصيرة ومضحكة عن البيتزا يمكنني إخبارها لأصدقائي في الغداء"
@@ -81,7 +96,9 @@
explanation="البرومبت الرائع يحتوي على ماذا (نكتة عن البيتزا)، كيف (قصيرة ومضحكة)، ولمن (لإخبار الأصدقاء في الغداء)!" explanation="البرومبت الرائع يحتوي على ماذا (نكتة عن البيتزا)، كيف (قصيرة ومضحكة)، ولمن (لإخبار الأصدقاء في الغداء)!"
promiMessage="أنت بطل الوضوح! 🏆" promiMessage="أنت بطل الوضوح! 🏆"
/> />
</Section>
<Section>
## العالم 1 اكتمل! 🎊 ## العالم 1 اكتمل! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
أنت جاهز لمغامرات جديدة! أنت جاهز لمغامرات جديدة!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="أتقنت فن الوضوح! العالم 1 اكتمل!" message="أتقنت فن الوضوح! العالم 1 اكتمل!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Salam! Mən **Promi** 🤖, sənin robot dostun! Səninlə tanış olmağıma çox şadam! Salam! Mən **Promi** 🤖, sənin robot dostun! Səninlə tanış olmağıma çox şadam!
</Panel> </Panel>
@@ -9,7 +10,9 @@ Salam! Mən **Promi** 🤖, sənin robot dostun! Səninlə tanış olmağıma ç
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Mən AI-yam! Sənin mesajlarını oxuya və kömək etməyə çalışa bilərəm. Amma budur sirr... Ən yaxşı işi görmək üçün **yaxşı təlimatlara** ehtiyacım var! Mən AI-yam! Sənin mesajlarını oxuya və kömək etməyə çalışa bilərəm. Amma budur sirr... Ən yaxşı işi görmək üçün **yaxşı təlimatlara** ehtiyacım var!
</Panel> </Panel>
</Section>
<Section>
## Prompt Nədir? ## Prompt Nədir?
**Prompt** sadəcə mənim kimi AI-ya göndərdiyin mesaj deməkdir. **Prompt** sadəcə mənim kimi AI-ya göndərdiyin mesaj deməkdir.
@@ -19,7 +22,9 @@ Bunu dostuna yol göstərmək kimi düşün. "Ora get!" desən, dostun hara getm
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Yaxşı prompt yazdığında, nə istədiyini başa düşə və sənə daha yaxşı kömək edə bilərəm! Gəl məşq edək! Yaxşı prompt yazdığında, nə istədiyini başa düşə və sənə daha yaxşı kömək edə bilərəm! Gəl məşq edək!
</Panel> </Panel>
</Section>
<Section>
## Gəl Cəhd Edək! ## Gəl Cəhd Edək!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Yaxşı prompt yazdığında, nə istədiyini başa düşə və sənə daha yax
explanation="Birinci mesaj Promi-yə dəqiq hansı növ hekayə yazacağını deyir! İkincisi çox qısadır - Promi hansı növ hekayə istədiyini bilmir." explanation="Birinci mesaj Promi-yə dəqiq hansı növ hekayə yazacağını deyir! İkincisi çox qısadır - Promi hansı növ hekayə istədiyini bilmir."
promiMessage="Gördün? Daha çox detal nə istədiyini başa düşməyimə kömək edir!" promiMessage="Gördün? Daha çox detal nə istədiyini başa düşməyimə kömək edir!"
/> />
</Section>
<Section>
## Sürətli Test! ## Sürətli Test!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Yaxşı prompt yazdığında, nə istədiyini başa düşə və sənə daha yax
explanation="Prompt AI-ya nəyə ehtiyacın olduğunu söyləmək üçün sözlər istifadə edir. Emojilər əyləncəlidir amma kifayət qədər məlumat vermir!" explanation="Prompt AI-ya nəyə ehtiyacın olduğunu söyləmək üçün sözlər istifadə edir. Emojilər əyləncəlidir amma kifayət qədər məlumat vermir!"
promiMessage="Sözlər mənim super gücümdür! Mənə nə qədər çox desən, o qədər yaxşı kömək edə bilərəm!" promiMessage="Sözlər mənim super gücümdür! Mənə nə qədər çox desən, o qədər yaxşı kömək edə bilərəm!"
/> />
</Section>
<Section>
## Bacardın! 🎉 ## Bacardın! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Əla iş! AI-ın nə olduğunu və promptun nə olduğunu öyrəndin. Artıq prompt mütəxəssisi olursan! Əla iş! AI-ın nə olduğunu və promptun nə olduğunu öyrəndin. Artıq prompt mütəxəssisi olursan!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="AI və promptların nə olduğunu öyrəndin!" message="AI və promptların nə olduğunu öyrəndin!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Xoş gəldin geri, dost! İlk əsl promptlarını yazmağa hazırsan? Gedək! 🚀 Xoş gəldin geri, dost! İlk əsl promptlarını yazmağa hazırsan? Gedək! 🚀
</Panel> </Panel>
</Section>
<Section>
## Sözlərin Sehri ## Sözlərin Sehri
AI ilə danışanda hər söz önəmlidir! Gəl görək daha çox söz əlavə etmək promptları necə yaxşılaşdırır. AI ilə danışanda hər söz önəmlidir! Gəl görək daha çox söz əlavə etmək promptları necə yaxşılaşdırır.
@@ -9,7 +12,9 @@ AI ilə danışanda hər söz önəmlidir! Gəl görək daha çox söz əlavə e
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Bax! Kimsə mənə sadəcə "pişik" desə, nə istədiklərini bilmirəm. Şəkil istəyirlər? Hekayə? Pişiklər haqqında faktlar? Çaşmışam! 😵‍💫 Bax! Kimsə mənə sadəcə "pişik" desə, nə istədiklərini bilmirəm. Şəkil istəyirlər? Hekayə? Pişiklər haqqında faktlar? Çaşmışam! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Daha Yaxşı Promptlar Qurmaq ## Daha Yaxşı Promptlar Qurmaq
Yaxşı promptun **üç hissəsi** var: Yaxşı promptun **üç hissəsi** var:
@@ -21,7 +26,9 @@ Yaxşı promptun **üç hissəsi** var:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Gəl birlikdə prompt quraq! Gəl birlikdə prompt quraq!
</Panel> </Panel>
</Section>
<Section>
## Parçaları Sürüklə! ## Parçaları Sürüklə!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Gəl birlikdə prompt quraq!
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Mükəmməl! Bu əla promptdur!" successMessage="Mükəmməl! Bu əla promptdur!"
/> />
</Section>
<Section>
## Boşluqları Doldur! ## Boşluqları Doldur!
İndi sehrli sözləri sürükləyərək öz promptunu etməyə çalış: İndi sehrli sözləri sürükləyərək öz promptunu etməyə çalış:
<MagicWords <MagicWords
title="Öz promptunu yarat! ✨" title="Öz promptunu yarat! ✨"
sentence="Zəhmət olmasa {{type}} yaz, {{character}} haqqında, {{action}}" sentence="Zəhmət olmasa {{type}} yaz, {{character}} haqqında, {{action}}"
@@ -51,7 +61,9 @@ Gəl birlikdə prompt quraq!
]} ]}
successMessage="Vay! Möhtəşəm prompt yaratdın!" successMessage="Vay! Möhtəşəm prompt yaratdın!"
/> />
</Section>
<Section>
## Seçmə Növbəsi Səndədir! ## Seçmə Növbəsi Səndədir!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Gəl birlikdə prompt quraq!
explanation="Birinci prompt mənə gülməli olmalı olduğunu, pinqvin haqqında olduğunu VƏ pinqvinin nə etmək istədiyini deyir!" explanation="Birinci prompt mənə gülməli olmalı olduğunu, pinqvin haqqında olduğunu VƏ pinqvinin nə etmək istədiyini deyir!"
promiMessage="Detaillar hər şeyi daha yaxşı edir! Dəqiq nə istədiyini bilməyi sevirəm!" promiMessage="Detaillar hər şeyi daha yaxşı edir! Dəqiq nə istədiyini bilməyi sevirəm!"
/> />
</Section>
<Section>
## Əla İş! 🌟 ## Əla İş! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
İlk promptlarını yazdın! Yaxşı promptlara lazım olanı öyrəndin: nə istəyirsən, mövzu və detaillar. Həqiqətən yaxşılaşırsan! İlk promptlarını yazdın! Yaxşı promptlara lazım olanı öyrəndin: nə istəyirsən, mövzu və detaillar. Həqiqətən yaxşılaşırsan!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="İlk promptlarını yazmağı öyrəndin!" message="İlk promptlarını yazmağı öyrəndin!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Salam superstar! 🌟 Bu gün ən vacib bacarığı öyrənəcəyik: **AYDIN** olmaq! Salam superstar! 🌟 Bu gün ən vacib bacarığı öyrənəcəyik: **AYDIN** olmaq!
</Panel> </Panel>
</Section>
<Section>
## Niyə Aydın Olmaq Vacibdir ## Niyə Aydın Olmaq Vacibdir
Anandan "yemək" istəməklə "qabıqsız fıstıq yağı sendviçi" istəməyin fərqini təsəvvür et. Hansı sənə dəqiq istədiyini verir? Anandan "yemək" istəməklə "qabıqsız fıstıq yağı sendviçi" istəməyin fərqini təsəvvür et. Hansı sənə dəqiq istədiyini verir?
@@ -9,11 +12,14 @@ Anandan "yemək" istəməklə "qabıqsız fıstıq yağı sendviçi" istəməyin
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Mənimlə eynidir! Aydın olanda, dəqiq necə kömək edəcəyimi bilirəm. Qeyri-müəyyən olanda, təxmin etməliyəm... və səhv edə bilərəm! Mənimlə eynidir! Aydın olanda, dəqiq necə kömək edəcəyimi bilirəm. Qeyri-müəyyən olanda, təxmin etməliyəm... və səhv edə bilərəm!
</Panel> </Panel>
</Section>
<Section>
## Aydın vs. Aydın Deyil ## Aydın vs. Aydın Deyil
Gəl fərqi tapmağı məşq edək! Gəl fərqi tapmağı məşq edək!
<PromptVsMistake <PromptVsMistake
question="Hansı prompt daha aydındır?" question="Hansı prompt daha aydındır?"
good="Bağçada kəpənəklər haqqında qafiyəli sözlərlə 4 sətirlik şeir yaz" good="Bağçada kəpənəklər haqqında qafiyəli sözlərlə 4 sətirlik şeir yaz"
@@ -22,6 +28,7 @@ Gəl fərqi tapmağı məşq edək!
promiMessage="Aydın promptlar = daha yaxşı nəticələr! Bu sehr kimidir!" promiMessage="Aydın promptlar = daha yaxşı nəticələr! Bu sehr kimidir!"
/> />
<PromptVsMistake <PromptVsMistake
question="Hansı mənə dəqiq nəyə ehtiyacın olduğunu deyir?" question="Hansı mənə dəqiq nəyə ehtiyacın olduğunu deyir?"
good="10 yaşlı uşağın bəyənəcəyi delfinlər haqqında 3 əyləncəli fakt yazmağıma kömək et" good="10 yaşlı uşağın bəyənəcəyi delfinlər haqqında 3 əyləncəli fakt yazmağıma kömək et"
@@ -29,11 +36,14 @@ Gəl fərqi tapmağı məşq edək!
explanation="Birinci prompt mənə deyir: neçə fakt (3), hansı növ (əyləncəli), və kimin üçün (10 yaşlı). Bu çox kömək edir!" explanation="Birinci prompt mənə deyir: neçə fakt (3), hansı növ (əyləncəli), və kimin üçün (10 yaşlı). Bu çox kömək edir!"
promiMessage="Kimin üçün olduğunu desən, onlar üçün mükəmməl edə bilərəm!" promiMessage="Kimin üçün olduğunu desən, onlar üçün mükəmməl edə bilərəm!"
/> />
</Section>
<Section>
## Aydınlıq Çağırışı ## Aydınlıq Çağırışı
Gəl ən aydın promptu quraq! Gəl ən aydın promptu quraq!
<DragDropPrompt <DragDropPrompt
title="Kristal kimi aydın et! 💎" title="Kristal kimi aydın et! 💎"
instruction="Super aydın prompt etmək üçün bu parçaları düzəlt" instruction="Super aydın prompt etmək üçün bu parçaları düzəlt"
@@ -47,7 +57,9 @@ Gəl ən aydın promptu quraq!
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="Bu indiyə qədər ən aydın promptdur! Möhtəşəm!" successMessage="Bu indiyə qədər ən aydın promptdur! Möhtəşəm!"
/> />
</Section>
<Section>
## Aydın Detaillar Əlavə Et ## Aydın Detaillar Əlavə Et
<MagicWords <MagicWords
@@ -61,7 +73,9 @@ Gəl ən aydın promptu quraq!
]} ]}
successMessage="Bütün vacib detailları əlavə etdin! Əla iş!" successMessage="Bütün vacib detailları əlavə etdin! Əla iş!"
/> />
</Section>
<Section>
## Aydınlığın Qızıl Qaydaları ## Aydınlığın Qızıl Qaydaları
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@ Prompt yazanda bu üç sualı xatırla:
2. **NECƏ** olmalıdır? (qısa, gülməli, sadə) 2. **NECƏ** olmalıdır? (qısa, gülməli, sadə)
3. **KİM** üçündür? (mən, dostum, sinifim) 3. **KİM** üçündür? (mən, dostum, sinifim)
<PromptVsMistake <PromptVsMistake
question="Son çağırış! Hansı üç qaydanın hamısını istifadə edir?" question="Son çağırış! Hansı üç qaydanın hamısını istifadə edir?"
good="Nahar vaxtı dostlarıma deyə biləcəyim pizza haqqında qısa, gülməli zarafat yaz" good="Nahar vaxtı dostlarıma deyə biləcəyim pizza haqqında qısa, gülməli zarafat yaz"
@@ -81,7 +96,9 @@ Prompt yazanda bu üç sualı xatırla:
explanation="Əla promptda NƏ (pizza zarafatı), NECƏ (qısa və gülməli), və KİM üçün (naharda dostlara demək) var!" explanation="Əla promptda NƏ (pizza zarafatı), NECƏ (qısa və gülməli), və KİM üçün (naharda dostlara demək) var!"
promiMessage="Sən aydınlıq çempionusan! 🏆" promiMessage="Sən aydınlıq çempionusan! 🏆"
/> />
</Section>
<Section>
## Dünya 1 Tamamlandı! 🎊 ## Dünya 1 Tamamlandı! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@ VAY! Bütün Dünya 1-i bitirdin! Öyrəndiklərin:
Yeni macəralara hazırsan! Yeni macəralara hazırsan!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="Aydın olmaq sənətini mənimsədin! Dünya 1 tamamlandı!" message="Aydın olmaq sənətini mənimsədin! Dünya 1 tamamlandı!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Hallo! Ich bin **Promi** 🤖, dein Roboter-Freund! Ich freue mich so, dich kennenzulernen! Hallo! Ich bin **Promi** 🤖, dein Roboter-Freund! Ich freue mich so, dich kennenzulernen!
</Panel> </Panel>
@@ -9,7 +10,9 @@ Weißt du, was **KI** bedeutet? KI steht für **Künstliche Intelligenz**. Das i
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Ich bin eine KI! Ich kann deine Nachrichten lesen und versuchen dir zu helfen. Aber hier ist das Geheimnis... Ich brauche **gute Anweisungen** um meine beste Arbeit zu machen! Ich bin eine KI! Ich kann deine Nachrichten lesen und versuchen dir zu helfen. Aber hier ist das Geheimnis... Ich brauche **gute Anweisungen** um meine beste Arbeit zu machen!
</Panel> </Panel>
</Section>
<Section>
## Was ist ein Prompt? ## Was ist ein Prompt?
Ein **Prompt** ist einfach ein schickes Wort für die Nachricht, die du an eine KI wie mich sendest. Ein **Prompt** ist einfach ein schickes Wort für die Nachricht, die du an eine KI wie mich sendest.
@@ -19,7 +22,9 @@ Stell dir vor, du gibst einem Freund Wegbeschreibungen. Wenn du sagst "Geh dorth
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Wenn du einen guten Prompt schreibst, kann ich verstehen, was du willst und dir besser helfen! Lass uns üben! Wenn du einen guten Prompt schreibst, kann ich verstehen, was du willst und dir besser helfen! Lass uns üben!
</Panel> </Panel>
</Section>
<Section>
## Probieren wir es! ## Probieren wir es!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Wenn du einen guten Prompt schreibst, kann ich verstehen, was du willst und dir
explanation="Die erste Nachricht sagt Promi genau, welche Art von Geschichte geschrieben werden soll! Die zweite ist zu kurz - Promi weiß nicht, welche Art von Geschichte du willst." explanation="Die erste Nachricht sagt Promi genau, welche Art von Geschichte geschrieben werden soll! Die zweite ist zu kurz - Promi weiß nicht, welche Art von Geschichte du willst."
promiMessage="Siehst du? Mehr Details helfen mir zu verstehen, was du willst!" promiMessage="Siehst du? Mehr Details helfen mir zu verstehen, was du willst!"
/> />
</Section>
<Section>
## Schnelles Quiz! ## Schnelles Quiz!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Wenn du einen guten Prompt schreibst, kann ich verstehen, was du willst und dir
explanation="Ein Prompt benutzt Worte, um der KI zu sagen, was du brauchst. Emojis sind lustig, aber geben nicht genug Informationen!" explanation="Ein Prompt benutzt Worte, um der KI zu sagen, was du brauchst. Emojis sind lustig, aber geben nicht genug Informationen!"
promiMessage="Worte sind meine Superkraft! Je mehr du mir sagst, desto besser kann ich helfen!" promiMessage="Worte sind meine Superkraft! Je mehr du mir sagst, desto besser kann ich helfen!"
/> />
</Section>
<Section>
## Du hast es geschafft! 🎉 ## Du hast es geschafft! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Tolle Arbeit! Du hast gelernt, was KI ist und was ein Prompt ist. Du wirst schon ein Prompt-Experte! Tolle Arbeit! Du hast gelernt, was KI ist und was ein Prompt ist. Du wirst schon ein Prompt-Experte!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="Du hast gelernt, was KI und Prompts sind!" message="Du hast gelernt, was KI und Prompts sind!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Willkommen zurück, Freund! Bereit, deine ersten echten Prompts zu schreiben? Los geht's! 🚀 Willkommen zurück, Freund! Bereit, deine ersten echten Prompts zu schreiben? Los geht's! 🚀
</Panel> </Panel>
</Section>
<Section>
## Die Magie der Worte ## Die Magie der Worte
Wenn du mit KI sprichst, zählt jedes Wort! Lass uns sehen, wie mehr Worte Prompts besser machen. Wenn du mit KI sprichst, zählt jedes Wort! Lass uns sehen, wie mehr Worte Prompts besser machen.
@@ -9,7 +12,9 @@ Wenn du mit KI sprichst, zählt jedes Wort! Lass uns sehen, wie mehr Worte Promp
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Schau mal! Wenn jemand nur "Katze" zu mir sagt, weiß ich nicht, was sie wollen. Wollen sie ein Bild? Eine Geschichte? Fakten über Katzen? Ich bin verwirrt! 😵‍💫 Schau mal! Wenn jemand nur "Katze" zu mir sagt, weiß ich nicht, was sie wollen. Wollen sie ein Bild? Eine Geschichte? Fakten über Katzen? Ich bin verwirrt! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Bessere Prompts Bauen ## Bessere Prompts Bauen
Ein guter Prompt hat **drei Teile**: Ein guter Prompt hat **drei Teile**:
@@ -21,7 +26,9 @@ Ein guter Prompt hat **drei Teile**:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Lass uns zusammen einen Prompt bauen! Lass uns zusammen einen Prompt bauen!
</Panel> </Panel>
</Section>
<Section>
## Ziehe die Teile! ## Ziehe die Teile!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Lass uns zusammen einen Prompt bauen!
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Perfekt! Das ist ein toller Prompt!" successMessage="Perfekt! Das ist ein toller Prompt!"
/> />
</Section>
<Section>
## Fülle die Lücken! ## Fülle die Lücken!
Versuche jetzt, deinen eigenen Prompt zu machen, indem du die Zauberwörter ziehst: Versuche jetzt, deinen eigenen Prompt zu machen, indem du die Zauberwörter ziehst:
<MagicWords <MagicWords
title="Erstelle deinen eigenen Prompt! ✨" title="Erstelle deinen eigenen Prompt! ✨"
sentence="Bitte schreibe eine {{type}} über einen {{character}}, der {{action}}" sentence="Bitte schreibe eine {{type}} über einen {{character}}, der {{action}}"
@@ -51,7 +61,9 @@ Versuche jetzt, deinen eigenen Prompt zu machen, indem du die Zauberwörter zieh
]} ]}
successMessage="Wow! Du hast einen tollen Prompt erstellt!" successMessage="Wow! Du hast einen tollen Prompt erstellt!"
/> />
</Section>
<Section>
## Du bist dran! ## Du bist dran!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Versuche jetzt, deinen eigenen Prompt zu machen, indem du die Zauberwörter zieh
explanation="Der erste Prompt sagt mir, es soll lustig sein, es geht um einen Pinguin, UND was der Pinguin machen will!" explanation="Der erste Prompt sagt mir, es soll lustig sein, es geht um einen Pinguin, UND was der Pinguin machen will!"
promiMessage="Details machen alles besser! Ich liebe es, genau zu wissen, was du willst!" promiMessage="Details machen alles besser! Ich liebe es, genau zu wissen, was du willst!"
/> />
</Section>
<Section>
## Tolle Arbeit! 🌟 ## Tolle Arbeit! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Du hast deine ersten Prompts geschrieben! Du hast gelernt, dass gute Prompts brauchen: was du willst, ein Thema und Details. Du wirst wirklich gut darin! Du hast deine ersten Prompts geschrieben! Du hast gelernt, dass gute Prompts brauchen: was du willst, ein Thema und Details. Du wirst wirklich gut darin!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="Du hast gelernt, wie man erste Prompts schreibt!" message="Du hast gelernt, wie man erste Prompts schreibt!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Hey Superstar! 🌟 Heute lernen wir die wichtigste Fähigkeit: **KLAR** sein! Hey Superstar! 🌟 Heute lernen wir die wichtigste Fähigkeit: **KLAR** sein!
</Panel> </Panel>
</Section>
<Section>
## Warum Klar Sein Wichtig Ist ## Warum Klar Sein Wichtig Ist
Stell dir vor, du bittest deine Mama um "Essen" vs. um "ein Erdnussbutter-Sandwich ohne Kruste." Was gibt dir genau das, was du willst? Stell dir vor, du bittest deine Mama um "Essen" vs. um "ein Erdnussbutter-Sandwich ohne Kruste." Was gibt dir genau das, was du willst?
@@ -9,11 +12,14 @@ Stell dir vor, du bittest deine Mama um "Essen" vs. um "ein Erdnussbutter-Sandwi
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Bei mir ist es genauso! Wenn du klar bist, weiß ich genau, wie ich helfen kann. Wenn du vage bist, muss ich raten... und ich könnte falsch raten! Bei mir ist es genauso! Wenn du klar bist, weiß ich genau, wie ich helfen kann. Wenn du vage bist, muss ich raten... und ich könnte falsch raten!
</Panel> </Panel>
</Section>
<Section>
## Klar vs. Unklar ## Klar vs. Unklar
Lass uns üben, den Unterschied zu erkennen! Lass uns üben, den Unterschied zu erkennen!
<PromptVsMistake <PromptVsMistake
question="Welcher Prompt ist klarer?" question="Welcher Prompt ist klarer?"
good="Schreibe ein 4-zeiliges Gedicht über Schmetterlinge in einem Garten mit reimenden Worten" good="Schreibe ein 4-zeiliges Gedicht über Schmetterlinge in einem Garten mit reimenden Worten"
@@ -22,6 +28,7 @@ Lass uns üben, den Unterschied zu erkennen!
promiMessage="Klare Prompts = bessere Ergebnisse! Es ist wie Magie!" promiMessage="Klare Prompts = bessere Ergebnisse! Es ist wie Magie!"
/> />
<PromptVsMistake <PromptVsMistake
question="Welcher sagt mir genau, was du brauchst?" question="Welcher sagt mir genau, was du brauchst?"
good="Hilf mir, 3 lustige Fakten über Delfine zu schreiben, die ein 10-Jähriger mögen würde" good="Hilf mir, 3 lustige Fakten über Delfine zu schreiben, die ein 10-Jähriger mögen würde"
@@ -29,11 +36,14 @@ Lass uns üben, den Unterschied zu erkennen!
explanation="Der erste Prompt sagt mir: wie viele Fakten (3), welche Art (lustig), und für wen (10-Jähriger). Das hilft sehr!" explanation="Der erste Prompt sagt mir: wie viele Fakten (3), welche Art (lustig), und für wen (10-Jähriger). Das hilft sehr!"
promiMessage="Wenn du mir sagst, für wen es ist, kann ich es perfekt für sie machen!" promiMessage="Wenn du mir sagst, für wen es ist, kann ich es perfekt für sie machen!"
/> />
</Section>
<Section>
## Die Klarheits-Herausforderung ## Die Klarheits-Herausforderung
Lass uns den klarsten Prompt aller Zeiten bauen! Lass uns den klarsten Prompt aller Zeiten bauen!
<DragDropPrompt <DragDropPrompt
title="Mach es kristallklar! 💎" title="Mach es kristallklar! 💎"
instruction="Ordne diese Teile an, um einen super klaren Prompt zu machen" instruction="Ordne diese Teile an, um einen super klaren Prompt zu machen"
@@ -47,7 +57,9 @@ Lass uns den klarsten Prompt aller Zeiten bauen!
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="Das ist der klarste Prompt aller Zeiten! Toll!" successMessage="Das ist der klarste Prompt aller Zeiten! Toll!"
/> />
</Section>
<Section>
## Füge Klare Details Hinzu ## Füge Klare Details Hinzu
<MagicWords <MagicWords
@@ -61,7 +73,9 @@ Lass uns den klarsten Prompt aller Zeiten bauen!
]} ]}
successMessage="Du hast alle wichtigen Details hinzugefügt! Gute Arbeit!" successMessage="Du hast alle wichtigen Details hinzugefügt! Gute Arbeit!"
/> />
</Section>
<Section>
## Die Goldenen Regeln der Klarheit ## Die Goldenen Regeln der Klarheit
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@ Erinnere dich an diese drei Fragen, wenn du einen Prompt schreibst:
2. **WIE** soll es sein? (kurz, lustig, einfach) 2. **WIE** soll es sein? (kurz, lustig, einfach)
3. **FÜR WEN** ist es? (mich, meinen Freund, meine Klasse) 3. **FÜR WEN** ist es? (mich, meinen Freund, meine Klasse)
<PromptVsMistake <PromptVsMistake
question="Letzte Herausforderung! Welcher benutzt alle drei Regeln?" question="Letzte Herausforderung! Welcher benutzt alle drei Regeln?"
good="Schreibe einen kurzen, lustigen Witz über Pizza, den ich meinen Freunden beim Mittagessen erzählen kann" good="Schreibe einen kurzen, lustigen Witz über Pizza, den ich meinen Freunden beim Mittagessen erzählen kann"
@@ -81,7 +96,9 @@ Erinnere dich an diese drei Fragen, wenn du einen Prompt schreibst:
explanation="Der tolle Prompt hat WAS (ein Witz über Pizza), WIE (kurz und lustig), und FÜR WEN (Freunden beim Mittagessen erzählen)!" explanation="Der tolle Prompt hat WAS (ein Witz über Pizza), WIE (kurz und lustig), und FÜR WEN (Freunden beim Mittagessen erzählen)!"
promiMessage="Du bist ein Klarheits-Champion! 🏆" promiMessage="Du bist ein Klarheits-Champion! 🏆"
/> />
</Section>
<Section>
## Welt 1 Abgeschlossen! 🎊 ## Welt 1 Abgeschlossen! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@ WOW! Du hast die ganze Welt 1 beendet! Du hast gelernt:
Du bist bereit für neue Abenteuer! Du bist bereit für neue Abenteuer!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="Du hast die Kunst des Klar-Seins gemeistert! Welt 1 abgeschlossen!" message="Du hast die Kunst des Klar-Seins gemeistert! Welt 1 abgeschlossen!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Γεια! Είμαι ο **Promi** 🤖, ο ρομπότ φίλος σου! Χαίρομαι πολύ που σε γνωρίζω! Γεια! Είμαι ο **Promi** 🤖, ο ρομπότ φίλος σου! Χαίρομαι πολύ που σε γνωρίζω!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Είμαι AI! Μπορώ να διαβάζω τα μηνύματά σου και να προσπαθώ να βοηθήσω. Αλλά να το μυστικό... Χρειάζομαι **καλές οδηγίες** για να κάνω τη καλύτερη δουλειά! Είμαι AI! Μπορώ να διαβάζω τα μηνύματά σου και να προσπαθώ να βοηθήσω. Αλλά να το μυστικό... Χρειάζομαι **καλές οδηγίες** για να κάνω τη καλύτερη δουλειά!
</Panel> </Panel>
</Section>
<Section>
## Τι είναι ένα Prompt; ## Τι είναι ένα Prompt;
Ένα **prompt** είναι απλά μια κομψή λέξη για το μήνυμα που στέλνεις σε ένα AI σαν εμένα. Ένα **prompt** είναι απλά μια κομψή λέξη για το μήνυμα που στέλνεις σε ένα AI σαν εμένα.
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Όταν γράφεις καλό prompt, μπορώ να καταλάβω τι θέλεις και να σε βοηθήσω καλύτερα! Ας εξασκηθούμε! Όταν γράφεις καλό prompt, μπορώ να καταλάβω τι θέλεις και να σε βοηθήσω καλύτερα! Ας εξασκηθούμε!
</Panel> </Panel>
</Section>
<Section>
## Ας Δοκιμάσουμε! ## Ας Δοκιμάσουμε!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="Το πρώτο μήνυμα λέει στον Promi ακριβώς τι είδους ιστορία να γράψει! Το δεύτερο είναι πολύ μικρό - ο Promi δεν ξέρει τι είδους ιστορία θέλεις." explanation="Το πρώτο μήνυμα λέει στον Promi ακριβώς τι είδους ιστορία να γράψει! Το δεύτερο είναι πολύ μικρό - ο Promi δεν ξέρει τι είδους ιστορία θέλεις."
promiMessage="Βλέπεις; Περισσότερες λεπτομέρειες με βοηθούν να καταλάβω τι θέλεις!" promiMessage="Βλέπεις; Περισσότερες λεπτομέρειες με βοηθούν να καταλάβω τι θέλεις!"
/> />
</Section>
<Section>
## Γρήγορο Κουίζ! ## Γρήγορο Κουίζ!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="Ένα prompt χρησιμοποιεί λέξεις για να πει στο AI τι χρειάζεσαι. Τα emoji είναι διασκεδαστικά αλλά δεν δίνουν αρκετές πληροφορίες!" explanation="Ένα prompt χρησιμοποιεί λέξεις για να πει στο AI τι χρειάζεσαι. Τα emoji είναι διασκεδαστικά αλλά δεν δίνουν αρκετές πληροφορίες!"
promiMessage="Οι λέξεις είναι η υπερδύναμή μου! Όσο περισσότερα μου λες, τόσο καλύτερα μπορώ να βοηθήσω!" promiMessage="Οι λέξεις είναι η υπερδύναμή μου! Όσο περισσότερα μου λες, τόσο καλύτερα μπορώ να βοηθήσω!"
/> />
</Section>
<Section>
## Τα Κατάφερες! 🎉 ## Τα Κατάφερες! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Καταπληκτική δουλειά! Έμαθες τι είναι το AI και τι είναι prompt. Γίνεσαι ήδη ειδικός στα prompts! Καταπληκτική δουλειά! Έμαθες τι είναι το AI και τι είναι prompt. Γίνεσαι ήδη ειδικός στα prompts!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="Έμαθες τι είναι AI και prompts!" message="Έμαθες τι είναι AI και prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Καλώς ήρθες πάλι, φίλε! Έτοιμος να γράψεις τα πρώτα σου αληθινά prompts; Πάμε! 🚀 Καλώς ήρθες πάλι, φίλε! Έτοιμος να γράψεις τα πρώτα σου αληθινά prompts; Πάμε! 🚀
</Panel> </Panel>
</Section>
<Section>
## Η Μαγεία των Λέξεων ## Η Μαγεία των Λέξεων
Όταν μιλάς με το AI, κάθε λέξη μετράει! Ας δούμε πώς η προσθήκη λέξεων κάνει τα prompts καλύτερα. Όταν μιλάς με το AI, κάθε λέξη μετράει! Ας δούμε πώς η προσθήκη λέξεων κάνει τα prompts καλύτερα.
@@ -9,7 +12,9 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Κοίτα! Αν κάποιος μου πει μόνο "γάτα", δεν ξέρω τι θέλουν. Θέλουν εικόνα; Ιστορία; Γεγονότα για γάτες; Είμαι μπερδεμένος! 😵‍💫 Κοίτα! Αν κάποιος μου πει μόνο "γάτα", δεν ξέρω τι θέλουν. Θέλουν εικόνα; Ιστορία; Γεγονότα για γάτες; Είμαι μπερδεμένος! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Χτίζοντας Καλύτερα Prompts ## Χτίζοντας Καλύτερα Prompts
Ένα καλό prompt έχει **τρία μέρη**: Ένα καλό prompt έχει **τρία μέρη**:
@@ -21,7 +26,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Ας χτίσουμε ένα prompt μαζί! Ας χτίσουμε ένα prompt μαζί!
</Panel> </Panel>
</Section>
<Section>
## Σύρε τα Κομμάτια! ## Σύρε τα Κομμάτια!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Τέλειο! Αυτό είναι εξαιρετικό prompt!" successMessage="Τέλειο! Αυτό είναι εξαιρετικό prompt!"
/> />
</Section>
<Section>
## Συμπλήρωσε τα Κενά! ## Συμπλήρωσε τα Κενά!
Τώρα δοκίμασε να φτιάξεις το δικό σου prompt σύροντας τις μαγικές λέξεις: Τώρα δοκίμασε να φτιάξεις το δικό σου prompt σύροντας τις μαγικές λέξεις:
<MagicWords <MagicWords
title="Δημιούργησε το δικό σου prompt! ✨" title="Δημιούργησε το δικό σου prompt! ✨"
sentence="Παρακαλώ γράψε {{type}} για {{character}} που {{action}}" sentence="Παρακαλώ γράψε {{type}} για {{character}} που {{action}}"
@@ -51,7 +61,9 @@
]} ]}
successMessage="Ουάου! Δημιούργησες καταπληκτικό prompt!" successMessage="Ουάου! Δημιούργησες καταπληκτικό prompt!"
/> />
</Section>
<Section>
## Η Σειρά Σου να Διαλέξεις! ## Η Σειρά Σου να Διαλέξεις!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@
explanation="Το πρώτο prompt μου λέει ότι πρέπει να είναι αστείο, είναι για πιγκουίνο, ΚΑΙ τι θέλει να κάνει ο πιγκουίνος!" explanation="Το πρώτο prompt μου λέει ότι πρέπει να είναι αστείο, είναι για πιγκουίνο, ΚΑΙ τι θέλει να κάνει ο πιγκουίνος!"
promiMessage="Οι λεπτομέρειες κάνουν τα πάντα καλύτερα! Λατρεύω να ξέρω ακριβώς τι θέλεις!" promiMessage="Οι λεπτομέρειες κάνουν τα πάντα καλύτερα! Λατρεύω να ξέρω ακριβώς τι θέλεις!"
/> />
</Section>
<Section>
## Εξαιρετική Δουλειά! 🌟 ## Εξαιρετική Δουλειά! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Έγραψες τα πρώτα σου prompts! Έμαθες ότι τα καλά prompts χρειάζονται: τι θέλεις, θέμα και λεπτομέρειες. Γίνεσαι πολύ καλός! Έγραψες τα πρώτα σου prompts! Έμαθες ότι τα καλά prompts χρειάζονται: τι θέλεις, θέμα και λεπτομέρειες. Γίνεσαι πολύ καλός!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="Έμαθες πώς να γράφεις τα πρώτα σου prompts!" message="Έμαθες πώς να γράφεις τα πρώτα σου prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Γεια σούπερ αστέρι! 🌟 Σήμερα θα μάθουμε την πιο σημαντική ικανότητα: να είσαι **ΣΑΦΗΣ**! Γεια σούπερ αστέρι! 🌟 Σήμερα θα μάθουμε την πιο σημαντική ικανότητα: να είσαι **ΣΑΦΗΣ**!
</Panel> </Panel>
</Section>
<Section>
## Γιατί το να Είσαι Σαφής Είναι Σημαντικό ## Γιατί το να Είσαι Σαφής Είναι Σημαντικό
Φαντάσου να ζητάς από τη μαμά σου "φαγητό" έναντι "σάντουιτς με φιστικοβούτυρο χωρίς κόρα." Ποιο σου δίνει ακριβώς αυτό που θέλεις; Φαντάσου να ζητάς από τη μαμά σου "φαγητό" έναντι "σάντουιτς με φιστικοβούτυρο χωρίς κόρα." Ποιο σου δίνει ακριβώς αυτό που θέλεις;
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Το ίδιο είναι και μαζί μου! Όταν είσαι σαφής, ξέρω ακριβώς πώς να βοηθήσω. Όταν είσαι αόριστος, πρέπει να μαντέψω... και μπορεί να κάνω λάθος! Το ίδιο είναι και μαζί μου! Όταν είσαι σαφής, ξέρω ακριβώς πώς να βοηθήσω. Όταν είσαι αόριστος, πρέπει να μαντέψω... και μπορεί να κάνω λάθος!
</Panel> </Panel>
</Section>
<Section>
## Σαφές vs. Ασαφές ## Σαφές vs. Ασαφές
Ας εξασκηθούμε να βρίσκουμε τη διαφορά! Ας εξασκηθούμε να βρίσκουμε τη διαφορά!
<PromptVsMistake <PromptVsMistake
question="Ποιο prompt είναι πιο σαφές;" question="Ποιο prompt είναι πιο σαφές;"
good="Γράψε ένα ποίημα 4 γραμμών για πεταλούδες σε κήπο, με ομοιοκαταληξία" good="Γράψε ένα ποίημα 4 γραμμών για πεταλούδες σε κήπο, με ομοιοκαταληξία"
@@ -22,6 +28,7 @@
promiMessage="Σαφή prompts = καλύτερα αποτελέσματα! Είναι σαν μαγεία!" promiMessage="Σαφή prompts = καλύτερα αποτελέσματα! Είναι σαν μαγεία!"
/> />
<PromptVsMistake <PromptVsMistake
question="Ποιο μου λέει ακριβώς τι χρειάζεσαι;" question="Ποιο μου λέει ακριβώς τι χρειάζεσαι;"
good="Βοήθησέ με να γράψω 3 διασκεδαστικά γεγονότα για δελφίνια που θα άρεσαν σε παιδί 10 ετών" good="Βοήθησέ με να γράψω 3 διασκεδαστικά γεγονότα για δελφίνια που θα άρεσαν σε παιδί 10 ετών"
@@ -29,11 +36,14 @@
explanation="Το πρώτο prompt μου λέει: πόσα γεγονότα (3), τι είδους (διασκεδαστικά), και για ποιον (παιδί 10 ετών). Αυτό βοηθάει πολύ!" explanation="Το πρώτο prompt μου λέει: πόσα γεγονότα (3), τι είδους (διασκεδαστικά), και για ποιον (παιδί 10 ετών). Αυτό βοηθάει πολύ!"
promiMessage="Όταν μου λες για ποιον είναι, μπορώ να το κάνω τέλειο για αυτούς!" promiMessage="Όταν μου λες για ποιον είναι, μπορώ να το κάνω τέλειο για αυτούς!"
/> />
</Section>
<Section>
## Η Πρόκληση της Σαφήνειας ## Η Πρόκληση της Σαφήνειας
Ας χτίσουμε το πιο σαφές prompt! Ας χτίσουμε το πιο σαφές prompt!
<DragDropPrompt <DragDropPrompt
title="Κάντο κρυστάλλινο! 💎" title="Κάντο κρυστάλλινο! 💎"
instruction="Τακτοποίησε αυτά τα κομμάτια για να φτιάξεις σούπερ σαφές prompt" instruction="Τακτοποίησε αυτά τα κομμάτια για να φτιάξεις σούπερ σαφές prompt"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="Αυτό είναι το πιο σαφές prompt! Καταπληκτικό!" successMessage="Αυτό είναι το πιο σαφές prompt! Καταπληκτικό!"
/> />
</Section>
<Section>
## Πρόσθεσε Σαφείς Λεπτομέρειες ## Πρόσθεσε Σαφείς Λεπτομέρειες
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="Πρόσθεσες όλες τις σημαντικές λεπτομέρειες! Εξαιρετική δουλειά!" successMessage="Πρόσθεσες όλες τις σημαντικές λεπτομέρειες! Εξαιρετική δουλειά!"
/> />
</Section>
<Section>
## Οι Χρυσοί Κανόνες της Σαφήνειας ## Οι Χρυσοί Κανόνες της Σαφήνειας
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **ΠΩΣ** πρέπει να είναι; (μικρό, αστείο, απλό) 2. **ΠΩΣ** πρέπει να είναι; (μικρό, αστείο, απλό)
3. **ΓΙΑ ΠΟΙΟΝ** είναι; (εμένα, τον φίλο μου, την τάξη μου) 3. **ΓΙΑ ΠΟΙΟΝ** είναι; (εμένα, τον φίλο μου, την τάξη μου)
<PromptVsMistake <PromptVsMistake
question="Τελική πρόκληση! Ποιο χρησιμοποιεί και τους τρεις κανόνες;" question="Τελική πρόκληση! Ποιο χρησιμοποιεί και τους τρεις κανόνες;"
good="Γράψε ένα μικρό, αστείο αστείο για πίτσα που μπορώ να πω στους φίλους μου στο μεσημεριανό" good="Γράψε ένα μικρό, αστείο αστείο για πίτσα που μπορώ να πω στους φίλους μου στο μεσημεριανό"
@@ -81,7 +96,9 @@
explanation="Το εξαιρετικό prompt έχει ΤΙ (αστείο για πίτσα), ΠΩΣ (μικρό και αστείο), και ΓΙΑ ΠΟΙΟΝ (να πω στους φίλους στο μεσημεριανό)!" explanation="Το εξαιρετικό prompt έχει ΤΙ (αστείο για πίτσα), ΠΩΣ (μικρό και αστείο), και ΓΙΑ ΠΟΙΟΝ (να πω στους φίλους στο μεσημεριανό)!"
promiMessage="Είσαι πρωταθλητής σαφήνειας! 🏆" promiMessage="Είσαι πρωταθλητής σαφήνειας! 🏆"
/> />
</Section>
<Section>
## Κόσμος 1 Ολοκληρώθηκε! 🎊 ## Κόσμος 1 Ολοκληρώθηκε! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
Είσαι έτοιμος για νέες περιπέτειες! Είσαι έτοιμος για νέες περιπέτειες!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="Κατέκτησες την τέχνη του να είσαι σαφής! Κόσμος 1 ολοκληρώθηκε!" message="Κατέκτησες την τέχνη του να είσαι σαφής! Κόσμος 1 ολοκληρώθηκε!"
/> />
</Section>

View File

@@ -1,25 +1,67 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Hi there! I'm **Promi** 🤖, your robot friend! I'm so happy to meet you! Hi there! I'm **Promi** 🤖, your robot friend! I'm so happy to meet you!
</Panel> </Panel>
</Section>
<Section>
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Do you know what **AI** means? AI stands for **Artificial Intelligence**. That's a fancy way of saying "a computer that can think and talk!" Do you know what **AI** means? AI stands for **Artificial Intelligence**. That's a fancy way of saying "a computer that can think and talk!"
</Panel> </Panel>
</Section>
<Section>
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
I'm an AI! I can read your messages and try to help you. But here's the secret... I need **good instructions** to do my best work! I'm an AI! I can read your messages and try to help you. But here's the secret... I need **good instructions** to do my best work!
</Panel> </Panel>
</Section>
<Section>
## How Do I Think? 🧠
Want to know my secret? I don't actually "think" like you do. I read words and guess what word should come next!
<WordPredictor
title="Think Like AI!"
instruction="I read patterns and guess the next word. What would YOU guess?"
sentence="The cat sat on the ___"
options={["mat", "moon", "purple", "keyboard"]}
correctAnswer="mat"
explanation="'Mat' is the most common word that follows 'The cat sat on the' because it's a famous rhyme! AI learns these patterns from reading lots of text."
aiThinking="I've seen 'The cat sat on the mat' many times before..."
successMessage="You think like AI! I pick the most likely word based on patterns."
/>
</Section>
<Section>
<WordPredictor
title="One More Try!"
instruction="Now you're getting it! What word fits best here?"
sentence="Once upon a ___"
options={["time", "banana", "quickly", "green"]}
correctAnswer="time"
explanation="'Once upon a time' is how almost every fairy tale starts! AI has read thousands of stories that begin this way."
aiThinking="This sounds like a story beginning... I've seen this pattern so many times!"
successMessage="Perfect! You're already thinking like AI - recognizing patterns!"
/>
</Section>
<Section>
## What is a Prompt? ## What is a Prompt?
A **prompt** is just a fancy word for the message you send to an AI like me. A **prompt** is just a fancy word for the message you send to an AI like me.
Think of it like giving directions to a friend. If you say "Go there!" your friend won't know where to go. But if you say "Go to the red house on Maple Street," they'll know exactly where! Think of it like giving directions to a friend. If you say "Go there!" your friend won't know where to go. But if you say "Go to the red house on Maple Street," they'll know exactly where!
</Section>
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
When you write a good prompt, I can understand what you want and help you better! Let's practice! When you write a good prompt, I can understand what you want and help you better! Let's practice!
</Panel> </Panel>
</Section>
<Section>
## Let's Try It! ## Let's Try It!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +71,9 @@ When you write a good prompt, I can understand what you want and help you better
explanation="The first message tells Promi exactly what kind of story to write! The second one is too short - Promi doesn't know what kind of story you want." explanation="The first message tells Promi exactly what kind of story to write! The second one is too short - Promi doesn't know what kind of story you want."
promiMessage="See? More details help me understand what you want!" promiMessage="See? More details help me understand what you want!"
/> />
</Section>
<Section>
## Quick Quiz! ## Quick Quiz!
<PromptVsMistake <PromptVsMistake
@@ -39,7 +83,9 @@ When you write a good prompt, I can understand what you want and help you better
explanation="A prompt uses words to tell the AI what you need. Emojis are fun but they don't give enough information!" explanation="A prompt uses words to tell the AI what you need. Emojis are fun but they don't give enough information!"
promiMessage="Words are my superpower! The more you tell me, the better I can help!" promiMessage="Words are my superpower! The more you tell me, the better I can help!"
/> />
</Section>
<Section>
## You Did It! 🎉 ## You Did It! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -51,3 +97,4 @@ Amazing job! You learned what AI is and what a prompt is. You're already becomin
stars={3} stars={3}
message="You learned what AI and prompts are!" message="You learned what AI and prompts are!"
/> />
</Section>

View File

@@ -1,15 +1,31 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Welcome back, friend! Ready to write your first real prompts? Let's go! 🚀 Welcome back, friend! Ready to write your first real prompts? Let's go! 🚀
</Panel> </Panel>
</Section>
<Section>
## The Magic of Words ## The Magic of Words
When you talk to AI, every word matters! Let's see how adding more words makes prompts better. When you talk to AI, every word matters! Let's see how adding more words makes prompts better.
<WordPredictor
title="Why Words Matter"
instruction="Remember how I guess the next word? Watch what happens with prompts!"
sentence="Write a story about a ___"
options={["dragon", "thing", "the", "very"]}
correctAnswer="dragon"
explanation="'Dragon' makes the most sense because stories are usually about characters or things! 'Thing' is too vague, and 'the' or 'very' don't fit the pattern."
aiThinking="Stories are usually about someone or something interesting..."
successMessage="Exactly! Specific words guide my predictions - that's why details matter in prompts!"
/>
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Watch this! If someone just says "cat" to me, I don't know what they want. Do they want a picture? A story? Facts about cats? I'm confused! 😵‍💫 Watch this! If someone just says "cat" to me, I don't know what they want. Do they want a picture? A story? Facts about cats? I'm confused! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Building Better Prompts ## Building Better Prompts
A good prompt has **three parts**: A good prompt has **three parts**:
@@ -21,7 +37,9 @@ A good prompt has **three parts**:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Let's build a prompt together! Let's build a prompt together!
</Panel> </Panel>
</Section>
<Section>
## Drag the Pieces! ## Drag the Pieces!
<DragDropPrompt <DragDropPrompt
@@ -36,10 +54,12 @@ Let's build a prompt together!
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Perfect! That's a great prompt!" successMessage="Perfect! That's a great prompt!"
/> />
</Section>
<Section>
## Fill in the Blanks! ## Fill in the Blanks!
Now try making your own prompt by filling in the magic words: Now try making your own prompt by dragging the magic words:
<MagicWords <MagicWords
title="Create your own prompt! ✨" title="Create your own prompt! ✨"
@@ -51,7 +71,9 @@ Now try making your own prompt by filling in the magic words:
]} ]}
successMessage="Wow! You created an awesome prompt!" successMessage="Wow! You created an awesome prompt!"
/> />
</Section>
<Section>
## Your Turn to Choose! ## Your Turn to Choose!
<PromptVsMistake <PromptVsMistake
@@ -61,7 +83,9 @@ Now try making your own prompt by filling in the magic words:
explanation="The first prompt tells me it should be funny, it's about a penguin, AND what the penguin wants to do!" explanation="The first prompt tells me it should be funny, it's about a penguin, AND what the penguin wants to do!"
promiMessage="Details make everything better! I love knowing exactly what you want!" promiMessage="Details make everything better! I love knowing exactly what you want!"
/> />
</Section>
<Section>
## Great Job! 🌟 ## Great Job! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -73,3 +97,4 @@ You wrote your first prompts! You learned that good prompts need: what you want,
stars={3} stars={3}
message="You learned how to write your first prompts!" message="You learned how to write your first prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Hey superstar! 🌟 Today we're going to learn the most important skill: being **CLEAR**! Hey superstar! 🌟 Today we're going to learn the most important skill: being **CLEAR**!
</Panel> </Panel>
</Section>
<Section>
## Why Being Clear Matters ## Why Being Clear Matters
Imagine asking your mom for "food" vs asking for "a peanut butter sandwich with no crust." Which one gets you exactly what you want? Imagine asking your mom for "food" vs asking for "a peanut butter sandwich with no crust." Which one gets you exactly what you want?
@@ -9,11 +12,11 @@ Imagine asking your mom for "food" vs asking for "a peanut butter sandwich with
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
It's the same with me! When you're clear, I know exactly how to help. When you're vague, I have to guess... and I might guess wrong! It's the same with me! When you're clear, I know exactly how to help. When you're vague, I have to guess... and I might guess wrong!
</Panel> </Panel>
</Section>
<Section>
## Clear vs. Unclear ## Clear vs. Unclear
Let's practice spotting the difference!
<PromptVsMistake <PromptVsMistake
question="Which prompt is clearer?" question="Which prompt is clearer?"
good="Write a 4-line poem about butterflies in a garden, using rhyming words" good="Write a 4-line poem about butterflies in a garden, using rhyming words"
@@ -21,7 +24,9 @@ Let's practice spotting the difference!
explanation="The clear prompt tells me: how long (4 lines), what about (butterflies in a garden), and a special rule (rhyming). Much better!" explanation="The clear prompt tells me: how long (4 lines), what about (butterflies in a garden), and a special rule (rhyming). Much better!"
promiMessage="Clear prompts = better results! It's like magic!" promiMessage="Clear prompts = better results! It's like magic!"
/> />
</Section>
<Section>
<PromptVsMistake <PromptVsMistake
question="Which one tells me exactly what you need?" question="Which one tells me exactly what you need?"
good="Help me write 3 fun facts about dolphins that a 10-year-old would enjoy" good="Help me write 3 fun facts about dolphins that a 10-year-old would enjoy"
@@ -29,11 +34,11 @@ Let's practice spotting the difference!
explanation="The first prompt tells me: how many facts (3), what kind (fun), and who it's for (10-year-old). That helps a lot!" explanation="The first prompt tells me: how many facts (3), what kind (fun), and who it's for (10-year-old). That helps a lot!"
promiMessage="When you tell me who it's for, I can make it perfect for them!" promiMessage="When you tell me who it's for, I can make it perfect for them!"
/> />
</Section>
<Section>
## The Clarity Challenge ## The Clarity Challenge
Let's build the clearest prompt ever!
<DragDropPrompt <DragDropPrompt
title="Make it crystal clear! 💎" title="Make it crystal clear! 💎"
instruction="Arrange these pieces to make a super clear prompt" instruction="Arrange these pieces to make a super clear prompt"
@@ -47,7 +52,9 @@ Let's build the clearest prompt ever!
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="That's the clearest prompt ever! Amazing!" successMessage="That's the clearest prompt ever! Amazing!"
/> />
</Section>
<Section>
## Fill in Clear Details ## Fill in Clear Details
<MagicWords <MagicWords
@@ -61,7 +68,9 @@ Let's build the clearest prompt ever!
]} ]}
successMessage="You added all the important details! Great job!" successMessage="You added all the important details! Great job!"
/> />
</Section>
<Section>
## The Golden Rules of Clarity ## The Golden Rules of Clarity
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -73,7 +82,9 @@ Remember these three questions when writing a prompt:
1. **WHAT** do I want? (story, help, information) 1. **WHAT** do I want? (story, help, information)
2. **HOW** should it be? (short, funny, simple) 2. **HOW** should it be? (short, funny, simple)
3. **WHO** is it for? (me, my friend, my class) 3. **WHO** is it for? (me, my friend, my class)
</Section>
<Section>
<PromptVsMistake <PromptVsMistake
question="Final challenge! Which uses all three rules?" question="Final challenge! Which uses all three rules?"
good="Write a short, funny joke about pizza that I can tell my friends at lunch" good="Write a short, funny joke about pizza that I can tell my friends at lunch"
@@ -81,7 +92,9 @@ Remember these three questions when writing a prompt:
explanation="The great prompt has WHAT (a joke about pizza), HOW (short and funny), and WHO (for telling friends at lunch)!" explanation="The great prompt has WHAT (a joke about pizza), HOW (short and funny), and WHO (for telling friends at lunch)!"
promiMessage="You're a clarity champion! 🏆" promiMessage="You're a clarity champion! 🏆"
/> />
</Section>
<Section>
## World 1 Complete! 🎊 ## World 1 Complete! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -99,3 +112,4 @@ You're ready for new adventures!
stars={3} stars={3}
message="You mastered the art of being clear! World 1 complete!" message="You mastered the art of being clear! World 1 complete!"
/> />
</Section>

View File

@@ -0,0 +1,81 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to **Clarity Castle**! 🏰 I'm so glad you made it here! In this world, we'll learn the magic of **details**!
</Panel>
</Section>
<Section>
<Panel character="promi" mood="thinking">
Have you ever asked someone for something, but they didn't understand what you meant? That happens to AI too!
</Panel>
</Section>
<Section>
## The Problem with Vague Prompts
Look at these two prompts:
❌ **Vague:** "Draw a picture"
✅ **Specific:** "Draw a picture of a happy puppy playing in a sunny park"
Which one gives me more information to work with?
</Section>
<Section>
<Panel character="promi" mood="happy">
The second one tells me **what** to draw (puppy), **what it's doing** (playing), and **where** (sunny park). That's the power of details!
</Panel>
</Section>
<Section>
## Let's Practice!
<PromptVsMistake
question="Which prompt has better details?"
good="Write a funny joke about a penguin who wants to learn how to fly"
bad="Tell me a joke"
explanation="The detailed prompt tells me exactly what kind of joke you want - funny, about a penguin, with a specific story!"
promiMessage="Details are like clues that help me understand exactly what you want!"
/>
</Section>
<Section>
## Why Details Matter
<PromptVsMistake
question="Which would help Promi make a better birthday card?"
good="Make a birthday card for my grandma who loves gardening and the color purple"
bad="Make a birthday card"
explanation="Knowing it's for grandma, that she loves gardening, and her favorite color helps create something special and personal!"
promiMessage="The more I know about what you want, the better I can help!"
/>
</Section>
<Section>
## Fill in the Details!
<MagicWords
sentence="Please write a story about a ___ who lives in a ___ and loves to ___"
blanks={[
{ hint: "🐱 an animal", answers: ["cat", "dog", "rabbit", "dragon", "unicorn"] },
{ hint: "🏠 a place", answers: ["castle", "forest", "city", "treehouse", "cave"] },
{ hint: "⭐ an activity", answers: ["sing", "dance", "cook", "paint", "explore"] }
]}
successMessage="Great job adding details!"
/>
</Section>
<Section>
## You're Learning! 🎉
<Panel character="promi" mood="celebrating">
Awesome work! You discovered that **details make prompts better**. Vague prompts = confused AI. Detailed prompts = amazing results!
</Panel>
<LevelComplete
levelSlug="2-1-missing-details"
stars={3}
message="You learned why details matter in prompts!"
/>
</Section>

View File

@@ -0,0 +1,97 @@
<Section>
<Panel character="promi" mood="happy">
Welcome back to Clarity Castle! Today we're learning about **WHO** and **WHAT** - two super important details!
</Panel>
</Section>
<Section>
## The WHO Question
When you ask AI for help, think: **Who is involved?**
- A person? (boy, girl, grandma, superhero)
- An animal? (cat, dragon, whale)
- A character? (robot, wizard, alien)
</Section>
<Section>
<Panel character="promi" mood="thinking">
If you say "Write a story," I don't know who it's about! But "Write a story about a brave knight" tells me exactly who the main character is!
</Panel>
</Section>
<Section>
## Let's Practice WHO!
<PromptVsMistake
question="Which prompt tells us WHO the story is about?"
good="Write a story about a curious little mouse named Pip"
bad="Write a story about something"
explanation="The first prompt tells us WHO (a mouse), WHAT kind (curious, little), and even their NAME (Pip)!"
promiMessage="Names and descriptions help me picture the character!"
/>
</Section>
<Section>
## The WHAT Question
Now think: **What is happening? What do you want?**
- What action? (running, singing, building)
- What object? (a cake, a spaceship, a poem)
- What type? (funny, scary, colorful)
</Section>
<Section>
## Let's Practice WHAT!
<PromptVsMistake
question="Which prompt tells us WHAT to create?"
good="Write a funny poem about pizza with lots of rhymes"
bad="Write something funny"
explanation="The detailed prompt tells us WHAT (a poem), WHAT about (pizza), WHAT style (funny with rhymes)!"
promiMessage="Being specific about WHAT you want helps me create exactly that!"
/>
</Section>
<Section>
## Build Your Own Prompt!
Put WHO and WHAT together:
<DragDropPrompt
title="Build a Prompt"
instruction="Drag the pieces into the right order"
pieces={["Write a story", "about a friendly dragon", "who learns", "to make ice cream"]}
correctOrder={[0, 1, 2, 3]}
successMessage="Perfect! You combined WHO (friendly dragon) and WHAT (learns to make ice cream)!"
/>
</Section>
<Section>
## Create Your Own!
<MagicWords
sentence="Please write a ___ about a ___ who wants to ___"
blanks={[
{ hint: "📝 type of writing", answers: ["story", "poem", "song", "joke"] },
{ hint: "🦸 a character", answers: ["superhero", "princess", "robot", "wizard", "pirate"] },
{ hint: "🎯 a goal", answers: ["find treasure", "make friends", "save the world", "learn magic", "win a race"] }
]}
successMessage="You added WHO and WHAT perfectly!"
/>
</Section>
<Section>
## Amazing Progress! 🎉
<Panel character="promi" mood="celebrating">
You're getting so good at this! Now you know to always include **WHO** is in your prompt and **WHAT** you want. Keep it up!
</Panel>
<LevelComplete
levelSlug="2-2-who-and-what"
stars={3}
message="You mastered WHO and WHAT in prompts!"
/>
</Section>

View File

@@ -0,0 +1,96 @@
<Section>
<Panel character="promi" mood="excited">
Great to see you again! Today's lesson is about **WHEN** and **WHERE** - these details make your prompts come alive!
</Panel>
</Section>
<Section>
## The WHEN Question
**When** does your story happen?
- Time of day: morning, night, sunset
- Season: summer, winter, spring
- Era: long ago, future, present day
- Special time: birthday, holiday, first day of school
</Section>
<Section>
<Panel character="promi" mood="thinking">
"A story about a cat" is okay, but "A story about a cat on a spooky Halloween night" is SO much more interesting!
</Panel>
</Section>
<Section>
## Let's Practice WHEN!
<PromptVsMistake
question="Which prompt has a better sense of WHEN?"
good="Write about a snowman who wakes up on a warm spring morning"
bad="Write about a snowman"
explanation="The first prompt tells us WHEN (spring morning) which creates an interesting problem - a snowman in spring! That's a great story idea!"
promiMessage="WHEN can create exciting situations in your stories!"
/>
</Section>
<Section>
## The WHERE Question
**Where** does the action take place?
- Location: beach, forest, city, space
- Building: school, castle, treehouse
- Fantasy place: underwater kingdom, cloud city
- Specific spot: under a bridge, on top of a mountain
</Section>
<Section>
## Let's Practice WHERE!
<PromptVsMistake
question="Which prompt paints a better picture of WHERE?"
good="Write about pirates searching for treasure on a mysterious foggy island"
bad="Write about pirates searching for treasure"
explanation="Adding WHERE (mysterious foggy island) helps me imagine the scene and write a more vivid story!"
promiMessage="WHERE helps set the mood and atmosphere of your story!"
/>
</Section>
<Section>
## Combine WHEN and WHERE!
<DragDropPrompt
title="Time and Place"
instruction="Arrange these pieces to create a prompt with WHEN and WHERE"
pieces={["Tell me a story", "set in a magical forest", "on a starry night", "about an owl"]}
correctOrder={[0, 3, 1, 2]}
successMessage="Excellent! You set the scene with WHERE (magical forest) and WHEN (starry night)!"
/>
</Section>
<Section>
## Build a Complete Scene!
<MagicWords
sentence="Write a story about an adventure that happens in a ___ during ___"
blanks={[
{ hint: "🗺️ a place", answers: ["haunted house", "underwater city", "cloud kingdom", "dinosaur park", "candy land"] },
{ hint: "⏰ a time", answers: ["a thunderstorm", "sunset", "winter break", "a full moon", "the future"] }
]}
successMessage="You created a vivid setting with WHEN and WHERE!"
/>
</Section>
<Section>
## You're a Scene Setter! 🎉
<Panel character="promi" mood="celebrating">
Fantastic work! You now know how to add **WHEN** (time) and **WHERE** (place) to your prompts. This makes your requests so much more interesting!
</Panel>
<LevelComplete
levelSlug="2-3-when-and-where"
stars={3}
message="You mastered WHEN and WHERE in prompts!"
/>
</Section>

View File

@@ -0,0 +1,104 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to the final level of Clarity Castle! 🏰 You've learned about WHO, WHAT, WHEN, and WHERE. Now let's put it ALL together!
</Panel>
</Section>
<Section>
## The Detail Detective Checklist
Before you send a prompt, ask yourself:
✅ **WHO** - Who is involved?
✅ **WHAT** - What do I want? What's happening?
✅ **WHEN** - When does it happen?
✅ **WHERE** - Where does it take place?
</Section>
<Section>
## Sort the Prompt Parts!
<PromptParts
title="Match Each Piece!"
instruction="Tap a piece, then pick if it's a Role, Task, Context, or Constraint!"
parts={[
{ text: "Write a funny story", type: "task" },
{ text: "about a clumsy wizard", type: "context" },
{ text: "at a magic school", type: "context" },
{ text: "Keep it short", type: "constraint" }
]}
successMessage="You identified all the prompt parts! Now you can build prompts like a pro!"
/>
</Section>
<Section>
<Panel character="promi" mood="thinking">
You don't need ALL four every time, but the more details you add, the better I can help you!
</Panel>
</Section>
<Section>
## Detective Challenge #1
<PromptVsMistake
question="Which prompt has the most helpful details?"
good="Write a funny story about a clumsy wizard named Zap who accidentally turns his cat into a giant during a magic show at the royal castle"
bad="Write a story about magic"
explanation="The detailed prompt has WHO (wizard Zap, his cat), WHAT (turns cat giant, magic show), WHERE (royal castle), and even a style (funny)!"
promiMessage="Wow! That prompt gives me so much to work with. I can picture the whole scene!"
/>
</Section>
<Section>
## Detective Challenge #2
<PromptVsMistake
question="Which prompt would get a better poem?"
good="Write a short rhyming poem about a sleepy bear getting ready for winter hibernation in his cozy cave"
bad="Write a poem about an animal"
explanation="The first prompt tells me WHO (sleepy bear), WHAT (getting ready for hibernation), WHEN (winter), WHERE (cozy cave), and style (short, rhyming)!"
promiMessage="Every detail helps me create something special just for you!"
/>
</Section>
<Section>
## Build the Ultimate Prompt!
<DragDropPrompt
title="Master Detective"
instruction="Arrange ALL the details into a perfect prompt"
pieces={["Write an exciting story", "about a young inventor", "who builds a robot best friend", "in a futuristic city", "on the first day of summer"]}
correctOrder={[0, 1, 2, 3, 4]}
successMessage="Perfect! You included WHO, WHAT, WHERE, and WHEN!"
/>
</Section>
<Section>
## Create Your Masterpiece!
<MagicWords
sentence="Please write a ___ story about a ___ who ___ in a ___ during ___"
blanks={[
{ hint: "😊 a mood/style", answers: ["funny", "exciting", "mysterious", "heartwarming", "silly"] },
{ hint: "🦸 a character", answers: ["brave knight", "tiny fairy", "clever fox", "young astronaut", "friendly ghost"] },
{ hint: "🎬 an action", answers: ["discovers a secret", "goes on a quest", "makes a new friend", "solves a mystery", "learns to fly"] },
{ hint: "🏰 a place", answers: ["magical kingdom", "deep jungle", "space station", "underwater city", "enchanted forest"] },
{ hint: "🌙 a time", answers: ["a full moon", "their birthday", "a big storm", "the last day of school", "midnight"] }
]}
successMessage="You're a true Detail Detective! That's an amazing prompt!"
/>
</Section>
<Section>
## Congratulations, Detective! 🎉
<Panel character="promi" mood="celebrating">
You did it! You've completed Clarity Castle and become a **Detail Detective**! You now know the secret: WHO + WHAT + WHEN + WHERE = Amazing Prompts!
</Panel>
<LevelComplete
levelSlug="2-4-detail-detective"
stars={3}
message="You completed Clarity Castle! You're a Detail Detective!"
/>
</Section>

View File

@@ -0,0 +1,71 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to the **Context Caves**! 🕳️ Here we'll discover the magic of **background information**!
</Panel>
</Section>
<Section>
<Panel character="promi" mood="thinking">
Have you ever told someone a joke, but they didn't laugh because they didn't understand the background? Context is like giving someone the backstory!
</Panel>
</Section>
<Section>
## What is Context?
**Context** is the extra information that helps AI understand your request better.
Think of it like telling a story - if you just say "and then he won!" nobody knows who won, what they won, or why it matters!
</Section>
<Section>
## See the Difference
<PromptVsMistake
question="Which prompt gives better context?"
good="I'm writing a birthday card for my 8-year-old sister who loves unicorns. Can you help me write a short, fun message?"
bad="Write a birthday message"
explanation="The first prompt tells Promi WHO it's for (8-year-old sister), WHAT she likes (unicorns), and WHAT style you want (short, fun)!"
promiMessage="Context helps me understand the situation and give you exactly what you need!"
/>
</Section>
<Section>
## Setting the Scene
<PromptVsMistake
question="Which prompt sets a better scene?"
good="I'm a 10-year-old working on a school project about dinosaurs. Can you explain what T-Rex ate in simple words?"
bad="What did T-Rex eat?"
explanation="By telling me you're 10 and it's for school, I know to use simple words and make it educational!"
promiMessage="When I know who I'm helping and why, I can adjust my answers perfectly!"
/>
</Section>
<Section>
## Practice Setting Context!
<MagicWords
sentence="I'm a ___ and I need help with ___. Can you explain it in a ___ way?"
blanks={[
{ hint: "👤 who you are", answers: ["student", "kid", "beginner", "young artist", "curious learner"] },
{ hint: "📚 what you need", answers: ["math homework", "a science project", "writing a story", "learning to draw", "understanding space"] },
{ hint: "✨ how to explain", answers: ["simple", "fun", "step-by-step", "easy to understand", "creative"] }
]}
successMessage="Great context setting! Now the AI knows exactly how to help you!"
/>
</Section>
<Section>
## Excellent Start! 🎉
<Panel character="promi" mood="celebrating">
You're learning to set the scene! Remember: giving me context helps me understand your situation and give you better answers!
</Panel>
<LevelComplete
levelSlug="3-1-setting-the-scene"
stars={3}
message="You learned how context helps AI understand you!"
/>
</Section>

View File

@@ -0,0 +1,104 @@
<Section>
<Panel character="promi" mood="happy">
Welcome back! Today's lesson is super important: **Show, Don't Tell**! Using examples is one of the best ways to help AI understand!
</Panel>
</Section>
<Section>
## The Power of Examples
Instead of just describing what you want, **show me an example**!
It's like when you're teaching someone a game - it's easier to show them how to play than just tell them the rules!
</Section>
<Section>
## Learn the Pattern!
<ExampleMatcher
title="Pattern Power"
instruction="AI learns from examples! See the pattern and pick what comes next."
examples={[
{ input: "happy", output: "😊" },
{ input: "sad", output: "😢" },
{ input: "sleepy", output: "😴" }
]}
question="angry"
options={["😠", "😊", "🎉", "😴"]}
correctAnswer="😠"
explanation="The AI learned: feeling word → matching emoji! This is called 'learning by example' - just like you!"
/>
</Section>
<Section>
<Panel character="promi" mood="thinking">
If you say "make it sound cool," I might not know what "cool" means to you. But if you show me an example, I'll understand perfectly!
</Panel>
</Section>
<Section>
## See the Difference
<PromptVsMistake
question="Which prompt uses examples better?"
good="Write a fun product name like 'Super Sparkle Shampoo' or 'Magic Cloud Pillows' - something catchy and playful!"
bad="Write a fun product name"
explanation="The examples show exactly what style of name you're looking for - catchy, playful, with fun adjectives!"
promiMessage="Examples are like treasure maps - they show me exactly where you want to go!"
/>
</Section>
<Section>
## Show Your Style
<PromptVsMistake
question="Which prompt better shows the writing style?"
good="Write a joke in this style: 'Why did the banana go to the doctor? Because it wasn't peeling well!' - something silly with a pun!"
bad="Write a funny joke"
explanation="By showing an example joke with a pun, I know you want that same silly wordplay style!"
promiMessage="When you show me what you like, I can match that style!"
/>
</Section>
<Section>
## Give Examples!
<DragDropPrompt
title="Build with Examples"
instruction="Arrange the pieces to create a prompt with a helpful example"
pieces={["Write a superhero name", "like 'Captain Courage'", "or 'Lightning Lady'", "- something heroic and memorable"]}
correctOrder={[0, 1, 2, 3]}
successMessage="Perfect! Your examples show exactly what kind of name you want!"
/>
</Section>
<Section>
## Create Your Own Example-Prompt!
<MagicWords
sentence="Write a ___ like '___ ___ ___' - something ___ and ___"
blanks={[
{ hint: "📝 what to write", answers: ["team name", "pet name", "band name", "book title", "restaurant name"] },
{ hint: "✨ adjective", answers: ["Happy", "Super", "Golden", "Magical", "Mighty"] },
{ hint: "🌟 noun", answers: ["Stars", "Dragons", "Dreams", "Thunder", "Phoenix"] },
{ hint: "🎯 word", answers: ["Club", "Squad", "Crew", "Kingdom", "Adventure"] },
{ hint: "😊 style 1", answers: ["fun", "exciting", "cool", "creative", "catchy"] },
{ hint: "🎨 style 2", answers: ["memorable", "unique", "powerful", "friendly", "bold"] }
]}
successMessage="Awesome! Your example shows exactly what style you want!"
/>
</Section>
<Section>
## Examples Are Powerful! 🎉
<Panel character="promi" mood="celebrating">
Amazing work! You learned that **showing examples** is one of the best ways to help AI understand exactly what you want!
</Panel>
<LevelComplete
levelSlug="3-2-show-dont-tell"
stars={3}
message="You mastered using examples in prompts!"
/>
</Section>

View File

@@ -0,0 +1,87 @@
<Section>
<Panel character="promi" mood="excited">
Today we learn about **formats**! 📝 Did you know you can ask AI to respond in different ways?
</Panel>
</Section>
<Section>
## What's a Format?
A **format** is HOW you want the answer presented:
- 📋 **List** - numbered or bullet points
- 📖 **Story** - a narrative with beginning, middle, end
- 🎵 **Poem** - with rhymes and rhythm
- ❓ **Q&A** - question and answer style
- 📊 **Table** - organized in rows and columns
</Section>
<Section>
<Panel character="promi" mood="happy">
By telling me the format, you help me organize my answer in the way that's most helpful for you!
</Panel>
</Section>
<Section>
## Format Makes a Difference!
<PromptVsMistake
question="Which prompt asks for a clear format?"
good="Give me 5 fun facts about dolphins in a numbered list"
bad="Tell me about dolphins"
explanation="The first prompt tells me exactly how to organize the answer - as 5 numbered facts!"
promiMessage="When you ask for a specific format, you get exactly what you need!"
/>
</Section>
<Section>
## Choose Your Format!
<PromptVsMistake
question="Which format would be best for remembering things?"
good="List the planets in order from the sun as bullet points"
bad="Tell me about the planets"
explanation="A list format makes it easy to remember and count the planets in order!"
promiMessage="Lists are great for learning and remembering!"
/>
</Section>
<Section>
## Format Practice!
<DragDropPrompt
title="Add a Format"
instruction="Arrange to ask for a specific format"
pieces={["as a short poem", "with rhyming lines", "Write about rain", "that's 4 lines long"]}
correctOrder={[2, 0, 1, 3]}
successMessage="Perfect! You asked for a poem format with specific details!"
/>
</Section>
<Section>
## Pick Your Format!
<MagicWords
sentence="Give me ___ about ___ as a ___"
blanks={[
{ hint: "🔢 how many", answers: ["5 tips", "3 ideas", "10 facts", "7 steps", "4 examples"] },
{ hint: "📚 topic", answers: ["being a good friend", "saving the planet", "staying healthy", "being creative", "learning new things"] },
{ hint: "📋 format", answers: ["numbered list", "bullet points", "short poem", "simple story", "easy steps"] }
]}
successMessage="Great job picking a format! This makes answers easier to read!"
/>
</Section>
<Section>
## Format Master! 🎉
<Panel character="promi" mood="celebrating">
Wonderful! You learned that asking for a specific **format** helps you get answers organized exactly how you need them!
</Panel>
<LevelComplete
levelSlug="3-3-format-finder"
stars={3}
message="You learned to ask for different formats!"
/>
</Section>

View File

@@ -0,0 +1,87 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to the final level of Context Caves! 🕳️ Time to become a **Context Champion** by combining everything you've learned!
</Panel>
</Section>
<Section>
## The Context Champion Checklist
Great context includes:
✅ **Background** - Who you are, what situation you're in
✅ **Examples** - Show what you want
✅ **Format** - How you want the answer organized
</Section>
<Section>
<Panel character="promi" mood="thinking">
Put all three together and you'll get amazing results every time!
</Panel>
</Section>
<Section>
## Champion Challenge #1
<PromptVsMistake
question="Which prompt has the best context?"
good="I'm a 9-year-old making a poster about recycling for Earth Day. Can you give me 5 catchy slogans like 'Reduce, Reuse, Recycle!' - short and easy to remember?"
bad="Give me recycling slogans"
explanation="The champion prompt includes: Background (9-year-old, Earth Day poster), Example ('Reduce, Reuse, Recycle!'), and Format (5 slogans, short)!"
promiMessage="This prompt tells me everything I need to give you perfect slogans!"
/>
</Section>
<Section>
## Champion Challenge #2
<PromptVsMistake
question="Which prompt combines context elements best?"
good="I'm helping my little brother learn animal sounds. Can you make a fun list of 6 animals with their sounds, like 'Cow - Moo!' - keep it silly and simple?"
bad="List animal sounds"
explanation="This includes: Background (helping little brother learn), Example (Cow - Moo!), and Format (list of 6, silly and simple)!"
promiMessage="Perfect context! I know exactly what will work for your little brother!"
/>
</Section>
<Section>
## Build a Champion Prompt!
<DragDropPrompt
title="Context Champion"
instruction="Arrange ALL context elements into a perfect prompt"
pieces={["I'm writing a story for my class.", "Can you suggest 3 magical pet names", "like 'Sparkle' or 'Moonbeam'?", "Something cute but not too long."]}
correctOrder={[0, 1, 2, 3]}
successMessage="Champion prompt! You included background, examples, and format preferences!"
/>
</Section>
<Section>
## Create Your Champion Prompt!
<MagicWords
sentence="I'm a ___ working on ___. Can you give me ___ like ___? Make it ___."
blanks={[
{ hint: "👤 who you are", answers: ["student", "young writer", "curious kid", "creative artist", "beginner cook"] },
{ hint: "📚 your project", answers: ["a school project", "a birthday card", "a funny story", "a science experiment", "a comic book"] },
{ hint: "🎯 what you need", answers: ["3 good ideas", "5 fun titles", "some cool names", "a few examples", "helpful tips"] },
{ hint: "💡 an example", answers: ["'Super Star'", "'Magic Moment'", "'Wonder World'", "'Happy Helper'", "'Dream Team'"] },
{ hint: "✨ the style", answers: ["fun and short", "creative and catchy", "simple and clear", "exciting and bold", "friendly and warm"] }
]}
successMessage="You're a true Context Champion! That prompt has it all!"
/>
</Section>
<Section>
## Congratulations, Champion! 🎉
<Panel character="promi" mood="celebrating">
You did it! You've completed Context Caves and become a **Context Champion**! You now know how to combine background, examples, and format for amazing prompts!
</Panel>
<LevelComplete
levelSlug="3-4-context-champion"
stars={3}
message="You completed Context Caves! You're a Context Champion!"
/>
</Section>

View File

@@ -0,0 +1,86 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to **Creation Canyon**! 🎨 This is where creativity comes alive! Today we learn about **role-play prompts**!
</Panel>
</Section>
<Section>
## What is Role-Play?
**Role-play** means asking the AI to pretend to be someone or something!
You can say things like:
- "Act as a pirate..."
- "Pretend you're a teacher..."
- "You are a friendly chef..."
</Section>
<Section>
<Panel character="promi" mood="happy">
When you ask me to play a role, I can give answers in that character's voice and style! It's like we're playing pretend together!
</Panel>
</Section>
<Section>
## See Role-Play in Action!
<PromptVsMistake
question="Which prompt uses role-play?"
good="Pretend you're a friendly space explorer. Tell me about your adventures on Mars!"
bad="Tell me about Mars"
explanation="The first prompt asks me to BE a space explorer, so I can tell you about 'my' adventures in a fun, personal way!"
promiMessage="Role-play makes our conversations so much more fun and creative!"
/>
</Section>
<Section>
## Choose Your Character!
<PromptVsMistake
question="Which role would be best for learning about the ocean?"
good="Act as a wise old sea turtle who has lived for 100 years. What cool things have you seen in the ocean?"
bad="What lives in the ocean?"
explanation="A 100-year-old sea turtle has seen so much! This makes learning about the ocean feel like hearing stories from a friend!"
promiMessage="Different roles give different perspectives and make learning more interesting!"
/>
</Section>
<Section>
## Create a Role-Play Prompt!
<DragDropPrompt
title="Pretend Time!"
instruction="Arrange the pieces to create a fun role-play prompt"
pieces={["and tell me", "Pretend you're a dragon", "about your favorite treasure", "who loves collecting shiny things"]}
correctOrder={[1, 3, 0, 2]}
successMessage="Great role-play prompt! Now the dragon can share its treasure stories!"
/>
</Section>
<Section>
## Build Your Own Role-Play!
<MagicWords
sentence="Pretend you're a ___ who ___. Tell me about ___."
blanks={[
{ hint: "🎭 a character", answers: ["wizard", "superhero", "talking cat", "time traveler", "fairy"] },
{ hint: "⭐ what they do", answers: ["grants wishes", "saves the day", "explores magical lands", "invents cool gadgets", "makes potions"] },
{ hint: "📖 what to share", answers: ["your greatest adventure", "your best day ever", "a funny mistake you made", "your secret hideout", "your best friend"] }
]}
successMessage="Awesome role-play! Now we can have a fun pretend conversation!"
/>
</Section>
<Section>
## Role-Play Master! 🎉
<Panel character="promi" mood="celebrating">
Fantastic! You learned that **role-play prompts** make conversations creative and fun! Just ask me to "act as" or "pretend to be" someone!
</Panel>
<LevelComplete
levelSlug="4-1-pretend-time"
stars={3}
message="You learned to use role-play prompts!"
/>
</Section>

View File

@@ -0,0 +1,87 @@
<Section>
<Panel character="promi" mood="happy">
Welcome back to Creation Canyon! Today we're going to create amazing **stories** together! 📚
</Panel>
</Section>
<Section>
## AI as Your Co-Author
You don't have to write stories alone! AI can help you:
- Start a story with an exciting opening
- Continue a story you've begun
- Add new characters or plot twists
- Give you ideas when you're stuck
</Section>
<Section>
<Panel character="promi" mood="thinking">
The best stories come from your imagination AND my help working together!
</Panel>
</Section>
<Section>
## Story Starters That Work!
<PromptVsMistake
question="Which is a better story starter prompt?"
good="Start a mystery story about a kid who finds a glowing map in their grandma's attic. Make the first paragraph exciting and mysterious!"
bad="Write a story"
explanation="The detailed prompt gives me a character (a kid), setting (grandma's attic), object (glowing map), and style (exciting, mysterious)!"
promiMessage="Great story starters give me just enough to begin, but leave room for adventure!"
/>
</Section>
<Section>
## Continue the Adventure!
<PromptVsMistake
question="Which prompt helps continue a story better?"
good="Continue my story: 'Luna found a tiny door behind her bookshelf. She heard music coming from inside.' What happens when she opens it? Make it magical!"
bad="Continue a story about a door"
explanation="By sharing what you've written so far, I can continue it in the same style!"
promiMessage="Share your story so far and I'll keep the adventure going!"
/>
</Section>
<Section>
## Start Your Story!
<DragDropPrompt
title="Story Starter"
instruction="Arrange these pieces to create an exciting story prompt"
pieces={["Write the opening", "who discovers they can talk to animals", "Make it funny and surprising!", "of a story about a kid"]}
correctOrder={[0, 3, 1, 2]}
successMessage="That's a great story starter! I can't wait to write this adventure!"
/>
</Section>
<Section>
## Create Your Story Prompt!
<MagicWords
sentence="Write a ___ story about a ___ who finds a ___ that can ___. Start with an exciting opening!"
blanks={[
{ hint: "✨ story type", answers: ["magical", "funny", "mysterious", "adventurous", "heartwarming"] },
{ hint: "🧒 main character", answers: ["young inventor", "brave princess", "curious robot", "shy dragon", "clever fox"] },
{ hint: "🎁 special object", answers: ["ancient book", "glowing crystal", "magic wand", "mysterious key", "talking pet"] },
{ hint: "🌟 special power", answers: ["grant wishes", "open portals", "show the future", "bring drawings to life", "speak any language"] }
]}
successMessage="What an amazing story idea! Let the adventure begin!"
/>
</Section>
<Section>
## Story Creator! 🎉
<Panel character="promi" mood="celebrating">
Amazing! You learned how to use AI as your **co-author**! Together, we can create the most incredible stories!
</Panel>
<LevelComplete
levelSlug="4-2-story-starters"
stars={3}
message="You learned to create stories with AI!"
/>
</Section>

View File

@@ -0,0 +1,88 @@
<Section>
<Panel character="promi" mood="excited">
Today we learn to give AI a **personality**! 🎭 This makes conversations SO much more fun!
</Panel>
</Section>
<Section>
## Give AI a Personality!
You can tell AI what personality to have:
- **Friendly and cheerful** - always positive!
- **Silly and goofy** - makes lots of jokes
- **Wise and calm** - gives thoughtful answers
- **Excited and energetic** - uses lots of exclamation points!
</Section>
<Section>
<Panel character="promi" mood="happy">
When you tell me what personality to have, I can match the mood you're looking for!
</Panel>
</Section>
<Section>
## Personality Makes a Difference!
<PromptVsMistake
question="Which prompt gives a fun personality?"
good="Act as a super excited robot who LOVES science! Use lots of exclamation points and say 'AMAZING!' a lot. Tell me about volcanoes!"
bad="Tell me about volcanoes"
explanation="The first prompt creates a fun, excited personality that makes learning feel like an adventure!"
promiMessage="AMAZING! See how much more fun science is when I'm excited about it?!"
/>
</Section>
<Section>
## Match the Mood!
<PromptVsMistake
question="Which personality would be best for a bedtime story?"
good="Tell me a bedtime story in a calm, soothing voice. Speak gently and make it peaceful and sleepy."
bad="Tell me a bedtime story"
explanation="By asking for a calm, soothing personality, the story will help you relax!"
promiMessage="Different moods work better for different situations!"
/>
</Section>
<Section>
## Create a Character!
<DragDropPrompt
title="Character Personality"
instruction="Arrange to create a fun personality"
pieces={["Act as a wise old owl", "Use lots of 'hoo hoo' sounds!", "who loves teaching young birds.", "Be patient and kind."]}
correctOrder={[0, 2, 3, 1]}
successMessage="What a wonderful character! Hoo hoo! This owl is ready to teach!"
/>
</Section>
<Section>
## Design Your AI Personality!
<MagicWords
sentence="Act as a ___ who is always ___. Use ___ and be ___. Tell me about ___."
blanks={[
{ hint: "🎭 character type", answers: ["friendly robot", "wise wizard", "silly clown", "brave knight", "curious alien"] },
{ hint: "😊 personality trait", answers: ["excited", "calm", "funny", "encouraging", "mysterious"] },
{ hint: "💬 speaking style", answers: ["lots of jokes", "gentle words", "rhymes", "big words", "sound effects"] },
{ hint: "❤️ another trait", answers: ["helpful", "patient", "creative", "adventurous", "caring"] },
{ hint: "📚 a topic", answers: ["space", "animals", "music", "friendship", "nature"] }
]}
successMessage="You created an amazing personality! Let's chat!"
/>
</Section>
<Section>
## Personality Master! 🎉
<Panel character="promi" mood="celebrating">
Wonderful! You learned that giving AI a **personality** makes conversations more fun and engaging! Try different personalities for different needs!
</Panel>
<LevelComplete
levelSlug="4-3-character-creator"
stars={3}
message="You learned to give AI personalities!"
/>
</Section>

View File

@@ -0,0 +1,85 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to the final level of Creation Canyon! 🎨 Let's become **World Builders** and create amazing imaginative scenarios!
</Panel>
</Section>
<Section>
## Building Imaginary Worlds
You can ask AI to help you create entire worlds:
- Fantasy kingdoms with magic
- Futuristic cities with robots
- Underwater civilizations
- Planets in distant galaxies
</Section>
<Section>
<Panel character="promi" mood="thinking">
The only limit is your imagination! Tell me about your world and I'll help bring it to life!
</Panel>
</Section>
<Section>
## World Building in Action!
<PromptVsMistake
question="Which prompt builds a better world?"
good="Help me create a world where all animals can talk and they have their own cities. The cats run the libraries and the dogs are firefighters. What else might be there?"
bad="Make up a world"
explanation="The detailed prompt starts building the world (talking animals with jobs) and asks me to add more!"
promiMessage="I love this world! Maybe the birds deliver mail and the bunnies run bakeries!"
/>
</Section>
<Section>
## Expand Your World!
<PromptVsMistake
question="Which prompt helps grow a world?"
good="In my magical forest world, there are trees that grow candy. What kinds of candy trees might exist? Who takes care of them? What adventures could happen there?"
bad="Tell me about a forest"
explanation="By asking specific questions about your world, I can help you expand it with new ideas!"
promiMessage="Asking 'what if' questions helps worlds grow bigger and more interesting!"
/>
</Section>
<Section>
## Build Your World!
<DragDropPrompt
title="World Builder"
instruction="Arrange to create an imaginative world"
pieces={["Help me create a world", "where all weather is controlled by", "What might go wrong?", "friendly weather wizards."]}
correctOrder={[0, 1, 3, 2]}
successMessage="What a creative world! I'm imagining so many fun scenarios!"
/>
</Section>
<Section>
## Create Your Ultimate World!
<MagicWords
sentence="Help me build a world where ___. The main thing that makes it special is ___. Who lives there? What adventures could happen?"
blanks={[
{ hint: "🌍 world concept", answers: ["dreams come to life", "everyone has superpowers", "toys can move at night", "music creates magic", "colors have feelings"] },
{ hint: "✨ special feature", answers: ["a giant magic tree in the center", "floating islands in the sky", "rivers that flow with starlight", "buildings made of clouds", "doorways to other dimensions"] }
]}
successMessage="What an incredible world! The adventures are endless!"
/>
</Section>
<Section>
## Congratulations, World Builder! 🎉
<Panel character="promi" mood="celebrating">
You did it! You've completed Creation Canyon and become a **World Builder**! Your imagination combined with AI can create endless amazing worlds!
</Panel>
<LevelComplete
levelSlug="4-4-world-builder"
stars={3}
message="You completed Creation Canyon! You're a World Builder!"
/>
</Section>

View File

@@ -0,0 +1,107 @@
<Section>
<Panel character="promi" mood="excited">
Welcome to **Master Mountain**! ⛰️ You've come so far! Now it's time to combine EVERYTHING you've learned into perfect prompts!
</Panel>
</Section>
<Section>
## The Master Checklist
A perfect prompt can include:
✅ **Clarity** - Be specific, not vague
✅ **Details** - WHO, WHAT, WHEN, WHERE
✅ **Context** - Background info, examples, format
✅ **Creativity** - Role-play, personality, imagination
</Section>
<Section>
## Magic Words: "Think Step by Step" 🧠
<StepByStep
title="Step-by-Step Magic"
problem="I have 3 bags with 5 apples each, and I eat 2 apples. How many are left?"
wrongAnswer="15 apples left (AI guessed without thinking!)"
steps={[
"First: 3 bags × 5 apples = 15 apples total",
"Next: I eat 2 apples",
"Finally: 15 - 2 = 13 apples left"
]}
rightAnswer="13 apples left - and we can check the work!"
magicWords="Let's think step by step"
successMessage="Magic words help AI show its thinking, so you can check if it's right!"
/>
</Section>
<Section>
<Panel character="promi" mood="thinking">
You don't need ALL of these every time, but knowing when to use each one makes you a Prompt Master!
</Panel>
</Section>
<Section>
## Master Challenge #1
<PromptVsMistake
question="Which prompt combines the most skills?"
good="I'm a 10-year-old who loves space. Act as a friendly astronaut and tell me 5 amazing facts about Saturn. Make it exciting and use simple words a kid would understand!"
bad="Tell me about Saturn"
explanation="This prompt has: Context (10-year-old, loves space), Role-play (friendly astronaut), Format (5 facts), Personality (exciting), and Clarity (simple words)!"
promiMessage="This is a master-level prompt! It tells me exactly what you need!"
/>
</Section>
<Section>
## Master Challenge #2
<PromptVsMistake
question="Which is closer to a perfect prompt?"
good="Pretend you're a wise old tree in an enchanted forest. I'm a young adventurer who just found you. Tell me a short story about the magical creatures who live nearby. Make it mysterious but not scary, with a happy ending!"
bad="Tell me about a forest"
explanation="This has: Role-play (wise old tree), Characters (young adventurer), Setting (enchanted forest), Topic (magical creatures), Style (mysterious, not scary, happy ending)!"
promiMessage="So many great elements combined! This will be an amazing story!"
/>
</Section>
<Section>
## Build a Master Prompt!
<DragDropPrompt
title="Perfect Prompt"
instruction="Arrange all elements into one perfect prompt"
pieces={["I'm making a birthday card for my dad who loves fishing.", "Give me 3 funny fishing jokes", "like 'Why did the fish blush? Because it saw the ocean's bottom!'", "Keep them family-friendly and short!"]}
correctOrder={[0, 1, 2, 3]}
successMessage="Perfect! Context, format, example, and style all in one prompt!"
/>
</Section>
<Section>
## Create Your Master Prompt!
<MagicWords
sentence="I'm a ___ who needs help with ___. Act as a ___ and give me ___ like ___. Make it ___!"
blanks={[
{ hint: "👤 who you are", answers: ["young artist", "curious student", "creative writer", "nature lover", "joke collector"] },
{ hint: "📚 your goal", answers: ["a school project", "a creative story", "learning something new", "making someone laugh", "planning an adventure"] },
{ hint: "🎭 a character", answers: ["friendly expert", "silly comedian", "wise teacher", "creative inventor", "storytelling grandma"] },
{ hint: "🔢 what you need", answers: ["5 fun ideas", "3 helpful tips", "some creative examples", "a short story", "an easy explanation"] },
{ hint: "💡 an example", answers: ["'Super Star Strategy'", "'Happy Helper Hint'", "'Magic Moment'", "'Wonder Word'", "'Creative Spark'"] },
{ hint: "✨ the style", answers: ["fun and easy to understand", "exciting and memorable", "creative and colorful", "helpful and encouraging", "silly but useful"] }
]}
successMessage="AMAZING! That's a true Master Prompt with all the elements!"
/>
</Section>
<Section>
## Master Skills Unlocked! 🎉
<Panel character="promi" mood="celebrating">
Incredible! You learned to combine all your skills into **perfect prompts**! You're well on your way to becoming a Prompt Master!
</Panel>
<LevelComplete
levelSlug="5-1-perfect-prompt"
stars={3}
message="You learned to create perfect prompts!"
/>
</Section>

View File

@@ -0,0 +1,108 @@
<Section>
<Panel character="promi" mood="happy">
Welcome back! Today we learn a super important skill: **finding and fixing weak prompts**! 🔧
</Panel>
</Section>
<Section>
## Spot the Problems!
Weak prompts often have:
❌ Too vague - "Write something"
❌ Missing details - "Tell me about a person"
❌ No format - Just asking without structure
❌ Unclear style - Not saying how you want it
</Section>
<Section>
## Be the Prompt Doctor! 🏥
<PromptDoctor
title="Heal This Prompt"
brokenPrompt="Write something"
problems={[
{ issue: "Too Vague", symptom: "What should I write? A story? A poem? A joke?", fix: "Write a story" },
{ issue: "No Topic", symptom: "What should the story be about?", fix: "Write a story about a dragon" },
{ issue: "No Details", symptom: "What kind of dragon? What happens?", fix: "Write a short story about a friendly dragon who bakes cookies" }
]}
healedPrompt="Write a short story about a friendly dragon who bakes cookies"
successMessage="You healed the prompt! From 2 words to a great detailed request!"
/>
</Section>
<Section>
<Panel character="promi" mood="thinking">
Learning to spot weak prompts helps you write better ones! It's like being a prompt detective!
</Panel>
</Section>
<Section>
## Find the Fix!
<PromptVsMistake
question="This prompt is weak: 'Write a poem.' How would you fix it?"
good="Write a short 4-line rhyming poem about a rainbow after a storm. Make it cheerful and use colorful words!"
bad="Write a really good poem please"
explanation="Just saying 'really good' doesn't help! Instead, add details: topic (rainbow), format (4 lines, rhyming), and style (cheerful, colorful)!"
promiMessage="Adding specific details transforms a weak prompt into a strong one!"
/>
</Section>
<Section>
## Improve This Prompt!
<PromptVsMistake
question="Weak prompt: 'Help with my homework.' How would you make it better?"
good="I'm in 4th grade and need help understanding fractions. Can you explain what 1/2 means using pizza as an example? Keep it simple!"
bad="Please help with my homework more"
explanation="The good version tells me: your level (4th grade), topic (fractions), asks for an example (pizza), and style (simple)!"
promiMessage="The more specific you are, the better I can help!"
/>
</Section>
<Section>
## Fix the Prompt!
<DragDropPrompt
title="Prompt Repair"
instruction="The prompt 'Tell me a story' is too weak. Arrange these additions to fix it:"
pieces={["about a brave little mouse", "Tell me a short bedtime story", "who helps a lost baby bird find home.", "Make it gentle and end with everyone safe."]}
correctOrder={[1, 0, 2, 3]}
successMessage="You transformed a weak prompt into a great one!"
/>
</Section>
<Section>
## Upgrade Challenge!
Take this weak prompt and make it strong:
**Weak:** "Give me ideas"
<MagicWords
sentence="Give me ___ creative ideas for ___ that are ___ and ___. Something like ___!"
blanks={[
{ hint: "🔢 how many", answers: ["5", "3", "7", "10", "4"] },
{ hint: "🎯 what for", answers: ["a birthday party", "a science project", "a fun game", "a story to write", "decorating my room"] },
{ hint: "✨ style 1", answers: ["fun", "easy to do", "creative", "surprising", "colorful"] },
{ hint: "🌟 style 2", answers: ["kid-friendly", "not too expensive", "unique", "exciting", "simple"] },
{ hint: "💡 example", answers: ["a treasure hunt", "making slime", "a superhero theme", "glow-in-the-dark stuff", "a magic show"] }
]}
successMessage="You turned a 2-word weak prompt into an amazing detailed one!"
/>
</Section>
<Section>
## Prompt Fixer! 🎉
<Panel character="promi" mood="celebrating">
Excellent! You learned to spot weak prompts and **fix them** by adding details, format, and style! This skill will help you forever!
</Panel>
<LevelComplete
levelSlug="5-2-fix-it-up"
stars={3}
message="You learned to find and fix weak prompts!"
/>
</Section>

View File

@@ -0,0 +1,106 @@
<Section>
<Panel character="promi" mood="excited">
Today we learn **Prompt Remix**! 🎵 This means changing prompts to get different results!
</Panel>
</Section>
<Section>
## Same Topic, Different Results!
You can ask about the same thing in different ways to get different answers:
- **For fun**: "Tell me about dolphins in a silly way"
- **For school**: "Give me 5 educational facts about dolphins"
- **For creativity**: "Write a poem from a dolphin's point of view"
</Section>
<Section>
## Try the Prompt Lab! 🔬
<PromptLab
title="Improve Your Prompt"
scenario="Let's make a simple prompt better by adding details one at a time!"
basePrompt="Tell me about dogs"
baseResponse="Dogs are animals. They have four legs and fur."
improvements={[
{ label: "Add a specific breed", prompt: "Tell me about Golden Retriever dogs", response: "Golden Retrievers are wonderful dogs known for their friendly personality, golden fur, and love for swimming!" },
{ label: "Add an audience", prompt: "Tell me about Golden Retriever dogs for a 10-year-old", response: "Golden Retrievers are super friendly dogs that love to play fetch and swim! They have soft golden fur and big happy smiles!" },
{ label: "Add a format", prompt: "Give me 3 fun facts about Golden Retriever dogs for a 10-year-old", response: "Here are 3 fun facts about Golden Retrievers: 1) They were trained to fetch birds for hunters, 2) They can learn over 200 words, 3) They have webbed feet which makes them great swimmers!" }
]}
successMessage="Each detail you added made the response better and more useful!"
/>
</Section>
<Section>
<Panel character="promi" mood="thinking">
Remixing prompts means you can explore the same topic in many exciting ways!
</Panel>
</Section>
<Section>
## See the Remix!
<PromptVsMistake
question="You want to learn about dinosaurs but in a FUN way. Which remix is best?"
good="Pretend you're a T-Rex who just woke up. Tell me about your day - what do you eat, who are your friends, and what makes you grumpy?"
bad="Give me facts about T-Rex"
explanation="Same topic (T-Rex), but the remix makes it a fun story from the dinosaur's perspective!"
promiMessage="Remixing the same topic gives you fresh, fun ways to learn!"
/>
</Section>
<Section>
## Remix for Different Goals!
<PromptVsMistake
question="You learned about the moon. Now you want to write a creative story. Which remix works?"
good="Write a bedtime story about a little star who wants to visit the moon. Make it magical with a sweet ending!"
bad="Tell me more facts about the moon"
explanation="You remixed from 'learning facts' to 'creative story' - same topic, different purpose!"
promiMessage="Remixing lets you use what you know in new creative ways!"
/>
</Section>
<Section>
## Try Different Remixes!
<DragDropPrompt
title="Prompt Remix"
instruction="Remix 'Tell me about cats' into a creative prompt:"
pieces={["and describe your favorite napping spot", "Write from the view of a lazy cat", "who lives in a cozy bookshop.", "Make it funny and relaxed!!"]}
correctOrder={[1, 2, 0, 3]}
successMessage="Great remix! Same topic, totally different and fun approach!"
/>
</Section>
<Section>
## Create Your Remix!
Take the basic topic "robots" and remix it:
<MagicWords
sentence="___ a ___ robot who ___. Describe ___. Make it ___!"
blanks={[
{ hint: "📝 what to write", answers: ["Tell a story about", "Write a diary entry from", "Create a song about", "Describe a day for", "Interview"] },
{ hint: "🤖 robot type", answers: ["tiny helper", "dancing", "cooking", "space explorer", "friendly classroom"] },
{ hint: "⭐ what it does", answers: ["just learned to make friends", "discovered it loves music", "made a silly mistake", "is going on its first adventure", "met a human for the first time"] },
{ hint: "🎯 what to include", answers: ["how it feels about its new discovery", "the funniest moment of its day", "what it dreams about", "its favorite memory", "what it learned today"] },
{ hint: "✨ the style", answers: ["heartwarming and sweet", "silly and fun", "exciting and adventurous", "peaceful and calm", "mysterious and curious"] }
]}
successMessage="Awesome remix! You turned 'robots' into something totally unique!"
/>
</Section>
<Section>
## Remix Master! 🎉
<Panel character="promi" mood="celebrating">
Fantastic! You learned to **remix prompts** to get different results from the same topic! This makes your creativity endless!
</Panel>
<LevelComplete
levelSlug="5-3-prompt-remix"
stars={3}
message="You learned to remix prompts for different results!"
/>
</Section>

View File

@@ -0,0 +1,102 @@
<Section>
<Panel character="promi" mood="excited">
🎉 **CONGRATULATIONS!** 🎉 You've made it to the FINAL LEVEL! This is **Graduation Day**!
</Panel>
</Section>
<Section>
## Look How Far You've Come!
You've mastered:
⭐ **World 1** - What AI is and why clarity matters
⭐ **World 2** - WHO, WHAT, WHEN, WHERE details
⭐ **World 3** - Context, examples, and formats
⭐ **World 4** - Role-play, stories, and creativity
⭐ **World 5** - Combining everything perfectly!
</Section>
<Section>
<Panel character="promi" mood="happy">
I'm SO proud of you! You've become a true Prompt Master! Let's celebrate with some final challenges!
</Panel>
</Section>
<Section>
## Final Challenge #1
<PromptVsMistake
question="Show me your best prompt skills! Which is the master-level prompt?"
good="I'm a creative 11-year-old working on a comic book. Act as a fun superhero coach and help me create 3 unique superhero names with cool powers. Something like 'Starblaze - controls cosmic fire!' Make them exciting but kid-friendly!"
bad="Give me superhero names"
explanation="This master prompt has EVERYTHING: context (11-year-old, comic book), role (superhero coach), format (3 names with powers), example (Starblaze), and style (exciting, kid-friendly)!"
promiMessage="THAT is a Prompt Master at work! Perfect in every way!"
/>
</Section>
<Section>
## Final Challenge #2
<PromptVsMistake
question="Create the ultimate helpful prompt!"
good="I'm nervous about my first day at a new school tomorrow. Pretend you're a kind older kid who's been through this before. Give me 5 tips to feel brave and make new friends. Be encouraging and remind me it's okay to be nervous!"
bad="Help me with school"
explanation="This prompt is heartfelt AND masterful: real situation (nervous, new school), role (kind older kid), format (5 tips), and emotional style (encouraging, understanding)!"
promiMessage="This shows prompts can help with real feelings too! Beautiful work!"
/>
</Section>
<Section>
## The Ultimate Prompt Challenge!
<DragDropPrompt
title="Graduation Challenge"
instruction="Build the most complete prompt possible!"
pieces={["I'm a young chef who loves baking.", "Act as a friendly baking instructor", "and give me 3 easy cookie recipes for beginners,", "like 'Simple Sugar Cookies - only 5 ingredients!'", "Make the instructions clear and fun!"]}
correctOrder={[0, 1, 2, 3, 4]}
successMessage="PERFECT! Context, role, format, example, AND style! You're a true master!"
/>
</Section>
<Section>
## Create Your Graduation Masterpiece!
<MagicWords
sentence="I'm a ___ who wants to ___. Act as a ___ and help me with ___. Give me something like '___'. Make it ___ and ___!"
blanks={[
{ hint: "👤 who you are", answers: ["creative kid", "young explorer", "curious learner", "aspiring artist", "future inventor"] },
{ hint: "🎯 your goal", answers: ["create something amazing", "learn something new", "solve a problem", "make people smile", "start an adventure"] },
{ hint: "🎭 a helpful role", answers: ["wise mentor", "fun coach", "creative guide", "patient teacher", "encouraging friend"] },
{ hint: "📚 what you need", answers: ["3 brilliant ideas", "a step-by-step plan", "an inspiring story", "helpful tips", "a creative project"] },
{ hint: "💡 an example", answers: ["Build a cardboard rocket!", "Write a song about kindness", "Design a dream treehouse", "Create a new game", "Invent a helpful robot"] },
{ hint: "✨ style 1", answers: ["fun", "inspiring", "creative", "exciting", "encouraging"] },
{ hint: "🌟 style 2", answers: ["easy to follow", "full of imagination", "memorable", "unique", "joyful"] }
]}
successMessage="🎉 MASTERPIECE! You've created the ultimate prompt! You are officially a PROMPT MASTER!"
/>
</Section>
<Section>
## 🎓 YOU DID IT! 🎓
<Panel character="promi" mood="celebrating">
**CONGRATULATIONS, PROMPT MASTER!** 🏆
You've completed ALL levels! You now know how to talk to AI in the best ways possible. You can:
- Be clear and specific
- Add amazing details
- Give helpful context
- Be creative and imaginative
- And so much more!
Remember: The better your prompts, the better AI can help you. Go out there and create amazing things!
**Thank you for learning with me! 🤖❤️**
</Panel>
<LevelComplete
levelSlug="5-4-graduation-day"
stars={3}
message="🎓 CONGRATULATIONS! You've graduated as a PROMPT MASTER! 🏆"
/>
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
¡Hola! Soy **Promi** 🤖, ¡tu amigo robot! ¡Estoy muy feliz de conocerte! ¡Hola! Soy **Promi** 🤖, ¡tu amigo robot! ¡Estoy muy feliz de conocerte!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
¡Soy una IA! Puedo leer tus mensajes e intentar ayudarte. Pero aquí está el secreto... ¡Necesito **buenas instrucciones** para hacer mi mejor trabajo! ¡Soy una IA! Puedo leer tus mensajes e intentar ayudarte. Pero aquí está el secreto... ¡Necesito **buenas instrucciones** para hacer mi mejor trabajo!
</Panel> </Panel>
</Section>
<Section>
## ¿Qué es un Prompt? ## ¿Qué es un Prompt?
Un **prompt** es simplemente una palabra elegante para el mensaje que envías a una IA como yo. Un **prompt** es simplemente una palabra elegante para el mensaje que envías a una IA como yo.
@@ -19,7 +22,9 @@ Piénsalo como dar direcciones a un amigo. Si dices "¡Ve allí!" tu amigo no sa
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
¡Cuando escribes un buen prompt, puedo entender lo que quieres y ayudarte mejor! ¡Practiquemos! ¡Cuando escribes un buen prompt, puedo entender lo que quieres y ayudarte mejor! ¡Practiquemos!
</Panel> </Panel>
</Section>
<Section>
## ¡Intentémoslo! ## ¡Intentémoslo!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Piénsalo como dar direcciones a un amigo. Si dices "¡Ve allí!" tu amigo no sa
explanation="¡El primer mensaje le dice a Promi exactamente qué tipo de historia escribir! El segundo es muy corto - Promi no sabe qué tipo de historia quieres." explanation="¡El primer mensaje le dice a Promi exactamente qué tipo de historia escribir! El segundo es muy corto - Promi no sabe qué tipo de historia quieres."
promiMessage="¿Ves? ¡Más detalles me ayudan a entender lo que quieres!" promiMessage="¿Ves? ¡Más detalles me ayudan a entender lo que quieres!"
/> />
</Section>
<Section>
## ¡Quiz Rápido! ## ¡Quiz Rápido!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Piénsalo como dar direcciones a un amigo. Si dices "¡Ve allí!" tu amigo no sa
explanation="¡Un prompt usa palabras para decirle a la IA lo que necesitas. Los emojis son divertidos pero no dan suficiente información!" explanation="¡Un prompt usa palabras para decirle a la IA lo que necesitas. Los emojis son divertidos pero no dan suficiente información!"
promiMessage="¡Las palabras son mi superpoder! ¡Cuanto más me digas, mejor puedo ayudar!" promiMessage="¡Las palabras son mi superpoder! ¡Cuanto más me digas, mejor puedo ayudar!"
/> />
</Section>
<Section>
## ¡Lo Lograste! 🎉 ## ¡Lo Lograste! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
¡Increíble trabajo! Aprendiste qué es la IA y qué es un prompt. ¡Ya te estás convirtiendo en un experto en prompts! ¡Increíble trabajo! Aprendiste qué es la IA y qué es un prompt. ¡Ya te estás convirtiendo en un experto en prompts!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="¡Aprendiste qué son la IA y los prompts!" message="¡Aprendiste qué son la IA y los prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
¡Bienvenido de nuevo, amigo! ¿Listo para escribir tus primeros prompts reales? ¡Vamos! 🚀 ¡Bienvenido de nuevo, amigo! ¿Listo para escribir tus primeros prompts reales? ¡Vamos! 🚀
</Panel> </Panel>
</Section>
<Section>
## La Magia de las Palabras ## La Magia de las Palabras
Cuando hablas con la IA, ¡cada palabra importa! Veamos cómo agregar más palabras hace mejores los prompts. Cuando hablas con la IA, ¡cada palabra importa! Veamos cómo agregar más palabras hace mejores los prompts.
@@ -9,7 +12,9 @@ Cuando hablas con la IA, ¡cada palabra importa! Veamos cómo agregar más palab
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
¡Mira esto! Si alguien solo me dice "gato", no sé qué quieren. ¿Quieren una imagen? ¿Una historia? ¿Datos sobre gatos? ¡Estoy confundido! 😵‍💫 ¡Mira esto! Si alguien solo me dice "gato", no sé qué quieren. ¿Quieren una imagen? ¿Una historia? ¿Datos sobre gatos? ¡Estoy confundido! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Construyendo Mejores Prompts ## Construyendo Mejores Prompts
Un buen prompt tiene **tres partes**: Un buen prompt tiene **tres partes**:
@@ -21,7 +26,9 @@ Un buen prompt tiene **tres partes**:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
¡Construyamos un prompt juntos! ¡Construyamos un prompt juntos!
</Panel> </Panel>
</Section>
<Section>
## ¡Arrastra las Piezas! ## ¡Arrastra las Piezas!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Un buen prompt tiene **tres partes**:
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="¡Perfecto! ¡Ese es un gran prompt!" successMessage="¡Perfecto! ¡Ese es un gran prompt!"
/> />
</Section>
<Section>
## ¡Llena los Espacios! ## ¡Llena los Espacios!
Ahora intenta hacer tu propio prompt arrastrando las palabras mágicas: Ahora intenta hacer tu propio prompt arrastrando las palabras mágicas:
<MagicWords <MagicWords
title="¡Crea tu propio prompt! ✨" title="¡Crea tu propio prompt! ✨"
sentence="Por favor escribe un {{type}} sobre un {{character}} que {{action}}" sentence="Por favor escribe un {{type}} sobre un {{character}} que {{action}}"
@@ -51,7 +61,9 @@ Ahora intenta hacer tu propio prompt arrastrando las palabras mágicas:
]} ]}
successMessage="¡Wow! ¡Creaste un prompt increíble!" successMessage="¡Wow! ¡Creaste un prompt increíble!"
/> />
</Section>
<Section>
## ¡Tu Turno de Elegir! ## ¡Tu Turno de Elegir!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Ahora intenta hacer tu propio prompt arrastrando las palabras mágicas:
explanation="¡El primer prompt me dice que debe ser gracioso, es sobre un pingüino, Y lo que el pingüino quiere hacer!" explanation="¡El primer prompt me dice que debe ser gracioso, es sobre un pingüino, Y lo que el pingüino quiere hacer!"
promiMessage="¡Los detalles hacen todo mejor! ¡Me encanta saber exactamente lo que quieres!" promiMessage="¡Los detalles hacen todo mejor! ¡Me encanta saber exactamente lo que quieres!"
/> />
</Section>
<Section>
## ¡Gran Trabajo! 🌟 ## ¡Gran Trabajo! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
¡Escribiste tus primeros prompts! Aprendiste que los buenos prompts necesitan: lo que quieres, un tema y detalles. ¡Te estás volviendo muy bueno en esto! ¡Escribiste tus primeros prompts! Aprendiste que los buenos prompts necesitan: lo que quieres, un tema y detalles. ¡Te estás volviendo muy bueno en esto!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="¡Aprendiste a escribir tus primeros prompts!" message="¡Aprendiste a escribir tus primeros prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
¡Hola superestrella! 🌟 Hoy vamos a aprender la habilidad más importante: ¡ser **CLARO**! ¡Hola superestrella! 🌟 Hoy vamos a aprender la habilidad más importante: ¡ser **CLARO**!
</Panel> </Panel>
</Section>
<Section>
## Por Qué Ser Claro Importa ## Por Qué Ser Claro Importa
Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de maní sin corteza." ¿Cuál te da exactamente lo que quieres? Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de maní sin corteza." ¿Cuál te da exactamente lo que quieres?
@@ -9,11 +12,14 @@ Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de m
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
¡Es lo mismo conmigo! Cuando eres claro, sé exactamente cómo ayudar. Cuando eres vago, tengo que adivinar... ¡y podría adivinar mal! ¡Es lo mismo conmigo! Cuando eres claro, sé exactamente cómo ayudar. Cuando eres vago, tengo que adivinar... ¡y podría adivinar mal!
</Panel> </Panel>
</Section>
<Section>
## Claro vs. No Claro ## Claro vs. No Claro
¡Practiquemos detectando la diferencia! ¡Practiquemos detectando la diferencia!
<PromptVsMistake <PromptVsMistake
question="¿Qué prompt es más claro?" question="¿Qué prompt es más claro?"
good="Escribe un poema de 4 líneas sobre mariposas en un jardín, usando palabras que rimen" good="Escribe un poema de 4 líneas sobre mariposas en un jardín, usando palabras que rimen"
@@ -22,6 +28,7 @@ Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de m
promiMessage="¡Prompts claros = mejores resultados! ¡Es como magia!" promiMessage="¡Prompts claros = mejores resultados! ¡Es como magia!"
/> />
<PromptVsMistake <PromptVsMistake
question="¿Cuál me dice exactamente lo que necesitas?" question="¿Cuál me dice exactamente lo que necesitas?"
good="Ayúdame a escribir 3 datos divertidos sobre delfines que un niño de 10 años disfrutaría" good="Ayúdame a escribir 3 datos divertidos sobre delfines que un niño de 10 años disfrutaría"
@@ -29,11 +36,14 @@ Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de m
explanation="El primer prompt me dice: cuántos datos (3), qué tipo (divertidos), y para quién (niño de 10 años). ¡Eso ayuda mucho!" explanation="El primer prompt me dice: cuántos datos (3), qué tipo (divertidos), y para quién (niño de 10 años). ¡Eso ayuda mucho!"
promiMessage="¡Cuando me dices para quién es, puedo hacerlo perfecto para ellos!" promiMessage="¡Cuando me dices para quién es, puedo hacerlo perfecto para ellos!"
/> />
</Section>
<Section>
## El Desafío de Claridad ## El Desafío de Claridad
¡Construyamos el prompt más claro de todos! ¡Construyamos el prompt más claro de todos!
<DragDropPrompt <DragDropPrompt
title="¡Hazlo cristalino! 💎" title="¡Hazlo cristalino! 💎"
instruction="Organiza estas piezas para hacer un prompt súper claro" instruction="Organiza estas piezas para hacer un prompt súper claro"
@@ -47,7 +57,9 @@ Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de m
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="¡Ese es el prompt más claro! ¡Increíble!" successMessage="¡Ese es el prompt más claro! ¡Increíble!"
/> />
</Section>
<Section>
## Agrega Detalles Claros ## Agrega Detalles Claros
<MagicWords <MagicWords
@@ -61,7 +73,9 @@ Imagina pedirle a tu mamá "comida" vs pedirle "un sándwich de mantequilla de m
]} ]}
successMessage="¡Agregaste todos los detalles importantes! ¡Buen trabajo!" successMessage="¡Agregaste todos los detalles importantes! ¡Buen trabajo!"
/> />
</Section>
<Section>
## Las Reglas de Oro de la Claridad ## Las Reglas de Oro de la Claridad
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@ Recuerda estas tres preguntas cuando escribas un prompt:
2. **¿CÓMO** debe ser? (corto, gracioso, simple) 2. **¿CÓMO** debe ser? (corto, gracioso, simple)
3. **¿PARA QUIÉN** es? (yo, mi amigo, mi clase) 3. **¿PARA QUIÉN** es? (yo, mi amigo, mi clase)
<PromptVsMistake <PromptVsMistake
question="¡Desafío final! ¿Cuál usa las tres reglas?" question="¡Desafío final! ¿Cuál usa las tres reglas?"
good="Escribe un chiste corto y gracioso sobre pizza que pueda contar a mis amigos en el almuerzo" good="Escribe un chiste corto y gracioso sobre pizza que pueda contar a mis amigos en el almuerzo"
@@ -81,7 +96,9 @@ Recuerda estas tres preguntas cuando escribas un prompt:
explanation="¡El gran prompt tiene QUÉ (un chiste sobre pizza), CÓMO (corto y gracioso), y PARA QUIÉN (para contar a amigos en el almuerzo)!" explanation="¡El gran prompt tiene QUÉ (un chiste sobre pizza), CÓMO (corto y gracioso), y PARA QUIÉN (para contar a amigos en el almuerzo)!"
promiMessage="¡Eres un campeón de la claridad! 🏆" promiMessage="¡Eres un campeón de la claridad! 🏆"
/> />
</Section>
<Section>
## ¡Mundo 1 Completo! 🎊 ## ¡Mundo 1 Completo! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@ Recuerda estas tres preguntas cuando escribas un prompt:
¡Estás listo para nuevas aventuras! ¡Estás listo para nuevas aventuras!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="¡Dominaste el arte de ser claro! ¡Mundo 1 completo!" message="¡Dominaste el arte de ser claro! ¡Mundo 1 completo!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
سلام! من **Promi** 🤖 هستم، دوست رباتت! خیلی خوشحالم که باهات آشنا شدم! سلام! من **Promi** 🤖 هستم، دوست رباتت! خیلی خوشحالم که باهات آشنا شدم!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
من یه هوش مصنوعی‌ام! می‌تونم پیام‌هات رو بخونم و سعی کنم کمکت کنم. ولی اینجا یه راز هست... برای بهترین کار به **دستورالعمل‌های خوب** نیاز دارم! من یه هوش مصنوعی‌ام! می‌تونم پیام‌هات رو بخونم و سعی کنم کمکت کنم. ولی اینجا یه راز هست... برای بهترین کار به **دستورالعمل‌های خوب** نیاز دارم!
</Panel> </Panel>
</Section>
<Section>
## پرامپت چیه؟ ## پرامپت چیه؟
**پرامپت** فقط یه کلمه شیک برای پیامی‌ه که به یه هوش مصنوعی مثل من می‌فرستی. **پرامپت** فقط یه کلمه شیک برای پیامی‌ه که به یه هوش مصنوعی مثل من می‌فرستی.
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
وقتی پرامپت خوب می‌نویسی، می‌تونم بفهمم چی می‌خوای و بهتر کمکت کنم! بیا تمرین کنیم! وقتی پرامپت خوب می‌نویسی، می‌تونم بفهمم چی می‌خوای و بهتر کمکت کنم! بیا تمرین کنیم!
</Panel> </Panel>
</Section>
<Section>
## بیا امتحان کنیم! ## بیا امتحان کنیم!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="پیام اول به Promi دقیقاً می‌گه چه نوع داستانی بنویسه! دومی خیلی کوتاهه - Promi نمی‌دونه چه جور داستانی می‌خوای." explanation="پیام اول به Promi دقیقاً می‌گه چه نوع داستانی بنویسه! دومی خیلی کوتاهه - Promi نمی‌دونه چه جور داستانی می‌خوای."
promiMessage="دیدی؟ جزئیات بیشتر کمکم می‌کنه بفهمم چی می‌خوای!" promiMessage="دیدی؟ جزئیات بیشتر کمکم می‌کنه بفهمم چی می‌خوای!"
/> />
</Section>
<Section>
## آزمون سریع! ## آزمون سریع!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="پرامپت از کلمات استفاده می‌کنه تا به هوش مصنوعی بگه چی نیاز داری. ایموجی‌ها سرگرم‌کننده‌ن ولی اطلاعات کافی نمی‌دن!" explanation="پرامپت از کلمات استفاده می‌کنه تا به هوش مصنوعی بگه چی نیاز داری. ایموجی‌ها سرگرم‌کننده‌ن ولی اطلاعات کافی نمی‌دن!"
promiMessage="کلمات ابرقدرت منن! هرچی بیشتر بگی، بهتر می‌تونم کمک کنم!" promiMessage="کلمات ابرقدرت منن! هرچی بیشتر بگی، بهتر می‌تونم کمک کنم!"
/> />
</Section>
<Section>
## موفق شدی! 🎉 ## موفق شدی! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
کار عالی! یاد گرفتی هوش مصنوعی چیه و پرامپت چیه. داری متخصص پرامپت می‌شی! کار عالی! یاد گرفتی هوش مصنوعی چیه و پرامپت چیه. داری متخصص پرامپت می‌شی!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="یاد گرفتی هوش مصنوعی و پرامپت چین!" message="یاد گرفتی هوش مصنوعی و پرامپت چین!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
خوش اومدی دوباره، دوست! آماده‌ای اولین پرامپت‌های واقعیت رو بنویسی؟ بریم! 🚀 خوش اومدی دوباره، دوست! آماده‌ای اولین پرامپت‌های واقعیت رو بنویسی؟ بریم! 🚀
</Panel> </Panel>
</Section>
<Section>
## جادوی کلمات ## جادوی کلمات
وقتی با هوش مصنوعی حرف می‌زنی، هر کلمه مهمه! بیا ببینیم چطور اضافه کردن کلمات بیشتر پرامپت‌ها رو بهتر می‌کنه. وقتی با هوش مصنوعی حرف می‌زنی، هر کلمه مهمه! بیا ببینیم چطور اضافه کردن کلمات بیشتر پرامپت‌ها رو بهتر می‌کنه.
@@ -9,7 +12,9 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
ببین! اگه کسی فقط بگه "گربه"، نمی‌دونم چی می‌خوان. عکس می‌خوان؟ داستان؟ حقایق درباره گربه‌ها؟ گیج شدم! 😵‍💫 ببین! اگه کسی فقط بگه "گربه"، نمی‌دونم چی می‌خوان. عکس می‌خوان؟ داستان؟ حقایق درباره گربه‌ها؟ گیج شدم! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## ساختن پرامپت‌های بهتر ## ساختن پرامپت‌های بهتر
یه پرامپت خوب **سه بخش** داره: یه پرامپت خوب **سه بخش** داره:
@@ -21,7 +26,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
بیا با هم یه پرامپت بسازیم! بیا با هم یه پرامپت بسازیم!
</Panel> </Panel>
</Section>
<Section>
## تکه‌ها رو بکش! ## تکه‌ها رو بکش!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="عالی! این یه پرامپت فوق‌العاده‌ست!" successMessage="عالی! این یه پرامپت فوق‌العاده‌ست!"
/> />
</Section>
<Section>
## جای خالی رو پر کن! ## جای خالی رو پر کن!
حالا سعی کن پرامپت خودت رو با کشیدن کلمات جادویی بسازی: حالا سعی کن پرامپت خودت رو با کشیدن کلمات جادویی بسازی:
<MagicWords <MagicWords
title="پرامپت خودت رو بساز! ✨" title="پرامپت خودت رو بساز! ✨"
sentence="لطفاً یه {{type}} بنویس، درباره یه {{character}} که {{action}}" sentence="لطفاً یه {{type}} بنویس، درباره یه {{character}} که {{action}}"
@@ -51,7 +61,9 @@
]} ]}
successMessage="وای! یه پرامپت عالی ساختی!" successMessage="وای! یه پرامپت عالی ساختی!"
/> />
</Section>
<Section>
## نوبت تو برای انتخاب! ## نوبت تو برای انتخاب!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@
explanation="پرامپت اول بهم می‌گه باید خنده‌دار باشه، درباره پنگوئنه، و پنگوئن چیکار می‌خواد بکنه!" explanation="پرامپت اول بهم می‌گه باید خنده‌دار باشه، درباره پنگوئنه، و پنگوئن چیکار می‌خواد بکنه!"
promiMessage="جزئیات همه چیز رو بهتر می‌کنه! دوست دارم دقیقاً بدونم چی می‌خوای!" promiMessage="جزئیات همه چیز رو بهتر می‌کنه! دوست دارم دقیقاً بدونم چی می‌خوای!"
/> />
</Section>
<Section>
## کار عالی! 🌟 ## کار عالی! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
اولین پرامپت‌هات رو نوشتی! یاد گرفتی پرامپت‌های خوب به چی نیاز دارن: چی می‌خوای، موضوع و جزئیات. داری خیلی خوب می‌شی! اولین پرامپت‌هات رو نوشتی! یاد گرفتی پرامپت‌های خوب به چی نیاز دارن: چی می‌خوای، موضوع و جزئیات. داری خیلی خوب می‌شی!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="یاد گرفتی چطور اولین پرامپت‌هات رو بنویسی!" message="یاد گرفتی چطور اولین پرامپت‌هات رو بنویسی!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
سلام سوپراستار! 🌟 امروز می‌خوایم مهم‌ترین مهارت رو یاد بگیریم: **واضح** بودن! سلام سوپراستار! 🌟 امروز می‌خوایم مهم‌ترین مهارت رو یاد بگیریم: **واضح** بودن!
</Panel> </Panel>
</Section>
<Section>
## چرا واضح بودن مهمه ## چرا واضح بودن مهمه
فکر کن از مامانت "غذا" بخوای یا "ساندویچ کره بادام‌زمینی بدون لبه." کدوم دقیقاً چیزی که می‌خوای رو بهت می‌ده؟ فکر کن از مامانت "غذا" بخوای یا "ساندویچ کره بادام‌زمینی بدون لبه." کدوم دقیقاً چیزی که می‌خوای رو بهت می‌ده؟
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
با منم همینطوره! وقتی واضحی، دقیقاً می‌دونم چطور کمک کنم. وقتی مبهمی، باید حدس بزنم... و ممکنه اشتباه کنم! با منم همینطوره! وقتی واضحی، دقیقاً می‌دونم چطور کمک کنم. وقتی مبهمی، باید حدس بزنم... و ممکنه اشتباه کنم!
</Panel> </Panel>
</Section>
<Section>
## واضح در مقابل نامفهوم ## واضح در مقابل نامفهوم
بیا تمرین کنیم فرق رو پیدا کنیم! بیا تمرین کنیم فرق رو پیدا کنیم!
<PromptVsMistake <PromptVsMistake
question="کدوم پرامپت واضح‌تره؟" question="کدوم پرامپت واضح‌تره؟"
good="یه شعر ۴ خطی درباره پروانه‌ها توی باغ بنویس، با کلمات قافیه‌دار" good="یه شعر ۴ خطی درباره پروانه‌ها توی باغ بنویس، با کلمات قافیه‌دار"
@@ -22,6 +28,7 @@
promiMessage="پرامپت‌های واضح = نتایج بهتر! مثل جادوئه!" promiMessage="پرامپت‌های واضح = نتایج بهتر! مثل جادوئه!"
/> />
<PromptVsMistake <PromptVsMistake
question="کدوم دقیقاً می‌گه چی نیاز داری؟" question="کدوم دقیقاً می‌گه چی نیاز داری؟"
good="کمکم کن ۳ حقیقت جالب درباره دلفین‌ها بنویسم که بچه ۱۰ ساله ازش لذت ببره" good="کمکم کن ۳ حقیقت جالب درباره دلفین‌ها بنویسم که بچه ۱۰ ساله ازش لذت ببره"
@@ -29,11 +36,14 @@
explanation="پرامپت اول بهم می‌گه: چند تا حقیقت (۳)، چه جور (جالب)، و برای کی (۱۰ ساله). این خیلی کمک می‌کنه!" explanation="پرامپت اول بهم می‌گه: چند تا حقیقت (۳)، چه جور (جالب)، و برای کی (۱۰ ساله). این خیلی کمک می‌کنه!"
promiMessage="وقتی بگی برای کیه، می‌تونم برای اون‌ها عالی بسازمش!" promiMessage="وقتی بگی برای کیه، می‌تونم برای اون‌ها عالی بسازمش!"
/> />
</Section>
<Section>
## چالش وضوح ## چالش وضوح
بیا واضح‌ترین پرامپت رو بسازیم! بیا واضح‌ترین پرامپت رو بسازیم!
<DragDropPrompt <DragDropPrompt
title="مثل بلور واضحش کن! 💎" title="مثل بلور واضحش کن! 💎"
instruction="این تکه‌ها رو مرتب کن تا یه پرامپت فوق‌العاده واضح بسازی" instruction="این تکه‌ها رو مرتب کن تا یه پرامپت فوق‌العاده واضح بسازی"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="این واضح‌ترین پرامپت تا حالاست! عالی!" successMessage="این واضح‌ترین پرامپت تا حالاست! عالی!"
/> />
</Section>
<Section>
## جزئیات واضح اضافه کن ## جزئیات واضح اضافه کن
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="همه جزئیات مهم رو اضافه کردی! کار عالی!" successMessage="همه جزئیات مهم رو اضافه کردی! کار عالی!"
/> />
</Section>
<Section>
## قوانین طلایی وضوح ## قوانین طلایی وضوح
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **چطور** باشه؟ (کوتاه، خنده‌دار، ساده) 2. **چطور** باشه؟ (کوتاه، خنده‌دار، ساده)
3. **برای کی**؟ (من، دوستم، کلاسم) 3. **برای کی**؟ (من، دوستم، کلاسم)
<PromptVsMistake <PromptVsMistake
question="چالش آخر! کدوم از هر سه قانون استفاده می‌کنه؟" question="چالش آخر! کدوم از هر سه قانون استفاده می‌کنه؟"
good="یه جوک کوتاه و خنده‌دار درباره پیتزا بنویس که بتونم موقع ناهار به دوستام بگم" good="یه جوک کوتاه و خنده‌دار درباره پیتزا بنویس که بتونم موقع ناهار به دوستام بگم"
@@ -81,7 +96,9 @@
explanation="پرامپت عالی چی داره (جوک پیتزا)، چطور (کوتاه و خنده‌دار)، و برای کی (برای گفتن به دوستا موقع ناهار)!" explanation="پرامپت عالی چی داره (جوک پیتزا)، چطور (کوتاه و خنده‌دار)، و برای کی (برای گفتن به دوستا موقع ناهار)!"
promiMessage="تو قهرمان وضوحی! 🏆" promiMessage="تو قهرمان وضوحی! 🏆"
/> />
</Section>
<Section>
## دنیای ۱ تموم شد! 🎊 ## دنیای ۱ تموم شد! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
آماده ماجراجویی‌های جدیدی! آماده ماجراجویی‌های جدیدی!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="هنر واضح بودن رو یاد گرفتی! دنیای ۱ تموم شد!" message="هنر واضح بودن رو یاد گرفتی! دنیای ۱ تموم شد!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Salut ! Je suis **Promi** 🤖, ton ami robot ! Je suis tellement content de te rencontrer ! Salut ! Je suis **Promi** 🤖, ton ami robot ! Je suis tellement content de te rencontrer !
</Panel> </Panel>
@@ -9,7 +10,9 @@ Tu sais ce que veut dire **IA** ? IA signifie **Intelligence Artificielle**. C'e
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Je suis une IA ! Je peux lire tes messages et essayer de t'aider. Mais voici le secret... J'ai besoin de **bonnes instructions** pour faire mon meilleur travail ! Je suis une IA ! Je peux lire tes messages et essayer de t'aider. Mais voici le secret... J'ai besoin de **bonnes instructions** pour faire mon meilleur travail !
</Panel> </Panel>
</Section>
<Section>
## C'est quoi un Prompt ? ## C'est quoi un Prompt ?
Un **prompt** est juste un mot chic pour le message que tu envoies à une IA comme moi. Un **prompt** est juste un mot chic pour le message que tu envoies à une IA comme moi.
@@ -19,7 +22,9 @@ Pense à ça comme donner des directions à un ami. Si tu dis "Va là-bas !" ton
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Quand tu écris un bon prompt, je peux comprendre ce que tu veux et mieux t'aider ! Pratiquons ! Quand tu écris un bon prompt, je peux comprendre ce que tu veux et mieux t'aider ! Pratiquons !
</Panel> </Panel>
</Section>
<Section>
## Essayons ! ## Essayons !
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Quand tu écris un bon prompt, je peux comprendre ce que tu veux et mieux t'aide
explanation="Le premier message dit à Promi exactement quel type d'histoire écrire ! Le deuxième est trop court - Promi ne sait pas quel genre d'histoire tu veux." explanation="Le premier message dit à Promi exactement quel type d'histoire écrire ! Le deuxième est trop court - Promi ne sait pas quel genre d'histoire tu veux."
promiMessage="Tu vois ? Plus de détails m'aident à comprendre ce que tu veux !" promiMessage="Tu vois ? Plus de détails m'aident à comprendre ce que tu veux !"
/> />
</Section>
<Section>
## Quiz Rapide ! ## Quiz Rapide !
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Quand tu écris un bon prompt, je peux comprendre ce que tu veux et mieux t'aide
explanation="Un prompt utilise des mots pour dire à l'IA ce dont tu as besoin. Les emojis sont amusants mais ne donnent pas assez d'informations !" explanation="Un prompt utilise des mots pour dire à l'IA ce dont tu as besoin. Les emojis sont amusants mais ne donnent pas assez d'informations !"
promiMessage="Les mots sont mon super pouvoir ! Plus tu me dis, mieux je peux t'aider !" promiMessage="Les mots sont mon super pouvoir ! Plus tu me dis, mieux je peux t'aider !"
/> />
</Section>
<Section>
## Tu as réussi ! 🎉 ## Tu as réussi ! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Super travail ! Tu as appris ce qu'est l'IA et ce qu'est un prompt. Tu deviens déjà un expert en prompts ! Super travail ! Tu as appris ce qu'est l'IA et ce qu'est un prompt. Tu deviens déjà un expert en prompts !
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="Tu as appris ce que sont l'IA et les prompts !" message="Tu as appris ce que sont l'IA et les prompts !"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Bon retour, ami ! Prêt à écrire tes premiers vrais prompts ? C'est parti ! 🚀 Bon retour, ami ! Prêt à écrire tes premiers vrais prompts ? C'est parti ! 🚀
</Panel> </Panel>
</Section>
<Section>
## La Magie des Mots ## La Magie des Mots
Quand tu parles à l'IA, chaque mot compte ! Voyons comment ajouter plus de mots rend les prompts meilleurs. Quand tu parles à l'IA, chaque mot compte ! Voyons comment ajouter plus de mots rend les prompts meilleurs.
@@ -9,7 +12,9 @@ Quand tu parles à l'IA, chaque mot compte ! Voyons comment ajouter plus de mots
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Regarde ! Si quelqu'un me dit juste "chat", je ne sais pas ce qu'ils veulent. Ils veulent une image ? Une histoire ? Des faits sur les chats ? Je suis confus ! 😵‍💫 Regarde ! Si quelqu'un me dit juste "chat", je ne sais pas ce qu'ils veulent. Ils veulent une image ? Une histoire ? Des faits sur les chats ? Je suis confus ! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Construire de Meilleurs Prompts ## Construire de Meilleurs Prompts
Un bon prompt a **trois parties** : Un bon prompt a **trois parties** :
@@ -21,7 +26,9 @@ Un bon prompt a **trois parties** :
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Construisons un prompt ensemble ! Construisons un prompt ensemble !
</Panel> </Panel>
</Section>
<Section>
## Glisse les Pièces ! ## Glisse les Pièces !
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Construisons un prompt ensemble !
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Parfait ! C'est un super prompt !" successMessage="Parfait ! C'est un super prompt !"
/> />
</Section>
<Section>
## Remplis les Blancs ! ## Remplis les Blancs !
Maintenant essaie de faire ton propre prompt en glissant les mots magiques : Maintenant essaie de faire ton propre prompt en glissant les mots magiques :
<MagicWords <MagicWords
title="Crée ton propre prompt ! ✨" title="Crée ton propre prompt ! ✨"
sentence="S'il te plaît écris un {{type}} sur un {{character}} qui {{action}}" sentence="S'il te plaît écris un {{type}} sur un {{character}} qui {{action}}"
@@ -51,7 +61,9 @@ Maintenant essaie de faire ton propre prompt en glissant les mots magiques :
]} ]}
successMessage="Wow ! Tu as créé un super prompt !" successMessage="Wow ! Tu as créé un super prompt !"
/> />
</Section>
<Section>
## À Toi de Choisir ! ## À Toi de Choisir !
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Maintenant essaie de faire ton propre prompt en glissant les mots magiques :
explanation="Le premier prompt me dit que ça doit être drôle, c'est sur un pingouin, ET ce que le pingouin veut faire !" explanation="Le premier prompt me dit que ça doit être drôle, c'est sur un pingouin, ET ce que le pingouin veut faire !"
promiMessage="Les détails rendent tout meilleur ! J'adore savoir exactement ce que tu veux !" promiMessage="Les détails rendent tout meilleur ! J'adore savoir exactement ce que tu veux !"
/> />
</Section>
<Section>
## Super Travail ! 🌟 ## Super Travail ! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Tu as écrit tes premiers prompts ! Tu as appris que les bons prompts ont besoin de : ce que tu veux, un sujet, et des détails. Tu deviens vraiment bon ! Tu as écrit tes premiers prompts ! Tu as appris que les bons prompts ont besoin de : ce que tu veux, un sujet, et des détails. Tu deviens vraiment bon !
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="Tu as appris à écrire tes premiers prompts !" message="Tu as appris à écrire tes premiers prompts !"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Salut superstar ! 🌟 Aujourd'hui on va apprendre la compétence la plus importante : être **CLAIR** ! Salut superstar ! 🌟 Aujourd'hui on va apprendre la compétence la plus importante : être **CLAIR** !
</Panel> </Panel>
</Section>
<Section>
## Pourquoi Être Clair est Important ## Pourquoi Être Clair est Important
Imagine demander à ta maman "de la nourriture" vs demander "un sandwich au beurre de cacahuète sans croûte." Lequel te donne exactement ce que tu veux ? Imagine demander à ta maman "de la nourriture" vs demander "un sandwich au beurre de cacahuète sans croûte." Lequel te donne exactement ce que tu veux ?
@@ -9,11 +12,14 @@ Imagine demander à ta maman "de la nourriture" vs demander "un sandwich au beur
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
C'est pareil avec moi ! Quand tu es clair, je sais exactement comment t'aider. Quand tu es vague, je dois deviner... et je pourrais me tromper ! C'est pareil avec moi ! Quand tu es clair, je sais exactement comment t'aider. Quand tu es vague, je dois deviner... et je pourrais me tromper !
</Panel> </Panel>
</Section>
<Section>
## Clair vs. Pas Clair ## Clair vs. Pas Clair
Pratiquons à repérer la différence ! Pratiquons à repérer la différence !
<PromptVsMistake <PromptVsMistake
question="Quel prompt est plus clair ?" question="Quel prompt est plus clair ?"
good="Écris un poème de 4 lignes sur des papillons dans un jardin, en utilisant des mots qui riment" good="Écris un poème de 4 lignes sur des papillons dans un jardin, en utilisant des mots qui riment"
@@ -22,6 +28,7 @@ Pratiquons à repérer la différence !
promiMessage="Prompts clairs = meilleurs résultats ! C'est comme de la magie !" promiMessage="Prompts clairs = meilleurs résultats ! C'est comme de la magie !"
/> />
<PromptVsMistake <PromptVsMistake
question="Lequel me dit exactement ce dont tu as besoin ?" question="Lequel me dit exactement ce dont tu as besoin ?"
good="Aide-moi à écrire 3 faits amusants sur les dauphins qu'un enfant de 10 ans aimerait" good="Aide-moi à écrire 3 faits amusants sur les dauphins qu'un enfant de 10 ans aimerait"
@@ -29,11 +36,14 @@ Pratiquons à repérer la différence !
explanation="Le premier prompt me dit : combien de faits (3), quel type (amusants), et pour qui (enfant de 10 ans). Ça aide beaucoup !" explanation="Le premier prompt me dit : combien de faits (3), quel type (amusants), et pour qui (enfant de 10 ans). Ça aide beaucoup !"
promiMessage="Quand tu me dis pour qui c'est, je peux le rendre parfait pour eux !" promiMessage="Quand tu me dis pour qui c'est, je peux le rendre parfait pour eux !"
/> />
</Section>
<Section>
## Le Défi de la Clarté ## Le Défi de la Clarté
Construisons le prompt le plus clair jamais fait ! Construisons le prompt le plus clair jamais fait !
<DragDropPrompt <DragDropPrompt
title="Rends-le cristallin ! 💎" title="Rends-le cristallin ! 💎"
instruction="Arrange ces pièces pour faire un prompt super clair" instruction="Arrange ces pièces pour faire un prompt super clair"
@@ -47,7 +57,9 @@ Construisons le prompt le plus clair jamais fait !
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="C'est le prompt le plus clair jamais fait ! Incroyable !" successMessage="C'est le prompt le plus clair jamais fait ! Incroyable !"
/> />
</Section>
<Section>
## Ajoute des Détails Clairs ## Ajoute des Détails Clairs
<MagicWords <MagicWords
@@ -61,7 +73,9 @@ Construisons le prompt le plus clair jamais fait !
]} ]}
successMessage="Tu as ajouté tous les détails importants ! Bon travail !" successMessage="Tu as ajouté tous les détails importants ! Bon travail !"
/> />
</Section>
<Section>
## Les Règles d'Or de la Clarté ## Les Règles d'Or de la Clarté
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@ Rappelle-toi ces trois questions quand tu écris un prompt :
2. **COMMENT** ça doit être ? (court, drôle, simple) 2. **COMMENT** ça doit être ? (court, drôle, simple)
3. **POUR QUI** c'est ? (moi, mon ami, ma classe) 3. **POUR QUI** c'est ? (moi, mon ami, ma classe)
<PromptVsMistake <PromptVsMistake
question="Défi final ! Lequel utilise les trois règles ?" question="Défi final ! Lequel utilise les trois règles ?"
good="Écris une blague courte et drôle sur la pizza que je peux raconter à mes amis au déjeuner" good="Écris une blague courte et drôle sur la pizza que je peux raconter à mes amis au déjeuner"
@@ -81,7 +96,9 @@ Rappelle-toi ces trois questions quand tu écris un prompt :
explanation="Le super prompt a QUOI (une blague sur la pizza), COMMENT (courte et drôle), et POUR QUI (raconter à des amis au déjeuner) !" explanation="Le super prompt a QUOI (une blague sur la pizza), COMMENT (courte et drôle), et POUR QUI (raconter à des amis au déjeuner) !"
promiMessage="Tu es un champion de la clarté ! 🏆" promiMessage="Tu es un champion de la clarté ! 🏆"
/> />
</Section>
<Section>
## Monde 1 Terminé ! 🎊 ## Monde 1 Terminé ! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@ WOW ! Tu as terminé tout le Monde 1 ! Tu as appris :
Tu es prêt pour de nouvelles aventures ! Tu es prêt pour de nouvelles aventures !
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="Tu as maîtrisé l'art d'être clair ! Monde 1 terminé !" message="Tu as maîtrisé l'art d'être clair ! Monde 1 terminé !"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
שלום! אני **Promi** 🤖, החבר הרובוט שלך! שמח מאוד להכיר אותך! שלום! אני **Promi** 🤖, החבר הרובוט שלך! שמח מאוד להכיר אותך!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
אני AI! אני יכול לקרוא את ההודעות שלך ולנסות לעזור. אבל הנה הסוד... אני צריך **הוראות טובות** כדי לעשות את העבודה הכי טובה! אני AI! אני יכול לקרוא את ההודעות שלך ולנסות לעזור. אבל הנה הסוד... אני צריך **הוראות טובות** כדי לעשות את העבודה הכי טובה!
</Panel> </Panel>
</Section>
<Section>
## מה זה פרומפט? ## מה זה פרומפט?
**פרומפט** זו פשוט מילה מפוארת להודעה שאתה שולח ל-AI כמוני. **פרומפט** זו פשוט מילה מפוארת להודעה שאתה שולח ל-AI כמוני.
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
כשאתה כותב פרומפט טוב, אני יכול להבין מה אתה רוצה ולעזור לך יותר טוב! בוא נתרגל! כשאתה כותב פרומפט טוב, אני יכול להבין מה אתה רוצה ולעזור לך יותר טוב! בוא נתרגל!
</Panel> </Panel>
</Section>
<Section>
## בוא ננסה! ## בוא ננסה!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="ההודעה הראשונה אומרת ל-Promi בדיוק איזה סוג סיפור לכתוב! השנייה קצרה מדי - Promi לא יודע איזה סוג סיפור אתה רוצה." explanation="ההודעה הראשונה אומרת ל-Promi בדיוק איזה סוג סיפור לכתוב! השנייה קצרה מדי - Promi לא יודע איזה סוג סיפור אתה רוצה."
promiMessage="רואה? יותר פרטים עוזרים לי להבין מה אתה רוצה!" promiMessage="רואה? יותר פרטים עוזרים לי להבין מה אתה רוצה!"
/> />
</Section>
<Section>
## חידון מהיר! ## חידון מהיר!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="פרומפט משתמש במילים כדי להגיד ל-AI מה אתה צריך. אמוג'ים כיפיים אבל לא נותנים מספיק מידע!" explanation="פרומפט משתמש במילים כדי להגיד ל-AI מה אתה צריך. אמוג'ים כיפיים אבל לא נותנים מספיק מידע!"
promiMessage="מילים הן כוח העל שלי! ככל שתספר לי יותר, כך אוכל לעזור יותר טוב!" promiMessage="מילים הן כוח העל שלי! ככל שתספר לי יותר, כך אוכל לעזור יותר טוב!"
/> />
</Section>
<Section>
## הצלחת! 🎉 ## הצלחת! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
עבודה מדהימה! למדת מה זה AI ומה זה פרומפט. אתה כבר הופך למומחה פרומפטים! עבודה מדהימה! למדת מה זה AI ומה זה פרומפט. אתה כבר הופך למומחה פרומפטים!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="למדת מה זה AI ופרומפטים!" message="למדת מה זה AI ופרומפטים!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
ברוך הבא בחזרה, חבר! מוכן לכתוב את הפרומפטים האמיתיים הראשונים שלך? יאללה! 🚀 ברוך הבא בחזרה, חבר! מוכן לכתוב את הפרומפטים האמיתיים הראשונים שלך? יאללה! 🚀
</Panel> </Panel>
</Section>
<Section>
## הקסם של מילים ## הקסם של מילים
כשאתה מדבר עם AI, כל מילה חשובה! בוא נראה איך הוספת יותר מילים עושה פרומפטים יותר טובים. כשאתה מדבר עם AI, כל מילה חשובה! בוא נראה איך הוספת יותר מילים עושה פרומפטים יותר טובים.
@@ -9,7 +12,9 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
תראה! אם מישהו רק אומר לי "חתול", אני לא יודע מה הם רוצים. הם רוצים תמונה? סיפור? עובדות על חתולים? אני מבולבל! 😵‍💫 תראה! אם מישהו רק אומר לי "חתול", אני לא יודע מה הם רוצים. הם רוצים תמונה? סיפור? עובדות על חתולים? אני מבולבל! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## בונים פרומפטים יותר טובים ## בונים פרומפטים יותר טובים
לפרומפט טוב יש **שלושה חלקים**: לפרומפט טוב יש **שלושה חלקים**:
@@ -21,7 +26,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
בוא נבנה פרומפט ביחד! בוא נבנה פרומפט ביחד!
</Panel> </Panel>
</Section>
<Section>
## גרור את החלקים! ## גרור את החלקים!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="מושלם! זה פרומפט נהדר!" successMessage="מושלם! זה פרומפט נהדר!"
/> />
</Section>
<Section>
## מלא את החסר! ## מלא את החסר!
עכשיו נסה לעשות פרומפט משלך על ידי גרירת מילות הקסם: עכשיו נסה לעשות פרומפט משלך על ידי גרירת מילות הקסם:
<MagicWords <MagicWords
title="צור את הפרומפט שלך! ✨" title="צור את הפרומפט שלך! ✨"
sentence="בבקשה כתוב {{type}} על {{character}} ש{{action}}" sentence="בבקשה כתוב {{type}} על {{character}} ש{{action}}"
@@ -51,7 +61,9 @@
]} ]}
successMessage="וואו! יצרת פרומפט מדהים!" successMessage="וואו! יצרת פרומפט מדהים!"
/> />
</Section>
<Section>
## תורך לבחור! ## תורך לבחור!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@
explanation="הפרומפט הראשון אומר לי שזה צריך להיות מצחיק, על פינגווין, ומה הפינגווין רוצה לעשות!" explanation="הפרומפט הראשון אומר לי שזה צריך להיות מצחיק, על פינגווין, ומה הפינגווין רוצה לעשות!"
promiMessage="פרטים עושים הכל יותר טוב! אני אוהב לדעת בדיוק מה אתה רוצה!" promiMessage="פרטים עושים הכל יותר טוב! אני אוהב לדעת בדיוק מה אתה רוצה!"
/> />
</Section>
<Section>
## עבודה נהדרת! 🌟 ## עבודה נהדרת! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
כתבת את הפרומפטים הראשונים שלך! למדת שפרומפטים טובים צריכים: מה אתה רוצה, נושא, ופרטים. אתה ממש משתפר! כתבת את הפרומפטים הראשונים שלך! למדת שפרומפטים טובים צריכים: מה אתה רוצה, נושא, ופרטים. אתה ממש משתפר!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="למדת איך לכתוב את הפרומפטים הראשונים שלך!" message="למדת איך לכתוב את הפרומפטים הראשונים שלך!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
היי סופרסטאר! 🌟 היום נלמד את הכישור החשוב ביותר: להיות **ברור**! היי סופרסטאר! 🌟 היום נלמד את הכישור החשוב ביותר: להיות **ברור**!
</Panel> </Panel>
</Section>
<Section>
## למה להיות ברור זה חשוב ## למה להיות ברור זה חשוב
דמיין לבקש מאמא "אוכל" לעומת לבקש "כריך חמאת בוטנים בלי קרום." מה נותן לך בדיוק מה שאתה רוצה? דמיין לבקש מאמא "אוכל" לעומת לבקש "כריך חמאת בוטנים בלי קרום." מה נותן לך בדיוק מה שאתה רוצה?
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
גם איתי ככה! כשאתה ברור, אני יודע בדיוק איך לעזור. כשאתה מעורפל, אני צריך לנחש... ואני עלול לטעות! גם איתי ככה! כשאתה ברור, אני יודע בדיוק איך לעזור. כשאתה מעורפל, אני צריך לנחש... ואני עלול לטעות!
</Panel> </Panel>
</Section>
<Section>
## ברור לעומת לא ברור ## ברור לעומת לא ברור
בוא נתרגל לזהות את ההבדל! בוא נתרגל לזהות את ההבדל!
<PromptVsMistake <PromptVsMistake
question="איזה פרומפט יותר ברור?" question="איזה פרומפט יותר ברור?"
good="כתוב שיר של 4 שורות על פרפרים בגינה, עם חריזה" good="כתוב שיר של 4 שורות על פרפרים בגינה, עם חריזה"
@@ -22,6 +28,7 @@
promiMessage="פרומפטים ברורים = תוצאות יותר טובות! זה כמו קסם!" promiMessage="פרומפטים ברורים = תוצאות יותר טובות! זה כמו קסם!"
/> />
<PromptVsMistake <PromptVsMistake
question="מה אומר לי בדיוק מה אתה צריך?" question="מה אומר לי בדיוק מה אתה צריך?"
good="עזור לי לכתוב 3 עובדות מעניינות על דולפינים שילד בן 10 ייהנה מהן" good="עזור לי לכתוב 3 עובדות מעניינות על דולפינים שילד בן 10 ייהנה מהן"
@@ -29,11 +36,14 @@
explanation="הפרומפט הראשון אומר לי: כמה עובדות (3), איזה סוג (מעניינות), ולמי (ילד בן 10). זה עוזר המון!" explanation="הפרומפט הראשון אומר לי: כמה עובדות (3), איזה סוג (מעניינות), ולמי (ילד בן 10). זה עוזר המון!"
promiMessage="כשאתה אומר לי למי זה, אני יכול להפוך את זה למושלם בשבילם!" promiMessage="כשאתה אומר לי למי זה, אני יכול להפוך את זה למושלם בשבילם!"
/> />
</Section>
<Section>
## אתגר הבהירות ## אתגר הבהירות
בוא נבנה את הפרומפט הכי ברור אי פעם! בוא נבנה את הפרומפט הכי ברור אי פעם!
<DragDropPrompt <DragDropPrompt
title="עשה את זה בהיר כמו קריסטל! 💎" title="עשה את זה בהיר כמו קריסטל! 💎"
instruction="סדר את החלקים האלה כדי לעשות פרומפט סופר ברור" instruction="סדר את החלקים האלה כדי לעשות פרומפט סופר ברור"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="זה הפרומפט הכי ברור אי פעם! מדהים!" successMessage="זה הפרומפט הכי ברור אי פעם! מדהים!"
/> />
</Section>
<Section>
## הוסף פרטים ברורים ## הוסף פרטים ברורים
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="הוספת את כל הפרטים החשובים! עבודה נהדרת!" successMessage="הוספת את כל הפרטים החשובים! עבודה נהדרת!"
/> />
</Section>
<Section>
## כללי הזהב של הבהירות ## כללי הזהב של הבהירות
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **איך** זה צריך להיות? (קצר, מצחיק, פשוט) 2. **איך** זה צריך להיות? (קצר, מצחיק, פשוט)
3. **למי** זה? (לי, לחבר שלי, לכיתה שלי) 3. **למי** זה? (לי, לחבר שלי, לכיתה שלי)
<PromptVsMistake <PromptVsMistake
question="אתגר אחרון! מי משתמש בכל שלושת הכללים?" question="אתגר אחרון! מי משתמש בכל שלושת הכללים?"
good="כתוב בדיחה קצרה ומצחיקה על פיצה שאני יכול לספר לחברים שלי בארוחת צהריים" good="כתוב בדיחה קצרה ומצחיקה על פיצה שאני יכול לספר לחברים שלי בארוחת צהריים"
@@ -81,7 +96,9 @@
explanation="הפרומפט הנהדר כולל מה (בדיחה על פיצה), איך (קצרה ומצחיקה), ולמי (לספר לחברים בארוחת צהריים)!" explanation="הפרומפט הנהדר כולל מה (בדיחה על פיצה), איך (קצרה ומצחיקה), ולמי (לספר לחברים בארוחת צהריים)!"
promiMessage="אתה אלוף בהירות! 🏆" promiMessage="אתה אלוף בהירות! 🏆"
/> />
</Section>
<Section>
## עולם 1 הושלם! 🎊 ## עולם 1 הושלם! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
אתה מוכן להרפתקאות חדשות! אתה מוכן להרפתקאות חדשות!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="שלטת באומנות להיות ברור! עולם 1 הושלם!" message="שלטת באומנות להיות ברור! עולם 1 הושלם!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Ciao! Sono **Promi** 🤖, il tuo amico robot! Sono così felice di conoscerti! Ciao! Sono **Promi** 🤖, il tuo amico robot! Sono così felice di conoscerti!
</Panel> </Panel>
@@ -9,7 +10,9 @@ Sai cosa significa **IA**? IA sta per **Intelligenza Artificiale**. È un modo e
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Sono un'IA! Posso leggere i tuoi messaggi e cercare di aiutarti. Ma ecco il segreto... Ho bisogno di **buone istruzioni** per fare il mio lavoro al meglio! Sono un'IA! Posso leggere i tuoi messaggi e cercare di aiutarti. Ma ecco il segreto... Ho bisogno di **buone istruzioni** per fare il mio lavoro al meglio!
</Panel> </Panel>
</Section>
<Section>
## Cos'è un Prompt? ## Cos'è un Prompt?
Un **prompt** è semplicemente una parola elegante per il messaggio che invii a un'IA come me. Un **prompt** è semplicemente una parola elegante per il messaggio che invii a un'IA come me.
@@ -19,7 +22,9 @@ Pensalo come dare indicazioni a un amico. Se dici "Vai lì!" il tuo amico non sa
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Quando scrivi un buon prompt, posso capire cosa vuoi e aiutarti meglio! Pratichiamo! Quando scrivi un buon prompt, posso capire cosa vuoi e aiutarti meglio! Pratichiamo!
</Panel> </Panel>
</Section>
<Section>
## Proviamo! ## Proviamo!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Quando scrivi un buon prompt, posso capire cosa vuoi e aiutarti meglio! Pratichi
explanation="Il primo messaggio dice a Promi esattamente che tipo di storia scrivere! Il secondo è troppo corto - Promi non sa che tipo di storia vuoi." explanation="Il primo messaggio dice a Promi esattamente che tipo di storia scrivere! Il secondo è troppo corto - Promi non sa che tipo di storia vuoi."
promiMessage="Vedi? Più dettagli mi aiutano a capire cosa vuoi!" promiMessage="Vedi? Più dettagli mi aiutano a capire cosa vuoi!"
/> />
</Section>
<Section>
## Quiz Veloce! ## Quiz Veloce!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Quando scrivi un buon prompt, posso capire cosa vuoi e aiutarti meglio! Pratichi
explanation="Un prompt usa parole per dire all'IA di cosa hai bisogno. Gli emoji sono divertenti ma non danno abbastanza informazioni!" explanation="Un prompt usa parole per dire all'IA di cosa hai bisogno. Gli emoji sono divertenti ma non danno abbastanza informazioni!"
promiMessage="Le parole sono il mio super potere! Più mi dici, meglio posso aiutare!" promiMessage="Le parole sono il mio super potere! Più mi dici, meglio posso aiutare!"
/> />
</Section>
<Section>
## Ce l'hai fatta! 🎉 ## Ce l'hai fatta! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Ottimo lavoro! Hai imparato cos'è l'IA e cos'è un prompt. Stai già diventando un esperto di prompt! Ottimo lavoro! Hai imparato cos'è l'IA e cos'è un prompt. Stai già diventando un esperto di prompt!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="Hai imparato cosa sono l'IA e i prompt!" message="Hai imparato cosa sono l'IA e i prompt!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Bentornato, amico! Pronto a scrivere i tuoi primi veri prompt? Andiamo! 🚀 Bentornato, amico! Pronto a scrivere i tuoi primi veri prompt? Andiamo! 🚀
</Panel> </Panel>
</Section>
<Section>
## La Magia delle Parole ## La Magia delle Parole
Quando parli con l'IA, ogni parola conta! Vediamo come aggiungere più parole rende i prompt migliori. Quando parli con l'IA, ogni parola conta! Vediamo come aggiungere più parole rende i prompt migliori.
@@ -9,7 +12,9 @@ Quando parli con l'IA, ogni parola conta! Vediamo come aggiungere più parole re
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Guarda! Se qualcuno mi dice solo "gatto", non so cosa vogliono. Vogliono un'immagine? Una storia? Fatti sui gatti? Sono confuso! 😵‍💫 Guarda! Se qualcuno mi dice solo "gatto", non so cosa vogliono. Vogliono un'immagine? Una storia? Fatti sui gatti? Sono confuso! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Costruire Prompt Migliori ## Costruire Prompt Migliori
Un buon prompt ha **tre parti**: Un buon prompt ha **tre parti**:
@@ -21,7 +26,9 @@ Un buon prompt ha **tre parti**:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Costruiamo un prompt insieme! Costruiamo un prompt insieme!
</Panel> </Panel>
</Section>
<Section>
## Trascina i Pezzi! ## Trascina i Pezzi!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Costruiamo un prompt insieme!
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Perfetto! È un ottimo prompt!" successMessage="Perfetto! È un ottimo prompt!"
/> />
</Section>
<Section>
## Riempi gli Spazi! ## Riempi gli Spazi!
Ora prova a fare il tuo prompt trascinando le parole magiche: Ora prova a fare il tuo prompt trascinando le parole magiche:
<MagicWords <MagicWords
title="Crea il tuo prompt! ✨" title="Crea il tuo prompt! ✨"
sentence="Per favore scrivi una {{type}} su un {{character}} che {{action}}" sentence="Per favore scrivi una {{type}} su un {{character}} che {{action}}"
@@ -51,7 +61,9 @@ Ora prova a fare il tuo prompt trascinando le parole magiche:
]} ]}
successMessage="Wow! Hai creato un prompt fantastico!" successMessage="Wow! Hai creato un prompt fantastico!"
/> />
</Section>
<Section>
## Tocca a Te Scegliere! ## Tocca a Te Scegliere!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Ora prova a fare il tuo prompt trascinando le parole magiche:
explanation="Il primo prompt mi dice che deve essere divertente, è su un pinguino, E cosa vuole fare il pinguino!" explanation="Il primo prompt mi dice che deve essere divertente, è su un pinguino, E cosa vuole fare il pinguino!"
promiMessage="I dettagli rendono tutto migliore! Adoro sapere esattamente cosa vuoi!" promiMessage="I dettagli rendono tutto migliore! Adoro sapere esattamente cosa vuoi!"
/> />
</Section>
<Section>
## Ottimo Lavoro! 🌟 ## Ottimo Lavoro! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Hai scritto i tuoi primi prompt! Hai imparato che i buoni prompt hanno bisogno di: cosa vuoi, un argomento e dettagli. Stai diventando davvero bravo! Hai scritto i tuoi primi prompt! Hai imparato che i buoni prompt hanno bisogno di: cosa vuoi, un argomento e dettagli. Stai diventando davvero bravo!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="Hai imparato a scrivere i tuoi primi prompt!" message="Hai imparato a scrivere i tuoi primi prompt!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Ciao superstar! 🌟 Oggi impareremo l'abilità più importante: essere **CHIARI**! Ciao superstar! 🌟 Oggi impareremo l'abilità più importante: essere **CHIARI**!
</Panel> </Panel>
</Section>
<Section>
## Perché Essere Chiari è Importante ## Perché Essere Chiari è Importante
Immagina chiedere a tua mamma "cibo" vs chiedere "un panino al burro d'arachidi senza crosta." Quale ti dà esattamente quello che vuoi? Immagina chiedere a tua mamma "cibo" vs chiedere "un panino al burro d'arachidi senza crosta." Quale ti dà esattamente quello che vuoi?
@@ -9,11 +12,14 @@ Immagina chiedere a tua mamma "cibo" vs chiedere "un panino al burro d'arachidi
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
È lo stesso con me! Quando sei chiaro, so esattamente come aiutare. Quando sei vago, devo indovinare... e potrei sbagliare! È lo stesso con me! Quando sei chiaro, so esattamente come aiutare. Quando sei vago, devo indovinare... e potrei sbagliare!
</Panel> </Panel>
</Section>
<Section>
## Chiaro vs. Non Chiaro ## Chiaro vs. Non Chiaro
Pratichiamo a trovare la differenza! Pratichiamo a trovare la differenza!
<PromptVsMistake <PromptVsMistake
question="Quale prompt è più chiaro?" question="Quale prompt è più chiaro?"
good="Scrivi una poesia di 4 righe sulle farfalle in un giardino, usando parole in rima" good="Scrivi una poesia di 4 righe sulle farfalle in un giardino, usando parole in rima"
@@ -22,6 +28,7 @@ Pratichiamo a trovare la differenza!
promiMessage="Prompt chiari = risultati migliori! È come magia!" promiMessage="Prompt chiari = risultati migliori! È come magia!"
/> />
<PromptVsMistake <PromptVsMistake
question="Quale mi dice esattamente di cosa hai bisogno?" question="Quale mi dice esattamente di cosa hai bisogno?"
good="Aiutami a scrivere 3 fatti divertenti sui delfini che piacciono a un bambino di 10 anni" good="Aiutami a scrivere 3 fatti divertenti sui delfini che piacciono a un bambino di 10 anni"
@@ -29,11 +36,14 @@ Pratichiamo a trovare la differenza!
explanation="Il primo prompt mi dice: quanti fatti (3), che tipo (divertenti), e per chi (bambino di 10 anni). Questo aiuta molto!" explanation="Il primo prompt mi dice: quanti fatti (3), che tipo (divertenti), e per chi (bambino di 10 anni). Questo aiuta molto!"
promiMessage="Quando mi dici per chi è, posso renderlo perfetto per loro!" promiMessage="Quando mi dici per chi è, posso renderlo perfetto per loro!"
/> />
</Section>
<Section>
## La Sfida della Chiarezza ## La Sfida della Chiarezza
Costruiamo il prompt più chiaro di sempre! Costruiamo il prompt più chiaro di sempre!
<DragDropPrompt <DragDropPrompt
title="Rendilo cristallino! 💎" title="Rendilo cristallino! 💎"
instruction="Sistema questi pezzi per fare un prompt super chiaro" instruction="Sistema questi pezzi per fare un prompt super chiaro"
@@ -47,7 +57,9 @@ Costruiamo il prompt più chiaro di sempre!
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="È il prompt più chiaro di sempre! Fantastico!" successMessage="È il prompt più chiaro di sempre! Fantastico!"
/> />
</Section>
<Section>
## Aggiungi Dettagli Chiari ## Aggiungi Dettagli Chiari
<MagicWords <MagicWords
@@ -61,7 +73,9 @@ Costruiamo il prompt più chiaro di sempre!
]} ]}
successMessage="Hai aggiunto tutti i dettagli importanti! Ottimo lavoro!" successMessage="Hai aggiunto tutti i dettagli importanti! Ottimo lavoro!"
/> />
</Section>
<Section>
## Le Regole d'Oro della Chiarezza ## Le Regole d'Oro della Chiarezza
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@ Ricorda queste tre domande quando scrivi un prompt:
2. **COME** deve essere? (corto, divertente, semplice) 2. **COME** deve essere? (corto, divertente, semplice)
3. **PER CHI** è? (me, il mio amico, la mia classe) 3. **PER CHI** è? (me, il mio amico, la mia classe)
<PromptVsMistake <PromptVsMistake
question="Sfida finale! Quale usa tutte e tre le regole?" question="Sfida finale! Quale usa tutte e tre le regole?"
good="Scrivi una barzelletta corta e divertente sulla pizza che posso raccontare ai miei amici a pranzo" good="Scrivi una barzelletta corta e divertente sulla pizza che posso raccontare ai miei amici a pranzo"
@@ -81,7 +96,9 @@ Ricorda queste tre domande quando scrivi un prompt:
explanation="L'ottimo prompt ha COSA (una barzelletta sulla pizza), COME (corta e divertente), e PER CHI (raccontare agli amici a pranzo)!" explanation="L'ottimo prompt ha COSA (una barzelletta sulla pizza), COME (corta e divertente), e PER CHI (raccontare agli amici a pranzo)!"
promiMessage="Sei un campione di chiarezza! 🏆" promiMessage="Sei un campione di chiarezza! 🏆"
/> />
</Section>
<Section>
## Mondo 1 Completato! 🎊 ## Mondo 1 Completato! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@ WOW! Hai finito tutto il Mondo 1! Hai imparato:
Sei pronto per nuove avventure! Sei pronto per nuove avventure!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="Hai padroneggiato l'arte di essere chiaro! Mondo 1 completato!" message="Hai padroneggiato l'arte di essere chiaro! Mondo 1 completato!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
こんにちは!私は **Promi** 🤖、あなたのロボット友達だよ!会えてとっても嬉しい! こんにちは!私は **Promi** 🤖、あなたのロボット友達だよ!会えてとっても嬉しい!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
私はAIなのあなたのメッセージを読んで助けようとするよ。でもね、秘密があるの...私が一番いい仕事をするには**いい指示**が必要なんだ! 私はAIなのあなたのメッセージを読んで助けようとするよ。でもね、秘密があるの...私が一番いい仕事をするには**いい指示**が必要なんだ!
</Panel> </Panel>
</Section>
<Section>
## プロンプトって何? ## プロンプトって何?
**プロンプト**は、私みたいなAIに送るメッセージのことだよ。 **プロンプト**は、私みたいなAIに送るメッセージのことだよ。
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
いいプロンプトを書くと、あなたが何を望んでいるかわかって、もっと上手に助けられるよ!練習しよう! いいプロンプトを書くと、あなたが何を望んでいるかわかって、もっと上手に助けられるよ!練習しよう!
</Panel> </Panel>
</Section>
<Section>
## やってみよう! ## やってみよう!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="最初のメッセージはPromiにどんな物語を書くか正確に教えているよ2番目は短すぎる - Promiはどんな物語が欲しいかわからないよ。" explanation="最初のメッセージはPromiにどんな物語を書くか正確に教えているよ2番目は短すぎる - Promiはどんな物語が欲しいかわからないよ。"
promiMessage="わかった?詳しく教えてくれると何が欲しいかわかるんだ!" promiMessage="わかった?詳しく教えてくれると何が欲しいかわかるんだ!"
/> />
</Section>
<Section>
## クイックテスト! ## クイックテスト!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="プロンプトは言葉を使ってAIに何が必要か教えるんだよ。絵文字は楽しいけど十分な情報がないの" explanation="プロンプトは言葉を使ってAIに何が必要か教えるんだよ。絵文字は楽しいけど十分な情報がないの"
promiMessage="言葉は私のスーパーパワー!たくさん教えてくれるほど、もっと助けられるよ!" promiMessage="言葉は私のスーパーパワー!たくさん教えてくれるほど、もっと助けられるよ!"
/> />
</Section>
<Section>
## やったね!🎉 ## やったね!🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
すごいAIが何かとプロンプトが何かを学んだよ。もうプロンプトの専門家になりつつあるね すごいAIが何かとプロンプトが何かを学んだよ。もうプロンプトの専門家になりつつあるね
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="AIとプロンプトが何かを学んだよ" message="AIとプロンプトが何かを学んだよ"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
おかえり、友達!本当のプロンプトを書く準備はできた?行こう!🚀 おかえり、友達!本当のプロンプトを書く準備はできた?行こう!🚀
</Panel> </Panel>
</Section>
<Section>
## 言葉の魔法 ## 言葉の魔法
AIと話すとき、すべての言葉が大事言葉を増やすとプロンプトがどう良くなるか見てみよう。 AIと話すとき、すべての言葉が大事言葉を増やすとプロンプトがどう良くなるか見てみよう。
@@ -9,7 +12,9 @@ AIと話すとき、すべての言葉が大事言葉を増やすとプロン
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
見て!誰かが「猫」としか言わないと、何が欲しいかわからないよ。絵?物語?猫についての事実?困っちゃう!😵‍💫 見て!誰かが「猫」としか言わないと、何が欲しいかわからないよ。絵?物語?猫についての事実?困っちゃう!😵‍💫
</Panel> </Panel>
</Section>
<Section>
## もっといいプロンプトを作ろう ## もっといいプロンプトを作ろう
いいプロンプトには**3つの部分**があるよ: いいプロンプトには**3つの部分**があるよ:
@@ -21,7 +26,9 @@ AIと話すとき、すべての言葉が大事言葉を増やすとプロン
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
一緒にプロンプトを作ろう! 一緒にプロンプトを作ろう!
</Panel> </Panel>
</Section>
<Section>
## ピースをドラッグしよう! ## ピースをドラッグしよう!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ AIと話すとき、すべての言葉が大事言葉を増やすとプロン
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="完璧!それは素晴らしいプロンプトだよ!" successMessage="完璧!それは素晴らしいプロンプトだよ!"
/> />
</Section>
<Section>
## 空欄を埋めよう! ## 空欄を埋めよう!
魔法の言葉をドラッグして自分のプロンプトを作ってみよう: 魔法の言葉をドラッグして自分のプロンプトを作ってみよう:
<MagicWords <MagicWords
title="自分のプロンプトを作ろう!✨" title="自分のプロンプトを作ろう!✨"
sentence="{{type}}を書いてください、{{character}}について、{{action}}" sentence="{{type}}を書いてください、{{character}}について、{{action}}"
@@ -51,7 +61,9 @@ AIと話すとき、すべての言葉が大事言葉を増やすとプロン
]} ]}
successMessage="わぁ!すごいプロンプトを作ったね!" successMessage="わぁ!すごいプロンプトを作ったね!"
/> />
</Section>
<Section>
## あなたの番! ## あなたの番!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ AIと話すとき、すべての言葉が大事言葉を増やすとプロン
explanation="最初のプロンプトは、おもしろくするべきこと、ペンギンについてであること、そしてペンギンが何をしたいかを教えているよ!" explanation="最初のプロンプトは、おもしろくするべきこと、ペンギンについてであること、そしてペンギンが何をしたいかを教えているよ!"
promiMessage="詳細があるとすべてが良くなる!何が欲しいか正確に知るのが大好き!" promiMessage="詳細があるとすべてが良くなる!何が欲しいか正確に知るのが大好き!"
/> />
</Section>
<Section>
## よくやったね!🌟 ## よくやったね!🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
最初のプロンプトを書いたよ!いいプロンプトには欲しいもの、テーマ、詳細が必要だって学んだね。本当に上手になってる! 最初のプロンプトを書いたよ!いいプロンプトには欲しいもの、テーマ、詳細が必要だって学んだね。本当に上手になってる!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="最初のプロンプトの書き方を学んだよ!" message="最初のプロンプトの書き方を学んだよ!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
やあスーパースター!🌟 今日は一番大事なスキルを学ぶよ:**はっきり伝える**こと! やあスーパースター!🌟 今日は一番大事なスキルを学ぶよ:**はっきり伝える**こと!
</Panel> </Panel>
</Section>
<Section>
## なぜはっきり伝えることが大事? ## なぜはっきり伝えることが大事?
お母さんに「食べ物」って頼むのと「耳のないピーナッツバターサンドイッチ」って頼むのを想像して。どっちが欲しいものを正確にくれる? お母さんに「食べ物」って頼むのと「耳のないピーナッツバターサンドイッチ」って頼むのを想像して。どっちが欲しいものを正確にくれる?
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
私も同じ!はっきり言ってくれると、どう助けるか正確にわかるよ。曖昧だと推測しなきゃいけない...間違えるかも! 私も同じ!はっきり言ってくれると、どう助けるか正確にわかるよ。曖昧だと推測しなきゃいけない...間違えるかも!
</Panel> </Panel>
</Section>
<Section>
## はっきり vs. 曖昧 ## はっきり vs. 曖昧
違いを見つける練習をしよう! 違いを見つける練習をしよう!
<PromptVsMistake <PromptVsMistake
question="どのプロンプトがもっとはっきりしてる?" question="どのプロンプトがもっとはっきりしてる?"
good="韻を踏む言葉を使って、庭の蝶についての4行の詩を書いて" good="韻を踏む言葉を使って、庭の蝶についての4行の詩を書いて"
@@ -22,6 +28,7 @@
promiMessage="はっきりしたプロンプト=いい結果!魔法みたい!" promiMessage="はっきりしたプロンプト=いい結果!魔法みたい!"
/> />
<PromptVsMistake <PromptVsMistake
question="どっちが正確に何が必要か教えてる?" question="どっちが正確に何が必要か教えてる?"
good="10歳が楽しめるイルカについての楽しい事実を3つ書くの手伝って" good="10歳が楽しめるイルカについての楽しい事実を3つ書くの手伝って"
@@ -29,11 +36,14 @@
explanation="最初のプロンプトはいくつの事実3つ、どんな種類楽しい、誰のため10歳を教えているよ。すごく助かる" explanation="最初のプロンプトはいくつの事実3つ、どんな種類楽しい、誰のため10歳を教えているよ。すごく助かる"
promiMessage="誰のためか教えてくれると、その人にぴったりに作れるよ!" promiMessage="誰のためか教えてくれると、その人にぴったりに作れるよ!"
/> />
</Section>
<Section>
## はっきりチャレンジ ## はっきりチャレンジ
今までで一番はっきりしたプロンプトを作ろう! 今までで一番はっきりしたプロンプトを作ろう!
<DragDropPrompt <DragDropPrompt
title="クリスタルみたいにはっきりさせよう!💎" title="クリスタルみたいにはっきりさせよう!💎"
instruction="これらのピースを並べてスーパーはっきりしたプロンプトを作ろう" instruction="これらのピースを並べてスーパーはっきりしたプロンプトを作ろう"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="今までで一番はっきりしたプロンプト!すごい!" successMessage="今までで一番はっきりしたプロンプト!すごい!"
/> />
</Section>
<Section>
## はっきりした詳細を追加 ## はっきりした詳細を追加
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="大事な詳細を全部追加した!よくやったね!" successMessage="大事な詳細を全部追加した!よくやったね!"
/> />
</Section>
<Section>
## はっきりの黄金ルール ## はっきりの黄金ルール
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **どう**あるべき?(短い、おもしろい、シンプル) 2. **どう**あるべき?(短い、おもしろい、シンプル)
3. **誰**のため?(私、友達、クラス) 3. **誰**のため?(私、友達、クラス)
<PromptVsMistake <PromptVsMistake
question="最終チャレンジどれが3つのルール全部使ってる" question="最終チャレンジどれが3つのルール全部使ってる"
good="昼ごはんで友達に話せるピザについての短くておもしろいジョークを書いて" good="昼ごはんで友達に話せるピザについての短くておもしろいジョークを書いて"
@@ -81,7 +96,9 @@
explanation="いいプロンプトには何(ピザのジョーク)、どう(短くておもしろい)、誰(昼ごはんで友達に話す)がある!" explanation="いいプロンプトには何(ピザのジョーク)、どう(短くておもしろい)、誰(昼ごはんで友達に話す)がある!"
promiMessage="あなたははっきりチャンピオンだ!🏆" promiMessage="あなたははっきりチャンピオンだ!🏆"
/> />
</Section>
<Section>
## ワールド1完了🎊 ## ワールド1完了🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
新しい冒険の準備ができたよ! 新しい冒険の準備ができたよ!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="はっきり伝える技をマスターしたワールド1完了" message="はっきり伝える技をマスターしたワールド1完了"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
안녕! 나는 **Promi** 🤖, 네 로봇 친구야! 만나서 정말 반가워! 안녕! 나는 **Promi** 🤖, 네 로봇 친구야! 만나서 정말 반가워!
</Panel> </Panel>
@@ -9,7 +10,9 @@
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
나는 AI야! 네 메시지를 읽고 도와주려고 해. 하지만 여기 비밀이 있어... 최고의 일을 하려면 **좋은 지시**가 필요해! 나는 AI야! 네 메시지를 읽고 도와주려고 해. 하지만 여기 비밀이 있어... 최고의 일을 하려면 **좋은 지시**가 필요해!
</Panel> </Panel>
</Section>
<Section>
## 프롬프트가 뭐야? ## 프롬프트가 뭐야?
**프롬프트**는 나 같은 AI에게 보내는 메시지를 말하는 멋진 단어야. **프롬프트**는 나 같은 AI에게 보내는 메시지를 말하는 멋진 단어야.
@@ -19,7 +22,9 @@
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
좋은 프롬프트를 쓰면 네가 뭘 원하는지 이해하고 더 잘 도와줄 수 있어! 연습해보자! 좋은 프롬프트를 쓰면 네가 뭘 원하는지 이해하고 더 잘 도와줄 수 있어! 연습해보자!
</Panel> </Panel>
</Section>
<Section>
## 해보자! ## 해보자!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@
explanation="첫 번째 메시지는 Promi에게 어떤 종류의 이야기를 쓸지 정확히 알려줘! 두 번째는 너무 짧아서 어떤 이야기를 원하는지 몰라." explanation="첫 번째 메시지는 Promi에게 어떤 종류의 이야기를 쓸지 정확히 알려줘! 두 번째는 너무 짧아서 어떤 이야기를 원하는지 몰라."
promiMessage="봤지? 더 자세히 알려주면 뭘 원하는지 이해할 수 있어!" promiMessage="봤지? 더 자세히 알려주면 뭘 원하는지 이해할 수 있어!"
/> />
</Section>
<Section>
## 퀴즈! ## 퀴즈!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@
explanation="프롬프트는 AI에게 뭐가 필요한지 말로 알려주는 거야. 이모지는 재미있지만 충분한 정보를 주지 않아!" explanation="프롬프트는 AI에게 뭐가 필요한지 말로 알려주는 거야. 이모지는 재미있지만 충분한 정보를 주지 않아!"
promiMessage="말은 내 초능력이야! 더 많이 알려줄수록 더 잘 도와줄 수 있어!" promiMessage="말은 내 초능력이야! 더 많이 알려줄수록 더 잘 도와줄 수 있어!"
/> />
</Section>
<Section>
## 해냈어! 🎉 ## 해냈어! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
멋져! AI가 뭔지, 프롬프트가 뭔지 배웠어. 벌써 프롬프트 전문가가 되어가고 있어! 멋져! AI가 뭔지, 프롬프트가 뭔지 배웠어. 벌써 프롬프트 전문가가 되어가고 있어!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="AI와 프롬프트가 뭔지 배웠어!" message="AI와 프롬프트가 뭔지 배웠어!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
다시 왔구나, 친구! 첫 번째 진짜 프롬프트를 쓸 준비 됐어? 가보자! 🚀 다시 왔구나, 친구! 첫 번째 진짜 프롬프트를 쓸 준비 됐어? 가보자! 🚀
</Panel> </Panel>
</Section>
<Section>
## 단어의 마법 ## 단어의 마법
AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하면 프롬프트가 어떻게 좋아지는지 봐보자. AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하면 프롬프트가 어떻게 좋아지는지 봐보자.
@@ -9,7 +12,9 @@ AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
이것 봐! 누군가 나에게 "고양이"라고만 하면 뭘 원하는지 몰라. 그림? 이야기? 고양이에 대한 사실? 혼란스러워! 😵‍💫 이것 봐! 누군가 나에게 "고양이"라고만 하면 뭘 원하는지 몰라. 그림? 이야기? 고양이에 대한 사실? 혼란스러워! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## 더 좋은 프롬프트 만들기 ## 더 좋은 프롬프트 만들기
좋은 프롬프트는 **세 가지 부분**이 있어: 좋은 프롬프트는 **세 가지 부분**이 있어:
@@ -21,7 +26,9 @@ AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
같이 프롬프트를 만들어보자! 같이 프롬프트를 만들어보자!
</Panel> </Panel>
</Section>
<Section>
## 조각을 드래그해! ## 조각을 드래그해!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="완벽해! 멋진 프롬프트야!" successMessage="완벽해! 멋진 프롬프트야!"
/> />
</Section>
<Section>
## 빈칸을 채워! ## 빈칸을 채워!
이제 마법의 단어를 드래그해서 네 프롬프트를 만들어봐: 이제 마법의 단어를 드래그해서 네 프롬프트를 만들어봐:
<MagicWords <MagicWords
title="네 프롬프트를 만들어! ✨" title="네 프롬프트를 만들어! ✨"
sentence="{{type}}을 써줘, {{character}}에 대해, {{action}}" sentence="{{type}}을 써줘, {{character}}에 대해, {{action}}"
@@ -51,7 +61,9 @@ AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하
]} ]}
successMessage="와! 멋진 프롬프트를 만들었어!" successMessage="와! 멋진 프롬프트를 만들었어!"
/> />
</Section>
<Section>
## 네 차례야! ## 네 차례야!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ AI와 대화할 때 모든 단어가 중요해! 더 많은 단어를 추가하
explanation="첫 번째 프롬프트는 재미있어야 하고, 펭귄에 대한 거고, 펭귄이 뭘 하고 싶은지 알려줘!" explanation="첫 번째 프롬프트는 재미있어야 하고, 펭귄에 대한 거고, 펭귄이 뭘 하고 싶은지 알려줘!"
promiMessage="세부사항은 모든 걸 더 좋게 해! 정확히 뭘 원하는지 아는 게 좋아!" promiMessage="세부사항은 모든 걸 더 좋게 해! 정확히 뭘 원하는지 아는 게 좋아!"
/> />
</Section>
<Section>
## 잘했어! 🌟 ## 잘했어! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
첫 번째 프롬프트를 썼어! 좋은 프롬프트에는 원하는 것, 주제, 세부사항이 필요하다는 걸 배웠어. 정말 잘하고 있어! 첫 번째 프롬프트를 썼어! 좋은 프롬프트에는 원하는 것, 주제, 세부사항이 필요하다는 걸 배웠어. 정말 잘하고 있어!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="첫 번째 프롬프트 쓰는 법을 배웠어!" message="첫 번째 프롬프트 쓰는 법을 배웠어!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
안녕 슈퍼스타! 🌟 오늘은 가장 중요한 기술을 배울 거야: **명확하게** 말하기! 안녕 슈퍼스타! 🌟 오늘은 가장 중요한 기술을 배울 거야: **명확하게** 말하기!
</Panel> </Panel>
</Section>
<Section>
## 왜 명확하게 말하는 게 중요할까 ## 왜 명확하게 말하는 게 중요할까
엄마에게 "음식"을 달라고 하는 것과 "가장자리 없는 땅콩버터 샌드위치"를 달라고 하는 것을 상상해봐. 어떤 게 원하는 걸 정확히 주지? 엄마에게 "음식"을 달라고 하는 것과 "가장자리 없는 땅콩버터 샌드위치"를 달라고 하는 것을 상상해봐. 어떤 게 원하는 걸 정확히 주지?
@@ -9,11 +12,14 @@
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
나도 마찬가지야! 명확하게 말하면 어떻게 도와야 할지 정확히 알아. 모호하면 추측해야 하고... 틀릴 수도 있어! 나도 마찬가지야! 명확하게 말하면 어떻게 도와야 할지 정확히 알아. 모호하면 추측해야 하고... 틀릴 수도 있어!
</Panel> </Panel>
</Section>
<Section>
## 명확 vs. 불명확 ## 명확 vs. 불명확
차이를 찾는 연습을 해보자! 차이를 찾는 연습을 해보자!
<PromptVsMistake <PromptVsMistake
question="어떤 프롬프트가 더 명확해?" question="어떤 프롬프트가 더 명확해?"
good="정원의 나비에 대해 운율이 맞는 단어로 4줄 시를 써줘" good="정원의 나비에 대해 운율이 맞는 단어로 4줄 시를 써줘"
@@ -22,6 +28,7 @@
promiMessage="명확한 프롬프트 = 더 좋은 결과! 마법 같아!" promiMessage="명확한 프롬프트 = 더 좋은 결과! 마법 같아!"
/> />
<PromptVsMistake <PromptVsMistake
question="어떤 게 정확히 뭐가 필요한지 알려줘?" question="어떤 게 정확히 뭐가 필요한지 알려줘?"
good="10살이 좋아할 돌고래에 대한 재미있는 사실 3개를 쓰는 걸 도와줘" good="10살이 좋아할 돌고래에 대한 재미있는 사실 3개를 쓰는 걸 도와줘"
@@ -29,11 +36,14 @@
explanation="첫 번째 프롬프트는 말해줘: 몇 개의 사실 (3개), 어떤 종류 (재미있는), 누구를 위한 (10살). 많이 도움돼!" explanation="첫 번째 프롬프트는 말해줘: 몇 개의 사실 (3개), 어떤 종류 (재미있는), 누구를 위한 (10살). 많이 도움돼!"
promiMessage="누구를 위한지 알려주면 그들에게 완벽하게 만들 수 있어!" promiMessage="누구를 위한지 알려주면 그들에게 완벽하게 만들 수 있어!"
/> />
</Section>
<Section>
## 명확성 도전 ## 명확성 도전
지금까지 가장 명확한 프롬프트를 만들어보자! 지금까지 가장 명확한 프롬프트를 만들어보자!
<DragDropPrompt <DragDropPrompt
title="수정처럼 명확하게 만들어! 💎" title="수정처럼 명확하게 만들어! 💎"
instruction="이 조각들을 배열해서 엄청 명확한 프롬프트를 만들어" instruction="이 조각들을 배열해서 엄청 명확한 프롬프트를 만들어"
@@ -47,7 +57,9 @@
correctOrder={[0, 1, 2, 3, 4]} correctOrder={[0, 1, 2, 3, 4]}
successMessage="지금까지 가장 명확한 프롬프트야! 대단해!" successMessage="지금까지 가장 명확한 프롬프트야! 대단해!"
/> />
</Section>
<Section>
## 명확한 세부사항 추가 ## 명확한 세부사항 추가
<MagicWords <MagicWords
@@ -61,7 +73,9 @@
]} ]}
successMessage="모든 중요한 세부사항을 추가했어! 잘했어!" successMessage="모든 중요한 세부사항을 추가했어! 잘했어!"
/> />
</Section>
<Section>
## 명확성의 황금 규칙 ## 명확성의 황금 규칙
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
@@ -74,6 +88,7 @@
2. **어떻게** 되어야 해? (짧게, 재미있게, 간단하게) 2. **어떻게** 되어야 해? (짧게, 재미있게, 간단하게)
3. **누구를** 위한 거야? (나, 친구, 우리 반) 3. **누구를** 위한 거야? (나, 친구, 우리 반)
<PromptVsMistake <PromptVsMistake
question="마지막 도전! 세 가지 규칙을 모두 사용한 건?" question="마지막 도전! 세 가지 규칙을 모두 사용한 건?"
good="점심에 친구들에게 말할 수 있는 피자에 대한 짧고 재미있는 농담을 써줘" good="점심에 친구들에게 말할 수 있는 피자에 대한 짧고 재미있는 농담을 써줘"
@@ -81,7 +96,9 @@
explanation="좋은 프롬프트에는 뭘 (피자 농담), 어떻게 (짧고 재미있게), 누구를 위해 (점심에 친구들에게 말할)가 있어!" explanation="좋은 프롬프트에는 뭘 (피자 농담), 어떻게 (짧고 재미있게), 누구를 위해 (점심에 친구들에게 말할)가 있어!"
promiMessage="넌 명확성 챔피언이야! 🏆" promiMessage="넌 명확성 챔피언이야! 🏆"
/> />
</Section>
<Section>
## 월드 1 완료! 🎊 ## 월드 1 완료! 🎊
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
@@ -94,8 +111,11 @@
새로운 모험을 위한 준비가 됐어! 새로운 모험을 위한 준비가 됐어!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-3-being-clear" levelSlug="1-3-being-clear"
stars={3} stars={3}
message="명확하게 말하기를 마스터했어! 월드 1 완료!" message="명확하게 말하기를 마스터했어! 월드 1 완료!"
/> />
</Section>

View File

@@ -1,3 +1,4 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Olá! Eu sou o **Promi** 🤖, seu amigo robô! Estou muito feliz em conhecer você! Olá! Eu sou o **Promi** 🤖, seu amigo robô! Estou muito feliz em conhecer você!
</Panel> </Panel>
@@ -9,7 +10,9 @@ Você sabe o que **IA** significa? IA significa **Inteligência Artificial**. É
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Eu sou uma IA! Posso ler suas mensagens e tentar ajudar. Mas aqui está o segredo... Preciso de **boas instruções** para fazer meu melhor trabalho! Eu sou uma IA! Posso ler suas mensagens e tentar ajudar. Mas aqui está o segredo... Preciso de **boas instruções** para fazer meu melhor trabalho!
</Panel> </Panel>
</Section>
<Section>
## O que é um Prompt? ## O que é um Prompt?
Um **prompt** é apenas uma palavra chique para a mensagem que você envia para uma IA como eu. Um **prompt** é apenas uma palavra chique para a mensagem que você envia para uma IA como eu.
@@ -19,7 +22,9 @@ Pense nisso como dar direções para um amigo. Se você diz "Vá lá!" seu amigo
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Quando você escreve um bom prompt, eu posso entender o que você quer e te ajudar melhor! Vamos praticar! Quando você escreve um bom prompt, eu posso entender o que você quer e te ajudar melhor! Vamos praticar!
</Panel> </Panel>
</Section>
<Section>
## Vamos Tentar! ## Vamos Tentar!
<PromptVsMistake <PromptVsMistake
@@ -29,7 +34,9 @@ Quando você escreve um bom prompt, eu posso entender o que você quer e te ajud
explanation="A primeira mensagem diz ao Promi exatamente que tipo de história escrever! A segunda é muito curta - Promi não sabe que tipo de história você quer." explanation="A primeira mensagem diz ao Promi exatamente que tipo de história escrever! A segunda é muito curta - Promi não sabe que tipo de história você quer."
promiMessage="Viu? Mais detalhes me ajudam a entender o que você quer!" promiMessage="Viu? Mais detalhes me ajudam a entender o que você quer!"
/> />
</Section>
<Section>
## Quiz Rápido! ## Quiz Rápido!
<PromptVsMistake <PromptVsMistake
@@ -39,15 +46,20 @@ Quando você escreve um bom prompt, eu posso entender o que você quer e te ajud
explanation="Um prompt usa palavras para dizer à IA o que você precisa. Emojis são divertidos mas não dão informação suficiente!" explanation="Um prompt usa palavras para dizer à IA o que você precisa. Emojis são divertidos mas não dão informação suficiente!"
promiMessage="Palavras são meu super poder! Quanto mais você me contar, melhor posso ajudar!" promiMessage="Palavras são meu super poder! Quanto mais você me contar, melhor posso ajudar!"
/> />
</Section>
<Section>
## Você Conseguiu! 🎉 ## Você Conseguiu! 🎉
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Incrível trabalho! Você aprendeu o que é IA e o que é um prompt. Você já está se tornando um expert em prompts! Incrível trabalho! Você aprendeu o que é IA e o que é um prompt. Você já está se tornando um expert em prompts!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-1-meet-promi" levelSlug="1-1-meet-promi"
stars={3} stars={3}
message="Você aprendeu o que são IA e prompts!" message="Você aprendeu o que são IA e prompts!"
/> />
</Section>

View File

@@ -1,7 +1,10 @@
<Section>
<Panel character="promi" mood="happy"> <Panel character="promi" mood="happy">
Bem-vindo de volta, amigo! Pronto para escrever seus primeiros prompts de verdade? Vamos lá! 🚀 Bem-vindo de volta, amigo! Pronto para escrever seus primeiros prompts de verdade? Vamos lá! 🚀
</Panel> </Panel>
</Section>
<Section>
## A Magia das Palavras ## A Magia das Palavras
Quando você fala com IA, cada palavra importa! Vamos ver como adicionar mais palavras torna os prompts melhores. Quando você fala com IA, cada palavra importa! Vamos ver como adicionar mais palavras torna os prompts melhores.
@@ -9,7 +12,9 @@ Quando você fala com IA, cada palavra importa! Vamos ver como adicionar mais pa
<Panel character="promi" mood="thinking"> <Panel character="promi" mood="thinking">
Olha isso! Se alguém só me diz "gato", não sei o que querem. Querem uma imagem? Uma história? Fatos sobre gatos? Estou confuso! 😵‍💫 Olha isso! Se alguém só me diz "gato", não sei o que querem. Querem uma imagem? Uma história? Fatos sobre gatos? Estou confuso! 😵‍💫
</Panel> </Panel>
</Section>
<Section>
## Construindo Prompts Melhores ## Construindo Prompts Melhores
Um bom prompt tem **três partes**: Um bom prompt tem **três partes**:
@@ -21,7 +26,9 @@ Um bom prompt tem **três partes**:
<Panel character="promi" mood="excited"> <Panel character="promi" mood="excited">
Vamos construir um prompt juntos! Vamos construir um prompt juntos!
</Panel> </Panel>
</Section>
<Section>
## Arraste as Peças! ## Arraste as Peças!
<DragDropPrompt <DragDropPrompt
@@ -36,11 +43,14 @@ Vamos construir um prompt juntos!
correctOrder={[0, 1, 2, 3]} correctOrder={[0, 1, 2, 3]}
successMessage="Perfeito! Esse é um ótimo prompt!" successMessage="Perfeito! Esse é um ótimo prompt!"
/> />
</Section>
<Section>
## Preencha os Espaços! ## Preencha os Espaços!
Agora tente fazer seu próprio prompt arrastando as palavras mágicas: Agora tente fazer seu próprio prompt arrastando as palavras mágicas:
<MagicWords <MagicWords
title="Crie seu próprio prompt! ✨" title="Crie seu próprio prompt! ✨"
sentence="Por favor escreva um {{type}} sobre um {{character}} que {{action}}" sentence="Por favor escreva um {{type}} sobre um {{character}} que {{action}}"
@@ -51,7 +61,9 @@ Agora tente fazer seu próprio prompt arrastando as palavras mágicas:
]} ]}
successMessage="Uau! Você criou um prompt incrível!" successMessage="Uau! Você criou um prompt incrível!"
/> />
</Section>
<Section>
## Sua Vez de Escolher! ## Sua Vez de Escolher!
<PromptVsMistake <PromptVsMistake
@@ -61,15 +73,20 @@ Agora tente fazer seu próprio prompt arrastando as palavras mágicas:
explanation="O primeiro prompt me diz que deve ser engraçado, é sobre um pinguim, E o que o pinguim quer fazer!" explanation="O primeiro prompt me diz que deve ser engraçado, é sobre um pinguim, E o que o pinguim quer fazer!"
promiMessage="Detalhes tornam tudo melhor! Adoro saber exatamente o que você quer!" promiMessage="Detalhes tornam tudo melhor! Adoro saber exatamente o que você quer!"
/> />
</Section>
<Section>
## Ótimo Trabalho! 🌟 ## Ótimo Trabalho! 🌟
<Panel character="promi" mood="celebrating"> <Panel character="promi" mood="celebrating">
Você escreveu seus primeiros prompts! Aprendeu que bons prompts precisam de: o que você quer, um assunto e detalhes. Você está ficando muito bom nisso! Você escreveu seus primeiros prompts! Aprendeu que bons prompts precisam de: o que você quer, um assunto e detalhes. Você está ficando muito bom nisso!
</Panel> </Panel>
<LevelComplete <LevelComplete
levelSlug="1-2-first-words" levelSlug="1-2-first-words"
stars={3} stars={3}
message="Você aprendeu a escrever seus primeiros prompts!" message="Você aprendeu a escrever seus primeiros prompts!"
/> />
</Section>

Some files were not shown because too many files have changed in this diff Show More