⚡ ZERO (package:zero)

Pub Version License: MIT Buy Me A Coffee GitHub Sponsors

Next-Generation 120Hz Reactive State Engine for Flutter — Element-Bypass Rendering, Speculative Prefetching, Zero-Copy Isolates, Adaptive A2UI Topologies, and Incremental $O(1)$ HLC-CRDTs.

Published and maintained by RedLight Apps (redlightapps.com) • Created by Yusuf Kaval


🌍 Multi-Language Documentation (Zero-to-Hero Guides)

Language Complete Manual Link
🇬🇧 English Read English Guide in DOCUMENTATION.md • doc/EN_GUIDE.md
🇹🇷 Türkçe DOCUMENTATION.md Türkçe Tam Rehber • doc/TR_GUIDE.md
🇪🇸 Español Leer la Guía Completa en Español en DOCUMENTATION.md
🇩🇪 Deutsch Vollständiges Handbuch auf Deutsch in DOCUMENTATION.md lesen
🇫🇷 Français Lire le Guide Complet en Français dans DOCUMENTATION.md
🇨🇳 简体中文 在 DOCUMENTATION.md 中阅读简体中文从零开始的完整使用与集成指南
🇯🇵 日本語 DOCUMENTATION.md で日本語の完全導入・活用ガイドを読む
🇰🇷 한국어 DOCUMENTATION.md에서 한국어 초보자부터 전문가까지 완벽 사용 가이드 읽기
🇧🇷 Português Ler o Guia Completo em Português em DOCUMENTATION.md
🇷🇺 Русский Читать полное руководство на русском языке в DOCUMENTATION.md
🇸🇦 العربية اقرأ الدليل الشامل باللغة العربية في DOCUMENTATION.md

1. What is zero and Why Does It Exist?

Think of traditional Flutter state management like repainting an entire room every time a clock hand ticks. Whenever a variable changes in setState, ValueNotifier, Bloc, or Riverpod, Flutter marks an Element dirty, schedules a frame, runs Widget.build(), allocates new Widget instances, diffs the element tree, and finally reaches the RenderObject or GPU.

At 60Hz on simple screens, you barely notice. At 120Hz ProMotion with live order books, audio spectrums, canvas visualizations, shaders, offline-first sync, or speculative network prefetching, rebuilding the Widget tree on every tick wastes precious frame budget (< 8.33ms).

zero solves both sides of Flutter state management in a single, zero-dependency, pure widgets.dart package:

  1. Ergonomic Everyday Reactivity: Simple, boilerplate-free reactive cells (ZeroCell), declarative widgets (ZeroBuilder, ZeroSelector, ZeroConsumer, ZeroListener, ZeroScope), context.watch / read / select, diamond-glitch-free ZeroComputed graphs, undo/redo history, local persistence, and deduplicated async resource cells.
  2. Five Next-Generation Engine Pillars: Direct Element-Bypass rendering (0 widget rebuilds), Tri-Modal Speculative Intent Prefetching, Zero-Copy TransferableTypedData Background Isolates, Adaptive A2UI FrameTiming Topologies, and Incremental $O(1)$ Hybrid Logical Clock (HLC) CRDT stores with automatic server rollback.

Architectural Comparison

Capability setState / ValueNotifier flutter_bloc riverpod signals zero (package:zero)
Zero Boilerplate Reactive Cells ✅ ❌ ⚠️ ✅ ✅ (ZeroCell<T>)
Diamond-Glitch-Free Topological DAG ❌ ❌ ✅ ✅ ✅ (ZeroComputed + ZeroBatch)
Lazy Auto-Unsubscribing .select() ❌ ⚠️ ✅ ✅ ✅ (DerivedCell — 0 zombie listeners)
In-Flight Async Coalescing & ABA Guard ❌ ❌ ⚠️ ❌ ✅ (fetchDeduped + DeterministicRequestCoalescer)
Pillar 1: Element-Bypass (0 Widget Rebuilds) ❌ ❌ ❌ ❌ ✅ (ZeroPaintSurface, ZeroLayerBypass, ZeroShaderSurface)
Pillar 2: Speculative Intent & Shadow Cache ❌ ❌ ❌ ❌ ✅ (TriModalIntentTracker + ShadowStateCache)
Pillar 3: $O(1)$ Zero-Copy Isolate Graph ❌ ❌ ❌ ❌ ✅ (AutonomousIsolateGraph + ZeroGenericIsolateGraph)
Pillar 4: 120Hz FrameTiming A2UI Topology ❌ ❌ ❌ ❌ ✅ (ContextDecisionGraph + ZeroA2UiTopologyHost)
Pillar 5: $O(1)$ HLC-CRDT & Optimistic Rollback ❌ ❌ ❌ ❌ ✅ (ZeroLwwCrdtStore + OptimisticTransactionManager)

