Skip to content

vava-nessa/weirdstats

Repository files navigation

🌍 WeirdStats - World Statistics Dashboard

A real-time world statistics simulation dashboard built with Next.js, displaying global events like births, deaths, social events, and physiological data updated every 100ms.

✨ Features

  • Real-time Updates: Statistics refresh every 100ms with smooth transitions
  • 🎬 Animated Numbers: Smooth spring-physics animations for all counters (configurable)
  • Two Types of Statistics:
    • Cumulative Stats: Events that accumulate over your session (deaths, births, injuries, marriages, etc.)
    • Snapshot Stats: Real-time distribution by continent (people at home, at work, in transit, unemployed)
  • Session Timer: Track how long you've been viewing the statistics
  • Responsive Design: Mobile-first approach with horizontal scroll for wide tables
  • Type-Safe: Full TypeScript implementation with no any types
  • Number Formatting: Smart formatting (1.5K, 2.3M) with tabular numbers for stability
  • Color-Coded Categories: Visual distinction between death, birth, social, and physiological events

πŸš€ Tech Stack

πŸ“¦ Installation

Prerequisites

  • Node.js 18+
  • npm or yarn

Getting Started

  1. Clone the repository

    git clone https://github.com/vavanesssa/weirdstats.git
    cd weirdstats
  2. Install dependencies

    npm install
  3. Run the development server

    npm run dev
  4. Open your browser Navigate to http://localhost:3000

Building for Production

npm run build
npm run start

Linting and Formatting

npm run lint
npm run format

πŸ“ Project Structure

weirdstats/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/                      # Next.js App Router
β”‚   β”‚   β”œβ”€β”€ layout.tsx           # Root layout with metadata
β”‚   β”‚   β”œβ”€β”€ page.tsx             # Main dashboard page
β”‚   β”‚   β”œβ”€β”€ providers.tsx        # TanStack Query provider
β”‚   β”‚   └── globals.css          # Global styles
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ stats/               # Statistics components
β”‚   β”‚   β”‚   β”œβ”€β”€ CumulativeStatsTable.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ SnapshotStatsTable.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ PopulationCounter.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ SessionTimer.tsx
β”‚   β”‚   β”‚   └── StatRow.tsx
β”‚   β”‚   β”œβ”€β”€ ui/                  # Base UI components
β”‚   β”‚   β”‚   β”œβ”€β”€ AnimatedNumber.tsx  # 🎬 Animated counter component
β”‚   β”‚   β”‚   β”œβ”€β”€ Table.tsx
β”‚   β”‚   β”‚   └── Card.tsx
β”‚   β”‚   └── layout/              # Layout components
β”‚   β”‚       └── StatsLayout.tsx
β”‚   β”œβ”€β”€ hooks/                   # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ useStats.ts          # Main stats aggregator
β”‚   β”‚   β”œβ”€β”€ useCumulativeStats.ts
β”‚   β”‚   β”œβ”€β”€ useSnapshotStats.ts
β”‚   β”‚   └── useSessionTimer.ts
β”‚   β”œβ”€β”€ lib/                     # Utility functions
β”‚   β”‚   β”œβ”€β”€ animationConfig.ts   # πŸŽ›οΈ Animation settings & presets
β”‚   β”‚   β”œβ”€β”€ constants.ts         # Rates, regions, pool volume
β”‚   β”‚   β”œβ”€β”€ calculations.ts      # Stat calculation logic
β”‚   β”‚   └── formatters.ts        # Number formatting
β”‚   └── types/
β”‚       └── stats.ts             # TypeScript interfaces
β”œβ”€β”€ package.json
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ tailwind.config.ts
β”œβ”€β”€ next.config.js
└── README.md

πŸ—οΈ Architecture Decisions

State Management with useMemo

Statistics are calculated using useMemo hooks that recompute when elapsed time changes:

  • No external API calls - all data is derived from rates and elapsed time
  • Smooth updates - timer ticks every 100ms, memoized calculations prevent unnecessary re-renders
  • Type-safe - full TypeScript interfaces for all data structures

Component Design Philosophy

  • Separation of Concerns: Business logic in lib/, presentation in components/
  • Composition over Configuration: Small, focused components that compose together
  • Type Safety: Strict TypeScript with proper interfaces for all data structures
  • Reusability: Generic UI components (Card, Table, AnimatedNumber) used throughout

🎬 AnimatedNumber Component

A reusable animated number component that smoothly transitions between values using spring physics.

Location

  • Component: src/components/ui/AnimatedNumber.tsx
  • Configuration: src/lib/animationConfig.ts

Basic Usage

import { AnimatedNumber } from '@/components/ui/AnimatedNumber'

// Simple usage
<AnimatedNumber to={1500} />

// With formatting
<AnimatedNumber to={1500000} separator="," useCompactNotation={true} />

Props Reference

Property Type Default Description
to number required The target number to animate to
from number 0 Initial number (only on mount)
direction "up" | "down" "up" Direction of count
delay number 0 Delay before animation starts (seconds)
duration number 0.5 Animation duration factor
className string "" CSS class for styling
startWhen boolean true Control when animation starts
separator string " " Thousands separator ( French, , US)
useCompactNotation boolean true Use K/M suffixes
compactDecimals number 1 Decimals for K/M notation
compactThresholdK number 1000 Threshold for K suffix
compactThresholdM number 1000000 Threshold for M suffix
damping number 60 Spring damping (10-100)
stiffness number 100 Spring stiffness (50-500)
mass number 1 Spring mass (0.1-10)
onStart () => void β€” Callback when animation starts
onEnd () => void β€” Callback when animation ends

