Files
cv-site/prompts/002-animate-language-transitions.md
T
juanatsap 1f7757c848 good
2025-11-15 15:59:54 +00:00

14 KiB

Implement Skeleton Loader Transitions for Language Switching

Implement professional skeleton loader animations when switching between English and Spanish languages in the CV application. The goal is to create a polished, modern user experience similar to FriendKit (reference screenshots provided) where content transitions through skeleton/placeholder states with pulsing animations.

Visual Reference: The user provided screenshots showing gray pulsing placeholder boxes that appear during page transitions - these skeleton loaders make the transition feel smooth and intentional while new content loads.

This will transform the current instant language switch into a premium, modern web app experience.

**Current Implementation:** - Language switching uses HTMX with `/switch-language?lang={en|es}` endpoint - HTMX performs out-of-band swaps (`hx-swap-oob="innerHTML"`) to update: - `#language-selector` (primary target) - `#cv-inner-content-page-1` - `#cv-inner-content-page-2` - Currently uses `hx-swap="outerHTML"` which causes instant, jarring content replacement - No intermediate loading state - content just "pops" from one language to another

Reference Files: @templates/language-switch.html - Server response template with OOB swaps @templates/partials/navigation/language-selector.html - Language selector buttons @static/css/main.css - Existing CSS with some transitions already in place

Tech Stack:

  • HTMX for dynamic content swapping
  • Hyperscript for custom behaviors (already in use)
  • Vanilla CSS for animations (no external animation libraries)
  • Go templates for server-side rendering

Desired User Experience (from screenshots):

  1. User clicks language button (EN or ES)
  2. Current content fades out (200-300ms)
  3. Skeleton loaders appear - gray pulsing boxes matching the layout structure
  4. New language content loads from server
  5. Skeleton loaders fade out and new content fades in (200-300ms)
  6. Total smooth, professional transition feel

Why Skeleton Loaders Matter:

  • Perceived performance: Users perceive loading as faster when they see progressive feedback
  • Modern UX standard: Used by Facebook, LinkedIn, YouTube, and all modern web apps
  • Reduces cognitive load: Shows users "something is happening" vs blank screen or instant swap
  • Professional polish: Demonstrates attention to detail and quality
1. **Skeleton Loader Design:** - Gray placeholder boxes (`background: #e0e0e0` or similar) matching content structure - Pulsing/shimmer animation (subtle opacity or gradient shift) - Should roughly match the layout of CV sections (header, skills, experience, etc.) - Lightweight and fast to render
  1. Three-Phase Transition:

    • Phase 1 (Fade Out): Current content fades to opacity 0 (250ms)
    • Phase 2 (Skeleton Display): Show skeleton loaders with pulse animation
    • Phase 3 (Fade In): New content fades from opacity 0 to 1 (250ms)
    • Total transition: ~500-700ms (feels premium, not sluggish)
  2. HTMX Integration:

    • Use HTMX swap timing modifiers: swap:250ms settle:250ms
    • Leverage HTMX request lifecycle events for skeleton state management
    • Use htmx:beforeRequest to show skeleton
    • Use htmx:afterSwap to hide skeleton and fade in content
  3. CSS Animations:

    • Create .skeleton-loader component classes
    • Pulsing animation using CSS @keyframes (opacity or background gradient shift)
    • Animation should be subtle: 1.5s-2s loop, infinite
    • GPU-accelerated properties only (opacity, transform)
  4. Layout Matching:

    • Skeleton should mirror the actual CV layout structure
    • Consider creating skeleton variants for:
      • Header section (name, title, badges)
      • Skills sidebar sections
      • Experience entries
      • Education entries
    • Doesn't need to be pixel-perfect, just recognizable structure
  5. Performance:

    • Skeleton rendering should be instant (<16ms)
    • Animations GPU-accelerated for smooth 60fps
    • No layout thrashing during transitions
    • Total transition under 700ms
  6. Accessibility:

    • Respect prefers-reduced-motion - disable pulse animation
    • Add aria-busy="true" during loading states
    • Ensure screen readers announce loading state
  7. Consistency:

    • Use existing project timing patterns (0.2s-0.3s)
    • Match existing design language and color palette
    • Work on mobile and desktop viewports
