Skip to main content

Brutalist Design Philosophy

Off Grid uses a terminal-inspired brutalist design system with full light/dark theme support. The system emphasizes:
  • Information density over decoration
  • Functional minimalism with zero ornamental UI
  • Monochromatic palette with emerald accent
  • Monospace typography (Menlo) throughout
  • Crisp borders and geometric layouts
The design philosophy prioritizes clarity and function — no gradients, no rounded corners on interactive elements, and no visual hierarchy tricks that don’t serve the user’s immediate goal.

Theme System

Dynamic light/dark theming via src/theme/:

Core Files

  • palettes.ts — COLORS_LIGHT, COLORS_DARK, SHADOWS_LIGHT, SHADOWS_DARK, createElevation()
  • index.ts — useTheme() hook, getTheme(mode), Theme type
  • useThemedStyles.ts — useThemedStyles(createStyles) memoized style factory

Usage Pattern

Every screen and component follows this pattern:

Theme Toggle

Theme mode is stored in appStore.themeMode (persisted) and toggled via the Settings screen Dark Mode switch.

Token Organization

  • Theme-independent tokens stay in src/constants/: TYPOGRAPHY, SPACING, FONTS
  • Dynamic tokens come from hooks: colors.*, shadows.*

Color Palettes

Light Palette

Dark Palette


Shadows & Elevation

Light Shadows

Uses CSS boxShadow (RN 0.76+ with New Architecture) for cross-platform shadow rendering:

Dark Shadows

Crisp white glow for depth in dark mode:

Elevation Factory

The createElevation() function generates 5 elevation levels with appropriate backgrounds, borders, and blur effects:

Typography Scale

10-level scale, all Menlo monospace:

Usage Guidelines

  • h1 — Hero text only (24px, light weight)
  • h2 — Screen titles (16px)
  • h3 — Section headers (13px)
  • body — Primary content (14px)
  • bodySmall — Descriptions (13px)
  • label — Uppercase labels (10px)
  • meta — Timestamps, metadata (10px, lighter weight)

Spacing Scale

6-step scale for consistent whitespace:

Animation System

Powered by react-native-reanimated with spring-based physics and react-native-haptic-feedback.

AnimatedEntry

Staggered fade + slide entrance for lists and grids. Respects useReducedMotion(). Source: src/components/AnimatedEntry.tsx
Props:
  • index — Item index in list (for stagger calculation)
  • delay — Manual delay override (ms)
  • staggerMs — Delay per item (default: 30ms)
  • maxItems — Max items to animate (default: 10)
  • from — Initial style (default: { opacity: 0, translateY: 12 })
  • animate — Target style (default: { opacity: 1, translateY: 0 })
  • transition — Timing config (default: { duration: 300 })
  • trigger — Change this value to replay animation
Automatically skips animation if index >= maxItems to prevent performance issues in long lists.

AnimatedPressable

Spring scale-down on press with haptic feedback. Source: src/components/AnimatedPressable.tsx
Props:
  • scaleValue — Scale on press (default: 0.97)
  • hapticType — 'selection' | 'impactLight' | 'impactMedium' | 'impactHeavy' | 'notificationSuccess' | 'notificationWarning' | 'notificationError'
  • disabled — Disable interaction
  • Standard TouchableOpacity props

AppSheet

Custom swipe-to-dismiss bottom sheet with spring animation, replacing React Native modals. Source: src/components/AppSheet.tsx

useFocusTrigger

Hook that replays stagger animations on every tab focus.

Global Animation Behavior

  • Tab transitions — Fade animations + haptic feedback on bottom tab switches
  • Modal screens — slide_from_bottom animation for all modal presentations
  • Reduced motion — All animations automatically disabled when user has system-level reduced motion enabled

Design Tokens Reference

Quick Import

File Locations


Example Component

Complete example showing all design tokens in use: