Files
code-crispies/lessons/uk/06-transitions-animations.json
Michael Czechowski c560676544 feat: implement #4 — replace answer-revealing validation messages with pedagogical hints
Rewrite ~120 validation error messages across 17 English lesson modules
and their localized variants (ar, de, es, pl, uk) to use concept questions,
property hints, and directional nudges instead of revealing the exact
CSS property-value answers.

Priority modules (flexbox, box-model, colors, positioning) fully rewritten.
All remaining CSS modules updated. Only message strings changed — no
validation logic modifications.
2026-03-28 19:40:28 +01:00

146 lines
7.9 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

{
"$schema": "../../schemas/code-crispies-module-schema.json",
"id": "transitions-animations",
"title": "CSS Анімації",
"description": "Додайте інтерактивність до інтерфейсу через плавні переходи властивостей та анімації на основі keyframes.",
"difficulty": "intermediate",
"lessons": [
{
"id": "transitions-1",
"title": "Transitions",
"description": "Навчіться застосовувати <kbd>transition</kbd> до властивостей для плавних змін при зміні стану.<br><br><pre>transition: property duration;\n/* напр. transition: background-color 0.3s; */</pre>",
"task": "Додайте <kbd>transition: background-color 0.3s</kbd>, щоб колір плавно змінювався при наведенні.",
"previewHTML": "<button class=\"btn\">Hover Me</button>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: black; color: white; padding: 0.5rem 1rem; border: none; cursor: pointer; } .btn:hover { background: white; color: black; }",
"sandboxCSS": "",
"codePrefix": "/* Add transition */\n.btn {",
"initialCode": "",
"codeSuffix": "}",
"solution": " transition: background-color 0.3s;",
"previewContainer": "preview-area",
"validations": [
{
"type": "contains",
"value": "transition",
"message": "Використайте властивість <kbd>transition</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "regex",
"value": "transition:\\s*background-color\\s*0\\.3s",
"message": "Вкажіть, яку властивість анімувати та скільки це має тривати.",
"options": { "caseSensitive": false }
}
]
},
{
"id": "transitions-2",
"title": "Timing Funcs",
"description": "Дослідіть функції пом'якшення як <kbd>ease</kbd>, <kbd>linear</kbd>, <kbd>ease-in</kbd>, <kbd>ease-out</kbd> для контролю темпу анімації.",
"task": "Встановіть <kbd>transition-timing-function</kbd> на <kbd>ease-in-out</kbd>.",
"previewHTML": "<button class=\"btn\">Timing</button>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: navy; color: gold; padding: 0.5rem 1rem; border: none; cursor: pointer; transition: all 0.5s; } .btn:hover { background: gold; color: navy; transform: scale(1.1); }",
"sandboxCSS": "",
"codePrefix": "/* Set timing function */\n.btn {",
"initialCode": "",
"codeSuffix": "}",
"solution": " transition-timing-function: ease-in-out;",
"previewContainer": "preview-area",
"validations": [
{
"type": "contains",
"value": "transition-timing-function",
"message": "Використайте <kbd>transition-timing-function</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "transition-timing-function", "expected": "ease-in-out" },
"message": "Яке ключове слово пом'якшення починається повільно, прискорюється, а потім знову сповільнюється?"
}
]
},
{
"id": "transitions-3",
"title": "Keyframes",
"description": "Створюйте іменовані анімації використовуючи <kbd>@keyframes</kbd> та застосовуйте їх через скорочення <kbd>animation</kbd>.<br><br><pre>@keyframes bounce {\n 50% { transform: translateY(-20px); }\n}\n.ball {\n animation: bounce 1s infinite;\n}</pre>",
"task": "Визначте keyframe при <kbd>50%</kbd> з <kbd>transform: translateY(-20px)</kbd> та застосуйте <kbd>animation: bounce 1s infinite</kbd> на <kbd>.ball</kbd>.",
"previewHTML": "<div class=\"ball\"></div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: crimson; border-radius: 50%; margin: 2rem auto; }",
"sandboxCSS": "",
"codePrefix": "/* Define keyframes and apply animation */\n@keyframes bounce {",
"initialCode": "",
"codeSuffix": "}\n.ball { }",
"solution": " 50% { transform: translateY(-20px); }\n}\n.ball {\n animation: bounce 1s infinite;",
"previewContainer": "preview-area",
"validations": [
{
"type": "contains",
"value": "@keyframes bounce",
"message": "Визначте <kbd>@keyframes bounce</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "regex",
"value": "50%.*transform: translateY\\(-20px\\)",
"message": "При <kbd>50%</kbd>, використайте <kbd>transform: translateY(-20px)</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "contains",
"value": "animation",
"message": "Використайте властивість <kbd>animation</kbd> на <kbd>.ball</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "regex",
"value": "animation:.*bounce.*1s.*infinite",
"message": "Використайте скорочення <kbd>animation</kbd>: назва, тривалість та кількість повторень.",
"options": { "caseSensitive": false }
}
]
},
{
"id": "transitions-4",
"title": "Animation Properties",
"description": "Налаштуйте анімації за допомогою <kbd>animation-delay</kbd>, <kbd>animation-iteration-count</kbd>, <kbd>animation-direction</kbd> та <kbd>animation-fill-mode</kbd>.",
"task": "Застосуйте анімацію <kbd>pulse</kbd> до <kbd>.box</kbd> з <kbd>animation-name: pulse</kbd>, <kbd>animation-duration: 2s</kbd>, <kbd>animation-delay: 1s</kbd>, <kbd>animation-iteration-count: 2</kbd> та <kbd>animation-fill-mode: forwards</kbd>.",
"previewHTML": "<div class=\"box\">Pulse</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: black; color: white; display: flex; align-items: center; justify-content: center; margin: 2rem auto; } @keyframes pulse { 0% { background: black; color: white; transform: scale(1); } 50% { background: white; color: black; transform: scale(1.2); } 100% { background: limegreen; color: black; transform: scale(1); } }",
"sandboxCSS": "",
"codePrefix": "/* Apply animation properties */\n.box {",
"initialCode": "",
"codeSuffix": "}",
"solution": " animation-name: pulse;\n animation-duration: 2s;\n animation-delay: 1s;\n animation-iteration-count: 2;\n animation-fill-mode: forwards;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "animation-name", "expected": "pulse" },
"message": "Яка властивість пов'язує елемент з іменованим правилом <kbd>@keyframes</kbd>?"
},
{
"type": "property_value",
"value": { "property": "animation-duration", "expected": "2s" },
"message": "Скільки має тривати один повний цикл анімації?"
},
{
"type": "property_value",
"value": { "property": "animation-delay", "expected": "1s" },
"message": "Яка властивість змушує анімацію зачекати перед початком?"
},
{
"type": "property_value",
"value": { "property": "animation-iteration-count", "expected": "2" },
"message": "Яка властивість контролює кількість повторень анімації?"
},
{
"type": "property_value",
"value": { "property": "animation-fill-mode", "expected": "forwards" },
"message": "Яка властивість зберігає стиль елемента в його фінальному стані keyframe після завершення анімації?"
}
]
}
]
}