Skill

Generate Neo-Brutalist UI Components and Styles

Design-style skill for Neo-Brutalism: hard zero-blur shadows, thick black outlines, and vibrant flat colors with a press effect.

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


82
Spark score
out of 100
Updated 26 days ago
Version 13.6.1

Add to Favorites

Why it matters

This skill helps developers and designers implement Neo-Brutalist design patterns in their web projects by generating component code, CSS styles, and layout structures that follow the bold, raw, and unapologetically functional aesthetic of Neo-Brutalism.

Outcomes

What it gets done

01

Generate Neo-Brutalist UI components with thick borders, bold shadows, and raw typography

02

Create CSS stylesheets following Neo-Brutalist design principles and color schemes

03

Build layout structures with asymmetric grids and intentionally harsh visual hierarchies

04

Convert design concepts into production-ready Neo-Brutalist HTML and CSS code

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-neo-brutalism | bash

Overview

Neo-Brutalism

A design-style skill for Neo-Brutalism - hard zero-blur shadows, thick black outlines, and vibrant flat colors, with a signature button-press interaction - with matching Web CSS and SwiftUI implementations. Use it for indie product pages, creative portfolios, or playful consumer apps wanting bold graphic energy; distinct from plain unstyled Brutalism, which rejects color and shadow entirely.

What it does

Neo-Brutalism is a design-style child skill ('brutalism, but make it pop - hard lines, stark shadows, and vibrant, unashamed colors'), part of the design-it family and not meant to be triggered directly - distinct from plain Brutalism's unstyled, default-browser look. Three core principles: Hard Drop Shadows (solid black shadows with zero blur, usually offset a few pixels down and right), Thick Outlines (every element has a heavy, solid black border, typically 2-4px), and Flat High-Contrast Colors (bright saturated pastels or primary colors against pure white or black).

When to use - and when NOT to