2. 5-Minute Quick Start (Hello World Counter)

Step 1: Install zero

Add zero to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  zero_state: ^1.0.0

Step 2: Create a ZeroCell and Bind It with ZeroBuilder

No code generation (build_runner), no ceremony, and no StatefulWidget boilerplate:

import 'package:flutter/material.dart';
import 'package:zero_state/zero_state.dart';

// 1. Create a reactive cell holding an integer (starts at 0).
final counterCell = ZeroCell<int>(0, debugLabel: 'counter');

void main() => runApp(const MaterialApp(home: CounterScreen()));

class CounterScreen extends StatelessWidget {
  const CounterScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Zero Quick Start')),
      body: Center(
        // 2. ZeroBuilder rebuilds ONLY this Text widget when counterCell changes.
        child: ZeroBuilder<int>(
          cell: counterCell,
          builder: (context, count) => Text(
            'Count: $count',
            style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        // 3. Mutate .value directly — listeners are notified synchronously!
        onPressed: () => counterCell.value++,
        child: const Icon(Icons.add),
      ),
    );
  }
}

3. Complete Reactive Primitives Guide (Every Class Explained)

3.1 ZeroCell<T>, DerivedCell<S, R> (.select()), and ZeroList<E>

  • ZeroCell<T>: The core atomic unit of state. Tracks an epoch counter on every mutation, notifies listeners only when nextValue != previousValue, and supports in-flight network deduplication (fetchDeduped) with ABA stale-overwrite protection.
  • DerivedCell<S, R> (cell.select(...)): Creates a lazy, surgical projection of a cell. It does not subscribe to the source cell until a listener is attached, and automatically unsubscribes when the last listener is removed (zero memory leaks). Even with zero listeners, reading .value checks the source epoch so you never get a stale value.
  • ZeroList<E>: An immutable, value-equatable list wrapper designed for Dart 3 Record states so list selectors don't trigger false rebuilds when contents haven't changed.
import 'package:zero_state/zero_state.dart';

typedef UserProfile = ({String name, int coins, ZeroList<String> badges});

void exampleCells() {
  final userCell = ZeroCell<UserProfile>((
    name: 'Yusuf',
    coins: 100,
    badges: ZeroList<String>(const ['Founder', '120Hz']),
  ));

  // Surgical selector: only emits when `coins` changes!
  final coinsCell = userCell.select<int>((u) => u.coins);

  // Changing `name` with identical `coins` and `badges` does NOT notify `coinsCell`!
  userCell.value = (
    name: 'Yusuf Kaval',
    coins: 100,
    badges: ZeroList<String>(['Founder', '120Hz']), // Value-equal ZeroList!
  );
}

3.2 UI Widgets: ZeroBuilder, ZeroSelector, ZeroListener, ZeroMultiListener, ZeroConsumer

All UI widgets live on top of pure package:flutter/widgets.dart (compatible with Material, Cupertino, or custom design systems):

import 'package:flutter/material.dart';
import 'package:zero_state/zero_state.dart';

class OrderWidget extends StatelessWidget {
  const OrderWidget({super.key, required this.orderCell, required this.alertCell});

  final ZeroCell<({String status, double total})> orderCell;
  final ZeroCell<String?> alertCell;

