Skill

Flat Design 2.0 (Semi-Flat)

Design-style skill for Flat Design 2.0 (Semi-Flat): flat aesthetics with subtle, tinted shadows that hint at interactability.

Maintainer of this project? Claim this page to edit the listing.


81
Spark score
out of 100
Updated 28 days ago
Version 13.5.0

Add to Favorites

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-flat-design-2 | bash

Overview

Flat Design 2.0 (Semi-Flat)

A design-style skill for Flat Design 2.0 (Semi-Flat) - flat surfaces with subtle, tinted shadows that hint at interactability without breaking the flat aesthetic - with matching Web CSS and SwiftUI implementations. Use it for modern SaaS or consumer products that want flat clarity plus a light interactivity cue, distinct from both harsh drop-shadow skeuomorphism and totally flat, shadow-free design.

What it does

Flat Design 2.0 (Semi-Flat) is a design-style child skill ('flat aesthetics, but with subtle hints of physics to communicate interactability'), part of the design-it family and not meant to be triggered directly - and distinct from plain Flat Design, which forbids shadows entirely. Three core principles: Mostly Flat (the primary aesthetic stays 2D and solid), Subtle Elevation (extremely soft, large-spread shadows used strictly to indicate interactable elements like buttons and floating action buttons, or layered elements like modals), and Micro-Gradients (occasional, barely-noticeable linear gradients so large surfaces don't feel dead).

When to use - and when NOT to

Use it when the user's request matches this restrained-but-not-totally-flat aesthetic - modern SaaS products or clean consumer apps that want flat's clarity without feeling lifeless or losing interactivity cues. As a design sub-style, it's selected by the parent design-it skill's routing rather than invoked on its own.

Inputs and outputs

Visual DNA pairs well with Warm Tech or Earth-Grounded Elegance palettes, clean readable sans-serifs, and a strict shadow discipline: shadows must be low opacity, high blur, and tinted with the background color rather than pure black - rgba(43, 48, 58, 0.08) instead of a generic black shadow. The web implementation applies a very subtle, diffuse box-shadow to cards (0 10px 30px var(--shadow-color)), deepening slightly with a lift (translateY(-4px)) on hover, and gives interactive buttons a small colored shadow tinted to the button's own accent color rather than neutral black.

.flat2-card {
  box-shadow: 0 10px 30px var(--shadow-color);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.flat2-card:hover { transform: translateY(-4px); }

Integrations

SwiftUI enforces the same restraint with explicit numeric guidance: shadow opacity should stay in the 0.05-0.08 range with a 10-16pt blur radius - "if you can immediately see the shadow, it's too heavy" - always tinted (e.g. Color.accentColor.opacity(0.25) for a button shadow, never pure black), plus a subtle scaleEffect press-down animation to add physical feedback without breaking the flat illusion, driven by a long-press gesture that tracks pressed state rather than a full button-press animation.

Who it's for

Designers and developers building a modern SaaS or consumer product who want flat design's clarity plus just enough tinted, understated shadow to signal what's interactable - without sliding into either harsh drop-shadow skeuomorphism or completely flat, feedback-less surfaces - the tell for getting it right is that the shadow should never be the first thing a user consciously notices about the layout.

Source README

Flat Design 2.0 (Semi-Flat)

"Flat aesthetics, but with subtle hints of physics to communicate interactability."

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. Mostly Flat: The primary aesthetic remains 2D and solid.
  2. Subtle Elevation: Use extremely soft, large-spread shadows strictly to indicate interactable elements (buttons, floating action buttons) or layers (modals).
  3. Micro-Gradients: Occasional, barely noticeable linear gradients to prevent large surfaces from feeling dead.

Visual DNA

  • Colors: Pairs well with Warm Tech or Earth-Grounded Elegance.
  • Typography: Clean, readable sans-serifs.
  • Shadows: Shadows must be low opacity, high blur, and usually tinted with the background color, not pure black.

Web Implementation

  • CSS Example:
:root {
  --shadow-color: rgba(43, 48, 58, 0.08); /* Tinted shadow */
}

.flat2-card {
  background-color: var(--bg-primary);
  border-radius: 8px;
  padding: 32px;
  /* Very subtle, diffuse shadow */
  box-shadow: 0 10px 30px var(--shadow-color);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.flat2-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 40px rgba(43, 48, 58, 0.12);
}

.flat2-btn {
  background: var(--cta-highlight);
  border-radius: 4px;
  padding: 12px 24px;
  color: white;
  border: none;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

App Implementation

SwiftUI

struct SemiFlatCard: View {
    @State private var isPressed = false
    
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Semi-Flat Card")
                .font(.system(size: 18, weight: .semibold))
            Text("Flat aesthetic with just enough depth to hint at interactivity.")
                .font(.system(size: 15))
                .foregroundColor(.secondary)
        }
        .padding(24)
        .background(Color(.systemBackground))
        .cornerRadius(8)
        // The key: very soft, tinted shadow — NOT harsh black
        .shadow(color: Color.black.opacity(0.06), radius: 12, x: 0, y: 4)
        .scaleEffect(isPressed ? 0.98 : 1.0)
        .animation(.easeOut(duration: 0.2), value: isPressed)
        .onLongPressGesture(minimumDuration: .infinity, pressing: { pressing in
            isPressed = pressing
        }, perform: {})
    }
}

struct SemiFlatButton: View {
    var body: some View {
        Button(action: {}) {
            Text("Continue")
                .font(.system(size: 15, weight: .semibold))
                .foregroundColor(.white)
                .padding(.horizontal, 24)
                .padding(.vertical, 12)
                .background(Color.accentColor)
                .cornerRadius(4)
                // Subtle button shadow
                .shadow(color: Color.accentColor.opacity(0.25), radius: 8, x: 0, y: 4)
        }
        .buttonStyle(.plain)
    }
}
  • Shadow color should be tinted (e.g., Color.accentColor.opacity(0.15)), never pure black.
  • Use radius: 10...16 with opacity: 0.05...0.08 - if you can immediately see the shadow, it's too heavy.
  • Add subtle scaleEffect on press to hint at physical feedback.

Flutter

class SemiFlatCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(24),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        // Very soft, tinted shadow
        boxShadow: [
          BoxShadow(
            color: const Color(0xFF2B303A).withOpacity(0.08),
            blurRadius: 24,
            offset: const Offset(0, 8),
            spreadRadius: 0,
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Semi-Flat Card',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
          const SizedBox(height: 16),
          const Text('Flat aesthetic with just enough depth to hint at interactivity.',
            style: TextStyle(fontSize: 15, color: Colors.black54)),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {},
            style: ElevatedButton.styleFrom(
              elevation: 2,  // Very low — just enough to feel clickable
              shadowColor: Theme.of(context).primaryColor.withOpacity(0.3),
              backgroundColor: Theme.of(context).primaryColor,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
              padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
            ),
            child: const Text('Continue', style: TextStyle(fontWeight: FontWeight.w600)),
          ),
        ],
      ),
    );
  }
}
  • Use elevation: 1 to elevation: 4 max. Never exceed elevation: 6.
  • Tint the shadowColor to match the card's background or the brand color.
  • Use InkWell for ripple effects and a slight Transform.translate animation on press.

React Native

const SemiFlatCard = () => (
  <View style={{
    padding: 24,
    backgroundColor: '#FFFFFF',
    borderRadius: 8,
    // Very subtle, diffuse shadow
    shadowColor: '#2B303A',
    shadowOffset: { width: 0, height: 8 },
    shadowOpacity: 0.08,
    shadowRadius: 24,
    // Android
    elevation: 3,
  }}>
    <Text style={{ fontSize: 18, fontWeight: '600', marginBottom: 16 }}>
      Semi-Flat Card
    </Text>
    <Text style={{ fontSize: 15, color: '#666', marginBottom: 20 }}>
      Flat aesthetic with just enough depth to hint at interactivity.
    </Text>
    <Pressable
      style={({ pressed }) => ({
        backgroundColor: '#4A90D9',
        paddingHorizontal: 24,
        paddingVertical: 12,
        borderRadius: 4,
        alignSelf: 'flex-start',
        transform: [{ scale: pressed ? 0.97 : 1 }],
        shadowColor: '#4A90D9',
        shadowOffset: { width: 0, height: 4 },
        shadowOpacity: 0.25,
        shadowRadius: 8,
      })}
    >
      <Text style={{ color: '#FFF', fontWeight: '600' }}>Continue</Text>
    </Pressable>
  </View>
);
  • On iOS use shadowOpacity: 0.05...0.10 with shadowRadius: 16...24 for a diffuse spread.
  • On Android, elevation: 2...4 is equivalent. Avoid going above elevation: 6.
  • Use Pressable with ({ pressed }) style callback for animated press states.

Jetpack Compose

@Composable
fun SemiFlatCard() {
    Card(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(8.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
        colors = CardDefaults.cardColors(containerColor = Color.White),
    ) {
        Column(modifier = Modifier.padding(24.dp)) {
            Text("Semi-Flat Card", fontSize = 18.sp, fontWeight = FontWeight.SemiBold)
            Spacer(Modifier.height(16.dp))
            Text("Flat aesthetic with just enough depth to hint at interactivity.",
                fontSize = 15.sp, color = Color(0xFF666666))
            Spacer(Modifier.height(20.dp))
            Button(
                onClick = {},
                shape = RoundedCornerShape(4.dp),
                elevation = ButtonDefaults.buttonElevation(defaultElevation = 2.dp),
                contentPadding = PaddingValues(horizontal = 24.dp, vertical = 12.dp),
            ) {
                Text("Continue", fontWeight = FontWeight.SemiBold)
            }
        }
    }
}
  • Use CardDefaults.cardElevation(defaultElevation = 2.dp) - keep it under 4dp.
  • On hover/press: hoveredElevation = 4.dp, pressedElevation = 1.dp for subtle physics.
  • Tint shadows by using Modifier.shadow(elevation, shape, ambientColor, spotColor) with custom tinted colors.

Do's and Don'ts

  • DO: Keep shadows incredibly subtle. If you immediately notice the shadow, it's too dark.
  • DON'T: Use inner shadows, heavy gradients, or skeuomorphic textures.

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.

FAQ

Common questions

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.