feat: reorder learning path for design students and improve animations

Learning path changes:
- Reorder modules: CSS visual (selectors, colors, typography) first,
  then layout (flexbox, grid), then HTML structure last
- Add intro lessons on CSS property syntax before selectors
- Add Figure module (images with captions)
- Remove Progress/Meter module (too niche)
- Reduce Tables from 3 to 1 lesson
- Reduce Form Validation from 3 to 1 lesson
- Rename "CSS Selectors" module to "CSS Basics"

Animation improvements:
- Change success text to "Your CODE looks CRISPY!"
- Increase animation duration to 3s
- Fix Firefox glow: use linear-gradient pulse instead of conic rotation
- Fix expected result toggle: match padding to prevent layout jump

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2026-01-14 01:30:19 +01:00
parent c397397c54
commit f6c7cca63f
6 changed files with 236 additions and 304 deletions

View File

@@ -630,7 +630,7 @@ function runCode() {
elements.previewWrapper?.classList.add("matched");
setTimeout(() => {
elements.previewWrapper?.classList.remove("matched");
}, 3000);
}, 3500);
updateNavigationButtons();
updateProgressDisplay();

View File

@@ -6,7 +6,6 @@
// English lesson imports
import welcomeEN from "../../lessons/00-welcome.json";
import basicSelectorsEN from "../../lessons/00-basic-selectors.json";
import advancedSelectorsEN from "../../lessons/01-advanced-selectors.json";
import boxModelEN from "../../lessons/01-box-model.json";
import colorsEN from "../../lessons/03-colors.json";
import typographyEN from "../../lessons/04-typography.json";
@@ -17,7 +16,7 @@ import htmlElementsEN from "../../lessons/20-html-elements.json";
import htmlFormsBasicEN from "../../lessons/21-html-forms-basic.json";
import htmlFormsValidationEN from "../../lessons/22-html-forms-validation.json";
import htmlDetailsSummaryEN from "../../lessons/23-html-details-summary.json";
import htmlProgressMeterEN from "../../lessons/24-html-progress-meter.json";
import htmlFigureEN from "../../lessons/29-html-figure.json";
import htmlTablesEN from "../../lessons/30-html-tables.json";
import htmlSvgEN from "../../lessons/32-html-svg.json";
import flexboxEN from "../../lessons/flexbox.json";
@@ -35,7 +34,6 @@ import htmlElementsDE from "../../lessons/de/20-html-elements.json";
import htmlFormsBasicDE from "../../lessons/de/21-html-forms-basic.json";
import htmlFormsValidationDE from "../../lessons/de/22-html-forms-validation.json";
import htmlDetailsSummaryDE from "../../lessons/de/23-html-details-summary.json";
import htmlProgressMeterDE from "../../lessons/de/24-html-progress-meter.json";
import htmlTablesDE from "../../lessons/de/30-html-tables.json";
import htmlSvgDE from "../../lessons/de/32-html-svg.json";
import flexboxDE from "../../lessons/de/flexbox.json";
@@ -51,7 +49,6 @@ import htmlElementsPL from "../../lessons/pl/20-html-elements.json";
import htmlFormsBasicPL from "../../lessons/pl/21-html-forms-basic.json";
import htmlFormsValidationPL from "../../lessons/pl/22-html-forms-validation.json";
import htmlDetailsSummaryPL from "../../lessons/pl/23-html-details-summary.json";
import htmlProgressMeterPL from "../../lessons/pl/24-html-progress-meter.json";
import htmlTablesPL from "../../lessons/pl/30-html-tables.json";
import htmlSvgPL from "../../lessons/pl/32-html-svg.json";
import flexboxPL from "../../lessons/pl/flexbox.json";
@@ -67,7 +64,6 @@ import htmlElementsES from "../../lessons/es/20-html-elements.json";
import htmlFormsBasicES from "../../lessons/es/21-html-forms-basic.json";
import htmlFormsValidationES from "../../lessons/es/22-html-forms-validation.json";
import htmlDetailsSummaryES from "../../lessons/es/23-html-details-summary.json";
import htmlProgressMeterES from "../../lessons/es/24-html-progress-meter.json";
import htmlTablesES from "../../lessons/es/30-html-tables.json";
import htmlSvgES from "../../lessons/es/32-html-svg.json";
import flexboxES from "../../lessons/es/flexbox.json";
@@ -83,7 +79,6 @@ import htmlElementsAR from "../../lessons/ar/20-html-elements.json";
import htmlFormsBasicAR from "../../lessons/ar/21-html-forms-basic.json";
import htmlFormsValidationAR from "../../lessons/ar/22-html-forms-validation.json";
import htmlDetailsSummaryAR from "../../lessons/ar/23-html-details-summary.json";
import htmlProgressMeterAR from "../../lessons/ar/24-html-progress-meter.json";
import htmlTablesAR from "../../lessons/ar/30-html-tables.json";
import htmlSvgAR from "../../lessons/ar/32-html-svg.json";
import flexboxAR from "../../lessons/ar/flexbox.json";
@@ -99,199 +94,180 @@ import htmlElementsUK from "../../lessons/uk/20-html-elements.json";
import htmlFormsBasicUK from "../../lessons/uk/21-html-forms-basic.json";
import htmlFormsValidationUK from "../../lessons/uk/22-html-forms-validation.json";
import htmlDetailsSummaryUK from "../../lessons/uk/23-html-details-summary.json";
import htmlProgressMeterUK from "../../lessons/uk/24-html-progress-meter.json";
import htmlTablesUK from "../../lessons/uk/30-html-tables.json";
import htmlSvgUK from "../../lessons/uk/32-html-svg.json";
import flexboxUK from "../../lessons/uk/flexbox.json";
// English module store - ordered by learning path
// English module store - ordered for design students
const moduleStoreEN = [
// Welcome
welcomeEN,
// HTML Fundamentals
htmlElementsEN,
htmlFormsBasicEN,
htmlFormsValidationEN,
// HTML Interactive
htmlDetailsSummaryEN,
htmlProgressMeterEN,
// HTML Data
htmlTablesEN,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsEN,
advancedSelectorsEN,
colorsEN,
typographyEN,
boxModelEN,
unitsVariablesEN,
// CSS Graphics
htmlSvgEN,
// CSS Layouts
// CSS Layout
flexboxEN,
gridEN,
unitsVariablesEN,
responsiveEN,
// CSS Animation
// CSS Polish
transitionsAnimationsEN,
// HTML Structure
htmlElementsEN,
htmlFigureEN,
htmlSvgEN,
// HTML Interactive
htmlDetailsSummaryEN,
htmlFormsBasicEN,
htmlFormsValidationEN,
htmlTablesEN,
// Goodbye
goodbyeEN
];
// German module store - ordered by learning path
// German module store - ordered for design students
const moduleStoreDE = [
// Welcome
welcomeDE,
// HTML Fundamentals
htmlElementsDE,
htmlFormsBasicDE,
htmlFormsValidationDE,
// HTML Interactive
htmlDetailsSummaryDE,
htmlProgressMeterDE,
// HTML Data
htmlTablesDE,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsDE,
advancedSelectorsEN, // Using EN fallback until translated
colorsEN, // Using EN fallback until translated
typographyEN, // Using EN fallback until translated
boxModelDE,
unitsVariablesDE,
// CSS Graphics
htmlSvgDE,
// CSS Layouts
// CSS Layout
flexboxDE,
gridEN, // Using EN fallback until translated
unitsVariablesDE,
responsiveDE,
// CSS Animation
// CSS Polish
transitionsAnimationsDE,
// HTML Structure
htmlElementsDE,
htmlFigureEN, // Using EN fallback until translated
htmlSvgDE,
// HTML Interactive
htmlDetailsSummaryDE,
htmlFormsBasicDE,
htmlFormsValidationDE,
htmlTablesDE,
// Goodbye
goodbyeEN
];
// Polish module store - ordered by learning path
// Polish module store - ordered for design students
const moduleStorePL = [
// Welcome
welcomePL,
// HTML Fundamentals
htmlElementsPL,
htmlFormsBasicPL,
htmlFormsValidationPL,
// HTML Interactive
htmlDetailsSummaryPL,
htmlProgressMeterPL,
// HTML Data
htmlTablesPL,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsPL,
advancedSelectorsEN, // Using EN fallback until translated
colorsEN, // Using EN fallback until translated
typographyEN, // Using EN fallback until translated
boxModelPL,
unitsVariablesPL,
// CSS Graphics
htmlSvgPL,
// CSS Layouts
// CSS Layout
flexboxPL,
gridEN, // Using EN fallback until translated
unitsVariablesPL,
responsivePL,
// CSS Animation
// CSS Polish
transitionsAnimationsPL,
// HTML Structure
htmlElementsPL,
htmlFigureEN, // Using EN fallback until translated
htmlSvgPL,
// HTML Interactive
htmlDetailsSummaryPL,
htmlFormsBasicPL,
htmlFormsValidationPL,
htmlTablesPL,
// Goodbye
goodbyeEN
];
// Spanish module store - ordered by learning path
// Spanish module store - ordered for design students
const moduleStoreES = [
// Welcome
welcomeES,
// HTML Fundamentals
htmlElementsES,
htmlFormsBasicES,
htmlFormsValidationES,
// HTML Interactive
htmlDetailsSummaryES,
htmlProgressMeterES,
// HTML Data
htmlTablesES,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsES,
advancedSelectorsEN, // Using EN fallback until translated
colorsEN, // Using EN fallback until translated
typographyEN, // Using EN fallback until translated
boxModelES,
unitsVariablesES,
// CSS Graphics
htmlSvgES,
// CSS Layouts
// CSS Layout
flexboxES,
gridEN, // Using EN fallback until translated
unitsVariablesES,
responsiveES,
// CSS Animation
// CSS Polish
transitionsAnimationsES,
// HTML Structure
htmlElementsES,
htmlFigureEN, // Using EN fallback until translated
htmlSvgES,
// HTML Interactive
htmlDetailsSummaryES,
htmlFormsBasicES,
htmlFormsValidationES,
htmlTablesES,
// Goodbye
goodbyeEN
];
// Arabic module store - ordered by learning path
// Arabic module store - ordered for design students
const moduleStoreAR = [
// Welcome
welcomeAR,
// HTML Fundamentals
htmlElementsAR,
htmlFormsBasicAR,
htmlFormsValidationAR,
// HTML Interactive
htmlDetailsSummaryAR,
htmlProgressMeterAR,
// HTML Data
htmlTablesAR,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsAR,
advancedSelectorsEN, // Using EN fallback until translated
colorsEN, // Using EN fallback until translated
typographyEN, // Using EN fallback until translated
boxModelAR,
unitsVariablesAR,
// CSS Graphics
htmlSvgAR,
// CSS Layouts
// CSS Layout
flexboxAR,
gridEN, // Using EN fallback until translated
unitsVariablesAR,
responsiveAR,
// CSS Animation
// CSS Polish
transitionsAnimationsAR,
// HTML Structure
htmlElementsAR,
htmlFigureEN, // Using EN fallback until translated
htmlSvgAR,
// HTML Interactive
htmlDetailsSummaryAR,
htmlFormsBasicAR,
htmlFormsValidationAR,
htmlTablesAR,
// Goodbye
goodbyeEN
];
// Ukrainian module store - ordered by learning path
// Ukrainian module store - ordered for design students
const moduleStoreUK = [
// Welcome
welcomeUK,
// HTML Fundamentals
htmlElementsUK,
htmlFormsBasicUK,
htmlFormsValidationUK,
// HTML Interactive
htmlDetailsSummaryUK,
htmlProgressMeterUK,
// HTML Data
htmlTablesUK,
// CSS Fundamentals
// CSS Visual (immediate impact)
basicSelectorsUK,
advancedSelectorsEN, // Using EN fallback until translated
colorsEN, // Using EN fallback until translated
typographyEN, // Using EN fallback until translated
boxModelUK,
unitsVariablesUK,
// CSS Graphics
htmlSvgUK,
// CSS Layouts
// CSS Layout
flexboxUK,
gridEN, // Using EN fallback until translated
unitsVariablesUK,
responsiveUK,
// CSS Animation
// CSS Polish
transitionsAnimationsUK,
// HTML Structure
htmlElementsUK,
htmlFigureEN, // Using EN fallback until translated
htmlSvgUK,
// HTML Interactive
htmlDetailsSummaryUK,
htmlFormsBasicUK,
htmlFormsValidationUK,
htmlTablesUK,
// Goodbye
goodbyeEN
];

