SINT

SINT Framework

State, Injection, Navigation, Translation — The Four Pillars of High-Fidelity Flutter Infrastructure.

pub package

Languages:

English Spanish Arabic French Portuguese Russian Japanese Chinese Korean Indonesian Turkish Vietnamese



About SINT

SINT is an architectural evolution of GetX (v5.0.0-rc), built as a focused framework around four pillars only:

Pillar Responsibility
S — State Management SintController, SintBuilder, Obx, .obs, Rx types, Workers, SintStatus, SintListener
I — Injection Sint.put, Sint.find, Sint.lazyPut, Sint.putAsync, Bindings, SmartManagement
N — Navigation SintPage, Sint.toNamed, Sint.toInitial, routeParam, pathParam, queryParam, middleware, SintMaterialApp, SintSnackBarStyle, web-safe back()
T — Translation .tr extension, Translations class, locale management, loadTranslations, PathTranslator, translateEndpoints

Everything outside these four pillars has been removed: no HTTP client, no animations, no string validators, no generic utilities. The result is 37.7% less code than GetX — 12,849 LOC vs 20,615 LOC.

Key principles:

  • PERFORMANCE: No Streams or ChangeNotifier overhead. Minimal RAM consumption.
  • PRODUCTIVITY: Simple syntax. One import: import 'package:sint/sint.dart';
  • ORGANIZATION: Clean Architecture structure. 5 modules, each mapping to a pillar.

What's New in 1.3.0

Focus: Vanity URLs & Slug Resolution — the missing web piece.

Vanity / Slug URL Resolution

Single-segment vanity URLs now route correctly through unknownRoute:

SintMaterialApp(
  initialRoute: '/',
  unknownRoute: SintPage(name: '/not-found', page: () => SlugResolverPage()),
  sintPages: [
    SintPage(name: '/', page: () => HomePage()),
    SintPage(name: '/book/:bookId', page: () => BookDetail()),
  ],
)

// User visits: https://myapp.com/serzenmontoya
// Before 1.3.0: silently redirected to HomePage (GetX bug)
// After 1.3.0:  routes to SlugResolverPage with original URL preserved

The problem (inherited from GetX): Any URL starting with / matched the root route /, so unknownRoute never triggered for paths like /serzenmontoya. GetX documents this as: "any string that starts with '/' will correspond to the '/' route". SINT 1.3.0 fixes this.

URL-Preserving unknownRoute

When unknownRoute fires, Sint.currentRoute now returns the original requested URL — not /not-found:

// In your SlugResolverPage
final currentRoute = Sint.currentRoute;  // '/serzenmontoya' ✓ (not '/not-found')
final slug = currentRoute.replaceFirst('/', '').split('/').first;

// Resolve the slug against your backend
final match = await MySlugRouter.resolve(slug);
if (match != null) {
  Sint.offAllNamed(match.targetRoute);
}

This enables catch-all resolver pages that read the original slug and perform async lookups (Firestore, API, etc.) to identify the content type and navigate to the correct page.

See CHANGELOG.md for the full list of changes.


What's New in 1.2.0

Focus: Flutter Web, Deep Links & i18n URL Routing — without breaking mobile.

RESTful Route Parameters

Spring Boot-inspired parameter extraction that works identically on mobile and web:

// Define routes with path parameters (same as before)
SintPage(name: '/book/:bookId', page: () => BookDetail()),
SintPage(name: '/shop/product/:productId', page: () => ProductPage()),

// Navigate (works on all platforms)
Sint.toNamed('/book/abc123');
Sint.toNamed('/shop/product/42?color=red&size=lg');

// Extract parameters — clean API, no manual parsing
String? bookId    = Sint.routeParam;                       // 'abc123'
String? productId = Sint.pathParam('productId');           // '42'
String? color     = Sint.queryParam('color');              // 'red'
String  size      = Sint.queryParamOrDefault('size', 'm'); // 'lg'
Method Equivalent (Spring Boot) Description
Sint.routeParam @PathVariable First path parameter value
Sint.pathParam('id') @PathVariable("id") Named path parameter
Sint.queryParam('q') @RequestParam Query string parameter
Sint.queryParamOrDefault('sort', 'asc') @RequestParam(defaultValue) Query with fallback

All four methods support SintTestMode for unit testing without a running app.

i18n URL Routing (translateEndpoints)

Localized URLs in the browser address bar — zero configuration beyond what you already have:

SintMaterialApp(
  translateEndpoints: true,  // Enable URL localization
  translationsKeys: AppTranslations.keys,
  locale: Locale('es'),
  sintPages: [
    SintPage(name: '/book/:bookId', page: () => BookDetail()),
    SintPage(name: '/event/:eventId', page: () => EventDetail()),
  ],
)

Your existing translations automatically power the URL routing:

// In your translations file — no extra config needed
'es': { 'book': 'libro', 'event': 'evento', ... }
'fr': { 'book': 'livre', 'event': 'evenement', ... }
'de': { 'book': 'buch', 'event': 'veranstaltung', ... }

Result:

Locale Browser URL Internal Route
EN /book/abc123 /book/abc123
ES /libro/abc123 /book/abc123
FR /livre/abc123 /book/abc123
DE /buch/abc123 /book/abc123

How it works:

  1. PathTranslator is built automatically from your registered routes + translations
  2. Incoming URLs are canonicalized before route matching (/libro/x/book/x)
  3. Outgoing URLs are localized for the browser bar (/book/x/libro/x)
  4. Diacritics are normalized automatically (Publicaciónpublicacion)
  5. On mobile, translateEndpoints has zero overhead — path translation only activates for web URL parsing

Global Snackbar Theming

Define snackbar appearance once, apply everywhere:

SintMaterialApp(
  snackBarStyle: SintSnackBarStyle(
    backgroundColor: Colors.grey[900],
    colorText: Colors.white,
    borderRadius: 12,
    margin: EdgeInsets.all(16),
    snackPosition: SnackPosition.bottom,
    duration: Duration(seconds: 3),
  ),
)

// All snackbar calls inherit the global style
Sint.snackbar('Title', 'Message');
// Call-site params still override when needed
Sint.snackbar('Error', 'Failed', backgroundColor: Colors.red);

Three-level cascade: call-site > global style > hardcoded defaults.

See CHANGELOG.md for the full list of changes.


What's New in 1.1.0

Reactive Workers

Auto-cancelling reactive listeners on SintController:

class SearchController extends SintController {
  final query = ''.obs;

  @override
  void onInit() {
    super.onInit();
    debounce(query, (q) => fetchResults(q));       // Wait 400ms after typing stops
    once(query, (_) => analytics.track('search'));  // Fire once, then auto-cancel
    ever(query, (q) => print('Query: $q'));         // Every change
    interval(query, (q) => save(q));                // Max once per second
  }
}
// All subscriptions auto-cancel on onClose(). Zero cleanup code.

SintStatus Pattern Matching

Exhaustive .when() and .maybeWhen() on SintStatus<T>:

final status = SintStatus<User>.loading().obs;

Obx(() => status.value.when(
  loading: () => CircularProgressIndicator(),
  success: (user) => Text(user.name),
  error: (err) => Text('$err'),
  empty: () => Text('No data'),
));

// Convenience: status.value.isLoading, .dataOrNull, .errorOrNull

SintListener