Use it when the user's request matches this bold, playful, heavy-outlined aesthetic - indie product landing pages, creative portfolios, or Gen-Z-targeted consumer apps that want energetic, unapologetic visual punch. 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 starts with an off-white background (#FDF8F5), stark black borders, and saturated accent colors like lemon yellow, bright cyan, or coral, paired with very bold geometric sans-serifs (Space Grotesk, Archivo Black, Inter Black) and shapes ranging from sharp rectangles to fully rounded pills, always with a heavy stroke. The web implementation's defining technique is a box-shadow with zero blur radius - a hard-edged offset shadow (6px 6px 0px #000000) that reads as a solid shape rather than a soft glow - combined with a thick solid border. Buttons get their own smaller hard shadow, and the signature interaction is the "press" effect: on :active, the button translates exactly the shadow's offset distance and the shadow collapses to zero, visually simulating the button being physically pushed flush against the card beneath it.

.neo-btn {
  border: 3px solid #000000;
  box-shadow: 4px 4px 0px #000000;
}
.neo-btn:active {
  transform: translate(4px, 4px);
  box-shadow: 0px 0px 0px #000000;
}

Integrations

SwiftUI reproduces the thick solid outline with a Rectangle().stroke(Color.black, lineWidth:) overlay at the same 3pt weight, bold black-weight system font for headlines, and a bright solid accent color (coral) as the card fill - built as a Button with pressed-state tracking so the same hard-shadow "press" interaction can be reproduced natively.

Who it's for

Designers and developers building an indie product page, creative portfolio, or playful consumer app that wants bold, high-contrast, unapologetically graphic visual energy with a tactile "pressable" button interaction, distinct from both plain unstyled Brutalism and softer modern UI trends.

Source README

Neo-Brutalism

"Brutalism, but make it pop. Hard lines, stark shadows, and vibrant, unashamed colors."

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. Hard Drop Shadows: Solid black shadows with no blur. Usually offset by a few pixels down and to the right.
  2. Thick Outlines: Everything has a heavy, solid black border (usually 2px-4px).
  3. Flat, High-Contrast Colors: Bright, saturated pastels or primary colors contrasting against pure white or black.

Visual DNA

  • Colors: Start with an off-white background (like #FDF8F5), add stark black borders #000000, and use saturated accents like lemon yellow, bright cyan, or coral.
  • Typography: Very bold, geometric sans-serifs (e.g., Space Grotesk, Archivo Black, Inter Black).
  • Shapes: Sharp rectangles or completely rounded pill shapes, but always with a heavy stroke.

Web Implementation

  • The defining feature is the box-shadow with 0 blur.
  • CSS Example:
:root {
  --neo-border: 3px solid #000000;
  --neo-shadow: 6px 6px 0px #000000;
  --neo-bg: #F4F4F0;
  --neo-accent: #FF3366;
}

body {
  background-color: var(--neo-bg);
  font-family: 'Space Grotesk', sans-serif;
}

.neo-card {
  background-color: #ffffff;
  border: var(--neo-border);
  box-shadow: var(--neo-shadow);
  border-radius: 8px; /* Optional, sharp is fine too */
  padding: 32px;
  transition: transform 0.1s, box-shadow 0.1s;
}

.neo-btn {
  background-color: var(--neo-accent);
  color: #000;
  font-weight: 800;
  text-transform: uppercase;
  border: var(--neo-border);
  box-shadow: 4px 4px 0px #000000;
  padding: 16px 32px;
  cursor: pointer;
  transition: all 0.1s ease;
}

.neo-btn:active {
  /* The "press" effect is removing the shadow and moving it down */
  transform: translate(4px, 4px);
  box-shadow: 0px 0px 0px #000000;
}

App Implementation

SwiftUI

struct NeoCard: View {
    @State private var isPressed = false
    let neoBorder: CGFloat = 3
    let neoShadow: CGFloat = 6
    
    var body: some View {
        Button(action: {}) {
            VStack(alignment: .leading, spacing: 16) {
                Text("NEO-BRUTALISM")
                    .font(.system(size: 24, weight: .black, design: .default))
                    .foregroundColor(.black)
                Text("Stark shadows, bright colors.")
                    .font(.system(size: 16, weight: .bold))
                    .foregroundColor(.black)
            }
            .padding(24)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(Color(red: 1.0, green: 0.2, blue: 0.4)) // Bright Coral
            // Neo-brutalist solid outline
            .overlay(
                Rectangle()
                    .stroke(Color.black, lineWidth: neoBorder)
            )
        }
        .buttonStyle(.plain)
        // Hard drop shadow (0 blur)
        .shadow(color: .black, radius: 0, x: isPressed ? 0 : neoShadow, y: isPressed ? 0 : neoShadow)
        // Translate the button physically when pressed to cover the shadow
        .offset(x: isPressed ? neoShadow : 0, y: isPressed ? neoShadow : 0)
        .simultaneousGesture(
            DragGesture(minimumDistance: 0)
                .onChanged { _ in isPressed = true }
                .onEnded { _ in isPressed = false }
        )
        // Instant pop, no smooth animation
        .animation(.none, value: isPressed)
    }
}
  • .shadow(radius: 0) is the secret. Set an offset (e.g. x: 6, y: 6).
  • For interactions, remove the shadow and translate the element by the same offset amounts using .offset().
  • Ensure .animation(.none) - Neo-brutalism interactions should be instant, snapping like physical switches.

Flutter

class NeoCard extends StatefulWidget {
  @override
  State<NeoCard> createState() => _NeoCardState();
}

class _NeoCardState extends State<NeoCard> {
  bool _isPressed = false;
  final double neoOffset = 6.0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => setState(() => _isPressed = true),
      onTapUp: (_) => setState(() => _isPressed = false),
      onTapCancel: () => setState(() => _isPressed = false),
      child: Transform.translate(
        // Move the container when pressed
        offset: Offset(_isPressed ? neoOffset : 0, _isPressed ? neoOffset : 0),
        child: Container(
          padding: const EdgeInsets.all(24),
          decoration: BoxDecoration(
            color: const Color(0xFFFF3366), // Bright coral
            border: Border.all(color: Colors.black, width: 3),
            // Sharp shadow disappears on press
            boxShadow: _isPressed ? [] : [
              BoxShadow(
                color: Colors.black,
                blurRadius: 0,     // Critical: 0 blur
                spreadRadius: 0,
                offset: Offset(neoOffset, neoOffset),
              ),
            ],
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: const [
              Text('NEO-BRUTALISM',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.w900, color: Colors.black)),
              SizedBox(height: 16),
              Text('Stark shadows, bright colors.',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)),
            ],
          ),
        ),
      ),
    );
  }
}
  • blurRadius: 0 inside BoxShadow creates the solid block color.
  • Remove the shadow array entirely when _isPressed is true, and simultaneously use Transform.translate to shift the widget down-right.

