Skill

Generate 3D perspective UI components with rotation

Design-style skill for 3D UI: true Z-axis depth, interactive rotation, and perspective, with Web/SwiftUI/Flutter code.


77
Spark score
out of 100
Updated 27 days ago
Version 13.5.0

Add to Favorites

Why it matters

Developers hire this skill to create interactive three-dimensional user interface components that respond to user input with realistic depth, perspective, and rotation effects across web and mobile platforms.

Outcomes

What it gets done

01

Generate CSS perspective transforms with rotateX/rotateY for web cards

02

Build SwiftUI components with rotation3DEffect and drag gestures

03

Create Flutter Matrix4 perspective transforms with pan gesture handlers

04

Implement React Native and Jetpack Compose 3D rotation animations

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-3d-ui | bash

Overview

3D UI

A design-style skill for 3D, rotatable-space interfaces - true Z-axis depth, interactive tilt via mouse or gyroscope - with matching Web CSS, SwiftUI, and Flutter implementations. Use it for product cards, showcases, or panels that should feel physically manipulable in 3D space; it's a design sub-style selected via the parent design-it skill, not invoked directly.

What it does

3D UI is a design-style child skill ('breaking the plane') for interfaces that exist in a three-dimensional, rotatable space, part of the design-it skill family and not meant to be triggered directly. Three core principles: True Depth (elements physically move closer to or further from the camera via Z-axis translation, not just shadows), Perspective (CSS perspective or WebGL to create realistic vanishing points), and Interactive Rotation (elements respond to mouse movement or device gyroscope by tilting or rotating in 3D space).

When to use - and when NOT to

Use it when the user's request matches this 3D, depth-driven aesthetic - card interfaces, product showcases, or interactive panels that should feel physically manipulable in space rather than flat. As a design sub-style, it's selected by the parent design-it skill's routing, not invoked on its own.

Inputs and outputs

Visual DNA: bold, striking palettes like Midnight Luxury or Industrial Chic, since 3D elements need high contrast to reveal their geometry; bold, blocky, or extruded typography; and rendered 3D assets (.glb, .gltf, or high-res PNGs of 3D objects) instead of flat icons. Web implementation relies on perspective, transform-style: preserve-3d, and rotateX/rotateY - a card starts at a slight rotateX(15deg) rotateY(-15deg) tilt, straightens and pushes toward the viewer on hover (translateZ(50px)), with inner content pushed forward independently via its own translateZ. SwiftUI implements the same effect with .rotation3DEffect() on two axes linked to a drag gesture, using the perspective parameter (default 1/6, higher values distort more) to control camera distance, and can link rotation to CoreMotion gyroscope input for a fully interactive 3D card. Flutter achieves the equivalent via a GestureDetector tracking pan offset with a spring-back animation on release - the perspective trick specifically is Matrix4.identity()..setEntry(3, 2, 0.001) applied inside a Transform widget, with TweenAnimationBuilder smoothing the return-to-center physics. React Native uses PanResponder and an Animated.ValueXY to track drag position, springing back to {x: 0, y: 0} on release with Animated.spring.

Integrations

All three platform implementations share the same interaction model - drag or gyroscope input maps directly to rotation angle on two axes, with a spring-based snap-back to neutral when the gesture ends - so the 3D feel stays consistent whether the surface is CSS, SwiftUI, or Flutter.

Who it's for

Designers and frontend developers building an interface that should feel spatial and physically manipulable - product cards, showcases, interactive panels - rather than a flat 2D layout with only shadow-based depth cues.

Source README

3D UI

"Breaking the plane. Interfaces that exist in a three-dimensional, rotatable space."

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. True Depth (Z-Axis Translation): Elements don't just have shadows; they physically move closer to or further from the camera.
  2. Perspective: Use CSS perspective or WebGL to create realistic vanishing points.
  3. Interactive Rotation: Elements should respond to mouse movement or device gyroscope by tilting or rotating in 3D space.

Visual DNA

  • Colors: Bold, striking palettes like Midnight Luxury or Industrial Chic. 3D elements need high contrast to show their geometry.
  • Typography: Bold, blocky, or extruded text.
  • Graphics: Instead of flat icons, use rendered 3D assets (.glb, .gltf, or high-res PNGs of 3D objects).

Web Implementation

  • Rely heavily on perspective, transform-style: preserve-3d, and rotateX/rotateY.
  • CSS Example:
.perspective-container {
  perspective: 1000px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.card-3d {
  width: 300px;
  height: 400px;
  transform-style: preserve-3d;
  transition: transform 0.5s ease;
  
  /* Initial slight rotation */
  transform: rotateX(15deg) rotateY(-15deg);
}

.card-3d:hover {
  /* Straighten out on hover */
  transform: rotateX(0) rotateY(0) translateZ(50px);
}

/* Inner elements popping out */
.card-content {
  transform: translateZ(30px); /* Pushes content 30px closer to viewer */
}

App Implementation

SwiftUI

struct Card3D: View {
    @State private var dragOffset = CGSize.zero
    
    var body: some View {
        VStack {
            Text("3D Card")
                .font(.largeTitle.bold())
                .foregroundColor(.white)
        }
        .frame(width: 300, height: 400)
        .background(
            LinearGradient(colors: [.blue, .purple], startPoint: .topLeading, endPoint: .bottomTrailing)
        )
        .cornerRadius(24)
        .shadow(radius: 20)
        // Magic 3D effect based on drag gesture
        .rotation3DEffect(
            .degrees(Double(dragOffset.width / 10)),
            axis: (x: 0, y: 1, z: 0),
            perspective: 0.5
        )
        .rotation3DEffect(
            .degrees(Double(-dragOffset.height / 10)),
            axis: (x: 1, y: 0, z: 0),
            perspective: 0.5
        )
        .gesture(
            DragGesture()
                .onChanged { value in
                    withAnimation(.interactiveSpring()) {
                        dragOffset = value.translation
                    }
                }
                .onEnded { _ in
                    withAnimation(.spring()) {
                        dragOffset = .zero
                    }
                }
        )
    }
}
  • SwiftUI makes this incredibly easy with .rotation3DEffect().
  • Use the perspective parameter (default 1/6, higher = more distorted) to control the camera distance.
  • Link the rotation axes (x, y) to drag gestures or CoreMotion (gyroscope) for interactive 3D UI.

Flutter

class Card3D extends StatefulWidget {
  @override
  State<Card3D> createState() => _Card3DState();
}

class _Card3DState extends State<Card3D> {
  Offset _offset = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: (details) {
        setState(() => _offset += details.delta);
      },
      onPanEnd: (_) {
        setState(() => _offset = Offset.zero); // Snap back
      },
      child: TweenAnimationBuilder(
        tween: Tween<Offset>(begin: Offset.zero, end: _offset),
        duration: const Duration(milliseconds: 200),
        curve: Curves.easeOut,
        builder: (context, Offset offset, child) {
          // Perspective Matrix
          final transform = Matrix4.identity()
            ..setEntry(3, 2, 0.001) // perspective
            ..rotateX(-offset.dy * 0.01)
            ..rotateY(offset.dx * 0.01);

          return Transform(
            transform: transform,
            alignment: FractionalOffset.center,
            child: Container(
              width: 300,
              height: 400,
              decoration: BoxDecoration(
                gradient: const LinearGradient(colors: [Colors.blue, Colors.purple]),
                borderRadius: BorderRadius.circular(24),
                boxShadow: const [BoxShadow(color: Colors.black45, blurRadius: 20)],
              ),
              alignment: Alignment.center,
              child: const Text('3D Card', 
                style: TextStyle(color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold)),
            ),
          );
        },
      ),
    );
  }
}
  • The secret to perspective in Flutter is Matrix4.identity()..setEntry(3, 2, 0.001).
  • Wrap the target container in a Transform widget and apply rotations on the X and Y axes.
  • Use TweenAnimationBuilder to smooth out the return-to-center physics.

React Native

const Card3D = () => {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], { useNativeDriver: false }),
      onPanResponderRelease: () => {
        Animated.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: false }).start();
      },
    })
  ).current;

  // Map drag distance to degrees
  const rotateX = pan.y.interpolate({ inputRange: [-200, 200], outputRange: ['20deg', '-20deg'] });
  const rotateY = pan.x.interpolate({ inputRange: [-200, 200], outputRange: ['-20deg', '20deg'] });

  return (
    <Animated.View
      {...panResponder.panHandlers}
      style={{
        width: 300, height: 400,
        backgroundColor: '#6b21a8',
        borderRadius: 24,
        justifyContent: 'center', alignItems: 'center',
        // Pseudo-3D transforms
        transform: [
          { perspective: 1000 },
          { rotateX },
          { rotateY }
        ]
      }}
    >
      <Text style={{ color: '#fff', fontSize: 32, fontWeight: '700' }}>3D Card</Text>
    </Animated.View>
  );
};
  • True 3D models require react-three-fiber.
  • For UI perspective transforms, use the transform array: [{ perspective: 1000 }, { rotateX: '...' }, { rotateY: '...' }].
  • perspective MUST be the first item in the transform array for the effect to render correctly.

Jetpack Compose

@Composable
fun Card3D() {
    var offset by remember { mutableStateOf(Offset.Zero) }
    val animatedOffset by animateOffsetAsState(
        targetValue = offset,
        animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy)
    )

    Box(
        modifier = Modifier
            .size(300.dp, 400.dp)
            .pointerInput(Unit) {
                detectDragGestures(
                    onDrag = { change, dragAmount ->
                        change.consume()
                        offset += dragAmount
                    },
                    onDragEnd = { offset = Offset.Zero },
                    onDragCancel = { offset = Offset.Zero }
                )
            }
            .graphicsLayer {
                // Apply 3D rotation based on drag offset
                rotationX = -animatedOffset.y * 0.1f
                rotationY = animatedOffset.x * 0.1f
                cameraDistance = 8f * density // Sets the perspective
            }
            .shadow(20.dp, RoundedCornerShape(24.dp))
            .clip(RoundedCornerShape(24.dp))
            .background(Brush.linearGradient(listOf(Color.Blue, Color.Magenta)))
    ) {
        Text("3D Card",
            color = Color.White, fontSize = 32.sp, fontWeight = FontWeight.Bold,
            modifier = Modifier.align(Alignment.Center))
    }
}
  • Apply 3D transformations inside Modifier.graphicsLayer { }.
  • Set rotationX and rotationY for the tilt.
  • Critical: Set cameraDistance to establish the Z-axis perspective vanishing point. Usually 8f * density is a good starting point.

Do's and Don'ts

  • DO: Tie 3D rotation to user input (mouse move on web, device tilt on mobile) for maximum impact.
  • DON'T: Make text itself 3D unless it's a massive headline. 3D text is generally unreadable at small sizes.

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.