Frontend Interaction Skills Through Solitaire

What is Frontend Development?

Frontend development is about creating the user interface - the part of an application that users see and interact with. In solitaire, this means:

  • How cards look and feel when you drag them
  • Visual feedback when you hover over valid drop zones
  • Smooth animations that make interactions feel natural
  • Responsive design that works on phones and computers

The Big Picture: Frontend is the bridge between users and your application’s functionality.

graph TD
    A[User Interaction] --> B[Frontend Event Handler]
    B --> C[Visual Feedback]
    B --> D[Game State Update]
    D --> E[DOM Re-render]
    E --> F[Updated UI]

The Frontend Stack: HTML, CSS, JavaScript

graph TB
    subgraph "Frontend Architecture"
        A[HTML<br/>Structure & Semantics] 
        B[CSS<br/>Styling & Layout]
        C[JavaScript<br/>Behavior & Interactivity]
    end
    
    A --> D[Semantic Elements]
    B --> E[Visual Design]
    C --> F[Event Handling]
    
    D --> G[Accessible Interface]
    E --> G
    F --> G

HTML: Semantic Structure

<!-- Semantic structure tells browsers AND users what each area does -->
<div class="game-container">
    <div class="foundation-row">
        <div id="foundation_0" class="card-pile foundation" 
             data-pile="foundation" data-index="0"></div>
    </div>
    
    <div class="tableau-area">
        <div id="tableau_0" class="card-pile tableau" 
             data-pile="tableau" data-index="0"></div>
    </div>
</div>

Key Principle: HTML creates the skeleton. Data attributes (data-pile, data-index) connect structure to functionality.

CSS: Visual Design & User Experience

.card {
    width: 76px;
    height: 106px;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.3s ease; /* Smooth animations */
}

.card.dragging {
    transform: rotate(5deg) scale(1.05);
    z-index: 1000;
}

.card-pile.valid-drop {
    box-shadow: 0 0 15px rgba(0, 255, 0, 0.5);
}

Key Principle: CSS provides visual feedback that guides user behavior. Every interaction should have a visual response.

JavaScript: Event Handling & DOM Manipulation

// Event handling connects user actions to application responses
card.addEventListener('dragstart', (e) => {
    card.classList.add('dragging');
    this.draggedCard = card;
});

card.addEventListener('click', () => {
    controller.handleCardClick(card.id); // Connects to game logic
});

Key Concepts: Event listeners, event delegation, DOM manipulation, mobile compatibility

Core Frontend Skills You’ll Learn

Skill 1: Making Things Interactive

Learning Goal: Understand how user actions trigger code responses

sequenceDiagram
    participant User
    participant Frontend
    participant Game Logic
    
    User->>Frontend: Clicks card
    Frontend->>Frontend: Add 'selected' visual style
    Frontend->>Game Logic: "Can this card move?"
    Game Logic-->>Frontend: "Yes" or "No"
    Frontend->>User: Show valid moves OR error message

Why This Matters: Every click, hover, and drag needs a response. Users expect immediate feedback.

// Teaching point: Event listeners connect user actions to code
card.addEventListener('click', (e) => {
    // 1. Visual feedback first (fast)
    card.classList.add('selected');
    
    // 2. Check game rules (logical)
    if (gameLogic.canCardMove(card.id)) {
        highlightValidTargets();
    } else {
        showErrorMessage("This card cannot move");
    }
});

Skill 2: Visual State Management

Learning Goal: Keep what users see synchronized with what’s actually happening

graph TD
    A[Game State Changes] --> B[Update DOM Elements]
    B --> C[User Sees Current State]
    C --> D[User Makes Action]
    D --> A

Why This Matters: If visuals don’t match reality, users get confused.

// Teaching point: Always update display when data changes
class GameUI {
    updateAfterMove(gameState) {
        // Score changed? Update it
        this.scoreElement.textContent = gameState.score;
        
        // Cards moved? Re-render piles
        this.renderAllPiles(gameState.piles);
        
        // Game won? Show celebration
        if (gameState.isWon) {
            this.showWinAnimation();
        }
    }
}

Skill 3: Multi-Device Support