**Recommended Implementation Strategy:**

Step 1: Create Skeleton Loader HTML Structure

Create a new template or partial: templates/partials/skeleton-loader.html

This should contain a simplified version of your CV layout with placeholder boxes:

  • Header skeleton (circular avatar placeholder, horizontal bars for name/title)
  • Left sidebar skeleton (rectangular blocks for skills)
  • Main content skeleton (blocks for experience entries)
  • Right sidebar skeleton (blocks for additional skills)

Step 2: Create Skeleton CSS Animations

Add to static/css/main.css or create static/css/skeleton.css:

/* Skeleton loader base styles */
.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeleton-pulse 1.5s ease-in-out infinite;
  border-radius: 4px;
}

@keyframes skeleton-pulse {
  0%, 100% { background-position: 200% 0; }
  50% { background-position: 0 0; }
}

/* Skeleton container - hidden by default */
.skeleton-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: white;
  z-index: 10;
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms ease;
}

.skeleton-overlay.active {
  opacity: 1;
  pointer-events: all;
}

/* Skeleton shapes - create boxes matching your layout */
.skeleton-header { height: 120px; margin-bottom: 20px; }
.skeleton-sidebar-item { height: 60px; margin-bottom: 10px; }
.skeleton-content-item { height: 100px; margin-bottom: 15px; }

/* Reduce motion support */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: #e0e0e0; }
}

Step 3: Update Language Selector with HTMX Timing

Modify templates/partials/navigation/language-selector.html:

  • Add hx-swap="outerHTML swap:250ms settle:250ms"
  • Add hx-indicator="#skeleton-loader" to show skeleton during request
  • Add hyperscript to manage skeleton visibility

Step 4: Add Skeleton Loader to Main Template

Insert the skeleton loader overlay into your main CV template:

  • Position it absolutely over the content area
  • Initially hidden with opacity: 0
  • Activated via HTMX events or hyperscript

Step 5: HTMX Event Handling with Hyperscript

Add hyperscript behavior to show/hide skeleton:

on htmx:beforeRequest from #language-selector
  add .active to #skeleton-loader
end

on htmx:afterSwap from #language-selector
  wait 100ms  -- Brief delay to ensure content is rendered
  remove .active from #skeleton-loader
end

Alternative Approach (Pure HTMX): Use hx-indicator attribute with CSS to control visibility:

  • hx-indicator="#skeleton-loader" on language buttons
  • HTMX automatically adds .htmx-request class during requests
  • CSS: #skeleton-loader.htmx-request { opacity: 1; }

Step 6: Content Fade Transitions

Add fade-in/out to actual content sections:

.cv-page-content-wrapper {
  transition: opacity 250ms ease;
}

.cv-page-content-wrapper.htmx-swapping {
  opacity: 0;
}

.cv-page-content-wrapper.htmx-settling {
  opacity: 1;
}

What to Prioritize:

  1. Get basic skeleton structure showing/hiding correctly
  2. Add pulsing animation
  3. Refine skeleton shapes to better match layout
  4. Polish timing and transitions
  5. Add accessibility features

What to Avoid:

  • Don't create overly complex skeleton markup - simple boxes are fine
  • Don't make the skeleton identical to real content - approximate is better
  • Don't use JavaScript animations - stick to CSS for performance
  • Don't make transitions too long - 500-700ms total maximum
  • Don't forget to test rapid clicking (skeleton should handle interruptions gracefully)

Why These Constraints Matter:

  • Simplicity: Complex skeletons are harder to maintain when layout changes
  • Performance: CSS animations are GPU-accelerated; JS animations cause jank
  • UX Research: 400-700ms is the sweet spot - longer feels broken, shorter feels pointless
  • Resilience: Users click fast - implementation must handle interruptions without breaking
