Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Web and App implementation guide for Tile Design. Trigger when user wants Microsoft Metro style, sharp square information units, and horizontal scrolling grids.
.claude/skills/lingxling-tile-design/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 45% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 80% | 0% |
> "Authentically digital. Clean, sharp squares relying purely on typography and flat color."
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.
Segoe UI Light). Text is almost always pure white.cssbody { background-color: #111; color: #fff; font-family: 'Segoe UI', sans-serif; overflow-x: auto; /* Horizontal scroll */ } .tile-group { display: grid; grid-template-columns: repeat(4, 150px); grid-auto-rows: 150px; gap: 8px; padding: 40px; } .tile { background-color: #0078D7; /* Classic Windows Blue */ padding: 12px; display: flex; flex-direction: column; justify-content: space-between; cursor: pointer; /* The "tilt" click effect */ transition: transform 0.1s; transform-origin: center; } .tile:active { transform: scale(0.95); } .tile-wide { grid-column: span 2; } .tile-large { grid-column: span 2; grid-row: span 2; } /* Live Tile Animation */ .tile-live-content { animation: slideUp 5s infinite; } @keyframes slideUp { 0%, 45% { transform: translateY(0); } 50%, 95% { transform: translateY(-100%); } /* Slides up to reveal next item */ 100% { transform: translateY(0); } }
swiftstruct TileDesignView: View { let rows = [GridItem(.fixed(150), spacing: 8), GridItem(.fixed(150), spacing: 8)] var body: some View { ScrollView(.horizontal, showsIndicators: false) { LazyHGrid(rows: rows, spacing: 8) { TileView(title: "Mail", color: Color(hex: "0078D7"), icon: "envelope") TileView(title: "Photos", color: Color(hex: "00CC6A"), icon: "photo", isLarge: true) TileView(title: "Weather", color: Color(hex: "2D7D9A"), icon: "cloud.sun") TileView(title: "Calendar", color: Color(hex: "D13438"), icon: "calendar") } .padding(40) } .background(Color(hex: "111111").ignoresSafeArea()) } } struct TileView: View { let title: String let color: Color let icon: String var isLarge: Bool = false @State private var isPressed = false var body: some View { VStack(alignment: .leading) { Image(systemName: icon) .font(.system(size: 32, weight: .light)) .foregroundColor(.white) Spacer() Text(title) .font(.custom("Segoe UI", size: 16)) .foregroundColor(.white) } .padding(16) // Sharp corners are mandatory .frame(width: isLarge ? 308 : 150, height: isLarge ? 308 : 150, alignment: .leading) .background(color) .scaleEffect(isPressed ? 0.95 : 1.0) .animation(.spring(response: 0.2, dampingFraction: 0.5), value: isPressed) .onLongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity, pressing: { pressing in isPressed = pressing }, perform: {}) } }
LazyHGrid inside a horizontal ScrollView perfectly replicates the Windows Phone / Windows 8 start screen.isPressed state triggering a .scaleEffect(0.95) replicates the physical "tilt" interaction of Metro tiles.dartclass TileDesignScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF111111), body: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.all(40), child: SizedBox( height: 308, // Two rows of 150px + 8px spacing child: Wrap( direction: Axis.vertical, spacing: 8, runSpacing: 8, children: [ _buildTile('Mail', const Color(0xFF0078D7), Icons.mail_outline), _buildTile('Weather', const Color(0xFF2D7D9A), Icons.cloud_outlined), _buildTile('Photos', const Color(0xFF00CC6A), Icons.photo_outlined, isLarge: true), _buildTile('Calendar', const Color(0xFFD13438), Icons.calendar_today), ], ), ), ), ); } Widget _buildTile(String title, Color color, IconData icon, {bool isLarge = false}) { return StatefulBuilder( builder: (context, setState) { bool isPressed = false; return GestureDetector( onTapDown: (_) => setState(() => isPressed = true), onTapUp: (_) => setState(() => isPressed = false), onTapCancel: () => setState(() => isPressed = false), child: AnimatedScale( scale: isPressed ? 0.95 : 1.0, duration: const Duration(milliseconds: 100), child: Container( width: isLarge ? 308 : 150, height: isLarge ? 308 : 150, color: color, // Sharp corners padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(icon, color: Colors.white, size: 32), Text(title, style: const TextStyle(color: Colors.white, fontFamily: 'Segoe UI', fontSize: 16)), ], ), ), ), ); } ); } }
Wrap with direction: Axis.vertical inside a horizontally scrolling SizedBox is the easiest way to build a Metro grid that flows left-to-right.GestureDetector and AnimatedScale to handle the press animation.jsxconst TileDesignScreen = () => { return ( <ScrollView horizontal style={{ flex: 1, backgroundColor: '#111' }} contentContainerStyle={{ padding: 40 }}> <View style={{ flexDirection: 'column', flexWrap: 'wrap', height: 308, gap: 8 }}> <Tile title="Mail" color="#0078D7" /> <Tile title="Weather" color="#2D7D9A" /> <Tile title="Photos" color="#00CC6A" isLarge /> <Tile title="Calendar" color="#D13438" /> </View> </ScrollView> ); }; const Tile = ({ title, color, isLarge }) => { const scale = useRef(new Animated.Value(1)).current; const handlePressIn = () => Animated.spring(scale, { toValue: 0.95, useNativeDriver: true }).start(); const handlePressOut = () => Animated.spring(scale, { toValue: 1, useNativeDriver: true }).start(); return ( <TouchableWithoutFeedback onPressIn={handlePressIn} onPressOut={handlePressOut}> <Animated.View style={{ width: isLarge ? 308 : 150, height: isLarge ? 308 : 150, backgroundColor: color, padding: 16, justifyContent: 'space-between', transform: [{ scale }] // The Metro tilt effect }}> <View style={{ width: 32, height: 32, backgroundColor: '#FFF', opacity: 0.5 }} /> <Text style={{ color: '#FFF', fontFamily: 'Segoe UI', fontSize: 16 }}>{title}</Text> </Animated.View> </TouchableWithoutFeedback> ); };
<ScrollView horizontal> combined with a child <View> that has a fixed height and flexWrap: 'wrap', flexDirection: 'column'. This forces children to form columns and flow horizontally.Animated.View and TouchableWithoutFeedback to create the scale animation.kotlin@Composable fun TileDesignScreen() { LazyHorizontalGrid( rows = GridCells.Fixed(2), modifier = Modifier.fillMaxSize().background(Color(0xFF111111)), contentPadding = PaddingValues(40.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { item(span = { GridItemSpan(1) }) { Tile("Mail", Color(0xFF0078D7)) } // Note: LazyHorizontalGrid doesn't easily support spanning multiple rows (2x2 tiles). // For a true Metro layout, you often have to build a custom Layout or use staggered grids. item(span = { GridItemSpan(2) }) { Tile("Photos Wide", Color(0xFF00CC6A)) } item(span = { GridItemSpan(1) }) { Tile("Weather", Color(0xFF2D7D9A)) } } } @Composable fun Tile(title: String, color: Color) { var isPressed by remember { mutableStateOf(false) } val scale by animateFloatAsState(if (isPressed) 0.95f else 1.0f) Box( modifier = Modifier .size(150.dp) // Or wide/large based on params .scale(scale) .background(color) // Sharp corners! No RoundedCornerShape .pointerInput(Unit) { detectTapGestures( onPress = { isPressed = true tryAwaitRelease() isPressed = false } ) } .padding(16.dp) ) { // Icon Box(modifier = Modifier.size(32.dp).background(Color.White.copy(alpha = 0.5f)).align(Alignment.TopStart)) // Text Text( text = title, color = Color.White, fontFamily = FontFamily.SansSerif, modifier = Modifier.align(Alignment.BottomStart) ) } }
LazyHorizontalGrid is the right tool, though building true 2x2 "Large" tiles requires custom layout math in Compose if mixing with 1x1 tiles.Modifier.scale() paired with pointerInput detectTapGestures handles the Metro interaction.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 15,687 | 26,460 | +69% | 1 | 1 | 0% | 3,303 | 6,004 | +82% | 0 | 0 | — |
case-02 | pass→pass | 16,017 | 11,283 | -30% | 1 | 1 | 0% | 2,500 | 5,044 | +102% | 0 | 0 | — |
case-03 | fail→fail | 26,947 | 32,983 | +22% | 1 | 1 | 0% | 5,062 | 9,448 | +87% | 0 | 0 | — |
case-04 | pass→pass | 19,638 | 13,264 | -32% | 1 | 1 | 0% | 3,020 | 5,176 | +71% | 0 | 0 | — |
case-05 | pass→pass | 17,310 | 7,073 | -59% | 1 | 1 | 0% | 2,761 | 4,135 | +50% | 0 | 0 | — |
case-06 | fail→pass | 25,686 | 30,490 | +19% | 1 | 1 | 0% | 4,106 | 7,674 | +87% | 0 | 0 | — |
case-07 | fail→fail | 25,358 | 18,806 | -26% | 1 | 1 | 0% | 3,971 | 5,784 | +46% | 0 | 0 | — |
case-08 | pass→fail | 38,912 | 29,349 | -25% | 1 | 1 | 0% | 5,061 | 7,881 | +56% | 0 | 0 | — |
case-09 | fail→pass | 22,124 | 16,943 | -23% | 1 | 1 | 0% | 3,556 | 6,309 | +77% | 0 | 0 | — |
case-10 | pass→pass | 26,772 | 26,163 | -2% | 1 | 1 | 0% | 5,747 | 8,546 | +49% | 0 | 0 | — |
case-11 | fail→pass | 35,010 | 21,790 | -38% | 1 | 1 | 0% | 4,625 | 6,717 | +45% | 0 | 0 | — |
case-12 | fail→pass | 17,004 | 17,137 | +1% | 1 | 1 | 0% | 3,053 | 5,496 | +80% | 0 | 0 | — |
case-13 | pass→pass | 13,248 | 7,071 | -47% | 1 | 1 | 0% | 1,895 | 3,999 | +111% | 0 | 0 | — |
case-14 | pass→pass | 6,356 | 3,100 | -51% | 1 | 1 | 0% | 946 | 3,351 | +254% | 0 | 0 | — |
case-15 | pass→pass | 14,214 | 13,244 | -7% | 1 | 1 | 0% | 2,140 | 4,674 | +118% | 0 | 0 | — |
case-16 | pass→pass | 15,802 | 9,102 | -42% | 1 | 1 | 0% | 2,297 | 4,428 | +93% | 0 | 0 | — |
case-17 | pass→pass | 8,031 | 4,352 | -46% | 1 | 1 | 0% | 1,150 | 3,636 | +216% | 0 | 0 | — |
case-18 | pass→pass | 17,008 | 5,931 | -65% | 1 | 1 | 0% | 2,549 | 3,957 | +55% | 0 | 0 | — |
case-19 | pass→pass | 16,275 | 8,227 | -49% | 1 | 1 | 0% | 2,811 | 4,199 | +49% | 0 | 0 | — |
case-20 | pass→pass | 15,480 | 8,508 | -45% | 1 | 1 | 0% | 2,376 | 4,518 | +90% | 0 | 0 | — |
case-21 | fail→pass | 11,510 | 33,681 | +193% | 1 | 1 | 0% | 2,127 | 4,757 | +124% | 0 | 0 | — |
case-22 | pass→pass | 25,558 | 30,981 | +21% | 1 | 1 | 0% | 3,958 | 10,022 | +153% | 0 | 0 | — |
case-23 | pass→pass | 39,713 | 39,102 | -2% | 1 | 1 | 0% | 8,220 | 11,220 | +36% | 0 | 0 | — |
case-24 | pass→pass | 20,920 | 23,345 | +12% | 1 | 1 | 0% | 3,164 | 6,515 | +106% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +21 percentage points is the difference between those two pass rates over the 24 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.