React to state without rebuilding (like BLoC's BlocListener):

SintListener<String>(
  rx: controller.errorMsg,
  listener: (msg) => Sint.snackbar(msg),
  child: MyPage(),
)

Async DI

await Sint.putAsync<SharedPreferences>(
  () => SharedPreferences.getInstance(),
);
final prefs = Sint.find<SharedPreferences>();

Hard Reset Navigation

Sint.toInitial();                                    // Full reset
Sint.toInitial(keep: {AuthController});              // Keep auth alive

Lazy Translation Loading

await Sint.loadTranslations(() async {
  final json = await rootBundle.loadString('assets/i18n/shop_es.json');
  return {'es': Map<String, String>.from(jsonDecode(json))};
});

See CHANGELOG.md for the full list of changes.


Installing

Add SINT to your pubspec.yaml:

dependencies:
  sint: ^1.3.0

Import it:

import 'package:sint/sint.dart';

High-Fidelity Performance (Benchmarks)

SINT is built for speed. Every pillar is audited against the Open Neom Standard.

Pillar Metric Result Context
S (State) Reactive .obs update 0.09 us/op 50,000 updates
S (State) Simple update() 0.11 us/op 50,000 updates
S (State) Rx with listener 6.23 us/op 30,000 updates stress test
I (Injection) Registry Lookup 1.34 us/find Depth 10 dependency resolution
N (Navigation) Middleware Latency 23 ms 5-layer middleware chain
T (Translation) Dynamic Interpolation 2.65 us/op 10,000 trParams lookups

Why SINT is faster:

  • Pillar S: Avoids Stream overhead by using direct ListNotifier propagation. 15-30x faster than BLoC.
  • Pillar I: O(1) hash lookups in the global registry with lifecycle management.
  • Pillar N: Context-less navigation removes heavy widget tree lookups during routing.

The Four Pillars

SINT — The Four Pillars

State Management (S)

Two approaches: Reactive (.obs + Obx) and Simple (SintBuilder).

// Reactive
var count = 0.obs;
Obx(() => Text('${count.value}'));

// Simple
SintBuilder<Controller>(
  builder: (_) => Text('${_.counter}'),
)

Workers for reactive side effects:

ever(rx, callback);       // Every change
once(rx, callback);       // First change only
debounce(rx, callback);   // After pause (400ms default)
interval(rx, callback);   // Max once per duration (1s default)

SintStatus for async state:

status.value.when(
  loading: () => spinner,
  success: (data) => content(data),
  error: (err) => errorView(err),
  empty: () => emptyView,
);

Full documentation

Injection (I)

Dependency injection without context:

Sint.put(AuthController());
Sint.lazyPut(() => ApiService());
await Sint.putAsync(() => SharedPreferences.getInstance());

final controller = Sint.find<AuthController>();

Full documentation

Route management without context — optimized for web deep links and mobile alike:

SintMaterialApp(
  initialRoute: '/',
  translateEndpoints: true,                          // i18n URLs (web)
  snackBarStyle: SintSnackBarStyle(...),              // Global theming
  sintPages: [
    SintPage(name: '/', page: () => Home()),
    SintPage(name: '/book/:bookId', page: () => BookDetail()),
    SintPage(name: '/search', page: () => Search()),
  ],
)

// Navigation
Sint.toNamed('/book/abc123?ref=home');
Sint.back();                                         // Web-safe
Sint.toInitial();                                    // Hard reset to home
Sint.toInitial(keep: {AuthController});              // Keep specific controllers

// RESTful parameter extraction
String? id   = Sint.routeParam;                      // 'abc123'
String? id   = Sint.pathParam('bookId');              // 'abc123'
String? ref  = Sint.queryParam('ref');                // 'home'
String  sort = Sint.queryParamOrDefault('sort', 'a'); // 'a' (default)

// Snackbar with global style
Sint.snackbar('Title', 'Message');

Full documentation

Translation (T)

Internationalization with .tr — now powers URL routing too:

Text('hello'.tr);
Text('welcome'.trParams({'name': 'Serzen'}));
Sint.updateLocale(Locale('es', 'ES'));

// Lazy loading per module
await Sint.loadTranslations(() async {
  final json = await rootBundle.loadString('assets/i18n/shop.json');
  return {'es': Map<String, String>.from(jsonDecode(json))};
});

// URL path translation (automatic when translateEndpoints: true)
// Your translation keys double as URL segment mappings:
//   'book' → 'libro' (ES), 'livre' (FR), 'buch' (DE)
//
// PathTranslator handles:
//   canonicalizePath('/libro/abc')  → '/book/abc'   (incoming)
//   localizePath('/book/abc', 'es') → '/libro/abc'  (outgoing)

Full documentation


SINT is designed with a web-first, mobile-safe philosophy. Every feature works identically across platforms, but web gets extra optimizations:

Feature Web Behavior Mobile Behavior
Sint.back() No-op if no internal history (browser arrows handle it) Standard Navigator.pop()
Sint.routeParam Extracted from browser URL path Extracted from route arguments
Sint.queryParam() Extracted from URL query string ?key=value Extracted from route arguments
translateEndpoints Localizes browser URL bar + canonicalizes incoming URLs No overhead — flag is ignored
Vanity / slug URLs unknownRoute fires correctly for /slug paths; original URL preserved Same behavior via deep links
Sint.showBackButton false (browser has native arrows) true
Default transition Transition.fade (GPU-light for web canvas) Platform default (Cupertino/Material)
Scroll behavior Drag enabled for touch, mouse, and trackpad Platform default
SintSnackBarStyle Same styling across web and mobile Same styling across web and mobile
// 1. Define routes with parameters
SintMaterialApp(
  initialRoute: '/',
  translateEndpoints: true,
  translationsKeys: AppTranslations.keys,
  locale: Locale('es'),
  sintPages: [
    SintPage(name: '/', page: () => HomePage()),
    SintPage(name: '/book/:bookId', page: () => BookDetail()),
    SintPage(name: '/profile/:userId', page: () => ProfilePage()),
  ],
)

// 2. In your controller — same code works everywhere
class BookDetailController extends SintController {
  late final String bookId;

  @override
  void onInit() {
    super.onInit();
    // Works from: browser URL, deep link, or Sint.toNamed()
    bookId = Sint.routeParam ?? '';
    loadBook(bookId);
  }
}

On web: User visits https://myapp.com/libro/abc123 → SINT canonicalizes to /book/abc123 → routes to BookDetailSint.routeParam returns 'abc123' → browser shows /libro/abc123.

On mobile: Sint.toNamed('/book/abc123') → routes to BookDetailSint.routeParam returns 'abc123'.

Same controller. Same routes. Same parameters. Zero platform checks.


Counter App with SINT

void main() => runApp(SintMaterialApp(
  initialRoute: '/',
  sintPages: [
    SintPage(name: '/', page: () => Home()),
    SintPage(name: '/other', page: () => Other()),
  ],
));

class Controller extends SintController {
  var count = 0.obs;
  increment() => count++;
}

class Home extends StatelessWidget {
  @override
  Widget build(context) {
    final c = Sint.put(Controller());
    return Scaffold(
      appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
      body: Center(
        child: ElevatedButton(
          child: Text("Go to Other"),
          onPressed: () => Sint.toNamed('/other'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: c.increment,
      ),
    );
  }
}

class Other extends StatelessWidget {
  final Controller c = Sint.find();
  @override
  Widget build(context) {
    return Scaffold(body: Center(child: Text("${c.count}")));
  }
}

Migration from GetX

  1. Replace get: with sint: in pubspec.yaml
  2. Replace import 'package:get/get.dart' with import 'package:sint/sint.dart'
  3. Your existing Get. calls work — gradually replace with Sint. to remove deprecation warnings
  4. GetMaterialAppSintMaterialApp
  5. GetPageSintPage

Origin & Philosophy

SINT is a hard fork of GetX v5.0.0-rc. After 8 years of accumulated code, GetX's repository became inactive and carried significant unused weight. SINT strips away everything that does not serve the four pillars, resulting in a clean, maintainable foundation built with Clean Architecture principles.

GetX: "Do everything." SINT: "Do the right things."

S + I + N + T — State, Injection, Navigation, Translation. Nothing more, nothing less.


License

SINT is released under the MIT License.

Part of the Open Neom ecosystem.

Libraries

core/sint_core
core/src/domain/enums/smart_management
core/src/domain/errors/bind_error
core/src/domain/errors/obx_error
core/src/domain/extensions/sint_reset
core/src/domain/interfaces/sint_interface
core/src/domain/models/rx_bool
core/src/domain/models/rx_custom
core/src/domain/models/rx_impl
core/src/domain/models/rx_interface
core/src/domain/models/rx_list
core/src/domain/models/rx_map
core/src/domain/models/rx_num
core/src/domain/models/rx_set
core/src/domain/models/rx_string
core/src/domain/typedefs/core_typedefs
core/src/domain/typedefs/legacy_typedefs
core/src/sint_engine
core/src/sint_main
core/src/sint_queue
core/src/utils/log
core/src/utils/testing/wrapper
core/src/utils/testing/wrapper_named
core/src/utils/testing/wrapper_translations
injection/sint_injection
injection/src/bind
injection/src/domain/extensions/injection_extension
injection/src/domain/interfaces/binding
injection/src/domain/interfaces/bindings_interface
injection/src/domain/models/binds
injection/src/domain/models/instance_info
injection/src/domain/typedefs/injection_typedefs
injection/src/lifecycle
injection/src/ui/bind_element
injection/src/ui/binder
navigation/sint_navigation
navigation/src/domain/enums/pop_mode
navigation/src/domain/enums/prevent_duplicate_handling_mode
navigation/src/domain/enums/row_style
navigation/src/domain/enums/snack_hover_state
navigation/src/domain/enums/snackbar_position
navigation/src/domain/enums/snackbar_status
navigation/src/domain/enums/snackbar_style
navigation/src/domain/enums/transition
navigation/src/domain/extensions/bottomsheet_extension
navigation/src/domain/extensions/context_extensions
navigation/src/domain/extensions/dialog_extension
navigation/src/domain/extensions/event_loop_extension
navigation/src/domain/extensions/first_where_extension
navigation/src/domain/extensions/overlay_extension
navigation/src/domain/extensions/page_arg_extension
navigation/src/domain/extensions/snackbar_extension
navigation/src/domain/interfaces/custom_transition
navigation/src/domain/interfaces/sint_middleware
navigation/src/domain/mixins/sint_navigation_mixin
navigation/src/domain/mixins/sint_transition_mixin
navigation/src/domain/models/config_data
navigation/src/domain/models/path_decoded
navigation/src/domain/models/route_data
navigation/src/domain/models/route_node
navigation/src/domain/models/routing
navigation/src/domain/models/sint_snackbar_style
navigation/src/router/circular_reveal_clipper
navigation/src/router/index
navigation/src/router/middleware_runner
navigation/src/router/page_redirect
navigation/src/router/page_settings
navigation/src/router/route_decoder
navigation/src/router/route_match_result
navigation/src/router/route_matcher
navigation/src/router/route_parser
navigation/src/router/route_tree
navigation/src/router/route_tree_result
navigation/src/router/router_report_manager
navigation/src/router/sint_delegate
navigation/src/router/sint_information_parser
navigation/src/router/sint_navigator
navigation/src/router/sint_page
navigation/src/router/sint_page_route
navigation/src/router/sint_test_mode
navigation/src/router/url_strategy/impl/io_url
navigation/src/router/url_strategy/impl/stub_url
navigation/src/router/url_strategy/impl/web_url
navigation/src/router/url_strategy/url_strategy
navigation/src/sint_navigation_observer
navigation/src/ui/dialog/dialog_route
navigation/src/ui/sint_cupertino_app
navigation/src/ui/sint_material_app
navigation/src/ui/sint_root
navigation/src/ui/snackbar/snackbar
navigation/src/ui/snackbar/snackbar_controller
navigation/src/ui/snackbar/snackbar_queue
navigation/src/ui/transitions/circular_reveal_transition
navigation/src/ui/transitions/fade_in_transition
navigation/src/ui/transitions/left_to_right_fade_transition
navigation/src/ui/transitions/no_transition
navigation/src/ui/transitions/right_to_left_fade_transition
navigation/src/ui/transitions/size_transitions
navigation/src/ui/transitions/slide_down_transition
navigation/src/ui/transitions/slide_left_transition
navigation/src/ui/transitions/slide_right_transition
navigation/src/ui/transitions/slide_top_transition
navigation/src/ui/transitions/zoom_in_transition
navigation/src/ui/widgets/directionality_drag_gesture_recognizer
navigation/src/ui/widgets/sint_app_bar
navigation/src/ui/widgets/sint_back_gesture_controller
navigation/src/ui/widgets/sint_back_gesture_detector
sint
SINT Framework 1.0.0
state_manager/sint_state_manager
state_manager/src/domain/mixins/equality_mixin
state_manager/src/domain/mixins/rx_ticket_provider_mixin
state_manager/src/domain/notify_data
state_manager/src/domain/sint_status
state_manager/src/domain/typedefs/state_typedefs
state_manager/src/engine/get_builder
state_manager/src/engine/list_notifier
state_manager/src/engine/notifier
state_manager/src/engine/sint_controller
state_manager/src/sint_listenable
state_manager/src/ui/obx_reacive_element
state_manager/src/ui/obx_widget
state_manager/src/ui/sint_listener
translation/sint_translation
translation/src/domain/extensions/locale_extension
translation/src/domain/extensions/trans_extension
translation/src/domain/interfaces/translations
translation/src/domain/models/intl_host
translation/src/domain/models/path_translator
translation/src/utils/translations_constants