Skip to main content

UI Overview

True Life's UI system is built with React 19 and the React Compiler for automatic optimization, combined with the observable system for cross-runtime state management. It provides a modern, performant interface for in-game HUDs and pages.

Technology Stack

TechnologyVersionPurpose
React19UI framework
React CompilerLatestAutomatic memoization and optimization
Observable System-State management with cross-runtime sync
Tailwind CSS3.4Utility-first styling
shadcn/uiLatestComponent library (React)
Motion12.23Animations
Vite7.3Build tool

Architecture

Feature Types

HUDs

HUDs are small overlays positioned in a 3x3 grid:

HUDs are:

  • Always visible during gameplay (unless group is hidden)
  • Positioned via hudPosition property
  • Stacked by hudPriority within a position
  • Grouped via hudGroup for visibility control

Pages

Pages are full-screen interfaces:

  • Open/close via client events
  • Block game input when visible
  • Used for menus, inventories, etc.

Project Structure

ui/
├── src/
│   ├── main.tsx              # React app entry point
│   ├── modules/index.ts      # Feature discovery from MODULES
│   ├── feature.ts            # HudDefinition, PageDefinition, HUD groups
│   ├── shells/               # Layout containers
│   │   ├── HudShell/         # 3x3 grid HUD container
│   │   └── PageShell/        # Full-screen container
│   ├── components/           # Reusable components
│   │   └── ui/               # shadcn/ui components (React)
│   └── lib/                  # Utilities
│       ├── rpc.ts            # Web RPC (global.rpc for web)
│       └── telemetry/        # Web telemetry
├── vite.config.ts
└── tailwind.config.cjs

Development Server

Start the UI dev server:

pnpm dev:ui
# Runs at http://127.0.0.1:41524

The dev server provides:

  • Fast refresh for React components
  • Mock NUI events for testing
  • React DevTools support

Path Aliases

AliasPath
@ui/*./ui/src/*
@core/*./src/lib/*
@modules/*./src/modules/*

Key Concepts

Services and Observables

UI state is managed through services and webOwned observables:

// In a service
export class MyService {
	public hudState = webOwned<HudState>({
		id: "my:hud",
		initialValue: { data: null },
	});
}
 
// In a component
import { useService, useObservable } from "@core/react";
 
function MyComponent() {
	const myService = useService(MyService);
	const state = useObservable(myService.hudState);
 
	return <div>{state.data}</div>;
}

HUD Groups

Control visibility of HUD clusters:

import { setHudGroupVisible, isHudGroupVisible } from "@ui/feature";
 
// Hide all HUDs in the "default" group
setHudGroupVisible("default", false);
 
// Check visibility
if (isHudGroupVisible("default")) {
	// HUDs are visible
}

Best Practices

  1. Use webOwned for UI state - Not Redux, use observables
  2. Access services via useService - Dependency injection for consistency
  3. Use useObservable for reactivity - Auto-subscription and cleanup
  4. Use Tailwind utilities - Consistent styling
  5. Leverage shadcn/ui - Pre-built accessible components
  6. Add animations - CSS animations or Motion library
  7. Use HUD groups - For fullscreen overlays that need to hide HUDs
  8. Let React Compiler optimize - Avoid manual useMemo/useCallback unless necessary