Learning Goal: Make one interface work on phones, tablets, and computers

graph TB
    A[Single Codebase] --> B[📱 Mobile: Touch Events]
    A --> C[đź’» Desktop: Mouse Events] 
    A --> D[⌨️ Accessibility: Keyboard Events]
    
    B --> B1[Bigger buttons<br/>Touch-friendly]
    C --> C1[Hover effects<br/>Precise pointing]
    D --> D1[Tab navigation<br/>Screen readers]

Why This Matters: Your game should work for everyone, everywhere.

// Teaching point: Progressive enhancement - start basic, add features
class CardInteraction {
    constructor(cardElement) {
        // Basic click works everywhere
        cardElement.addEventListener('click', this.selectCard);
        
        // Enhanced features for capable devices
        if ('draggable' in cardElement) {
            this.addDragDrop(cardElement);
        }
        
        if ('ontouchstart' in window) {
            this.addTouchSupport(cardElement);
        }
    }
}

What You Just Learned

🎯 Skill 1: Making interfaces interactive through event handling 🎯 Skill 2: Keeping visuals synchronized with data
🎯 Skill 3: Building responsive, accessible experiences

Why This Leads to JavaScript OOP

Look at this code structure:

graph TB
    A[CardElement class] --> B[DropZone class]
    B --> C[GameUI class]
    C --> D[Controller class]
    
    A --> A1[Handle card interactions]
    B --> B1[Handle drop zones] 
    C --> C1[Manage display updates]
    D --> D1[Coordinate everything]

The Problem: As your frontend gets more complex, you need better ways to organize all this code.

The Solution: JavaScript Object-Oriented Programming - building reusable, organized code modules.

Quick Experiments to Try

  1. Visual Feedback: Add a subtle glow effect to valid drop zones when dragging
  2. Animation: Create a smooth card flip animation when revealing face-down cards
  3. Theme Toggle: Implement a dark/light theme switcher using CSS custom properties
  4. Mobile Gestures: Add basic touch support for card selection

Key Takeaways

âś… Frontend = User Experience: Every click, hover, and animation shapes how users feel about your application

âś… HTML + CSS + JavaScript: Three technologies working together, each with a specific role

âś… Visual Feedback is Essential: Users need immediate confirmation of their actions

âś… Responsive Design: Modern applications work on all devices

âś… Performance Matters: Smooth interactions require efficient code

âś… Accessibility Included: Good frontend works for everyone

Next Up: JavaScript OOP will show us how to organize this frontend code into maintainable, scalable applications.


Lesson: Designing to Teach — LxD Meets Array Algorithms

Duration: ~90 minutes (can be split into two 45‑min sessions)
Audience: AP CSA students
Meta‑Goal: Students learn how to teach a topic (LxD) by designing a lesson for a computer science concept.


1. Warm‑Up Hook (5 min)

Scenario for students:

Imagine you’ve just joined your school’s tutoring club.
A younger student asks: “How does sorting an array work?”
You have 5 minutes to make them understand.

Activity: Students quickly write their first‑draft explanation on paper — no props, no slides, no internet.


2. Mini‑Lesson on LxD Principles (10 min)

Briefly introduce:

  • Empathy: Know your learner’s starting point.
    If they’ve never coded, “O(n log n)” means nothing — but “organizing music tracks fastest” might click.
  • Context: Place the concept in a real‑world frame.
    E.g., seating guests at a wedding by name.
  • Narrative: Tell it like a story with a beginning, challenge, and resolution.
    The “messy playlist” becomes an ordered one.
  • Interaction: Give them something to do, not just watch.
    Let them manually swap items in a small list.

3. Core AP CSA Topic Briefing — Array Algorithms (15 min)

Key Concepts:

  • Arrays in Java (int[], String[])
  • Two common algorithms: Selection Sort and Linear Search
// Linear Search in JavaScript
function find(arr, target) {
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] === target) {
        return i; // found at index i
      }
    }
    return -1; // not found
  }
  
  // Example usage:
  const nums = [42, 7, 19, 7, 3, 25];
  console.log(find(nums, 19)); // → 2
  console.log(find(nums, 100)); // → -1