--- name: skeuomorphism description: Web and App implementation guide for Skeuomorphism. Trigger when user wants UI to mimic real-world objects, realistic textures, or physical metaphors. date_added: "2026-06-17" risk: safe source: self source_type: self --- # Skeuomorphism > "Digital interfaces that look and behave like their physical counterparts." ## When to Use Use this sub-style when the user's request matches the aesthetic described above. This is a child reference of the `design-it` skill and is not meant to be triggered directly. ## Core Principles 1. **Realistic Textures**: Leather, brushed metal, wood grain, paper. The UI should feel like a physical object you can touch. 2. **Physical Lighting & Depth**: Intense attention to specular highlights, drop shadows, inner shadows, bevels, and ambient occlusion. 3. **Real-world Metaphors**: Switches that look like hardware toggles, dials with physical notches, notepads with binding rings. ## Visual DNA - **Colors**: Highly dependent on the material being simulated. For rich, classic skeuomorphism, use the **Industrial Chic** (for metal/hardware) or **Monochromatic Brown** (for wood/leather) palettes. - **Typography**: Fonts that match the physical object (e.g., typewriter fonts for paper, LCD fonts for digital screens, embossed sans-serifs for hardware buttons). - **Details**: Screws, stitching, glare, and gradients are your primary tools. ## Web Implementation - Heavy use of layered background images (textures), complex gradients, and multiple box-shadows. - **CSS Example**: ```css .skeuo-button { /* Brushed metal effect */ background: linear-gradient(180deg, #e0e0e0 0%, #a0a0a0 100%), url('brushed-metal-texture.png'); background-blend-mode: overlay; border: 1px solid #7a7a7a; border-radius: 50%; width: 80px; height: 80px; /* Bevel, inner highlight, and drop shadow */ box-shadow: inset 0 2px 4px rgba(255,255,255,0.8), /* Top highlight */ inset 0 -2px 4px rgba(0,0,0,0.4), /* Bottom shading */ 0 4px 6px rgba(0,0,0,0.5), /* Drop shadow */ 0 1px 1px rgba(0,0,0,0.2); } .skeuo-button:active { /* Pressing the physical button */ box-shadow: inset 0 4px 8px rgba(0,0,0,0.6), inset 0 -1px 2px rgba(255,255,255,0.4), 0 1px 1px rgba(0,0,0,0.2); transform: translateY(2px); } ``` ## App Implementation ### SwiftUI ```swift struct SkeuoButton: View { @State private var isPressed = false var body: some View { Button(action: {}) { Text("POWER") .font(.system(size: 14, weight: .bold)) .foregroundColor(.white) .textCase(.uppercase) } .frame(width: 80, height: 80) .background( ZStack { // Brushed metal base Circle() .fill( LinearGradient( colors: [Color(white: 0.88), Color(white: 0.63)], startPoint: .top, endPoint: .bottom ) ) // Inner highlight (top bevel) Circle() .stroke( LinearGradient( colors: [.white.opacity(0.8), .clear], startPoint: .top, endPoint: .center ), lineWidth: 2 ) .padding(1) } ) .clipShape(Circle()) // Outer bezel ring .overlay(Circle().stroke(Color(white: 0.5), lineWidth: 1)) // Physical drop shadow .shadow(color: .black.opacity(isPressed ? 0.2 : 0.5), radius: isPressed ? 2 : 6, x: 0, y: isPressed ? 1 : 4) .scaleEffect(isPressed ? 0.96 : 1.0) .animation(.easeOut(duration: 0.1), value: isPressed) .simultaneousGesture( DragGesture(minimumDistance: 0) .onChanged { _ in isPressed = true } .onEnded { _ in isPressed = false } ) } } ``` - Stack multiple shapes (`Circle`, `RoundedRectangle`) with different gradients to build up realistic depth. - Use `.overlay()` with stroked shapes for highlight bezels along the edges. - The pressed state should reduce shadow AND scale — simulating a physical push. ### Flutter ```dart class SkeuoButton extends StatefulWidget { @override State createState() => _SkeuoButtonState(); } class _SkeuoButtonState extends State { bool _isPressed = false; @override Widget build(BuildContext context) { return GestureDetector( onTapDown: (_) => setState(() => _isPressed = true), onTapUp: (_) => setState(() => _isPressed = false), onTapCancel: () => setState(() => _isPressed = false), child: AnimatedContainer( duration: const Duration(milliseconds: 100), width: 80, height: 80, decoration: BoxDecoration( shape: BoxShape.circle, // Brushed metal gradient gradient: LinearGradient( colors: [Colors.grey[300]!, Colors.grey[600]!], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), border: Border.all(color: Colors.grey[500]!, width: 1), boxShadow: [ // Outer drop shadow BoxShadow( color: Colors.black.withOpacity(_isPressed ? 0.2 : 0.5), blurRadius: _isPressed ? 4 : 12, offset: Offset(0, _isPressed ? 2 : 6), ), // Inner top highlight (faked with a light inset) BoxShadow( color: Colors.white.withOpacity(0.6), blurRadius: 1, offset: const Offset(0, -1), spreadRadius: -1, ), ], ), transform: Matrix4.identity()..scale(_isPressed ? 0.96 : 1.0), alignment: Alignment.center, child: const Text('POWER', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, shadows: [ Shadow(color: Colors.black54, offset: Offset(0, 1), blurRadius: 2), ])), ), ); } } ``` - Use `AnimatedContainer` for smooth press transitions. Adjust `boxShadow`, `transform`, and gradient on tap. - Layer `BoxShadow` entries: one for the outer drop shadow, one for the inner top-edge highlight. - For complex textures (leather, wood), use `DecorationImage` with an asset file inside `BoxDecoration`. ### React Native ```jsx const SkeuoButton = () => { const [pressed, setPressed] = useState(false); return ( setPressed(true)} onPressOut={() => setPressed(false)} style={{ width: 80, height: 80, borderRadius: 40, alignItems: 'center', justifyContent: 'center', // Metal gradient must be done via an image or LinearGradient component backgroundColor: '#A0A0A0', borderWidth: 1, borderColor: '#7A7A7A', // Shadow changes on press shadowColor: '#000', shadowOffset: { width: 0, height: pressed ? 1 : 4 }, shadowOpacity: pressed ? 0.2 : 0.5, shadowRadius: pressed ? 2 : 6, elevation: pressed ? 2 : 8, transform: [{ scale: pressed ? 0.96 : 1 }], }} > POWER ); }; ``` - For realistic textures, use `ImageBackground` with exported texture assets (leather.png, brushed-metal.png). - Use `Pressable` with `onPressIn`/`onPressOut` to animate shadow depth, scale, and opacity changes. - Complex gradient bevels require `react-native-linear-gradient` or `expo-linear-gradient`. ### Jetpack Compose ```kotlin @Composable fun SkeuoButton() { var isPressed by remember { mutableStateOf(false) } val scale by animateFloatAsState(if (isPressed) 0.96f else 1f) val elevation by animateDpAsState(if (isPressed) 2.dp else 8.dp) Box( modifier = Modifier .size(80.dp) .graphicsLayer { scaleX = scale; scaleY = scale } .shadow(elevation, CircleShape) .clip(CircleShape) .background( Brush.verticalGradient( colors = listOf(Color(0xFFE0E0E0), Color(0xFFA0A0A0)) ) ) .border(1.dp, Color(0xFF7A7A7A), CircleShape) .pointerInput(Unit) { detectTapGestures( onPress = { isPressed = true tryAwaitRelease() isPressed = false } ) }, contentAlignment = Alignment.Center, ) { Text("POWER", color = Color.White, fontWeight = FontWeight.Bold, fontSize = 14.sp, style = TextStyle(shadow = Shadow( color = Color.Black.copy(alpha = 0.5f), offset = Offset(0f, 2f), blurRadius = 4f, ))) } } ``` - Use `Brush.verticalGradient()` for metallic surfaces and `Modifier.border()` with `CircleShape` for bezels. - Animate `shadow` elevation and `graphicsLayer { scaleX/scaleY }` on press for realistic physical push. - For textures, use `Modifier.paint(painterResource(R.drawable.brushed_metal))` as a background. ## Do's and Don'ts - **DO**: Ensure the metaphor makes sense for the user's task. - **DON'T**: Overuse it to the point of clutter. Keep the interactive elements highly realistic, but let the structural layout remain clean. ## Limitations - This is a styling reference and does not replace environment-specific validation, accessibility testing, or expert review. - Ensure appropriate contrast ratios and responsive behaviors are verified separately.