starwars
Animated Star Wars themed widgets for Flutter.
Drop a playful BB-8 toggle into your app — complete with Tatooine sand, twin suns, stars, and a smooth day/night sky transition. Pixel-perfect fidelity from the original Uiverse.io design by Galahhad.
pub.dev tip: screenshots also appear in the package sidebar carousel (click the thumbnail next to the scores).
Features
| Widget | Description |
|---|---|
Bb8Toggle |
Animated BB-8 switch — day/night sky, Tatooine scenery, rolling droid |
HtmlWebView |
Shared HTML/CSS widget host for future Star Wars controls |
JsBridge |
Standard syncState / WidgetChannel contract between Flutter and HTML |
Platform support
| Platform | Supported | Engine |
|---|---|---|
| iOS | ✅ | Native WebView |
| Android | ✅ | Native WebView |
| Web | ✅ | iframe + postMessage |
| Windows / macOS / Linux | ❌ | — |
Performance: each instance uses ~5–15 MB RAM on mobile. Use 1–3 per screen. Not suitable for long lists or grids.
Installation
Add to pubspec.yaml:
dependencies:
starwars: ^0.5.2
flutter pub get
Quick start
Bb8Toggle requires WidgetsFlutterBinding.ensureInitialized() before runApp:
import 'package:flutter/material.dart';
import 'package:starwars/starwars.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool darkMode = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: darkMode
? const Color(0xFF101820)
: const Color(0xFFE8E8E8),
body: Center(
child: Bb8Toggle(
value: darkMode,
onChanged: (value) => setState(() => darkMode = value),
size: 32,
semanticsLabel: 'Dark mode',
),
),
),
);
}
}
Run the included example:
cd example
flutter pub get
flutter run -d chrome # Web
flutter run -d "iPhone 17" # iOS Simulator
flutter run -d android # Android
Bb8Toggle API
Bb8Toggle(
value: isOn, // false = day, true = night
onChanged: (v) => ..., // null = disabled
size: 16, // 1em = size logical pixels (default 16)
semanticsLabel: 'BB-8 toggle',
lazy: false, // defer WebView/iframe init until first frame
)
| Parameter | Type | Default | Description |
|---|---|---|---|
value |
bool |
required | false = day sky, true = night sky |
onChanged |
ValueChanged<bool>? |
required | Called when toggled. null disables interaction |
size |
double |
16 |
Scale factor (16 = original Uiverse size) |
semanticsLabel |
String |
'BB-8 toggle' |
Screen reader label |
lazy |
bool |
false |
Defer WebView/iframe creation until after first frame |
Size guide
size |
Approx. width × height | Best for |
|---|---|---|
16 |
170 × 119 px | Compact settings rows |
24 |
255 × 179 px | Standard controls |
32 |
340 × 238 px | Hero / demo screens |
Disabled state
Bb8Toggle(
value: true,
onChanged: null, // disables tap and dims the widget
size: 24,
)
Lazy loading (off-screen widgets)
Bb8Toggle(
value: value,
onChanged: onChanged,
lazy: true, // useful in tabs or scroll views
)
How it works
Bb8Toggle renders the original HTML/CSS inside a platform view:
┌─────────────────────────────────────┐
│ Bb8Toggle (Flutter widget) │
│ ┌───────────────────────────────┐ │
│ │ HtmlWebView │ │
│ │ iOS/Android → WebView │ │
│ │ Web → iframe │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ bb8_toggle.html (CSS) │ │ │
│ │ │ BB-8 + Tatooine scenery │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
│ ↕ JsBridge │
│ syncState() / WidgetChannel │
└─────────────────────────────────────┘
- Flutter → HTML:
syncState({ value, enabled }) - HTML → Flutter:
WidgetChannel.postMessage({ type: 'changed', value })
Adding a custom HTML widget
- Add
assets/html/your_widget.htmland registerassets/html/inpubspec.yaml. - Implement the JS bridge in your HTML:
window.syncState = (state) => {
// apply state from Flutter
};
// On user interaction:
WidgetChannel.postMessage(JSON.stringify({ type: 'changed', value: true }));
- Use CSS variables for runtime sizing (recommended over
{{PLACEHOLDER}}):
:root {
--sw-viewport-width: 200px;
--sw-viewport-height: 100px;
}
- Wrap with
HtmlWebView:
HtmlWebView(
assetPath: StarWarsAssets.html('your_widget.html'),
width: 200,
height: 100,
contentKey: size,
syncState: JsBridge.toggleState(value: myValue, enabled: true),
buildHtml: (template) => template, // inject :root vars here
onMessage: (message) {
final next = JsBridge.changedBoolValue(message);
if (next != null) onChanged(next);
},
)
Package layout
lib/src/webview/ # HtmlWebView, JsBridge, template cache
assets/html/ # one HTML file per widget
lib/src/widgets/ # public Flutter widgets (Bb8Toggle, …)
doc/screenshots/ # README / pub.dev images
Regenerating screenshots
Place source media in assets/bb8/:
*.mov— screen recording for the animated GIF*.png— iOS simulator screenshots (day / night)
Then run:
chmod +x tool/generate_screenshots.sh
./tool/generate_screenshots.sh
Output lands in doc/screenshots/ (bb8_demo.gif, bb8_day.png, bb8_night.png).
Publishing to pub.dev
Images in the README must use absolute GitHub URLs (?raw=true). pub.dev does not render relative paths or local doc/screenshots/ links.
Before publishing:
- Create the GitHub repo and push the package (including
doc/screenshots/):
cd code/modules/flutter/starwars
git init
git add .
git commit -m "Initial starwars package"
git branch -M main
git remote add origin https://github.com/ignaciowinitzky/starwars.git
git push -u origin main
- Publish:
flutter pub publish
Ensure homepage, repository, and issue_tracker in pubspec.yaml match your public GitHub repo.
Credits & legal
- BB-8 toggle design: Uiverse.io by Galahhad
- Not affiliated with Lucasfilm Ltd. or The Walt Disney Company.
Links
Libraries
- starwars
- Star Wars themed Flutter widgets.