Tech & AHA-Stack

How the Math Box was built

The Math Box is a demo application for the AHA-Stack and @casoon/fragment-renderer. It demonstrates how modern web applications can be built with minimal JavaScript and maximum performance.

What is the AHA-Stack?

The AHA-Stack combines three lightweight technologies:

Astro

Astro - A modern web framework for content-focused websites with zero-JS default

HTMX

HTMX - Enables dynamic interactions through HTML attributes instead of JavaScript

Alpine.js

Alpine.js - Lightweight JavaScript for reactive UI components

@casoon/fragment-renderer

The Fragment Renderer is a library from casoon that enables server-side rendering of Astro components as HTML fragments. This is ideal for HTMX-based applications.

Features:
  • Server-side rendering of Astro components
  • HTMX integration with automatic response headers
  • Preset for the AHA-Stack
  • TypeScript support

Example: Feedback Fragment

This is how feedback is rendered in the Math Box after an answer:

// task-renderer.ts
import { createAstroRuntime } from "@casoon/fragment-renderer";
import { ahaStackPreset } from "@casoon/fragment-renderer/presets/aha-stack";

// One runtime per locale, cached - not rebuilt per request
const runtime = createAstroRuntime({
  ...ahaStackPreset({ locale, htmxHeaders: true }),
  components: [
    { id: "feedback-correct", loader: () => import("@fragments/FeedbackCorrect.astro") },
    { id: "feedback-incorrect", loader: () => import("@fragments/FeedbackIncorrect.astro") },
  ],
});

// Render feedback as an HTML fragment
const html = result.isCorrect
  ? await runtime.renderToString({
      componentId: "feedback-correct",
      props: { locale, nextUrl, isComplete, delayMs },
    })
  : await runtime.renderToString({
      componentId: "feedback-incorrect",
      props: { locale, correctAnswer, hint, nextUrl, isComplete },
    });

The Task System

The Math Box uses a modular task system with:

  • Unified interface for all task types
  • Self-validating tasks with hints
  • SVG visualizations for geometry and fractions
  • Multiple-choice and drag-and-drop support
  • Adaptive difficulty and error retry
// Unified Task Interface
interface TaskInstance {
  id: string;
  question: string;
  validate(answer: string): ValidationResult;
  getHint(): string;
  getCorrectAnswer(): string | number;
}

// Self-validating task
const result = task.validate(userAnswer);
if (!result.isCorrect) {
  console.log(result.hint);  // "Der kleine Zeiger zeigt die Stunde..."
}

Links

Back to practising