Create/modify the following files:
  1. ./templates/partials/skeleton-loader.html (NEW)

    • Skeleton loader HTML structure
    • Simplified CV layout with placeholder boxes
    • Should mirror the structure of CV content sections
  2. ./static/css/skeleton.css (NEW)

    • Skeleton loader styles
    • Pulsing animation keyframes
    • Skeleton overlay positioning and transitions
    • Responsive skeleton layouts
    • Accessibility overrides for prefers-reduced-motion
  3. ./templates/partials/navigation/language-selector.html

    • Add HTMX swap timing modifiers
    • Add skeleton loader indicator reference
    • Add hyperscript for skeleton show/hide events
  4. ./templates/language-switch.html

    • May need to coordinate OOB swap timing
    • Ensure skeleton works with all content updates
  5. ./static/css/main.css

    • Add content fade-in/out transitions
    • Import skeleton.css if created separately
    • Add HTMX animation class styles
  6. Include skeleton loader in main template (wherever CV content lives)

    • Add <div id="skeleton-loader" class="skeleton-overlay">...</div>
    • Position over content area
    • Initially hidden, shown during language switch
Before declaring complete, perform these tests:

1. Visual Verification:

  • Click EN button: Content fades out → Skeleton appears → New content fades in
  • Click ES button: Same smooth transition with skeleton
  • Skeleton boxes pulse/shimmer smoothly
  • Skeleton roughly matches CV layout (recognizable structure)
  • No flashing or jarring jumps during transition

2. Timing Verification:

  • Total transition feels responsive (<700ms)
  • Skeleton appears immediately when language button clicked
  • Content fade-out is smooth (not instant)
  • Content fade-in is smooth after skeleton disappears

3. Interaction Testing:

  • Rapidly click between EN and ES - no broken states
  • Click language button while skeleton is showing - handles gracefully
  • Mobile viewport - skeleton works correctly
  • Desktop viewport - skeleton works correctly

4. Performance Testing:

  • Open DevTools Performance tab
  • Record during language switch
  • Verify 60fps animation (no dropped frames)
  • No layout thrashing or long tasks
  • GPU acceleration active for animations

5. Accessibility Testing:

  • Enable "Reduce motion" in OS settings → Skeleton pulse disabled
  • Screen reader announces loading state
  • Keyboard navigation still works during transitions
  • Focus management doesn't break

6. Browser Compatibility:

  • Chrome: Smooth skeleton animations
  • Firefox: Smooth skeleton animations
  • Safari: Smooth skeleton animations
  • Mobile browsers: Touch interactions work correctly

7. Edge Cases:

  • Slow network simulation (throttle to 3G) - skeleton visible longer
  • Fast network - skeleton doesn't flash too quickly (minimum display time?)
  • First load vs subsequent switches - consistent behavior
  • Page refresh during skeleton display - recovers gracefully

Success Indicators: Skeleton loaders appear during language transitions Pulsing animation is smooth and subtle Total transition time feels professional (500-700ms) No jarring content jumps or flashes Works consistently across browsers and devices Respects accessibility preferences Handles rapid interactions gracefully

<success_criteria>

  1. Skeleton loaders with pulsing animation appear during language switching
  2. Three-phase transition: fade-out → skeleton → fade-in
  3. Total transition time: 500-700ms (feels premium, not sluggish)
  4. Skeleton structure roughly matches CV layout (recognizable)
  5. Animations are GPU-accelerated and buttery smooth (60fps)
  6. Respects prefers-reduced-motion accessibility setting
  7. Handles rapid clicking without breaking or visual glitches
  8. Works consistently across modern browsers and device sizes
  9. Code follows existing project patterns and conventions
  10. Implementation is maintainable and doesn't overcomplicate the codebase </success_criteria>
**HTMX Documentation:** - Swap timing: https://htmx.org/attributes/hx-swap/ - Request indicators: https://htmx.org/attributes/hx-indicator/ - CSS transitions: https://htmx.org/examples/animations/

Skeleton Loader Patterns:

  • Facebook-style skeleton screens
  • Modern progressive loading UX patterns
  • LinkedIn content placeholders

Visual Reference (provided by user):

  • FriendKit example pages showing gray pulsing placeholder boxes
  • Boxes animate with subtle shimmer/pulse effect
  • Content appears progressively after skeleton state

<additional_context> If you can provide the FriendKit code: If you have access to the actual CSS/HTML from the FriendKit examples, examining their skeleton loader implementation would be valuable for:

  • Exact timing values they use
  • Gradient/animation patterns for the pulse effect
  • How they structure skeleton markup
  • Any clever performance optimizations

However, we can implement an excellent skeleton loader without that code - the visual reference is sufficient to create a premium experience. </additional_context>