diff --git a/apps/figgos/apps/mobile/app.json b/apps/figgos/apps/mobile/app.json
index b13ce9593..888d972f7 100644
--- a/apps/figgos/apps/mobile/app.json
+++ b/apps/figgos/apps/mobile/app.json
@@ -6,7 +6,7 @@
"scheme": "figgos",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
- "userInterfaceStyle": "automatic",
+ "userInterfaceStyle": "dark",
"newArchEnabled": true,
"splash": {
"image": "./assets/images/splash-icon.png",
diff --git a/apps/figgos/apps/mobile/app/(auth)/_layout.tsx b/apps/figgos/apps/mobile/app/(auth)/_layout.tsx
deleted file mode 100644
index 819279f22..000000000
--- a/apps/figgos/apps/mobile/app/(auth)/_layout.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Stack } from 'expo-router';
-
-export default function AuthLayout() {
- return (
-
-
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/(auth)/login.tsx b/apps/figgos/apps/mobile/app/(auth)/login.tsx
deleted file mode 100644
index 759c75fa3..000000000
--- a/apps/figgos/apps/mobile/app/(auth)/login.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useState } from 'react';
-import { View, Text, TextInput, Pressable, KeyboardAvoidingView, Platform } from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-import { useAuth } from '~/contexts/AuthContext';
-
-export default function LoginScreen() {
- const { signIn } = useAuth();
- const [email, setEmail] = useState('');
- const [password, setPassword] = useState('');
- const [error, setError] = useState(null);
- const [loading, setLoading] = useState(false);
-
- const handleLogin = async () => {
- if (!email || !password) {
- setError('Please enter email and password');
- return;
- }
-
- setLoading(true);
- setError(null);
-
- const result = await signIn(email, password);
-
- if (result.error) {
- setError(result.error.message || 'Login failed');
- }
-
- setLoading(false);
- };
-
- return (
-
-
-
- Figgos
- Collect your action figures
-
-
-
-
-
-
-
- {error && {error}}
-
-
-
- {loading ? 'Signing in...' : 'Sign In'}
-
-
-
-
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/(tabs)/_layout.tsx b/apps/figgos/apps/mobile/app/(tabs)/_layout.tsx
deleted file mode 100644
index 7275f38bf..000000000
--- a/apps/figgos/apps/mobile/app/(tabs)/_layout.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Tabs } from 'expo-router';
-import { Ionicons } from '@expo/vector-icons';
-
-export default function TabLayout() {
- return (
-
- (
-
- ),
- }}
- />
- (
-
- ),
- }}
- />
- (
-
- ),
- }}
- />
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/(tabs)/create.tsx b/apps/figgos/apps/mobile/app/(tabs)/create.tsx
deleted file mode 100644
index a9ea88e82..000000000
--- a/apps/figgos/apps/mobile/app/(tabs)/create.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import { useState } from 'react';
-import {
- View,
- Text,
- TextInput,
- Pressable,
- ScrollView,
- KeyboardAvoidingView,
- Platform,
- ActivityIndicator,
-} from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-import { api } from '~/services/api';
-import type { FigureResponse, FigureRarity } from '@figgos/shared';
-
-const RARITY_STYLES: Record = {
- common: { bg: 'bg-rarity-common', text: 'text-rarity-common-foreground' },
- rare: { bg: 'bg-rarity-rare', text: 'text-rarity-rare-foreground' },
- epic: { bg: 'bg-rarity-epic', text: 'text-rarity-epic-foreground' },
- legendary: { bg: 'bg-rarity-legendary', text: 'text-rarity-legendary-foreground' },
-};
-
-function RarityBadge({ rarity }: { rarity: FigureRarity }) {
- const s = RARITY_STYLES[rarity];
- return (
-
- {rarity}
-
- );
-}
-
-export default function CreateScreen() {
- const [name, setName] = useState('');
- const [description, setDescription] = useState('');
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState(null);
- const [result, setResult] = useState(null);
-
- const handleGenerate = async () => {
- if (!name.trim() || !description.trim()) {
- setError('Please enter a name and description');
- return;
- }
- setLoading(true);
- setError(null);
- try {
- const { figure } = await api.figures.create(name.trim(), description.trim());
- setResult(figure);
- } catch (e: any) {
- setError(e.message || 'Failed to create figure');
- } finally {
- setLoading(false);
- }
- };
-
- const handleReset = () => {
- setName('');
- setDescription('');
- setResult(null);
- setError(null);
- };
-
- if (result) {
- return (
-
-
-
-
- ðŸŽ
-
- {result.name}
-
- {result.userInput.description}
-
-
-
-
-
-
-
-
- Create Another
-
-
-
-
- );
- }
-
- return (
-
-
-
- Create a Figure
-
- Describe your character and we'll generate a collectible figure.
-
-
- Name
-
-
- Description
-
-
- {error && {error}}
-
-
- {loading ? (
-
-
- Generating...
-
- ) : (
-
- Generate Figure
-
- )}
-
-
-
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/(tabs)/index.tsx b/apps/figgos/apps/mobile/app/(tabs)/index.tsx
deleted file mode 100644
index 9ff76af4a..000000000
--- a/apps/figgos/apps/mobile/app/(tabs)/index.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { View, Text } from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-
-export default function CommunityScreen() {
- return (
-
-
- Community
-
- Public figures from the community will appear here.
-
-
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/(tabs)/shelf.tsx b/apps/figgos/apps/mobile/app/(tabs)/shelf.tsx
deleted file mode 100644
index 5d672bbc5..000000000
--- a/apps/figgos/apps/mobile/app/(tabs)/shelf.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { useState, useEffect, useCallback } from 'react';
-import { View, Text, FlatList, ActivityIndicator } from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-import { api } from '~/services/api';
-import type { FigureResponse, FigureRarity } from '@figgos/shared';
-
-const RARITY_STYLES: Record = {
- common: { bg: 'bg-rarity-common', text: 'text-rarity-common-foreground' },
- rare: { bg: 'bg-rarity-rare', text: 'text-rarity-rare-foreground' },
- epic: { bg: 'bg-rarity-epic', text: 'text-rarity-epic-foreground' },
- legendary: { bg: 'bg-rarity-legendary', text: 'text-rarity-legendary-foreground' },
-};
-
-function RarityBadge({ rarity }: { rarity: FigureRarity }) {
- const s = RARITY_STYLES[rarity];
- return (
-
- {rarity}
-
- );
-}
-
-function FigureCard({ figure }: { figure: FigureResponse }) {
- return (
-
-
- ðŸŽ
-
-
- {figure.name}
-
-
-
-
-
- );
-}
-
-export default function ShelfScreen() {
- const [figures, setFigures] = useState([]);
- const [loading, setLoading] = useState(true);
- const [refreshing, setRefreshing] = useState(false);
-
- const loadFigures = useCallback(async () => {
- try {
- const { figures: data } = await api.figures.list();
- setFigures(data);
- } catch (e) {
- console.error('Failed to load figures:', e);
- } finally {
- setLoading(false);
- setRefreshing(false);
- }
- }, []);
-
- useEffect(() => {
- loadFigures();
- }, [loadFigures]);
-
- const handleRefresh = () => {
- setRefreshing(true);
- loadFigures();
- };
-
- if (loading) {
- return (
-
-
-
- );
- }
-
- return (
-
- item.id}
- numColumns={2}
- contentContainerStyle={{ padding: 12 }}
- renderItem={({ item }) => }
- onRefresh={handleRefresh}
- refreshing={refreshing}
- ListEmptyComponent={
-
- 📦
- No figures yet
-
- Head to the Create tab to generate your first figure!
-
-
- }
- />
-
- );
-}
diff --git a/apps/figgos/apps/mobile/app/+not-found.tsx b/apps/figgos/apps/mobile/app/+not-found.tsx
deleted file mode 100644
index 25e0660e1..000000000
--- a/apps/figgos/apps/mobile/app/+not-found.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { View, Text } from 'react-native';
-import { Link, Stack } from 'expo-router';
-
-export default function NotFoundScreen() {
- return (
- <>
-
-
- Page not found
-
- Go to home
-
-
- >
- );
-}
diff --git a/apps/figgos/apps/mobile/app/_layout.tsx b/apps/figgos/apps/mobile/app/_layout.tsx
index 9ea1a4251..8c1ae6f97 100644
--- a/apps/figgos/apps/mobile/app/_layout.tsx
+++ b/apps/figgos/apps/mobile/app/_layout.tsx
@@ -1,14 +1,20 @@
import '../global.css';
-import { Stack } from 'expo-router';
-import { GestureHandlerRootView } from 'react-native-gesture-handler';
+import { NativeTabs, Icon, Label } from 'expo-router/unstable-native-tabs';
-export default function RootLayout() {
+export default function TabLayout() {
return (
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/apps/figgos/apps/mobile/app/collection.tsx b/apps/figgos/apps/mobile/app/collection.tsx
new file mode 100644
index 000000000..3d93a9f81
--- /dev/null
+++ b/apps/figgos/apps/mobile/app/collection.tsx
@@ -0,0 +1,46 @@
+import { View, Text } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+export default function CollectionScreen() {
+ return (
+
+
+ {/* Empty state card */}
+
+
+
+
+ 📦
+
+
+ No figures yet
+
+
+ Create your first Figgo{'\n'}to start your collection.
+
+
+
+
+
+ );
+}
diff --git a/apps/figgos/apps/mobile/app/index.tsx b/apps/figgos/apps/mobile/app/index.tsx
new file mode 100644
index 000000000..974bd8006
--- /dev/null
+++ b/apps/figgos/apps/mobile/app/index.tsx
@@ -0,0 +1,412 @@
+import { useState } from 'react';
+import {
+ View,
+ Text,
+ TextInput,
+ Pressable,
+ ScrollView,
+ KeyboardAvoidingView,
+ Platform,
+ ActivityIndicator,
+} from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import type { FigureResponse, FigureRarity } from '@figgos/shared';
+
+// ── Rarity ──
+
+const RARITY_SHADOW: Record = {
+ common: 'rgb(80, 90, 100)',
+ rare: 'rgb(60, 120, 180)',
+ epic: 'rgb(120, 80, 180)',
+ legendary: 'rgb(180, 130, 20)',
+};
+
+function RarityBadge({ rarity }: { rarity: FigureRarity }) {
+ const shadowColor = RARITY_SHADOW[rarity];
+ const bgClass = `bg-rarity-${rarity}`;
+ const fgClass = `text-rarity-${rarity}-foreground`;
+ return (
+
+
+
+
+ {rarity}
+
+
+
+ );
+}
+
+// ── Screen ──
+
+export default function CreateScreen() {
+ const [name, setName] = useState('');
+ const [description, setDescription] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [result, setResult] = useState(null);
+
+ const handleGenerate = async () => {
+ if (!name.trim() || !description.trim()) {
+ setError('Give your figure a name and a story');
+ return;
+ }
+ setLoading(true);
+ setError(null);
+ try {
+ await new Promise((r) => setTimeout(r, 1500));
+ const rarities: FigureRarity[] = [
+ 'common',
+ 'common',
+ 'common',
+ 'rare',
+ 'rare',
+ 'epic',
+ 'legendary',
+ ];
+ setResult({
+ id: 'mock-id',
+ userId: 'mock-user',
+ name: name.trim(),
+ userInput: { description: description.trim() },
+ imageUrl: null,
+ rarity: rarities[Math.floor(Math.random() * rarities.length)],
+ isPublic: false,
+ isArchived: false,
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ });
+ } catch (e: any) {
+ setError(e.message || 'Something went wrong');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleReset = () => {
+ setName('');
+ setDescription('');
+ setResult(null);
+ setError(null);
+ };
+
+ // ── Result ──
+ if (result) {
+ return (
+
+
+
+ {/* Badge */}
+
+
+ Unboxing
+
+
+
+ {/* Figure Card */}
+
+
+
+ {/* Image */}
+
+
+ Image coming soon
+
+
+
+
+ {result.name}
+
+
+ {result.userInput.description}
+
+
+
+
+
+
+
+
+ {/* Create Another */}
+
+
+
+
+
+
+ Create Another
+
+
+
+
+
+
+
+
+ );
+ }
+
+ // ── Create ──
+ return (
+
+
+
+ {/* Header */}
+
+
+
+ New Drop
+
+
+
+ CREATE YOUR{'\n'}FIGGO
+
+
+
+ {/* Form */}
+
+ {/* Name */}
+
+ Name
+
+
+
+
+
+
+ {/* Story */}
+
+ Story
+
+
+
+
+
+
+ {/* Error */}
+ {error && (
+
+
+ {error}
+
+
+ )}
+
+ {/* Generate Button */}
+
+
+
+
+ {loading ? (
+
+
+
+ Rolling...
+
+
+ ) : (
+
+ Generate Figgo
+
+ )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/figgos/apps/mobile/app/neo-brutalist.tsx b/apps/figgos/apps/mobile/app/neo-brutalist.tsx
new file mode 100644
index 000000000..e326f4a9d
--- /dev/null
+++ b/apps/figgos/apps/mobile/app/neo-brutalist.tsx
@@ -0,0 +1,189 @@
+import { View, Text, TextInput, Pressable, ScrollView } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+const C = {
+ bg: '#0f0f1e',
+ card: '#1a1a35',
+ border: '#ffcc00',
+ borderDark: '#b38f00',
+ accent: '#ff3366',
+ accentDark: '#b3234a',
+ text: '#f5f5f5',
+ textMuted: '#8888aa',
+ input: '#141428',
+ button: '#ffcc00',
+ buttonText: '#0f0f1e',
+};
+
+export default function NeoBrutalistScreen() {
+ return (
+
+
+ {/* Header */}
+
+
+
+ New Drop
+
+
+
+ CREATE YOUR{'\n'}FIGGO
+
+
+
+
+ {/* Name */}
+
+ Name
+
+
+
+
+
+
+ {/* Story */}
+
+ Story
+
+
+
+
+
+
+ {/* Button */}
+ ({ opacity: pressed ? 0.9 : 1 })}>
+
+
+
+
+ Generate Figure
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/figgos/apps/mobile/app/retro-pixel.tsx b/apps/figgos/apps/mobile/app/retro-pixel.tsx
new file mode 100644
index 000000000..1df30e231
--- /dev/null
+++ b/apps/figgos/apps/mobile/app/retro-pixel.tsx
@@ -0,0 +1,271 @@
+import { View, Text, TextInput, Pressable, ScrollView } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+const C = {
+ bg: '#1a1a2e',
+ card: '#16213e',
+ cardBorder: '#e94560',
+ blue: '#0f3460',
+ red: '#e94560',
+ redDark: '#a3304a',
+ yellow: '#f5c518',
+ yellowDark: '#b8940f',
+ text: '#eeeef0',
+ textMuted: '#6a6a8a',
+ inputBg: '#0f1a30',
+ inputBorder: '#2a3a5a',
+};
+
+export default function RetroPixelScreen() {
+ return (
+
+
+ {/* Header */}
+
+ {/* Chunky badge */}
+
+
+ Player 1
+
+
+
+ Create your{'\n'}Figgo
+
+
+
+
+ {/* Form container */}
+
+ {/* Name */}
+
+
+
+ Name
+
+
+
+
+ {/* Story */}
+
+
+
+ Story
+
+
+
+
+
+ {/* Button */}
+ ({ transform: [{ scale: pressed ? 0.97 : 1 }] })}>
+
+
+
+
+ Generate!
+
+
+
+
+
+ {/* Stats bar */}
+
+
+
+ Common
+
+ 60%
+
+
+
+ Rare
+
+ 25%
+
+
+
+ Epic
+
+ 12%
+
+
+
+ Lgndy
+
+ 3%
+
+
+
+
+
+ );
+}
diff --git a/apps/figgos/apps/mobile/global.css b/apps/figgos/apps/mobile/global.css
index 1220c7720..4ffd3bb49 100644
--- a/apps/figgos/apps/mobile/global.css
+++ b/apps/figgos/apps/mobile/global.css
@@ -3,83 +3,64 @@
@tailwind utilities;
/* =============================================================================
- Figgos Design System — Toy Collectible Theme
+ Figgos Design System — Neo-Brutalist Game UI
Color strategy:
- - Primary: Vibrant purple — playful, gaming, fun
- - Secondary: Electric blue — action, energy
- - Accent: Teal green — success, highlights
- - Rarity colors: Common(gray), Rare(blue), Epic(purple), Legendary(gold)
+ - Primary: Electric Yellow — bold, in-your-face, action
+ - Secondary: Hot Pink — accents, badges, highlights
+ - Surface: Deep navy — dark but warm enough for contrast
+ - Borders: Thick, visible, part of the design language
+ - Shadows: Hard offset layers, not soft blurs
Values are RGB triplets for Tailwind alpha support:
rgb(var(--color) / )
============================================================================= */
-/* Light Mode */
:root {
- --background: 248 249 250;
- --foreground: 45 52 54;
- --surface: 255 255 255;
- --surface-elevated: 255 255 255;
- --muted: 223 230 233;
- --muted-foreground: 99 110 114;
+ --background: 15 15 30;
+ --foreground: 245 245 245;
- --primary: 108 92 231;
- --primary-foreground: 255 255 255;
- --secondary: 9 132 227;
+ --surface: 26 26 53;
+ --surface-elevated: 35 35 65;
+
+ --muted: 55 55 80;
+ --muted-foreground: 136 136 170;
+
+ /* Electric Yellow */
+ --primary: 255 204 0;
+ --primary-foreground: 15 15 30;
+ --primary-dark: 179 143 0;
+
+ /* Hot Pink */
+ --secondary: 255 51 102;
--secondary-foreground: 255 255 255;
- --accent: 0 184 148;
- --accent-foreground: 255 255 255;
- --destructive: 231 76 60;
- --destructive-foreground: 255 255 255;
+ --secondary-dark: 179 35 74;
- --border: 223 230 233;
- --input: 223 230 233;
- --ring: 108 92 231;
+ /* Teal (success, positive actions) */
+ --accent: 0 210 170;
+ --accent-foreground: 15 15 30;
+ --accent-dark: 0 150 120;
+
+ --destructive: 255 80 80;
+ --destructive-foreground: 15 15 30;
+
+ /* Borders — yellow is the signature */
+ --border: 255 204 0;
+ --border-muted: 50 50 80;
+
+ --input: 20 20 40;
+ --ring: 255 204 0;
/* Rarity System */
- --rarity-common: 178 190 195;
- --rarity-rare: 9 132 227;
- --rarity-epic: 108 92 231;
- --rarity-legendary: 248 214 43;
+ --rarity-common: 136 136 170;
+ --rarity-common-foreground: 245 245 245;
- /* Rarity Text (on rarity background) */
- --rarity-common-foreground: 45 52 54;
- --rarity-rare-foreground: 255 255 255;
- --rarity-epic-foreground: 255 255 255;
- --rarity-legendary-foreground: 30 30 30;
-}
-
-/* Dark Mode */
-.dark {
- --background: 26 26 46;
- --foreground: 255 255 255;
- --surface: 22 33 62;
- --surface-elevated: 31 52 96;
- --muted: 45 52 54;
- --muted-foreground: 178 190 195;
-
- --primary: 162 155 254;
- --primary-foreground: 26 26 46;
- --secondary: 116 185 255;
- --secondary-foreground: 26 26 46;
- --accent: 85 239 196;
- --accent-foreground: 26 26 46;
- --destructive: 255 107 107;
- --destructive-foreground: 26 26 46;
-
- --border: 45 52 54;
- --input: 45 52 54;
- --ring: 162 155 254;
-
- /* Rarity System (brighter in dark mode) */
- --rarity-common: 99 110 114;
- --rarity-rare: 116 185 255;
- --rarity-epic: 162 155 254;
- --rarity-legendary: 248 214 43;
-
- --rarity-common-foreground: 255 255 255;
- --rarity-rare-foreground: 26 26 46;
- --rarity-epic-foreground: 26 26 46;
- --rarity-legendary-foreground: 30 30 30;
+ --rarity-rare: 100 180 255;
+ --rarity-rare-foreground: 15 15 30;
+
+ --rarity-epic: 180 130 255;
+ --rarity-epic-foreground: 15 15 30;
+
+ --rarity-legendary: 255 185 30;
+ --rarity-legendary-foreground: 25 25 25;
}
diff --git a/apps/figgos/apps/mobile/tailwind.config.js b/apps/figgos/apps/mobile/tailwind.config.js
index 551dd2d6c..07591c67e 100644
--- a/apps/figgos/apps/mobile/tailwind.config.js
+++ b/apps/figgos/apps/mobile/tailwind.config.js
@@ -6,7 +6,6 @@ module.exports = {
theme: {
extend: {
colors: {
- // Semantic tokens
background: 'rgb(var(--background) / )',
foreground: 'rgb(var(--foreground) / )',
surface: {
@@ -20,24 +19,29 @@ module.exports = {
primary: {
DEFAULT: 'rgb(var(--primary) / )',
foreground: 'rgb(var(--primary-foreground) / )',
+ dark: 'rgb(var(--primary-dark) / )',
},
secondary: {
DEFAULT: 'rgb(var(--secondary) / )',
foreground: 'rgb(var(--secondary-foreground) / )',
+ dark: 'rgb(var(--secondary-dark) / )',
},
accent: {
DEFAULT: 'rgb(var(--accent) / )',
foreground: 'rgb(var(--accent-foreground) / )',
+ dark: 'rgb(var(--accent-dark) / )',
},
destructive: {
DEFAULT: 'rgb(var(--destructive) / )',
foreground: 'rgb(var(--destructive-foreground) / )',
},
- border: 'rgb(var(--border) / )',
+ border: {
+ DEFAULT: 'rgb(var(--border) / )',
+ muted: 'rgb(var(--border-muted) / )',
+ },
input: 'rgb(var(--input) / )',
ring: 'rgb(var(--ring) / )',
- // Rarity system (game-specific)
rarity: {
common: {
DEFAULT: 'rgb(var(--rarity-common) / )',
@@ -57,6 +61,9 @@ module.exports = {
},
},
},
+ borderWidth: {
+ 3: '3px',
+ },
},
},
plugins: [],