  @override
  Widget build(BuildContext context) {
    // ZeroMultiListener listens to multiple cells without nesting hell.
    return ZeroMultiListener(
      listeners: [
        ZeroListener<({String status, double total})>(
          cell: orderCell,
          listenWhen: (prev, curr) => prev.status != curr.status,
          listener: (context, state) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Order status: ${state.status}')),
            );
          },
        ),
        ZeroListener<String?>(
          cell: alertCell,
          listenWhen: (prev, curr) => curr != null,
          listener: (context, msg) => debugPrint('Alert: $msg'),
        ),
      ],
      child: Column(
        children: [
          // ZeroSelector rebuilds ONLY when the selected sub-field (`total`) changes.
          ZeroSelector<({String status, double total}), double>(
            cell: orderCell,
            selector: (state) => state.total,
            builder: (context, total) => Text('Total: \$${total.toStringAsFixed(2)}'),
          ),
          // ZeroConsumer combines both `listener` side-effects and `builder` UI in one widget.
          ZeroConsumer<({String status, double total})>(
            cell: orderCell,
            buildWhen: (prev, curr) => prev.status != curr.status,
            listenWhen: (prev, curr) => curr.total > 1000,
            listener: (context, state) => debugPrint('High-value order!'),
            builder: (context, state) => Text('Status: ${state.status}'),
          ),
        ],
      ),
    );
  }
}

3.3 ZeroScope (Dependency Injection) & context.read / context.watch / context.select

Provide cells to a widget subtree with automatic disposal (autoDispose: true by default) and override them effortlessly in widget tests:

import 'package:flutter/material.dart';
import 'package:zero_state/zero_state.dart';

class CounterApp extends StatelessWidget {
  const CounterApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ZeroScope(
      // Lazily created once when ZeroScope mounts, and auto-disposed when unmounted:
      cellFactories: [
        () => ZeroCell<int>(0, debugLabel: 'scopedCounter'),
      ],
      child: const CounterView(),
    );
  }
}

class CounterView extends StatelessWidget {
  const CounterView({super.key});

  @override
  Widget build(BuildContext context) {
    // 1. context.watch<C>() rebuilds this widget whenever ZeroCell<int> changes:
    final count = context.watch<ZeroCell<int>>().value;

    // 2. context.select<C, R>() rebuilds ONLY when the boolean `isEven` changes:
    final isEven = context.select<ZeroCell<int>, bool>((c) => c.value.isEven);

    return Column(
      children: [
        Text('Count: $count (Even: $isEven)'),
        ElevatedButton(
          // 3. context.read<C>() fetches the cell without subscribing (ideal for callbacks):
          onPressed: () => context.read<ZeroCell<int>>().value++,
          child: const Text('Increment'),
        ),
      ],
    );
  }
}

3.4 ZeroComputed, ZeroBatch, and ZeroEffect

  • ZeroComputed: Combines 2, 3, or a list of cells (combine2, combine3, combineList) into a derived ZeroCombinedCell. Uses topological depth ordering (reactiveDepth) so diamond dependency graphs (A -> B & C -> D) compute D exactly once without intermediate glitches.
  • ZeroBatch.run(...): Groups multiple cell mutations into a single atomic commit.
  • ZeroEffect: Runs a side-effect callback whenever any tracked cell mutates, with built-in protection against infinite reactive loops inside ZeroBatch.
import 'package:zero_state/zero_state.dart';

void computedAndBatchExample() {
  final price = ZeroCell<double>(100.0);
  final quantity = ZeroCell<int>(2);
  final taxRate = ZeroCell<double>(0.20);

  // Automatically recomputes when price, quantity, or taxRate changes:
  final total = ZeroComputed.combine3<double, int, double, double>(
    price,
    quantity,
    taxRate,
    (p, q, t) => (p * q) * (1.0 + t),
  );

  final effect = ZeroEffect([total], () {
    print('Updated total: ${total.value}');
  });

  // Mutate all 3 cells atomically — `total` and `effect` fire ONLY ONCE!
  ZeroBatch.run(() {
    price.value = 150.0;
    quantity.value = 3;
    taxRate.value = 0.18;
  });

  effect.dispose();
}

3.5 Async State: ZeroResourceCell<T>, ZeroFutureCell<T>, and ZeroStreamCell<T>

Every async cell wraps a sealed ZeroResource<T> (ResourceIdle, ResourceLoading, ResourceReady, ResourceFailed) with exhaustive pattern matching (when, maybeWhen), previous-data preservation during reloads, exponential backoff retries (maxRetries), and .refresh():

import 'package:zero_state/zero_state.dart';

Future<void> asyncResourceExample() async {
  final userResource = ZeroResourceCell<String>.seeded('Cached User');

  // Deduplicated load with automatic exponential backoff retry:
  await userResource.loadResourceDeduped(
    'fetch_user_42',
    () async => 'Yusuf Kaval (Verified)',
    maxRetries: 2,
    initialRetryDelay: const Duration(milliseconds: 200),
  );

  // Exhaustive pattern matching:
  final label = userResource.value.when(
    idle: () => 'Idle',
    loading: (prev, isSpeculative) =>
        'Loading (previous: $prev, speculative: $isSpeculative)...',
    ready: (data, epoch, fromShadowCache) =>
        'Loaded: $data (epoch $epoch, shadow: $fromShadowCache)',
    failed: (err, stackTrace, prev) => 'Error: $err (fallback: $prev)',
  );
  print(label);

  // Re-run the last loader at any time (e.g., Pull-to-Refresh):
  await userResource.refresh();
}
  • ZeroFutureCell<T>(Future<T> Function() loader): Immediately starts loader on creation and exposes a ZeroResourceCell<T>.
  • ZeroStreamCell<T>(Stream<T> stream, {T? initialData}): Binds a Dart Stream<T> to a ZeroResourceCell<T> and cancels the subscription automatically on dispose().

3.6 ZeroHistoryCell<T>, ZeroHydratedCell<T>, and ZeroFamily<Arg, T>

import 'package:zero_state/zero_state.dart';

Future<void> lifecycleUtilitiesExample() async {
  // 1. Undo / Redo Time-Travel Cell:
  final editorCell = ZeroHistoryCell<String>('Draft 1', maxHistoryLength: 50);
  editorCell.value = 'Draft 2';
  editorCell.undo(); // Back to 'Draft 1'
  editorCell.redo(); // Forward to 'Draft 2'

  // 2. Persistent Hydrated Cell (auto-restores & auto-saves JSON to storage):
  final storage = InMemoryHydratedStorage(); // Implement ZeroHydratedStorage for SharedPreferences/Hive
  final themeCell = ZeroHydratedCell<String>(
    'dark',
    storageKey: 'app_theme',
    storage: storage,
    fromJson: (json) => json['mode'] as String,
    toJson: (mode) => {'mode': mode},
  );
  themeCell.value = 'oled_black'; // Persisted automatically!

  // 3. Parameterized Cell Family with TTL Auto-Dispose:
  final productFamily = ZeroFamily<int, String>.fromValue(
    (productId) => 'Product #$productId',
    keepAliveDuration: const Duration(seconds: 30),
  );
  final item42 = productFamily(42); // Created on demand and evicted 30s after last listener detaches
  print(item42.value);
}

3.7 Rate-Limiting Operators (ZeroDebouncer, ZeroThrottler) & ZeroObserver

import 'package:zero_state/zero_state.dart';

void operatorsAndObserverExample() {
  // Global lifecycle observer for logging, crash reporting, or DevTools:
  ZeroObserver.addObserver(
    ZeroObserver(
      onCreated: (cell) => print('Created: ${cell.debugLabel}'),
      onChanged: (cell, prev, next, epoch) => print('${cell.debugLabel} [$epoch]: $prev -> $next'),
      onError: (source, error, stack) => print('Error in $source: $error'),
      onDisposed: (cell) => print('Disposed: ${cell.debugLabel}'),
    ),
  );

  final searchQuery = ZeroCell<String>('', debugLabel: 'searchQuery');

  // Debounce: waits 300ms after the user stops typing before updating searchQuery.value
  searchQuery.setDebounced('flutter zero', const Duration(milliseconds: 300));

  // Throttle: updates immediately and ignores subsequent calls for 500ms
  searchQuery.setThrottled('instant', const Duration(milliseconds: 500));
}

4. The 5 Next-Generation Architectural Pillars (Advanced Guide)

Pillar 1: Element-Bypass Rendering (0 Widget Rebuilds at 120Hz)

