Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Web and App implementation guide for Widget-Based Design. Trigger when user wants modular blocks, iOS Home Screen aesthetics, and customizable mini-apps.
.claude/skills/lingxling-widget-based-design/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 105% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 153% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 123% | 0% |
> "Miniature applications. Small, highly functional blocks of UI designed to be rearranged."
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.
css.widget-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); grid-auto-rows: 160px; /* Force squares */ gap: 16px; padding: 32px; } .widget { background-color: #ffffff; border-radius: 24px; /* Classic iOS widget radius */ box-shadow: 0 8px 24px rgba(0,0,0,0.08); padding: 16px; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; position: relative; } /* Specific Sizes */ .widget-small { grid-column: span 1; grid-row: span 1; } .widget-medium { grid-column: span 2; grid-row: span 1; } .widget-large { grid-column: span 2; grid-row: span 2; } /* Weather Widget Example */ .widget.weather { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; } .weather-temp { font-size: 3rem; font-weight: 300; } .weather-icon { position: absolute; top: 16px; right: 16px; font-size: 2rem; }
swiftstruct WidgetDesignView: View { let columns = [GridItem(.flexible(), spacing: 16), GridItem(.flexible(), spacing: 16)] var body: some View { ScrollView { LazyVGrid(columns: columns, spacing: 16) { // 2x1 Widget WeatherWidget() .frame(height: 160) // Base unit height // 1x1 Widget FitnessWidget() .frame(height: 160) // 1x1 Widget MusicWidget() .frame(height: 160) } .padding(24) } .background(Color(white: 0.95)) } } struct WeatherWidget: View { var body: some View { ZStack(alignment: .topTrailing) { LinearGradient(colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")], startPoint: .topLeading, endPoint: .bottomTrailing) Image(systemName: "cloud.sun.fill") .foregroundColor(.white) .font(.system(size: 40)) .padding() VStack(alignment: .leading) { Spacer() Text("72°") .font(.system(size: 48, weight: .thin)) .foregroundColor(.white) Text("San Francisco") .font(.subheadline) .foregroundColor(.white.opacity(0.8)) } .frame(maxWidth: .infinity, alignment: .leading) .padding() } .cornerRadius(24) // Classic iOS widget radius .shadow(color: .black.opacity(0.1), radius: 10, y: 5) } }
LazyVGrid handles the layout, and cornerRadius(24) matches Apple's default widget styling perfectly.ZStack as the root of the widget to easily overlay content on top of complex gradients or images.dartclass WidgetDesignScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF2F2F2), body: GridView.count( crossAxisCount: 2, // 2 columns for a typical phone padding: const EdgeInsets.all(24), mainAxisSpacing: 16, crossAxisSpacing: 16, childAspectRatio: 1.0, // 1x1 squares children: [ // Note: Flutter GridView doesn't easily span rows/cols out of the box. // flutter_staggered_grid_view is highly recommended for real widget layouts. _buildWeatherWidget(), _buildFitnessWidget(), _buildMusicWidget(), ], ), ); } Widget _buildWeatherWidget() { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), gradient: const LinearGradient(colors: [Color(0xFF4FACFE), Color(0xFF00F2FE)]), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5))], ), padding: const EdgeInsets.all(16), child: Stack( children: [ const Align( alignment: Alignment.topRight, child: Icon(Icons.cloud, color: Colors.white, size: 40), ), Align( alignment: Alignment.bottomLeft, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('72°', style: TextStyle(color: Colors.white, fontSize: 48, fontWeight: FontWeight.w300)), Text('San Francisco', style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14)), ], ), ) ], ), ); } }
Stack inside a Container with BorderRadius.circular(24) is the blueprint for every widget.GridView is too rigid for mixed 2x1 and 1x1 widgets. Use the flutter_staggered_grid_view package for production apps.jsxconst WidgetDesignScreen = () => { return ( <ScrollView style={{ flex: 1, backgroundColor: '#F2F2F2' }} contentContainerStyle={{ padding: 24 }}> <View style={{ flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', gap: 16 }}> {/* 2x1 Widget (Full width minus padding) */} <View style={[styles.widget, { width: '100%' }]}> <LinearGradient colors={['#4facfe', '#00f2fe']} style={styles.widgetBg} /> <Text style={styles.temp}>72°</Text> <Text style={styles.sub}>San Francisco</Text> </View> {/* 1x1 Widgets (Half width minus half gap) */} <View style={[styles.widget, { width: '47%' }]}><Text>Fitness</Text></View> <View style={[styles.widget, { width: '47%' }]}><Text>Music</Text></View> </View> </ScrollView> ); }; const styles = StyleSheet.create({ widget: { height: 160, // Fixed height forces square/rectangular aspect ratios borderRadius: 24, backgroundColor: '#FFF', padding: 16, justifyContent: 'flex-end', shadowColor: '#000', shadowOffset: { width: 0, height: 5 }, shadowOpacity: 0.1, shadowRadius: 10, elevation: 5, overflow: 'hidden' }, widgetBg: { ...StyleSheet.absoluteFillObject, borderRadius: 24, }, temp: { fontSize: 48, fontWeight: '300', color: '#FFF' }, sub: { fontSize: 14, color: 'rgba(255,255,255,0.8)' } });
flexWrap: 'wrap' combined with percentage widths (e.g., 47% for 2 columns with a gap) is the cleanest way to build a responsive widget layout.LinearGradient from expo-linear-gradient or react-native-linear-gradient, apply StyleSheet.absoluteFillObject so it sits behind the text.kotlin@Composable fun WidgetDesignScreen() { LazyVerticalGrid( columns = GridCells.Fixed(2), modifier = Modifier.fillMaxSize().background(Color(0xFFF2F2F2)).padding(24.dp), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { // 2x1 Widget (Spans both columns) item(span = { GridItemSpan(2) }) { WeatherWidget(Modifier.height(160.dp)) } // 1x1 Widgets item { Box(Modifier.height(160.dp).background(Color.White, RoundedCornerShape(24.dp))) } item { Box(Modifier.height(160.dp).background(Color.White, RoundedCornerShape(24.dp))) } } } @Composable fun WeatherWidget(modifier: Modifier = Modifier) { Box( modifier = modifier .fillMaxWidth() .shadow(10.dp, RoundedCornerShape(24.dp)) .background(Brush.linearGradient(listOf(Color(0xFF4FACFE), Color(0xFF00F2FE))), RoundedCornerShape(24.dp)) .padding(16.dp) ) { // Icon Icon(Icons.Filled.Cloud, contentDescription = null, tint = Color.White, modifier = Modifier.align(Alignment.TopEnd).size(40.dp)) // Data Column(modifier = Modifier.align(Alignment.BottomStart)) { Text("72°", fontSize = 48.sp, fontWeight = FontWeight.Light, color = Color.White) Text("San Francisco", fontSize = 14.sp, color = Color.White.copy(alpha = 0.8f)) } } }
LazyVerticalGrid with GridCells.Fixed(2) and GridItemSpan perfectly recreate iOS widget grids.RoundedCornerShape(24.dp) is essential to sell the look.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 14,957 | 19,591 | +31% | 1 | 1 | 0% | 2,887 | 5,455 | +89% | 0 | 0 | — |
case-02 | pass→pass | 7,085 | 5,687 | -20% | 1 | 1 | 0% | 1,027 | 3,683 | +259% | 0 | 0 | — |
case-03 | fail→fail | 13,953 | 27,379 | +96% | 1 | 1 | 0% | 2,602 | 8,424 | +224% | 0 | 0 | — |
case-04 | fail→pass | 18,790 | 14,983 | -20% | 1 | 1 | 0% | 2,777 | 5,690 | +105% | 0 | 0 | — |
case-05 | pass→pass | 12,249 | 12,903 | +5% | 1 | 1 | 0% | 2,196 | 4,521 | +106% | 0 | 0 | — |
case-06 | fail→pass | 15,308 | 10,367 | -32% | 1 | 1 | 0% | 2,068 | 4,273 | +107% | 0 | 0 | — |
case-07 | fail→fail | 18,794 | 26,120 | +39% | 1 | 1 | 0% | 3,535 | 8,433 | +139% | 0 | 0 | — |
case-08 | pass→pass | 16,445 | 11,812 | -28% | 1 | 1 | 0% | 2,326 | 4,719 | +103% | 0 | 0 | — |
case-09 | fail→pass | 18,264 | 21,837 | +20% | 1 | 1 | 0% | 2,988 | 7,553 | +153% | 0 | 0 | — |
case-10 | fail→pass | 11,610 | 4,182 | -64% | 1 | 1 | 0% | 2,034 | 3,436 | +69% | 0 | 0 | — |
case-11 | fail→fail | 21,141 | 14,591 | -31% | 1 | 1 | 0% | 2,817 | 5,476 | +94% | 0 | 0 | — |
case-12 | fail→pass | 17,882 | 17,974 | +1% | 1 | 1 | 0% | 2,415 | 5,379 | +123% | 0 | 0 | — |
case-13 | pass→pass | 13,670 | 16,276 | +19% | 1 | 1 | 0% | 2,207 | 5,851 | +165% | 0 | 0 | — |
case-14 | pass→pass | 12,854 | 13,480 | +5% | 1 | 1 | 0% | 1,879 | 4,827 | +157% | 0 | 0 | — |
case-15 | pass→pass | 21,821 | 10,820 | -50% | 1 | 1 | 0% | 3,490 | 4,748 | +36% | 0 | 0 | — |
case-16 | pass→pass | 16,209 | 14,380 | -11% | 1 | 1 | 0% | 2,681 | 5,170 | +93% | 0 | 0 | — |
case-17 | pass→pass | 11,143 | 10,704 | -4% | 1 | 1 | 0% | 2,278 | 4,602 | +102% | 0 | 0 | — |
case-18 | fail→pass | 15,331 | 3,292 | -79% | 1 | 1 | 0% | 2,225 | 3,408 | +53% | 0 | 0 | — |
case-19 | fail→fail | 13,231 | 10,574 | -20% | 1 | 1 | 0% | 2,022 | 4,431 | +119% | 0 | 0 | — |
case-20 | pass→pass | 21,383 | 34,497 | +61% | 1 | 1 | 0% | 4,864 | 9,358 | +92% | 0 | 0 | — |
case-21 | pass→pass | 50,914 | 48,423 | -5% | 1 | 1 | 0% | 8,219 | 11,073 | +35% | 0 | 0 | — |
case-22 | pass→fail | 27,308 | 37,670 | +38% | 1 | 1 | 0% | 4,731 | 11,069 | +134% | 0 | 0 | — |
case-23 | pass→pass | 28,187 | 39,821 | +41% | 1 | 1 | 0% | 5,854 | 11,068 | +89% | 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. 23 cases were attempted. The headline lift of +22 percentage points is the difference between those two pass rates over the 23 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.