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.
146 lines
6.9 KiB
JSON
146 lines
6.9 KiB
JSON
{
|
|
"$schema": "../../schemas/code-crispies-module-schema.json",
|
|
"id": "transitions-animations",
|
|
"title": "Animaciones CSS",
|
|
"description": "Añade interactividad a tu UI mediante transiciones suaves de propiedades y animaciones basadas en keyframes.",
|
|
"difficulty": "intermediate",
|
|
"lessons": [
|
|
{
|
|
"id": "transitions-1",
|
|
"title": "Transitions",
|
|
"description": "Aprende a aplicar <kbd>transition</kbd> a propiedades para cambios suaves en estados.<br><br><pre>transition: property duration;\n/* ej. transition: background-color 0.3s; */</pre>",
|
|
"task": "Añade <kbd>transition: background-color 0.3s</kbd> para que el color cambie suavemente al hacer hover.",
|
|
"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": "Usa la propiedad <kbd>transition</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
},
|
|
{
|
|
"type": "regex",
|
|
"value": "transition:\\s*background-color\\s*0\\.3s",
|
|
"message": "Especifica qué propiedad transicionar y cuánto debe durar.",
|
|
"options": { "caseSensitive": false }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "transitions-2",
|
|
"title": "Timing Funcs",
|
|
"description": "Explora funciones de easing como <kbd>ease</kbd>, <kbd>linear</kbd>, <kbd>ease-in</kbd>, <kbd>ease-out</kbd> para controlar el ritmo de la animación.",
|
|
"task": "Establece <kbd>transition-timing-function</kbd> a <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": "Usa <kbd>transition-timing-function</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "transition-timing-function", "expected": "ease-in-out" },
|
|
"message": "¿Qué palabra clave de easing empieza lento, acelera, y luego desacelera de nuevo?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "transitions-3",
|
|
"title": "Keyframes",
|
|
"description": "Crea animaciones nombradas usando <kbd>@keyframes</kbd> y aplícalas con el atajo <kbd>animation</kbd>.<br><br><pre>@keyframes bounce {\n 50% { transform: translateY(-20px); }\n}\n.ball {\n animation: bounce 1s infinite;\n}</pre>",
|
|
"task": "Define un keyframe en <kbd>50%</kbd> con <kbd>transform: translateY(-20px)</kbd> y aplica <kbd>animation: bounce 1s infinite</kbd> a <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": "Define <kbd>@keyframes bounce</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
},
|
|
{
|
|
"type": "regex",
|
|
"value": "50%.*transform: translateY\\(-20px\\)",
|
|
"message": "En <kbd>50%</kbd>, usa <kbd>transform: translateY(-20px)</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
},
|
|
{
|
|
"type": "contains",
|
|
"value": "animation",
|
|
"message": "Usa la propiedad <kbd>animation</kbd> en <kbd>.ball</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
},
|
|
{
|
|
"type": "regex",
|
|
"value": "animation:.*bounce.*1s.*infinite",
|
|
"message": "Usa el atajo <kbd>animation</kbd>: nombre, duración y número de repeticiones.",
|
|
"options": { "caseSensitive": false }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "transitions-4",
|
|
"title": "Animation Properties",
|
|
"description": "Ajusta las animaciones con <kbd>animation-delay</kbd>, <kbd>animation-iteration-count</kbd>, <kbd>animation-direction</kbd> y <kbd>animation-fill-mode</kbd>.",
|
|
"task": "Aplica la animación <kbd>pulse</kbd> a <kbd>.box</kbd> con <kbd>animation-name: pulse</kbd>, <kbd>animation-duration: 2s</kbd>, <kbd>animation-delay: 1s</kbd>, <kbd>animation-iteration-count: 2</kbd> y <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": "¿Qué propiedad vincula un elemento a una regla <kbd>@keyframes</kbd> nombrada?"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "animation-duration", "expected": "2s" },
|
|
"message": "¿Cuánto debe durar un ciclo completo de la animación?"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "animation-delay", "expected": "1s" },
|
|
"message": "¿Qué propiedad hace que la animación espere antes de comenzar?"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "animation-iteration-count", "expected": "2" },
|
|
"message": "¿Qué propiedad controla cuántas veces se repite la animación?"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "animation-fill-mode", "expected": "forwards" },
|
|
"message": "¿Qué propiedad mantiene el elemento con los estilos de su último keyframe después de que termina la animación?"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|