1 Architecture
justinaquino edited this page 2026-02-02 21:40:49 +08:00

Architecture

Overview

Mneme World Generator (MWG) is a Progressive Web Application (PWA) built with React 19, TypeScript, and Vite 7. It generates fictional worlds for tabletop RPGs based on the Mneme World Generator rulebook.


Tech Stack

Layer Technology Description
Frontend Framework React 19 + TypeScript Component-based UI library with static typing
Build Tool Vite 7 Next-generation frontend build tool with hot module replacement
UI Components shadcn/ui (Radix UI primitives) Accessible, unstyled component primitives
Styling Tailwind CSS v4 Utility-first CSS framework
Routing React Router DOM v7 Declarative routing for React SPAs
Database IndexedDB via Dexie Client-side NoSQL database for offline storage
Icons Lucide React Open-source icon library

What These Technologies Do

React + TypeScript

React is a JavaScript library for building user interfaces using components—reusable, self-contained pieces of UI. Each component is a function that returns JSX (HTML-like syntax in JavaScript).

TypeScript adds static types to JavaScript, catching errors at compile-time rather than runtime. Types define the shape of data (e.g., "a star must have a name and a class").

Vite

Vite is a build tool that serves code during development with near-instant hot module replacement (HMR). When you save a file, changes appear in the browser immediately without a full page reload.

Tailwind CSS

Tailwind uses utility classes directly in HTML/JSX instead of writing CSS files. Example: className="text-xl font-bold text-blue-500" applies font size, weight, and color.


Project Structure

src/
├── assets/          # Static assets (images, fonts)
├── components/      # React components
│   ├── layout/      # Layout components (header, footer, nav)
│   ├── shared/      # Reusable components across pages
│   ├── stellar/     # Star/stellar-specific components
│   └── ui/          # Base UI components (shadcn/ui)
├── lib/             # Business logic and utilities
│   ├── db/          # Database layer (IndexedDB)
│   │   └── queries/ # Database query functions
│   ├── export/      # Export to JSON/other formats
│   ├── generators/  # World generation algorithms
│   ├── import/      # Import from external sources
│   └── stellar/     # Stellar calculations
├── models/          # TypeScript types and interfaces
│   ├── common/      # Shared types
│   ├── stellar/     # Star-related types
│   │   ├── data/    # Constants (spectral classes, etc.)
│   │   └── types/   # Type definitions and enums
│   └── world/       # World/planet types
├── pages/           # Route page components
├── App.tsx          # Root application component
├── routes.tsx       # Route definitions
├── main.tsx         # Application entry point
└── index.css        # Global styles

Pages (src/pages/)

What is a Page?

A page is a React component that represents an entire screen in the application. Pages map 1:1 with URL routes—when you navigate to /create-primary-star, the CreatePrimaryStar page component renders.

Pages are composed of smaller components and connect to business logic (generators, database queries).

How Pages Work

  1. Route Definition: Routes are defined in routes.tsx using React Router
  2. Component Rendering: When a URL matches, React Router renders the corresponding page component
  3. State Management: Pages use React hooks (useState, useEffect, useCallback) to manage local state
  4. Data Flow: Pages call functions from lib/ to generate data and save to the database

Page Components

Page Route Purpose
Home.tsx / Landing page with navigation to create or open worlds
CreateNew.tsx /create-new Start new world creation wizard
CreatePrimaryStar.tsx /create-primary-star Configure the system's primary star
CreateCompanionStar.tsx /create-companion-star Add companion stars to the system
CreateWorldContext.tsx /create-world-context Set world context and parameters
CreateCircumstellarDisks.tsx /create-disks Generate asteroid belts and debris disks
CreatePlanetarySystem.tsx /create-planetary-system Generate planets in the system
CreateMainWorld.tsx /create-main-world Configure the primary habitable world
CreateSecondaryPlanets.tsx /create-secondary-planets Add additional planets
CreateMoons.tsx /create-moons Generate moons for planets
CreateHabitability.tsx /create-habitability Calculate world habitability
CreateInhabitants.tsx /create-inhabitants Define world population
CreateWorldCulture.tsx /create-culture Generate cultural attributes
CreateWorldStarport.tsx /create-starport Generate starport facilities
CreatePosition.tsx /create-position Set galactic position
MyWorlds.tsx /my-worlds View and manage saved worlds
QuickGenerate.tsx /quick-generate One-click full world generation

Anatomy of a Page Component

Using CreatePrimaryStar.tsx as an example:

export function CreatePrimaryStar() {
  // 1. HOOKS - React state and effects
  const navigate = useNavigate();                    // Router navigation
  const [starName, setStarName] = useState("");      // Local state
  const [selectedClass, setSelectedClass] = useState("G");

  // 2. DATABASE QUERIES - Reactive data from IndexedDB
  const stellarProperty = useLiveQuery(
    () => getStellarProperty(selectedClass, classGrade),
    [selectedClass, classGrade]
  );

  // 3. DERIVED DATA - Computed from state/queries
  const starData = useMemo(() => ({
    color: stellarProperty?.color,
    mass: stellarProperty?.mass,
  }), [stellarProperty]);

  // 4. EVENT HANDLERS - User interactions
  const handleRandom = useCallback(() => {
    // Call generator, update state
  }, []);

  // 5. EFFECTS - Side effects (save to localStorage, etc.)
  useEffect(() => {
    saveData();
  }, [saveData]);

  // 6. RENDER - Return JSX
  return (
    <div>
      <StarNameEditor name={starName} onNameChange={setStarName} />
      <StarClassSelector selectedClass={selectedClass} />
    </div>
  );
}

Key React Concepts Used

Concept Description Reference
useState Store and update component state React useState
useEffect Perform side effects (API calls, subscriptions) React useEffect
useCallback Memoize functions to prevent unnecessary re-renders React useCallback
useMemo Memoize computed values React useMemo
useNavigate Programmatic navigation React Router useNavigate
useLiveQuery Reactive database queries (Dexie) Dexie useLiveQuery

Components (src/components/)

What is a Component?

A React component is a reusable piece of UI. Components accept props (inputs) and return JSX (what to render). They follow a hierarchy: pages contain components, which contain smaller components.

Component Organization

ui/ - Base UI Components (shadcn/ui)

Atomic, unstyled components from shadcn/ui. These are the building blocks:

Component Purpose Radix Primitive
button.tsx Clickable buttons N/A
input.tsx Text input fields N/A
select.tsx Dropdown selection Radix Select
dialog.tsx Modal dialogs Radix Dialog
dropdown-menu.tsx Context menus Radix DropdownMenu
tooltip.tsx Hover tooltips Radix Tooltip
slider.tsx Range input slider Radix Slider
checkbox.tsx Boolean checkbox Radix Checkbox
radio-group.tsx Single-select options Radix RadioGroup
card.tsx Content container N/A
badge.tsx Status indicators N/A
alert.tsx Notification messages N/A
skeleton.tsx Loading placeholders N/A
sheet.tsx Slide-out panels Radix Dialog
collapsible.tsx Expandable sections Radix Collapsible
separator.tsx Visual dividers Radix Separator
label.tsx Form field labels Radix Label
navigation-menu.tsx Site navigation Radix NavigationMenu

layout/ - Layout Components

Structural components that define page layouts (headers, footers, navigation, sidebars).

shared/ - Shared Components

Reusable components used across multiple pages (e.g., loading spinners, error boundaries).

stellar/ - Domain Components

Star/stellar-specific components like:

  • StarNameEditor - Edit star names
  • StarClassSelector - Select stellar classification (O, B, A, F, G, K, M)
  • GradeControl - Adjust stellar grade (0-9)
  • StellarPropertiesCard - Display star properties (mass, luminosity, temperature)

Business Logic (src/lib/)

What is the lib/ Directory?

The lib/ directory contains business logic—code that implements the application's rules and algorithms, separate from UI rendering. This separation follows the separation of concerns principle.

Generators (lib/generators/)

Generators implement the Mneme world generation rules using dice-based procedural generation.

Generator Purpose
primaryStarGenerator.ts Generate primary star (class, grade, properties)
companionStarGenerator.ts Generate companion/binary stars
companionStarTables.ts Lookup tables for companion star generation
brownDwarfGenerator.ts Generate brown dwarf objects
brownDwarfTables.ts Brown dwarf lookup tables
diskGenerator.ts Generate circumstellar disks (asteroid belts)
diskTables.ts Disk generation tables
planetGenerator.ts Generate planets
moonGenerator.ts Generate moons
worldGenerator.ts Generate world characteristics
worldTables.ts World generation lookup tables
starportGenerator.ts Generate starport class and facilities
cultureGenerator.ts Generate cultural attributes

How Generators Work

Generators use dice rolls mapped to lookup tables to produce results. Example from primaryStarGenerator.ts:

// 1. Define lookup table mapping dice rolls to results
const STELLAR_CLASS_TABLE = [
  { minRoll: 5, maxRoll: 7, class: 'O' },   // Hottest, rarest
  { minRoll: 8, maxRoll: 10, class: 'B' },
  { minRoll: 11, maxRoll: 13, class: 'A' },
  { minRoll: 14, maxRoll: 17, class: 'F' },
  { minRoll: 18, maxRoll: 22, class: 'G' }, // Sun-like
  { minRoll: 23, maxRoll: 26, class: 'K' },
  { minRoll: 27, maxRoll: 30, class: 'M' }, // Coolest
];

// 2. Roll dice (5D6 = five six-sided dice)
export function rollForStellarClass() {
  const roll = roll5D6();  // Returns { total: number, dice: number[] }

  // 3. Look up result in table
  const entry = STELLAR_CLASS_TABLE.find(
    (e) => roll.total >= e.minRoll && roll.total <= e.maxRoll
  );

  return { class: entry.class, roll };
}

Database (lib/db/)

Uses Dexie, a wrapper around IndexedDB, for client-side persistence. IndexedDB is a NoSQL database built into browsers, enabling offline storage.

queries/ - Database Query Functions

Functions to read/write data:

  • stellarQueries.ts - Query stellar properties by class/grade
  • starQueries.ts - CRUD operations for stars

Stellar Calculations (lib/stellar/)

Astronomical calculations:

  • zoneCalculations.ts - Calculate habitable zones, frost lines based on stellar luminosity

Export/Import (lib/export/, lib/import/)

Data interchange functionality:

  • Export worlds to JSON for sharing/backup
  • Import worlds from JSON files

Data Models (src/models/)

What are Models?

Models are TypeScript interfaces that define the shape of data. They ensure type safety—the compiler verifies that data matches expected structures.

Model Organization

common/ - Shared Types

// Example: Generation method enum
enum GenerationMethod {
  PROCEDURAL = 'procedural',  // Dice-based random generation
  CUSTOM = 'custom',          // User-specified values
}

stellar/types/ - Star Types

// Example: Star data interface
interface StarData {
  id: string;
  name: string;
  stellarClass: StellarClass;    // O, B, A, F, G, K, M
  stellarGrade: StellarGrade;    // 0-9
  generationMethod: GenerationMethod;
  diceRolls?: StarDiceRolls;
  createdAt: string;
  updatedAt: string;
}

// Stellar class enum
type StellarClass = 'O' | 'B' | 'A' | 'F' | 'G' | 'K' | 'M';

// Stellar grade (0 = brightest, 9 = dimmest)
type StellarGrade = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

stellar/data/ - Constants

Static data like spectral class properties, temperature ranges, mass/luminosity values.

world/ - World Types

// Example: Planet, moon, culture, starport interfaces
interface Planet { ... }
interface Moon { ... }
interface Culture { ... }
interface Starport { ... }

Data Flow

┌─────────────────────────────────────────────────────────────────┐
│                        USER INTERACTION                         │
│                    (click, type, press 'R')                     │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      PAGE COMPONENT                             │
│              (CreatePrimaryStar.tsx)                            │
│                                                                 │
│  • Captures user input via event handlers                       │
│  • Manages local state with useState                            │
│  • Calls generators for procedural creation                     │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                        GENERATOR                                │
│              (lib/generators/primaryStarGenerator.ts)           │
│                                                                 │
│  • Rolls dice (5D6)                                             │
│  • Looks up results in tables                                   │
│  • Returns typed data object                                    │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                         MODEL                                   │
│              (models/stellar/types/interface.ts)                │
│                                                                 │
│  • TypeScript validates data shape                              │
│  • Ensures type safety at compile time                          │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                        DATABASE                                 │
│              (lib/db/ via Dexie/IndexedDB)                      │
│                                                                 │
│  • Persists data to browser storage                             │
│  • Enables offline access                                       │
│  • useLiveQuery provides reactive updates                       │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                       UI UPDATE                                 │
│              (React re-renders components)                      │
│                                                                 │
│  • State changes trigger re-render                              │
│  • useLiveQuery updates when DB changes                         │
│  • User sees updated UI                                         │
└─────────────────────────────────────────────────────────────────┘

PWA Features

A Progressive Web App provides native app-like experiences on the web:

Feature Implementation Benefit
Offline Support Service Worker + IndexedDB Works without internet
Installable Web App Manifest Add to home screen
Local Storage IndexedDB via Dexie Data persists across sessions
Export/Import JSON file download/upload Data portability and backup

External References

Core Technologies

UI Components

  • shadcn/ui - Component library used in this project
  • Radix UI - Underlying accessible primitives

Database

React Concepts

General Web Development