Native & Mobile Integration
pudge-ui specs translate to any rendering platform. The CSS properties map directly to native APIs: gradients become platform gradient constructors, shadows become platform shadow APIs, border-radius becomes corner radius, and the three-plane depth model works everywhere.
SwiftUI (iOS/macOS)
SwiftUI modifiers map cleanly to CSS properties. The depth model uses .shadow() for bottom
edges and .overlay() with stroked shapes for top highlights.
import SwiftUI
struct PushButton: View {
let label: String
var size: ButtonSize = .md
var material: ButtonMaterial = .panel
var isActive: Bool = false
var action: () -> Void
var body: some View {
Button(action: action) {
Text(label)
.font(.system(size: size.fontSize, weight: .semibold))
.tracking(1.5)
.textCase(.uppercase)
.foregroundColor(isActive ? Color("amber") : Color("textPrimary"))
}
.padding(.horizontal, size.hPadding)
.padding(.vertical, size.vPadding)
.background(
LinearGradient(
colors: [Color("bgPanel"), Color("bgSurface")],
startPoint: .top, endPoint: .bottom
)
)
.cornerRadius(8)
// Three-plane depth model
.shadow(color: .black.opacity(0.4), radius: 0, y: 2) // bottom edge
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.white.opacity(0.14), lineWidth: 1) // top highlight
.offset(y: -0.5)
)
}
}
// Size variants mirror the CSS spec
enum ButtonSize {
case xs, sm, md, lg, xl
var fontSize: CGFloat {
switch self {
case .xs: return 8; case .sm: return 9
case .md: return 10; case .lg: return 11; case .xl: return 13
}
}
var hPadding: CGFloat {
switch self {
case .xs: return 8; case .sm: return 10
case .md: return 14; case .lg: return 18; case .xl: return 22
}
}
var vPadding: CGFloat {
switch self {
case .xs: return 4; case .sm: return 5
case .md: return 6; case .lg: return 8; case .xl: return 10
}
}
} Jetpack Compose (Android)
Compose Modifier chains mirror CSS property stacks. Brush.verticalGradient replaces linear-gradient, and shadow() handles depth.
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
// pudge-ui tokens
val bgPanel = Color(0xFF22201E)
val bgSurface = Color(0xFF2A2826)
val textPrimary = Color(0xFFD8D4CC)
val amber = Color(0xFFF5A623)
@Composable
fun PushButton(
label: String,
isActive: Boolean = false,
onClick: () -> Unit
) {
Box(
modifier = Modifier
.shadow(2.dp, RoundedCornerShape(8.dp))
.background(
brush = Brush.verticalGradient(
colors = listOf(bgPanel, bgSurface)
),
shape = RoundedCornerShape(8.dp)
)
.padding(horizontal = 14.dp, vertical = 6.dp)
) {
Text(
text = label.uppercase(),
color = if (isActive) amber else textPrimary,
fontSize = 10.sp,
fontWeight = FontWeight.SemiBold,
letterSpacing = 1.5.sp
)
}
} Flutter
Flutter's BoxDecoration maps directly to the CSS box model. LinearGradient replaces linear-gradient, BoxShadow replaces box-shadow.
import 'package:flutter/material.dart';
// pudge-ui tokens
const bgPanel = Color(0xFF22201E);
const bgSurface = Color(0xFF2A2826);
const textPrimary = Color(0xFFD8D4CC);
const amber = Color(0xFFF5A623);
const borderDeep = Color(0xFF0A0908);
class PushButton extends StatelessWidget {
final String label;
final bool isActive;
final VoidCallback? onPressed;
const PushButton({
super.key,
required this.label,
this.isActive = false,
this.onPressed,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
// Three-plane depth: gradient + shadow + highlight
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [bgPanel, bgSurface],
),
borderRadius: BorderRadius.circular(8),
boxShadow: const [
BoxShadow(color: borderDeep, offset: Offset(0, 2)),
],
border: Border(
top: BorderSide(
color: Colors.white.withValues(alpha: 0.14),
width: 1,
),
),
),
child: Text(
label.toUpperCase(),
style: TextStyle(
color: isActive ? amber : textPrimary,
fontSize: 10,
fontWeight: FontWeight.w600,
letterSpacing: 1.5,
),
),
),
);
}
} React Native
React Native uses StyleSheet.create with platform-specific shadow handling. iOS gets
shadowColor/Offset/Opacity, Android gets elevation.
import { Pressable, Text, StyleSheet, Platform } from 'react-native';
// pudge-ui tokens
const tokens = {
bgPanel: '#22201e',
bgSurface: '#2a2826',
textPrimary: '#d8d4cc',
amber: '#f5a623',
borderDeep: '#0a0908',
};
export function PushButton({ label, active, onPress }) {
return (
<Pressable
onPress={onPress}
style={({ pressed }) => [
styles.button,
active && styles.active,
pressed && styles.pressed,
]}
>
<Text style={[
styles.label,
active && styles.activeLabel,
]}>
{label.toUpperCase()}
</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
paddingHorizontal: 14,
paddingVertical: 6,
backgroundColor: tokens.bgPanel,
borderRadius: 8,
// Three-plane depth (platform-specific shadows)
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.4,
shadowRadius: 0,
},
android: { elevation: 3 },
}),
borderTopWidth: 1,
borderTopColor: 'rgba(255,255,255,0.14)',
},
pressed: {
transform: [{ translateY: 1 }],
...Platform.select({
ios: { shadowOffset: { width: 0, height: 1 } },
android: { elevation: 1 },
}),
},
active: {
borderColor: tokens.amber,
borderWidth: 1,
},
label: {
color: tokens.textPrimary,
fontSize: 10,
fontWeight: '600',
letterSpacing: 1.5,
},
activeLabel: {
color: tokens.amber,
},
}); Translation Patterns
Every pudge-ui CSS property has a native equivalent:
| CSS Property | SwiftUI | Compose | Flutter |
|---|---|---|---|
linear-gradient | LinearGradient | Brush.verticalGradient | LinearGradient |
box-shadow | .shadow() | Modifier.shadow() | BoxShadow |
border-radius | .cornerRadius() | RoundedCornerShape | BorderRadius.circular() |
inset box-shadow | .overlay() + stroke | drawBehind | Border(top:) |
letter-spacing | .tracking() | letterSpacing | letterSpacing |
font-weight: 600 | .semibold | FontWeight.SemiBold | FontWeight.w600 |
text-transform: uppercase | .textCase(.uppercase) | .uppercase() | .toUpperCase() |
transition | .animation() | animateAs*() | AnimatedContainer |
pudge-ui specs describe visual physics (materials, depth, light), not web-specific
APIs. Any rendering engine that can draw gradients, shadows, and rounded rectangles can implement
the full spec.