Animation Presets

Ready-to-use animation presets in src/lib/animationConfig.ts:

import { ANIMATION_PRESETS } from '@/lib/animationConfig'

// Balanced default
<AnimatedNumber to={100} {...ANIMATION_PRESETS.default} />

// Fast, snappy (good for rapid updates)
<AnimatedNumber to={100} {...ANIMATION_PRESETS.snappy} />

// Smooth, fluid (good for large changes)
<AnimatedNumber to={100} {...ANIMATION_PRESETS.smooth} />

// Bouncy, playful (good for celebrations)
<AnimatedNumber to={100} {...ANIMATION_PRESETS.bouncy} />

// Instant, no animation
<AnimatedNumber to={100} {...ANIMATION_PRESETS.instant} />

Customizing Global Defaults

Edit src/lib/animationConfig.ts to change defaults for all AnimatedNumber instances:

// ─── src/lib/animationConfig.ts ───────────────────────────────

export const DEFAULT_ANIMATION_CONFIG: AnimationConfig = {
  // ─── Timing ──────────────────────────────────────────────
  duration: 0.5,      // Animation duration (seconds)
  delay: 0,           // Delay before start (seconds)

  // ─── Spring Physics ──────────────────────────────────────
  damping: 60,        // Higher = less bouncy (10-100)
  stiffness: 100,     // Higher = faster snap (50-500)
  mass: 1,            // Higher = more inertia (0.1-10)

  // ─── Formatting ──────────────────────────────────────────
  separator: ' ',           // Thousands separator
  useCompactNotation: true, // Show 1.5K, 1.5M
  compactDecimals: 1,       // Decimal places for K/M
  compactThresholdK: 1000,  // When to use K
  compactThresholdM: 1000000, // When to use M
}

Spring Physics Explained

The animation uses Framer Motion's spring physics:

Parameter Low Value High Value
damping More oscillation/bounce Smooth, controlled
stiffness Slow, fluid Fast, snappy
mass Light, responsive Heavy, more inertia

Recommended combinations:

  • Real-time stats: damping: 80, stiffness: 200 (snappy preset)
  • Large counters: damping: 40, stiffness: 60 (smooth preset)
  • Gamification: damping: 15, stiffness: 80 (bouncy preset)

  • All statistics have proper TypeScript interfaces
  • No any types allowed (enforced by ESLint)
  • Utility functions have JSDoc comments with examples
  • Type inference used where appropriate to reduce boilerplate

πŸ“Š Statistics Explained

Cumulative Stats (Incremental)

These statistics accumulate over time since you loaded the page:

  • Deaths: Broken down by cause (murder, suicide, tobacco, hunger, road accidents, other)
  • Births: Total births worldwide
  • Net Growth: Births minus deaths
  • Injuries: Broken legs and arms
  • Social Events: Marriages, divorces, abandonments, adoptions
  • Physiological: Poop, pee, sneezes, water consumption (in liters)
  • Pool Equivalents: Olympic pools filled with waste products

Snapshot Stats (Real-time Distribution)

These statistics show the current state based on time of day in each region:

  • At Home: People currently at home
  • At Work: People currently at work (based on work hours 9am-6pm)
  • In Transit: People commuting (7-9am, 6-8pm)
  • Unemployed: Based on regional unemployment rates

How Calculations Work

  1. Session Timer: Tracks elapsed time in seconds
  2. Rate Application: Each event has a rate per second (e.g., 4.43 births/second)
  3. Cumulative Calculation: event_count = rate Γ— elapsed_seconds
  4. Population Updates: current_population = base_population + net_growth
  5. Regional Distribution: Based on time zones and work/home patterns

Data Sources

⚠️ Note: All statistics are simulated based on approximate global rates. This is an educational visualization, not a source of precise real-world data.

Rates are derived from:

  • WHO mortality data
  • UN birth rate statistics
  • International labor statistics
  • Approximate physiological averages

🎨 Styling

The design follows a clean, minimal aesthetic:

  • Color Coding:

    • Deaths: Red (red-50/red-700)
    • Births: Green (green-50/green-700)
    • Growth: Blue (blue-50/blue-600)
    • Injuries: Orange (orange-50/orange-700)
    • Social: Amber (amber-50/amber-700)
    • Physiological: Purple (purple-50/purple-700)
    • Pools: Cyan (cyan-50/cyan-800)
  • Typography:

    • Tabular numbers for stable display
    • Inter font family
    • Responsive font sizes

🌐 Internationalization

Currently in French with structure ready for i18n:

  • All labels could be extracted to locale files
  • Number formatting supports different locales
  • Date/time formatting is locale-aware

🀝 Contributing

Contributions are welcome! Here's how:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Code Quality Guidelines

  • Follow the existing code style (Prettier configuration)
  • Write TypeScript with proper types (no any)
  • Add JSDoc comments for utility functions
  • Keep components small and focused
  • Extract magic numbers to constants
  • Test your changes thoroughly

πŸ“„ License

MIT License - see LICENSE file for details

πŸ™ Acknowledgments

  • Inspired by real-world statistics dashboards
  • Built with modern React and Next.js patterns
  • Powered by the TanStack ecosystem

Made with ❀️ for understanding our world through data

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published