Most hackathon applications look like prototypes within the first five seconds.
It’s rarely a lack of effort; it’s a lack of systematic constraints:
#007AFF, #1D4ED8, #2563EB).padding: 13, margin: 17, gap: 9).When we set out to build Isolyne for Shipaton 2026, our goal wasn’t just to build a working CQRS drift engine—we targeted the Shipaton Design Award.
To compete with the polished aesthetic of tools like Linear and Stripe, we banned ad-hoc styling and built a strict, tokenized design system (src/presentation/theme/tokens.ts) before writing a single screen.
Here is how we engineered our dark-mode visual hierarchy and tactile mobile interactions.
In dark-mode design, pure black (#000000) often feels harsh and lifeless on OLED screens, while standard gray (#1F2937) looks washed out.
We developed an Obsidian Base Palette rooted in deep indigo-black (#07080F):
export const color = {
// Elevation Layers
bg: '#07080F', // Deepest canvas
bgElevated: '#10121C', // Cards, floating modals
bgQuiet: '#0C0E16', // Recessed inputs, nested containers
// Structural Lines
line: '#1E2130', // Subtle separators
lineStrong: '#2A2F42', // Card borders, active outlines
// Text Hierarchy
text: '#F4F2FB', // Primary high-contrast text
textSecondary: '#9A95AB', // Metadata, descriptions
textMuted: '#6F6A80', // Timestamps, placeholders
textOnAccent: '#1A1630',
// Semantic Signals
accent: '#8B83FF', // Neon violet brand highlight
accentDim: '#2A2750', // Subtle glow backgrounds
risk: '#FF6B7A', // Divergence alert crimson
riskSoft: '#3A1820', // Alert card background
join: '#3DDC97', // Consensus emerald green
joinSoft: '#123528', // Resolved card background
caution: '#F0C14A', // Pro tier & pending decisions
} as const;
Every element in the app must belong to one of three elevation planes (bg →→ bgQuiet →→ bgElevated).
When a consensus gap is detected, the card doesn't just change font color—it shifts elevation and border intensity to riskSoft (#3A1820) and riskLine (#5C2430), immediately commanding attention without visual chaos.
Instead of guessing pixel margins, all screen layouts pull from a geometric 4px-grid spacing scale:
export const space = {
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 24,
xxl: 32,
stage: 48,
heroAir: 56, // Generous breathing room for hero states
} as const;
export const radius = {
sm: 10,
md: 14,
lg: 18,
xl: 24,
pill: 999,
} as const;
We tuned typography for quick scanning in high-pressure collaborative environments:
export const type = {
display: {
fontSize: 34,
lineHeight: 40,
fontWeight: '800' as const,
letterSpacing: -1.2,
},
title: {
fontSize: 22,
lineHeight: 28,
fontWeight: '800' as const,
letterSpacing: -0.5,
},
body: {
fontSize: 15,
lineHeight: 22,
fontWeight: '500' as const,
},
bodyStrong: {
fontSize: 15,
lineHeight: 22,
fontWeight: '700' as const,
},
label: {
fontSize: 11,
lineHeight: 14,
fontWeight: '800' as const,
letterSpacing: 1.2,
},
meta: {
fontSize: 13,
lineHeight: 18,
fontWeight: '600' as const,
},
button: {
fontSize: 15,
lineHeight: 20,
fontWeight: '800' as const,
},
} as const;
Labels use tight uppercase tracking (letterSpacing: 1.2), while hero headings use negative tracking (letterSpacing: -1.2) for a modern, compact display weight.
A great design system is more than static colors; it’s how the interface feels under your thumb.
Instead of default React Native opacity flickers, every interactive card and resolution button is wrapped in a custom <AnimatedPressable> component powered by spring physics:
import React, { useRef } from 'react';
import {
Animated,
Pressable,
PressableProps,
StyleProp,
ViewStyle,
} from 'react-native';
interface AnimatedPressableProps extends PressableProps {
style?: StyleProp<ViewStyle>;
activeScale?: number;
}
export function AnimatedPressable({
children,
style,
activeScale = 0.96,
onPressIn,
onPressOut,
...props
}: AnimatedPressableProps) {
const scale = useRef(
new Animated.Value(1)
).current;
const handlePressIn = (e: any) => {
Animated.spring(scale, {
toValue: activeScale,
useNativeDriver: true,
speed: 20,
bounciness: 10,
}).start();
onPressIn && onPressIn(e);
};
const handlePressOut = (e: any) => {
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
speed: 20,
bounciness: 10,
}).start();
onPressOut && onPressOut(e);
};
return (
<Animated.View
style={[
style,
{
transform: [
{ scale },
],
},
]}
>
<Pressable
onPressIn={handlePressIn}
onPressOut={handlePressOut}
style={{
flex: 1,
width: '100%',
}}
{...props}
>
{children}
</Pressable>
</Animated.View>
);
}
When a user taps [ Choose PostgreSQL ] to resolve a gap:
0.96 scale.expo-haptics triggers a heavy mechanical thud.A common pitfall in developer tools is using only red/green to convey status, which fails accessibility checks for colorblind engineers.
Throughout Isolyne:
<AlertCircle> icon and a bold DISPUTED badge.<CheckCircle> icon and clear voiceover aria-labels.hit.min: 44).Because our design system was codified early, our RevenueCat Pro Paywall looks like an organic part of the application rather than an ugly third-party modal dropped on top.
The paywall reuses our exact color.bgElevated, color.accent, and <AnimatedPressable> primitives. When a user navigates to upgrade, the visual continuity reinforces trust—critical for converting free users into paying subscribers.
How do we represent the metaphor of team alignment visually?
In Part 8, we’ll look into Visualizing Silence—how we built the animated concentric radar motif and sweeping vector beam in React Native.