When building 120Hz audio visualizers, live charts, particle systems, or GPU shaders, rebuilding widgets is unnecessary overhead. zero provides three direct render-tree primitives:

  1. ZeroPaintSurface<T>: Connects a ZeroCell<T> directly to a RenderBox (markNeedsPaint()), bypassing Element.rebuild() completely while throttling accessibility Semantics updates so screen readers never lag the raster thread.
  2. ZeroLayerBypass<T>: Pushes offset, scale, rotationRadians, and opacity directly into LayerHandle<TransformLayer> and LayerHandle<OpacityLayer> without rebuilding the child widget.
  3. ZeroShaderSurface<T> & ZeroShaderUniformBridge<T>: Packs state into a pre-allocated, zero-GC Float32List uniform buffer and flushes it straight to an Impeller ui.FragmentShader.
import 'package:flutter/widgets.dart';
import 'package:zero_state/zero_state.dart';

Widget buildZeroRebuildWaveform(ZeroCell<double> amplitudeCell) {
  return SizedBox(
    width: 300,
    height: 120,
    child: ZeroPaintSurface<double>(
      cell: amplitudeCell,
      semanticsThrottle: const Duration(milliseconds: 250),
      semanticsBuilder: (amp) => 'Wave amplitude ${(amp * 100).round()}%',
      painter: (canvas, size, amplitude, epoch) {
        // Runs at 120Hz inside RenderBox.paint() with 0 Widget rebuilds!
        final paint = Paint()..color = const Color(0xFF00E5FF);
        canvas.drawRect(
          Rect.fromLTWH(0, 0, size.width * amplitude, size.height),
          paint,
        );
      },
    ),
  );
}

Pillar 2: Tri-Modal Speculative Intent & Network Coalescing

Why wait for onTap when physics tells you what the user is about to tap 100ms early?

  • TriModalIntentTracker: Combines desktop pointer velocity/cosine trajectory vectors, mobile 100ms TouchDown -> TouchUp lead windows (with automatic scroll-slop cancellation), ballistic scroll landing prediction, and 1st-order Markov transition chains—protected by an anti-HTTP-429 Token Bucket rate limiter.
  • ShadowStateCache<K, V>: Stages prefetched payloads off-tree with a TTL and promotes them into your live ZeroCell in 0ms (promoteToCell) upon commit.
  • DeterministicRequestCoalescer & FrameBatchCoalescer<K, V>: Subsumes overlapping [offset, limit] range queries into a single network call and batches individual key lookups within a time window into one bulk query.
import 'package:zero_state/zero_state.dart';

Future<void> coalescerExample() async {
  final coalescer = DeterministicRequestCoalescer();

  // Suppose a parent widget requests items [0..50] while a child simultaneously requests [10..25].
  // Zero dispatches ONLY ONE network call for [0..50] and slices [10..25] in memory!
  final parentFuture = coalescer.coalesceRange<int>(
    resourceKey: 'feed_items',
    offset: 0,
    limit: 50,
    rangeLoader: (off, lim) async => List<int>.generate(lim, (i) => off + i),
  );
  final childFuture = coalescer.coalesceRange<int>(
    resourceKey: 'feed_items',
    offset: 10,
    limit: 15,
    rangeLoader: (off, lim) async => throw StateError('Never called — subsumed!'),
  );

  final results = await Future.wait([parentFuture, childFuture]);
  print('Parent count: ${results[0].length}, Child first item: ${results[1].first}');
}

Pillar 3: Autonomous Background Isolate Graph ($O(1)$ Zero-Copy TransferableTypedData)

Offload heavy math, JSON parsing, cryptography, or order-book aggregation to a persistent background isolate without blocking the UI thread or copying megabytes of memory:

import 'dart:typed_data';
import 'package:zero_state/zero_state.dart';

// Top-level isolate function returning a Float32List transferred in O(1) Zero-Copy!
Float32List computeSpectrum(({int count, double gain}) params) {
  final buffer = Float32List(params.count);
  for (var i = 0; i < params.count; i++) {
    buffer[i] = i * params.gain;
  }
  return buffer;
}

Future<void> isolateExample() async {
  final graph = AutonomousIsolateGraph();
  final zeroCopySamples = await graph.executeZeroCopyBufferTask(
    computeSpectrum,
    (count: 16384, gain: 0.25),
  );
  print('Received ${zeroCopySamples.length} floats with 0ms UI jank!');
  await graph.dispose();
}

