4.1 KiB
Meatbag Research: SDUI Inflation, Wear OS Haptics, and Server Push
This document summarizes architectural research for the Meatbag platform, focusing on performance, latency, and platform-specific haptic patterns.
1. Server-Driven UI (SDUI) in Compose Multiplatform
The Reflection-Free Pattern
To meet performance constraints and avoid runtime performance degradation on lightweight clients (such as Wear OS watches), Meatbag implements a strictly typed, reflection-free Component Registry.
@Composable
fun ComponentRegistry(primitive: UiPrimitive, onAction: (ApprovalResponse) -> Unit) {
when (primitive) {
is ApprovalRequest -> ApprovalRequestCard(primitive, onAction)
is ActionList -> ActionListContainer(primitive, onAction)
is TextInput -> TextInputField(primitive, onAction)
}
}
- Advantage: Compile-time safety. Polymorphic serialization (via
kotlinx.serializationwith custom class discriminators like"type") ensures payloads map directly to Kotlin data types without dynamic inspection. - State Management: Adheres to Unidirectional Data Flow (UDF). Primitives are read-only configuration blueprints; interactive widgets emit state updates upward through explicit event callbacks (
onAction), keeping clients entirely stateless.
2. Wear OS Haptic Feedback APIs
To minimize human response times, we utilize precise physical notifications based on the resolved AttentionTier.
Android / Wear OS API Mapping
For triggering haptics on physical Wear OS smartwatches, the system integrates with Android's hardware Vibrator API.
1. Predefined Effects (Android SDK 29+)
Modern Wear OS devices support the VibrationEffect API, which yields crisp, hardware-optimized clicks rather than fuzzy motor rumbling.
AttentionTier.SILENT_HAPTIC: Double short pulses to signal prompt urgency without making sound.val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator val effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1.0f) .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1.0f, 150) // 150ms delay .compose() vibrator.vibrate(effect)AttentionTier.BACKGROUND_NOTIFICATION: A light tick effect.vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))AttentionTier.OVERRIDE_SCREEN: Repetitive pulsing alert composition.val timings = longArrayOf(0, 200, 100, 200, 100, 500) // delay, vibe, pause, vibe... val amplitudes = intArrayOf(0, 255, 0, 255, 0, 255) vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
2. Legacy Fallbacks (Android SDK < 29)
- For older Wear OS versions, fallback to deprecated pattern arrays:
vibrator.vibrate(longArrayOf(0, 80, 100, 80), -1)
3. Server Push Architecture: WebSockets vs. SSE
Smartwatches are subject to battery constraints and intermittent connectivity. The push transport layer must be responsive yet lightweight.
| Feature | WebSockets | Server-Sent Events (SSE) |
|---|---|---|
| Protocol | Bi-directional, custom framing | Uni-directional (Server -> Client), HTTP/1.1 or HTTP/2 |
| Connection Overhead | Low (post-handshake) | Extremely low (standard HTTP connection) |
| Battery Impact | Higher (constant connection maintenance) | Lower (leverages HTTP client connection pooling) |
| Firewall Traversal | Can be blocked by strict proxy rules | Standard HTTP, easily passes through proxies |
| Meatbag MVP Selection | WebSockets (Allows immediate client confirmation frames and bi-directional pings) | Candidate for mobile clients (Fallback for phone targets via standard APNS / FCM) |
Recommended Hybrid Strategy
- Wear OS Smartwatches: Utilize persistent WebSockets with optimized ping-pong intervals (e.g. 30 seconds) when the app is active in the foreground.
- Mobile Phones (iOS & Android): Fall back to native push notification systems (FCM/APNS) to wake up the client, which then opens a short-lived WebSocket or POST connection to render the SDUI primitive.