skribble 0.1.1
skribble: ^0.1.1 copied to clipboard
Hand-drawn UI components for Flutter. 80+ sketchy widgets with familiar Material and Cupertino APIs — buttons, inputs, navigation, dialogs, and more, all with a hand-drawn aesthetic.
skribble #
Hand-drawn UI components for Flutter — every widget looks like it was sketched by hand, with drop-in familiar Material and Cupertino APIs.
Getting Started #
import 'package:skribble/skribble.dart';
Use WiredMaterialApp to customize colors across all Skribble widgets while keeping Material theming aligned:
final wiredTheme = WiredThemeData(
borderColor: Color(0xFF2D1B69), // Sketchy border color
textColor: Colors.black87,
fillColor: Color(0xFFFFF8E1), // Warm paper background
strokeWidth: 2,
roughness: 1,
);
WiredMaterialApp(
wiredTheme: wiredTheme,
home: const WiredScaffold(/* ... */),
);
Router-based apps are supported too:
WiredMaterialApp.router(
wiredTheme: wiredTheme,
routerConfig: appRouter,
);
Both constructors also expose high-value MaterialApp bootstrapping options like locale resolution callbacks, restoration, scroll behavior, shortcuts / actions, generated titles, theme animation controls, high-contrast theme variants, and common debug / diagnostics flags.
All wired widget implementations read from the nearest WiredTheme ancestor and fall back to defaults when no theme is provided. WiredThemeData also exposes toColorScheme() and toThemeData() helpers so your app shell, text, and Material fallbacks stay aligned with the Skribble palette, while WiredMaterialApp and WiredMaterialApp.router keep MaterialApp and WiredTheme synchronized.
Widget Catalog #
Buttons #
| Widget | Description |
|---|---|
WiredButton |
Hand-drawn rectangle border button |
WiredElevatedButton |
Elevated button with offset shadow |
WiredFilledButton |
Solid hachure-filled button |
WiredFloatingActionButton |
Hand-drawn circular FAB |
WiredIconButton |
Icon button with circle border |
WiredOutlinedButton |
Thick hand-drawn outlined button |
WiredTextButton |
Text button with sketchy underline |
WiredToggleButtons |
Multi-toggle button group |
WiredSegmentedButton |
Segmented button group with WiredButtonSegment |
WiredCupertinoButton |
Cupertino-style press-opacity button (+ .filled) |
Inputs #
| Widget | Description |
|---|---|
WiredInput |
Text field with sketchy rectangle border |
WiredTextArea |
Multiline text input |
WiredSearchBar |
Search input with sketchy border |
WiredCheckbox |
Hand-drawn checkbox |
WiredCheckboxListTile |
Checkbox with list tile layout |
WiredRadio |
Hand-drawn radio button |
WiredRadioListTile |
Radio with list tile layout |
WiredSwitch |
Hand-drawn toggle switch |
WiredSwitchListTile |
Switch with list tile layout |
WiredSlider |
Slider with sketchy track and thumb |
WiredRangeSlider |
Dual-handle range slider |
WiredToggle |
Simple on/off toggle |
WiredForm |
Form container with validation |
WiredAutocomplete |
Autocomplete with sketchy dropdown |
WiredCupertinoTextField |
Cupertino rounded border text field |
WiredCupertinoSlider |
Cupertino slider with hand-drawn track |
WiredCupertinoSwitch |
Cupertino toggle with animated thumb |
Navigation #
| Widget | Description |
|---|---|
WiredAppBar |
App bar with sketchy bottom border |
WiredBottomNavigationBar |
Bottom nav with sketchy top border |
WiredNavigationBar |
M3 navigation bar with WiredNavigationDestination |
WiredNavigationRail |
Vertical rail with WiredNavigationRailDestination |
WiredNavigationDrawer |
M3 drawer with WiredNavigationDrawerDestination |
WiredTabBar |
Tab bar with sketchy indicator |
WiredDrawer |
Side drawer panel |
WiredPopupMenuButton |
Popup menu with WiredPopupMenuItem |
WiredMenuBar |
M3 menu bar with WiredSubmenuButton / WiredMenuItemButton |
WiredDropdownMenu |
M3 dropdown menu (in wired_menu_bar.dart) |
WiredBottomAppBar |
M3 bottom bar with sketchy top border |
WiredSliverAppBar |
Collapsible sliver app bar |
WiredCupertinoNavigationBar |
Cupertino nav bar |
WiredCupertinoTabBar |
Cupertino bottom tab bar |
Selection #
| Widget | Description |
|---|---|
WiredChip |
Basic chip with hand-drawn border |
WiredChoiceChip |
Selectable chip |
WiredFilterChip |
Filter chip with checkmark |
WiredInputChip |
Deletable input chip |
WiredActionChip |
Action chip (in wired_input_chip.dart) |
WiredCombo |
Dropdown combo box |
WiredDatePicker / WiredTimePicker |
Date and time pickers |
WiredCalendarDatePicker |
Inline calendar picker |
WiredColorPicker |
Grid of sketchy circle color swatches |
WiredCupertinoPicker |
Cupertino wheel picker |
WiredCupertinoDatePicker |
Cupertino date/time picker |
WiredCupertinoSegmentedControl |
Cupertino segmented control |
WiredSlidingSegmentedControl |
Cupertino sliding segment control |
Feedback #
| Widget | Description |
|---|---|
WiredDialog |
Dialog with hand-drawn border |
WiredSnackBarContent / showWiredSnackBar |
Snack bar with sketchy border |
WiredTooltip |
Tooltip with hand-drawn background |
WiredProgress |
Linear progress bar with hachure fill |
WiredCircularProgress |
Circular progress with sketchy arc |
WiredBadge |
Notification badge with hand-drawn circle |
WiredBottomSheet |
Bottom sheet with sketchy top border |
WiredAboutDialog / showWiredAboutDialog |
Hand-drawn about dialog |
WiredContextMenu |
Long-press context menu with WiredContextMenuAction |
WiredAnimatedIcon |
Animated icon with Skribble styling |
WiredMaterialBanner |
Persistent banner with sketchy borders |
WiredCupertinoAlertDialog |
Cupertino alert with WiredCupertinoDialogAction |
WiredCupertinoActionSheet |
Cupertino action sheet with WiredCupertinoActionSheetAction |
Layout #
| Widget | Description |
|---|---|
WiredCard |
Card with hand-drawn rectangle border |
WiredDivider |
Hand-drawn horizontal line |
WiredListTile |
List tile with sketchy border |
WiredExpansionTile |
Expandable tile with sketchy border |
WiredDataTable |
Data table with WiredDataColumn / WiredDataRow |
WiredStepper |
Step-by-step indicator with WiredStep |
WiredCalendar |
Full calendar with sketchy cells |
WiredScrollbar |
Styled scrollbar with sketchy colors |
WiredScaffold |
Material page shell with paper-like background |
WiredReorderableListView |
Reorderable list with sketchy items |
WiredDismissible |
Swipe-to-dismiss with sketchy background |
WiredSelectableText |
Selectable text with Skribble styling |
WiredDrawerHeader / WiredUserAccountsDrawerHeader |
Drawer headers |
WiredAvatar |
Hand-drawn circle avatar |
WiredPageScaffold / WiredTabScaffold |
Cupertino scaffold layouts |
Theming #
| Widget | Description |
|---|---|
WiredTheme |
InheritedWidget providing theme to descendants |
WiredThemeData |
Border, text, fill colors + stroke width, roughness |
WiredThemeData.toThemeData() |
Material ThemeData bridge for app-level theming |
WiredMaterialApp |
Material app wrapper that syncs WiredTheme + theme |
WiredMaterialApp.router |
Router-based app wrapper with the same theme syncing |
| High-contrast wired themes | Optional high-contrast light/dark app theme variants |
API Patterns #
All Skribble widgets follow familiar Flutter conventions:
Wired*prefix mirrors the Flutter widget it replaces- Same constructor params:
child,onPressed,onChanged,value,selectedIndex HookWidgetonly — noStatefulWidgetorStatelessWidgetWiredTheme.of(context)for runtime color customizationRepaintBoundarywraps every widget for render isolation
Quality #
dart analyze --fatal-infos .passes with zero issues.- Widget, rough-engine, tool, and storybook suites are validated in CI.
- Screenshot artifacts are tracked in
docs/ui-snapshots/screenshot-manifest.txt.
Rough Icon Generation Pipeline #
Generate/refresh rough Material icons:
# Optional: pre-fetch Deno deps for faster first run
cd packages/skribble
deno cache tool/deno/svg2roughjs_cli.ts
dart run tool/generate_rough_icons.dart \
--kit flutter-material \
--rough-output-dir tool/icon_exports/rough-svg \
--font-output-dir tool/icon_exports/font \
--font-dart-output lib/src/generated/material_rough_icon_font.g.dart
Workspace shortcuts:
melos run rough-icons
melos run rough-icons-font
melos run rough-icons-baseline
melos run rough-icons-ci-check
rough-icons and rough-icons-font both apply the committed supplemental manifest (tool/examples/material_rough_icons.supplemental.manifest.json) and enforce unresolved regression gating via --unresolved-baseline tool/examples/material_rough_icons.unresolved-baseline.json plus --max-new-unresolved 0 (strict-mode equivalent). Use rough-icons-baseline to refresh that committed codePoints[] baseline file after intentional changes.
rough-icons-ci-check runs the same rough icon regression/sync checks enforced by CI via ./scripts/check_rough_icons_ci.sh all.
For targeted local debugging, run an individual CI-equivalent check:
./scripts/check_rough_icons_ci.sh regression./scripts/check_rough_icons_ci.sh baseline-sync./scripts/check_rough_icons_ci.sh generated-sync
On sync-check failures, the script prints git diff output and writes:
rough-icons-baseline-sync.diffrough-icons-generated-sync.diff
regression cleans up packages/skribble/unresolved-report.json after a successful local run. Set ROUGH_ICONS_KEEP_UNRESOLVED_REPORT=1 to keep it. Set ROUGH_ICONS_MAX_UNRESOLVED=<int> to enable total unresolved gating via --max-unresolved (default: disabled). By default, regression/generated-sync checks use --max-new-unresolved 0 (strict-mode equivalent). Set ROUGH_ICONS_MAX_NEW_UNRESOLVED=<int> to relax or tighten that threshold.
Pull-request CI explicitly sets ROUGH_ICONS_MAX_NEW_UNRESOLVED=0 for those checks to keep workflow configuration aligned with local defaults.
Pull-request CI also runs the unresolved gate in --rough-only mode, uploads a rough-icons-unresolved-report artifact for diagnostics, verifies the committed baseline file is up to date, checks that generated rough icon catalog files are committed/synced, and uploads diff artifacts (rough-icons-baseline-sync-diff, rough-icons-generated-sync-diff) when those sync checks fail.
Useful flags:
--list-kitsto print available icon-kit providers.--kit svg-manifest --manifest <path>to rough non-Material icon sets from JSON manifests (uniqueidentifier/codePointrequired;codePointsupports int, decimal string,0xhex, bare hex, andU+hex forms).--rough-onlyto skip Dart map generation and emit rough SVGs only.--rough-normalize-viewbox 128to upscale SVG geometry before roughing.--brand-icons-source <path>to provide a localsimple-iconspackage as fallback for brand identifiers missing in Material SVG packages.--supplemental-manifest <path>to provide custom SVGs for unresolvedflutter-materialidentifiers/codepoints (workspace defaults usetool/examples/material_rough_icons.supplemental.manifest.json).--unresolved-output <path>to emit unresolved icon codepoints/identifiers as JSON for follow-up manifest authoring (includesunresolved[]plusunresolvedCodePoints[], baseline-diff summary arrays when enabled, gate mode metadata, threshold metadata fields when unresolved gating thresholds are configured, awouldFailsummary boolean, per-gate failure booleans, anactiveGates[]configured-gates summary list, and afailedGates[]summary list).--unresolved-baseline-output <path>to emit a normalized unresolved baseline for regression gating (defaults tounresolved[]).--unresolved-baseline-output-format <unresolved|codepoints>to choose unresolved baseline output shape (unresolved[]orcodePoints[]; workspace defaults usecodepoints).--supplemental-manifest-output <path>to emit a starter supplemental manifest template for unresolved icons.--unresolved-baseline <path>to compare unresolved output against a baseline report (unresolved[]), manifest (icons[]), or minimal baseline (unresolvedCodePoints[]/unresolvedCodePoint[]/unresolvedCodepoint[]/unresolvedCodepoints[]/unresolved_code_points[]/unresolved_codepoint[]/unresolved_codepoints[]/unresolved-code-points[]/unresolved-codepoints[]/codePoints[], also acceptscodePoint[]/codepoints[]/codepoint[]/code_points[]/code-points[]), includingnewUnresolvedandresolvedSinceBaselinereport fields. For object entries inunresolved[]/icons[], the code point field may becodePoint,codepoint,code_point, orcode-point. String code points accept decimal,0xhex, bare hex, andU+hex forms.--max-unresolved <int>to allow a bounded unresolved count before failing.--fail-on-unresolvedto make the command exit non-zero if unresolved icons remain (cannot be combined with--max-unresolved).--max-new-unresolved <int>to allow a bounded number of newly unresolved entries versus baseline before failing (requires--unresolved-baseline).--fail-on-new-unresolvedto fail only when unresolved entries regress versus baseline (cannot be combined with--max-new-unresolved).--font-name skribble_rough_iconsto customize generated font family name.--font-dart-output <path>to emit Dart lookup helpers for generated font codepoints.CHROME_PATH=/path/to/chromeif Chromium/Chrome is not in a standard location.
Runtime helpers exposed by wired_icon.dart:
lookupMaterialRoughIconByIdentifier('search')→WiredSvgIconData?lookupMaterialRoughFontIcon('search')→IconData?for generated font usagematerialRoughIconIdentifiers/materialRoughFontCodePoints(includes legacy alias identifiers that share codepoints)materialRoughFontFamily
Contributing #
See CONTRIBUTING.md for development setup, widget conventions, testing requirements, and quality gates.
Docs #
- Parity Matrix — coverage vs Flutter defaults
- Screenshot Manifest — all visual snapshots
- Rough Icon Pipeline — icon generation and font tooling
- CHANGELOG — release history
License #
MIT — see LICENSE for details.
Choose the amount of hand-drawn ink #
Set WiredThemeData(roughnessLevel: WiredRoughness.gentle) on your WiredMaterialApp. The gentle, playful, and expressive presets coordinate borders, rough icons, and all four bundled font styles. Playful is the default. Nested WiredTheme scopes can select another level while retaining the parent palette through copyWith; explicit fonts and drawing configurations remain overrides. See the theming guide for custom font generation and inheritance details.
Typeface choices and brand icons #
Set font: WiredFont.casual, WiredFont.linear, or WiredFont.mono on WiredThemeData. Each choice follows the inherited roughness. Mono retains equal character spacing for code. These are static fonts with four genuine faces (400/700, upright/italic); they do not contain a variable-weight axis. Compare all three families.
Use WiredSvgIcon(data: WiredBrandIcon.github.data) for a curated Simple Icons brand mark. GitHub, Dart, Flutter, and Figma support solid and hatched ink through the same vector renderer as Material icons. See the examples and generation command.