View File

@@ -207,7 +207,7 @@ kbd {
font-weight: bold;
cursor: pointer;
color: var(--light-text);
transition: all 0.2s;
transition: color 0.2s, border-color 0.2s;
}
.help-toggle:hover {
@@ -587,7 +587,7 @@ kbd {
.expected-frame {
width: 100%;
height: 100%;
padding: var(--spacing-sm);
padding: var(--spacing-xs);
}
.expected-frame iframe {
@@ -617,17 +617,19 @@ kbd {
#7c4dff,
#9b59b6
) border-box;
animation: spin-border 2.5s linear forwards;
animation: spin-border 3s ease-out forwards;
overflow: visible;
}
/* Colorful glow effect layer */
/* Colorful glow effect layer on the preview area */
.preview-wrapper.matched::before {
content: "";
position: absolute;
inset: -12px;
border-radius: calc(var(--border-radius-md) + 12px);
background: conic-gradient(
from var(--border-angle),
/* Multi-color gradient glow - works in all browsers */
background: linear-gradient(
135deg,
#9b59b6,
#e040fb,
#00bcd4,
@@ -635,9 +637,50 @@ kbd {
#9b59b6
);
z-index: -1;
filter: blur(20px);
filter: blur(24px);
opacity: 0;
animation: spin-glow 2.5s linear forwards;
animation: glow-pulse 3s ease-out forwards;
pointer-events: none;
}
@keyframes glow-pulse {
0% {
opacity: 0;
transform: scale(0.95);
}
15% {
opacity: 0.8;
transform: scale(1);
}
60% {
opacity: 0.6;
}
100% {
opacity: 0;
transform: scale(1.02);
}
}
/* Animated CRISPY badge (matches logo style) */
.preview-wrapper.matched::after {
content: "Your CODE looks CRISPY!";
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%) translateY(-100%);
font-family: system-ui, -apple-system, sans-serif;
font-size: 2rem;
font-weight: 800;
letter-spacing: 0.05em;
color: white;
background: var(--primary-color);
padding: 0.5rem 1.25rem;
border-radius: 8px;
z-index: 10;
pointer-events: none;
animation: crispy-fall 3s ease-in-out forwards;
opacity: 0;
white-space: nowrap;
}
@keyframes spin-border {
@@ -656,6 +699,9 @@ kbd {
@keyframes spin-glow {
0% {
--border-angle: 0deg;
opacity: 0;
}
10% {
opacity: 0.8;
}
80% {
@@ -668,6 +714,30 @@ kbd {
}
}
@keyframes crispy-fall {
0% {
top: 0;
transform: translateX(-50%) translateY(-100%);
opacity: 0;
}
15% {
opacity: 1;
}
50% {
top: 50%;
transform: translateX(-50%) translateY(-50%);
opacity: 1;
}
85% {
opacity: 1;
}
100% {
top: 100%;
transform: translateX(-50%) translateY(0%);
opacity: 0;
}
}
/* ================= GAME CONTROLS ================= */
.game-controls {
display: flex;
@@ -895,7 +965,7 @@ button.lesson-list-item {
cursor: pointer;
font-family: var(--font-main);
font-size: 0.9rem;
transition: all 0.2s;
transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.btn:hover {
@@ -1056,7 +1126,7 @@ button.lesson-list-item {
height: 20px;
background: #ccc;
border-radius: 20px;
transition: 0.3s;
transition: background 0.3s;
margin-right: 8px;
flex-shrink: 0;
}
@@ -1070,7 +1140,7 @@ button.lesson-list-item {
bottom: 2px;
background: white;
border-radius: 50%;
transition: 0.3s;
transition: transform 0.3s;
}
input:checked + .toggle-slider {
@@ -1134,7 +1204,7 @@ input:checked + .toggle-slider::before {
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.2s;
transition: background 0.2s, color 0.2s;
}
.dialog-close:hover {
@@ -1201,7 +1271,7 @@ input:checked + .toggle-slider::before {
border: 1px solid var(--primary-bg-medium);
text-decoration: none;
color: var(--text-color);
transition: all 0.2s ease;
transition: background 0.2s, border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}
.project-card:hover {