React Native

const NeoCard = () => {
  const [pressed, setPressed] = useState(false);
  const offset = 6;

  return (
    <Pressable
      onPressIn={() => setPressed(true)}
      onPressOut={() => setPressed(false)}
      style={{
        backgroundColor: '#FF3366',
        padding: 24,
        borderWidth: 3,
        borderColor: '#000',
        transform: [
          { translateX: pressed ? offset : 0 },
          { translateY: pressed ? offset : 0 }
        ],
        // iOS Hard Shadow
        shadowColor: '#000',
        shadowOffset: { width: pressed ? 0 : offset, height: pressed ? 0 : offset },
        shadowOpacity: pressed ? 0 : 1,
        shadowRadius: 0,
        // Android elevation cannot do 0-blur offset shadows natively
        // elevation: 0
      }}
    >
      <Text style={{ fontSize: 24, fontWeight: '900', color: '#000' }}>
        NEO-BRUTALISM
      </Text>
    </Pressable>
  );
};
  • Android Limitation: Standard elevation CANNOT create an unblurred, offset drop shadow.
  • Solution: To make this work on Android, you MUST use the react-native-drop-shadow library or fake it by rendering an identical black <View> absolutely positioned directly behind the main card.

Jetpack Compose

@Composable
fun NeoCard() {
    var isPressed by remember { mutableStateOf(false) }
    val neoOffset = 6.dp
    
    // Compose Modifier.shadow() always blurs. 
    // To get a solid hard shadow, we use Modifier.drawBehind.
    Box(
        modifier = Modifier
            .padding(16.dp)
            .offset(
                x = if (isPressed) neoOffset else 0.dp,
                y = if (isPressed) neoOffset else 0.dp
            )
            .drawBehind {
                if (!isPressed) {
                    drawRect(
                        color = Color.Black,
                        topLeft = Offset(neoOffset.toPx(), neoOffset.toPx()),
                        size = size
                    )
                }
            }
            .background(Color(0xFFFF3366))
            .border(3.dp, Color.Black)
            .pointerInput(Unit) {
                detectTapGestures(
                    onPress = {
                        isPressed = true
                        tryAwaitRelease()
                        isPressed = false
                    }
                )
            }
            .padding(24.dp)
    ) {
        Column {
            Text("NEO-BRUTALISM",
                fontSize = 24.sp, fontWeight = FontWeight.Black, color = Color.Black)
            Spacer(Modifier.height(16.dp))
            Text("Stark shadows, bright colors.",
                fontSize = 16.sp, fontWeight = FontWeight.Bold, color = Color.Black)
        }
    }
}
  • Compose Limitation: Native Modifier.shadow() applies ambient blur which breaks the neo-brutalist aesthetic.
  • Use Modifier.drawBehind { drawRect(...) } with an offset to manually draw the solid shadow block behind the container.
  • Shift the container using Modifier.offset on press, while hiding the shadow layer.

Do's and Don'ts

  • DO: Make the active/pressed state visually translate the button to cover its shadow, creating a physical "click" feel.
  • DON'T: Use gradients or blurred shadows. The aesthetic relies entirely on flat, sharp vectors.

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.