Device features
Zvessa draws real native screens (Expo, React Native), so blocks, kits and mini-apps can use the phone itself: icons, haptics, sensors, camera, push and more. Each feature is one shared piece used by many blocks, never wired into one screen, and each asks for permission only when first needed, in words from the blueprint. Package choices and versions: the "myaibio packages and dependencies" plan in the project.
When column: Ready is in the app today. Next is in the first install list (Expo SDK 58, npx expo install). Later is added when the block or kit that needs it starts, so the app stays small until then.
Icons #
Icons are named by meaning, never by an SF Symbol or Material name: send, delete, ai, coin, game and about 120 more in src/icons/icons.json. A blueprint stores the name as a string (an icon prop), so it works the same on every platform.
import { Icon, ICON_NAMES, isIconName, type IconName } from "src/icons";
<Icon name="send" color="accent" size={20} label="Send" />
- iOS draws the matching SF Symbol (
expo-symbols). Android and web draw it from an 18 KB Material Symbols subset font, so only the icons we use ship. coloris a style colour name, andsizescales with the style's type. An unknown name draws a circle instead of breaking.- Adding an icon: add
"name": ["sf.symbol.name", "material_name"]toicons.json, runpython3 src/icons/build-font.py, then the typecheck.
More in docs/PERFORMANCE.md (Icons).
Look and feel #
| Feature | Used for | Package | When |
|---|---|---|---|
| Haptics | Taps, approve and undo, game feedback; follows the style's motion.haptics | expo-haptics | Next |
| Animation | Smooth motion on the UI thread; follows the style's motion.speed | react-native-reanimated | Next |
| Gestures | Swipes, drags, reorder, pinch-zoom | react-native-gesture-handler | Next |
| Frosted glass | Glass panes, sheets and tab bars (style treatment: glass) | expo-blur, expo-glass-effect | Next |
| Gradients | Gradient backdrops and buttons | expo-linear-gradient, expo-mesh-gradient | Next |
| Native controls | Real switches, pickers, sliders, date fields, sheets | @expo/ui, community pickers | Next |
| Native tabs | The real iOS tab bar and Android's bar; scrollable top tabs | expo-router native tabs | Next |
| Fast lists | Long chats, versions, collections | @shopify/flash-list | Next |
| Fast images | Cached images with placeholders | expo-image | Next |
| Animated stickers | Lottie celebrations and loaders | lottie-react-native | Next |
| Charts and shapes | Chart, progress and vector blocks | react-native-svg | Next |
Sensors #
expo-sensors (Next): accelerometer, gyroscope, device motion, magnetometer (compass), barometer and pedometer. Used for tilt and shake games, step trackers and motion effects, and passed to mini-apps through the bridge (Mini-apps).
Rules, because sensors drain the battery fastest:
- Subscribe only while the block or app is on screen and the app is in the foreground (
useLive(), Performance); unsubscribe when it turns false and on unmount. - Ask for the lowest rate that works (
setUpdateInterval): 30 Hz for tilt, 10 Hz for a compass, the pedometer's own counts for steps. Never above 60 Hz. - One shared subscription per sensor, fanned out to every block that wants it.
- Location (
expo-location, Later) uses the coarsest accuracy that works and never runs in the background unless the person turned that on for a kit.
Media #
| Feature | Package | When |
|---|---|---|
| Pick or take photos and video (HEIC converted on the phone) | expo-image-picker | Ready |
| Resize and compress before upload | expo-image-manipulator | Next |
| Background upload | expo-file-system | Next |
| Native video player, picture-in-picture | expo-video | Ready |
| Play and record audio, voice notes | expo-audio | Ready |
| Camera and QR scanning | expo-camera | Later |
| Save to the photo library | expo-media-library | Later |
Photos and small files go to Convex file storage; video and large files to Cloudflare R2 through the Convex R2 component, so the app never holds storage keys.
Calls and live #
Ready: LiveKit (@livekit/react-native, livekit-client on the web) for voice and video calls, group rooms, stages, screen share (iPhone through a broadcast extension) and recording, self-hosted next to Convex. Needs a development build. Setup: docs/LIVE.md.
Notifications #
Ready: expo-notifications on the phone, Expo's push service from Convex (convex/push.ts). Calls ring a closed phone with Answer and Decline buttons. People are asked to allow notifications the first time they need them, not at sign-in. People choose on, digest or off per kind and per space, quiet hours and pause, and a tap opens the exact page (Notifications).
Everything else #
| Feature | Package | When |
|---|---|---|
| Keep the sign-in token in the Keychain / Keystore | expo-secure-store | Ready |
| Sandboxed mini-apps | react-native-webview | Ready |
| Copy and paste | expo-clipboard | Next |
| Language and date format | expo-localization | Next |
| Random ids and hashes | expo-crypto | Next |
| Pick files | expo-document-picker | Ready |
| Share a page or export | expo-sharing | Later |
| In-app browser and OAuth | expo-web-browser | Later |
| Face ID / fingerprint to unlock or approve | expo-local-authentication | Later |
| Maps with pins | expo-maps | Later |
| Add to calendar, invite from contacts | expo-calendar, expo-contacts | Later |
| Read aloud | expo-speech | Later |
| Keep the screen on (games, recipes, timers) | expo-keep-awake | Later |
| Landscape for games and video | expo-screen-orientation | Later |
| Print or save as PDF; a page as an image | expo-print, react-native-view-shot | Later |
| Home-screen widgets; Siri and Shortcuts | expo-widgets, expo-app-intents | Later |
| Offline pages and drafts | expo-sqlite | Later |
Permissions #
One hook asks for camera, microphone, photos, location, motion and push only when first needed, explains why in words from the blueprint, and handles "no" without breaking the screen. A mini-app gets a device permission only after the person allows it for that app.
Limits #
- A brand-new native module needs an app update through the stores, so native power comes from this shipped kit of features. Blocks, kits, styles and mini-apps never need one.
- Claude can preview the web build; native screens are tested in a development build on a phone.
Links into the app #
Links that open the app use zvessa:// (for example an invite link when no web address is set). Older myaibio:// links still open the app.