Pillar 4: A2UI Context & Telemetry Decision Graph

Automatically adapt your UI layout to real-time device FrameTiming (120Hz vsync budget), network quality, and thermal state using ContextDecisionGraph<T> and ZeroA2UiTopologyHost<T>:

import 'package:flutter/material.dart';
import 'package:zero_state/zero_state.dart';

Widget buildAdaptiveUi(ContextDecisionGraph<String> decisionGraph) {
  // Attach to Flutter's SchedulerBinding to monitor real 120Hz (8.33ms) frame timings:
  decisionGraph.startAutoFrameTelemetry(
    targetFrameBudget: const Duration(microseconds: 8333),
  );

  return ZeroA2UiTopologyHost<String>(
    decisionGraph: decisionGraph,
    onHighFrequencySurface: (ctx, t) => Text('120Hz GPU Surface (${t.meta.targetFps} FPS)'),
    onRichInteractiveGrid: (ctx, t) => Text('Rich Grid (${t.meta.columns} columns)'),
    onDegradedCompactList: (ctx, t) => Text('Compact Mode: ${t.meta.degradationReason}'),
    onRecoveryAction: (ctx, t) => Text('Retry Recovery: ${t.meta.errorSummary}'),
  );
}

Pillar 5: Incremental $O(1)$ HLC-CRDT & Optimistic Transaction Rollback

Build local-first, collaborative, offline-capable apps that merge peer changes without central coordination and roll back optimistic UI edits cleanly on server failure:

import 'package:zero_state/zero_state.dart';

Future<void> crdtAndOptimisticExample() async {
  // 1. O(1) Incremental Last-Write-Wins CRDT Store with Hybrid Logical Clock (Drift Guard):
  final nodeA = ZeroLwwCrdtStore<String, String>(clock: HlcClock(nodeId: 'node_A'));
  final nodeB = ZeroLwwCrdtStore<String, String>(clock: HlcClock(nodeId: 'node_B'));

  nodeA.put('doc.title', 'Offline Draft');
  nodeB.put('doc.title', 'Merged Final Title');

  // Synchronize offline nodes via compact delta patches:
  nodeA.mergeDelta(nodeB.exportDelta());
  print('Converged title: ${nodeA.get("doc.title")}');

  // Watch a single key in O(1) time without cloning the entire map:
  final titleCell = nodeA.watchKey('doc.title');
  print('Watched key: ${titleCell.value}');

  // 2. Optimistic UI Mutation with Automatic Server Rollback:
  final stockCell = ZeroResourceCell<int>.seeded(10);
  final txManager = OptimisticTransactionManager<int>(targetCell: stockCell);

  final outcome = await txManager.runTransaction(
    fallbackSeed: 10,
    optimisticMutator: (stock) => stock - 1, // UI immediately shows 9 in 0ms!
    authoritativeAction: (optimisticStock) async {
      throw StateError('HTTP 409: Out of Stock'); // Simulated server rejection
    },
  );
  // Automatically rolled back to 10!
  print('Committed: ${outcome.committed}, Restored Stock: ${stockCell.value.dataOrNull}');
}

5. Multi-Arena Torture Suite (example/)

Want to see all 5 pillars running simultaneously under extreme load? Run the interactive showcase app in example/:

cd example
flutter run --release
  • Arena 1: Real Impeller .frag Shader + Zero-Copy Isolate + 120Hz SchedulerBinding A2UI Lab.
  • Arena 2: 12-Pair Live Crypto Exchange Order-Book Terminal with surgical select() rebuild counters.
  • Arena 3: Speculative Pointer Vector Radar + 100-Request Coalescer Storm.
  • Arena 4: 3-Node Offline/Online HLC-CRDT Sync Battlefield + HTTP 409 Optimistic Rollback.

6. Support & Donate ☕❤️

If zero helps you build faster, smoother 120Hz Flutter apps or saves you engineering time, consider supporting its ongoing R&D:

Buy Me A Coffee GitHub Sponsors


7. License & Publisher

Libraries

zero_state
Zero — Autonomous Reactive State & Data Engine for Flutter.