@sigx/lynx 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +102 -60
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,50 +1,108 @@
1
1
  # @sigx/lynx
2
2
 
3
- Public framework barrel for [SignalX](https://github.com/signalxjs) on Lynx. This is the package you import from in app code it re-exports everything from `@sigx/reactivity`, `@sigx/runtime-core`, and `@sigx/lynx-runtime` under one namespace.
3
+ **[SignalX](https://github.com/signalxjs/core) for [Lynx](https://lynxjs.org/)** lets you build native iOS and Android apps with SignalX's signal/effect reactivity model on top of ByteDance's Lynx runtime — with cross-thread gestures and animations that run on the device's main UI thread.
4
4
 
5
- ## Installation
5
+ **`@sigx/lynx`** is the package you import from in app code. It bundles [`@sigx/reactivity`](https://github.com/signalxjs/core/tree/main/packages/reactivity) (state), [`@sigx/runtime-core`](https://github.com/signalxjs/core/tree/main/packages/runtime-core) (components, lifecycle), and [`@sigx/lynx-runtime`](https://github.com/signalxjs/lynx/tree/main/packages/lynx-runtime) (the dual-thread renderer) behind one import path, so app code says `import { signal, component, useSharedValue } from '@sigx/lynx'` and nothing else.
6
+
7
+ ## Highlights
8
+
9
+ - **Native, not WebView.** Real `UIView` / `View` trees. Video maps to `AVPlayer` / `ExoPlayer`, maps to `MKMapView` / Google Maps, gestures hit the actual touch system — no DOM wrapper, no JS bridge in the hot path.
10
+ - **Zero-config native modules.** `pnpm add @sigx/lynx-camera` → `sigx prebuild` → done. The autolinker wires Podfile, Gradle, `Info.plist`, `AndroidManifest.xml`, and the native module registry from each package's `signalx-module.json`. You never edit a `Podfile` to add a dependency.
11
+ - **Main-thread gestures & animations.** Press, drag, swipe, scroll offsets, and spring + tween animations all run on Lepus (the platform's main thread). Your finger tracks at the display's refresh rate even when JS is busy.
12
+ - **`SharedValue` — cross-thread state for free.** Mutate from a `'main thread'` worklet; read reactively from a SignalX `effect` on the background thread. Powers gestures, scroll, animation, and any custom "fast state lives on MT" use case. Not available in react-lynx or vue-lynx as of 2026-04.
13
+ - **Type-first navigation.** `defineRoutes` plus module augmentation gives every navigator API (`useNav`, `useParams`, `useSearch`, `<Link>`) precise per-route inference. Native Stack / Tabs / Drawer / modals.
14
+ - **A real native-module catalog.** Camera, audio, video, maps, webview, biometric, secure storage, file system, location, push + local notifications, share sheet, clipboard, haptics, image picker, websocket, connectivity, device info, background tasks, appearance, safe area — all auto-linked.
15
+ - **Dev experience that doesn't fight you.** `sigx dev` runs rspeedy with HMR and streams device `console.*` straight to your terminal. `sigx run:ios` / `sigx run:android` go from scaffold to a running app in one command. `sigx doctor` verifies your toolchain. On-device dev menu, error overlay, perf HUD, and QR scanner are debug-only and dropped from release builds.
16
+ - **Build pipeline that disappears.** The plugin runs the SWC `'main thread'` worklet transform automatically — including across third-party packages that ship directives in their `dist/`, with no allowlist. Tailwind preset + DaisyUI components + build-time icon tree-shaking (only glyphs you actually render ship in the bundle).
17
+ - **Testable.** [`@sigx/lynx-testing`](https://github.com/signalxjs/lynx/tree/main/packages/lynx-testing) renders into an in-memory tree so component tests run under vitest like any other library — no Lynx runtime needed.
18
+
19
+ ## Quick start
20
+
21
+ Scaffold a new app:
22
+
23
+ ```bash
24
+ npm create @sigx@latest my-app
25
+ # pick: lynx (or lynx-tailwind)
26
+ cd my-app
27
+ pnpm install
28
+ pnpm dev
29
+ ```
30
+
31
+ Then in another terminal:
6
32
 
7
33
  ```bash
8
- npm install @sigx/lynx
34
+ pnpm run:ios # or run:android
9
35
  ```
10
36
 
37
+ That's it. The template wires the build plugin, the CLI, and a starter `App.tsx`.
38
+
39
+ ### Minimal app
40
+
11
41
  ```tsx
12
- import {
13
- signal, effect, computed, batch, // reactivity
14
- component, defineApp, onMounted, // runtime-core
15
- useMainThreadRef, runOnMainThread, // main-thread scripting
16
- runOnBackground, // BG-thread bridge
17
- useSharedValue, useScrollViewOffset, // cross-thread state
18
- useAnimatedStyle, // MT style bindings
19
- type MainThread, type Define,
20
- } from '@sigx/lynx';
42
+ // src/App.tsx
43
+ import { component, signal } from '@sigx/lynx';
44
+
45
+ const App = component(() => {
46
+ const count = signal(0);
47
+ return () => (
48
+ <view>
49
+ <text>count = {count.value}</text>
50
+ <view bindtap={() => { count.value++; }}>
51
+ <text>tap me</text>
52
+ </view>
53
+ </view>
54
+ );
55
+ });
56
+
57
+ export default App;
58
+ ```
59
+
60
+ ```tsx
61
+ // src/main.tsx
62
+ import { defineApp } from '@sigx/lynx';
63
+ import App from './App';
64
+
65
+ defineApp(<App />).mount(null);
21
66
  ```
22
67
 
23
- ## What's inside
68
+ ### Build plugin
69
+
70
+ If you're integrating into an existing Lynx project rather than scaffolding, register the plugin in your rspeedy / rspack config:
71
+
72
+ ```ts
73
+ // lynx.config.ts
74
+ import { defineConfig } from '@lynx-js/rspeedy';
75
+ import { pluginSigxLynx } from '@sigx/lynx-plugin';
76
+
77
+ export default defineConfig({
78
+ source: { entry: { main: './src/main.tsx' } },
79
+ plugins: [pluginSigxLynx()],
80
+ });
81
+ ```
24
82
 
25
- | Surface | From | Use for |
26
- | ---------------------- | -------------------------- | ------------------------------------------------------------- |
27
- | `signal`, `effect`, `computed`, `batch`, `untrack`, `watch`, `effectScope` | `@sigx/reactivity` | Reactive state and computations on the BG thread. |
28
- | `component`, `defineApp`, `defineDirective`, `onMounted`, `onUnmounted`, `onUpdated`, `onCreated`, `provide`/`inject` | `@sigx/runtime-core` | Component model, lifecycle, dependency injection. |
29
- | `useMainThreadRef`, `MainThreadRef` | `@sigx/lynx-runtime` | Refs whose `.current` value lives on the main UI thread. |
30
- | `runOnMainThread`, `runOnBackground`, `transformToWorklet` | `@sigx/lynx-runtime` | Cross-thread function calls. |
31
- | `useSharedValue`, `SharedValue`, `SharedValueState` | `@sigx/lynx-runtime` | **The cross-thread primitive** — MT-writable, BG-observable values (see below). |
32
- | `useAnimatedStyle` | `@sigx/lynx-runtime` | Bind an element style to a `SharedValue` via a named mapper (linear or range-mapped), applied on MT every flush. |
33
- | `OP`, `pushOp`, `scheduleFlush`, `takeOps`, `flushNow` | `@sigx/lynx-runtime` | Lower-level op-queue access for runtime authors. |
34
- | `registerBgSink`, `unregisterBgSink`, `ingestAvPublishes` | `@sigx/lynx-runtime` | Lower-level SharedValue bridge primitives (the building blocks under `useSharedValue`). |
35
- | `MainThread`, `Define`, `ViewAttributes`, etc. | `@sigx/lynx-runtime` | JSX type annotations. |
83
+ The plugin handles the BG / MT bundle split and the `'main thread'` worklet transform.
36
84
 
37
- For touch handling and gesture components (`<Pressable>`, `<Draggable>`, `<Swipeable>`), install [`@sigx/gestures`](../gestures) on top. For spring/tween animation drivers, install [`@sigx/motion`](../motion).
85
+ ## What you import
86
+
87
+ | Surface | Use for |
88
+ |---|---|
89
+ | `signal`, `effect`, `computed`, `batch`, `untrack`, `watch`, `effectScope` | Reactive state and computations (BG thread). |
90
+ | `component`, `defineApp`, `defineDirective`, `onMounted`, `onUnmounted`, `onUpdated`, `onCreated`, `provide` / `inject` | Component model, lifecycle, dependency injection. |
91
+ | `useMainThreadRef`, `MainThreadRef` | Refs whose `.current` value lives on the main UI thread. |
92
+ | `runOnMainThread`, `runOnBackground`, `transformToWorklet` | Cross-thread function calls. |
93
+ | `useSharedValue`, `SharedValue`, `SharedValueState` | The cross-thread primitive — MT-writable, BG-observable values. See below. |
94
+ | `useAnimatedStyle` | Bind an element style to a `SharedValue` via a named mapper (linear or range-mapped), applied on MT every flush. |
95
+ | `MainThread`, `Define`, `ViewAttributes`, … | JSX type annotations. |
38
96
 
39
97
  ## SharedValue — the cross-thread primitive
40
98
 
41
99
  `useSharedValue<T>(initial)` returns a value you can **write from a main-thread worklet** and **read reactively from the background thread**.
42
100
 
43
- It's not animation-specific. `SharedValue` is a general "fast state lives on the other thread" primitive. Animation, gestures, scroll, sensors, layout they're all parallel customers of the same bridge.
101
+ It's not animation-specific. `SharedValue` is a general "fast state lives on the other thread" primitive — animation, gestures, scroll, sensors, layout are all parallel customers of the same bridge.
44
102
 
45
103
  ```tsx
46
104
  import { useSharedValue } from '@sigx/lynx';
47
- import { Draggable } from '@sigx/gestures';
105
+ import { Draggable } from '@sigx/lynx-gestures';
48
106
 
49
107
  const tx = useSharedValue(0);
50
108
 
@@ -52,61 +110,45 @@ const tx = useSharedValue(0);
52
110
  <text>x = {tx.value}px</text> // BG-reactive, updates per drag frame
53
111
  ```
54
112
 
55
- The MT side mutates `tx.current.value` from inside a `'main thread'` worklet (zero-latency). On every `__FlushElementTree` boundary, the runtime diffs registered values and dispatches a single batched event to the BG thread, where each value lands in a sigx `signal`. A BG `effect(() => sv.value)` re-runs reactively without injecting BG into the gesture hot path.
56
-
57
- ### Customers of the bridge
58
-
59
- | Customer | What it provides | Built on |
60
- | --- | --- | --- |
61
- | Animation | `withSpring`, `withTiming`, `animate` | `@sigx/motion` |
62
- | Gestures | `<Pressable>`, `<Draggable>`, `<Swipeable>` | `@sigx/gestures` |
63
- | Scroll | `<ScrollView offsetY={sv} offsetX={sv}>` | `@sigx/gestures` |
64
- | Style bindings | `useAnimatedStyle(elRef, sv, mapperName, params)` | `@sigx/lynx` |
113
+ The MT side mutates `tx.current.value` from inside a `'main thread'` worklet (zero-latency). On every `__FlushElementTree` boundary the runtime diffs registered values and dispatches a single batched event to BG, where each value lands in a SignalX `signal`. A BG `effect(() => sv.value)` re-runs reactively without injecting BG into the gesture hot path.
65
114
 
66
115
  ### Scroll-driven UI example
67
116
 
68
117
  ```tsx
69
118
  import {
70
- useSharedValue, useAnimatedStyle, useMainThreadRef,
71
- type MainThread,
119
+ useSharedValue, useAnimatedStyle, useMainThreadRef,
120
+ type MainThread,
72
121
  } from '@sigx/lynx';
73
- import { ScrollView } from '@sigx/gestures';
122
+ import { ScrollView } from '@sigx/lynx-gestures';
74
123
 
75
124
  const scrollY = useSharedValue(0);
76
125
  const heroRef = useMainThreadRef<MainThread.Element | null>(null);
77
126
 
78
127
  // Parallax: as scroll goes 0 → 300, the hero translates 0 → -150 px.
79
128
  useAnimatedStyle(heroRef, scrollY, 'translateY', {
80
- inputRange: [0, 300],
81
- outputRange: [0, -150],
82
- extrapolate: 'clamp',
129
+ inputRange: [0, 300],
130
+ outputRange: [0, -150],
131
+ extrapolate: 'clamp',
83
132
  });
84
133
 
85
134
  <ScrollView offsetY={scrollY}>
86
- <view main-thread:ref={heroRef}><image src={hero} /></view>
87
- <text>Body…</text>
88
- <text>Scroll position (BG-reactive): {scrollY.value.toFixed(0)}px</text>
135
+ <view main-thread:ref={heroRef}><image src={hero} /></view>
136
+ <text>Body…</text>
137
+ <text>Scroll position (BG-reactive): {scrollY.value.toFixed(0)}px</text>
89
138
  </ScrollView>
90
139
  ```
91
140
 
92
- Scroll → `<ScrollView>`'s internal MT worklet writes `scrollY.current.value` → flush triggers `useAnimatedStyle`'s mapper and applies the transform → MT publishes the diff to BG → `<text>` updates reactively. End-to-end, never crosses to BG inside the scroll hot path. The user just passes a `SharedValue` — same shape as `<Draggable translateX={tx}>`.
93
-
94
- ### What this is not
95
-
96
- - **Not bidirectional.** Writes from BG (`sv.value = 100`) are no-op'd with a dev warning. Authoritative state lives on MT; BG observes. A bidirectional bridge would be a larger design and isn't currently scoped.
97
-
98
- ### Differentiator
99
-
100
- Neither vue-lynx nor react-lynx ships a BG-observable MT value. React-lynx's `MainThreadRef.current` *throws* on BG; framer-motion-style libraries store animation state in MT-only refs. The diff/publish bridge in `@sigx/lynx-runtime` is what makes `effect(() => sv.value)` work — a primitive unique to sigx-lynx as of 2026-04.
141
+ Scroll → `<ScrollView>`'s MT worklet writes `scrollY.current.value` → flush triggers `useAnimatedStyle`'s mapper and applies the transform → MT publishes the diff to BG → `<text>` updates reactively. End-to-end, never crosses to BG inside the scroll hot path. The user just passes a `SharedValue` — same shape as `<Draggable translateX={tx}>`.
101
142
 
102
- ### Deprecation note
143
+ ### Caveats
103
144
 
104
- Prior to Phase 2.8, `SharedValue` / `useSharedValue` were named `AnimatedValue` / `useAnimatedValue`. The old names still work via deprecated re-exports for one minor cycle. Migrate at your convenience.
145
+ - **Not bidirectional.** Writes from BG (`sv.value = 100`) are no-op'd with a dev warning. Authoritative state lives on MT; BG observes.
146
+ - **Mappers register on MT.** Custom mappers must be registered from a MT-side module via `registerMapper(name, fn)` — BG-side `useAnimatedStyle` only carries the *name*.
105
147
 
106
- ## Build pipeline
148
+ ## The rest of the ecosystem
107
149
 
108
- The `'main thread'` directive transform that powers main-thread event handlers is provided by [`@sigx/lynx-plugin`](../lynx-plugin) register it in your rspack/rspeedy config.
150
+ This package is the framework entry point. For the full list of native modules, UI packages, gestures, animation, navigation, icons, and dev tooling — see the [monorepo README](https://github.com/signalxjs/lynx#packages).
109
151
 
110
152
  ## License
111
153
 
112
- MIT
154
+ MIT — © Andreas Ekdahl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/lynx",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "sigx-lynx framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "dependencies": {
41
41
  "@sigx/reactivity": "^0.4.8",
42
42
  "@sigx/runtime-core": "^0.4.8",
43
- "@sigx/lynx-runtime": "^0.4.2"
43
+ "@sigx/lynx-runtime": "^0.4.3"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@typescript/native-preview": "7.0.0-dev.20260521.1",