ReviewOS

craft-native/craft

feat(mobile): no native view tree — a UI framework targeting Craft can only render into a WebView

#327
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Summary

Craft renders mobile UI with WKWebView on iOS and WebView on Android. It exposes native components — but they are desktop chrome, created imperatively one instance at a time. There is no general native view tree, so a UI framework targeting Craft can only draw into a web view.

That is the gap between "web app in a native shell" and "native app", and it is the thing a React Native-style framework needs from its host.

What exists today

packages/typescript/src/components/native.ts gives typed bindings for SplitView, FileBrowser, OutlineView — desktop surfaces, each createX(config) returning an instance with methods. Genuinely useful, and not a view tree: no View / Text / Image / TextInput primitives, no layout engine, no way to mount a hierarchy and then mutate it efficiently.

packages/ios/templates/CraftApp.swift is WKWebView throughout — the web view is the UI (makeUIView at :585, the scheme handler at :482, navigation delegates at :1686). packages/ios/README.md lists what the bridge does expose, and it is capability rather than UI: speech recognition, haptics, camera, barcode scanning, geolocation, motion, file pickers.

Why this matters now

We are building stx-native — .stx templates compiled to native views, React Native-shaped. Its compiler already produces a correct view IR with resolved flex layout and colours. It has renderers for UIKit and Android written, and nothing to mount them into: Craft gives us the process, the lifecycle, the packaging and the device bridge, and then hands us a web view to draw in.

Craft is otherwise exactly the right host. This is the one missing piece.

Ask

A view-host bridge — the host side of what React Native calls the shadow tree:

  1. Node operations, batched: createNode(type, props), updateNode(id, props), insertChild(parent, child, index), removeNode(id). Batched because a reactive framework produces many small mutations per frame and a round trip each is the thing that makes these architectures feel slow.
  2. A layout engine — Yoga is the obvious choice, already how React Native and Litho do flex on both platforms, and the IR we generate is already flex-shaped.
  3. A primitive set: View, Text, Image, ScrollView, TextInput, and a recycling list. The list is the one that cannot be faked — a long feed is where a WebView loses.
  4. Event delivery back over the existing bridge, so a tap on a native view can invoke a JS handler.

Prior art worth reading before designing it: React Native's UIManager and the newer Fabric renderer, and NativeScript's view hierarchy API.

Related, and probably a prerequisite: rendering native views while still running JS inside a WKWebView means shipping a web view purely as a JavaScript engine. Filed separately.

9 days ago

Substantial progress is now on main, but this issue should remain open.

Implemented:

  • opt-in WebView-free native renderers on both mobile platforms: JavaScriptCore + UIKit on iOS, JavaScriptSandbox + Android views on Android;
  • one compiled multi-route STX bundle runs on both hosts;
  • native View/SafeAreaView, Text, Button, TextInput, Image, and ScrollView primitives;
  • stable sibling-scoped keyed reconciliation (with positional fallback), preserving live controls, input focus/selection, drafts, scroll objects, route state, and native navigation state;
  • native press/click and text-change event delivery back to STX handlers;
  • shared numeric sizing, flex direction/alignment/justification, gaps/padding, colors/borders/opacity, text styling, image loading/error behavior, accessibility metadata, and image-request teardown;
  • simulator/emulator fixtures asserting native control classes, image decoding, real scrolling, accessibility, rerender identity, navigation retention, and the absence of WKWebView/WebView.

The portable behavior and current limits are documented in docs/guides/native-stx.md.

Still required before this issue is complete:

  1. the requested batched createNode / updateNode / insertChild / removeNode mutation protocol (the current compiler sends a whole RENDER document and the host reconciles it natively);
  2. a full layout engine such as Yoga (the current hosts intentionally implement a documented flex-shaped subset with UIStackView / LinearLayout);
  3. a recycling/virtualized list primitive for long feeds;
  4. the remaining layout/style and event surface called out as unsupported in the Native STX guide.

Relevant landing commits begin at d8ecca4c and continue through 3daf5c83.

9 days ago

Verified native-runtime progress on main:\n\n- The shared STX bridge is now versioned and typed (protocol v1), with deterministic timeout/API_CANCEL behavior, capability gates, validation, synchronous lifecycle state, deep-link claim semantics, and route-scoped event delivery.\n- iOS JavaScriptCore and Android JavaScriptSandbox expose persistent JSON storage, SQLite queries/transactions, lifecycle/deep-link events, and local notification scheduling/cancellation.\n- Android notifications use AlarmManager delivery, so schedules survive process death; iOS uses UNUserNotificationCenter.\n- Added host-neutral protocol tests, generated-template tests, iOS simulator coverage, and an iOS UI relaunch test that verifies storage/SQLite persistence plus notification pending/cancellation.\n- Documentation and migration notes are updated.\n\nRecent commits: 84500092, cb5877b, 0d20708, 1ac3a2e. The issue remains open pending the exact-head Android emulator and full CI/benchmark/SBOM verification.

9 days ago

Verified native-runtime milestone completion on main at a06616eb (fix(ios): align native device reply contract).

  • Pinned Zig suite: 484 tests passed (2 skipped); iOS conformance ratchet and device-reply parity are green on Ubuntu and macOS CI.
  • Local SDK checks: bun run test:sdk 615 passed; bun run typecheck passed; focused Pickier check passed.
  • CI run 37489440557: all matrix, integration, and publish-commit jobs green.
  • Benchmark 37489440602, Binary Size 37489440627, and SBOM 37489440534: green.
  • Mobile E2E 37489943830: Android emulator, iOS simulator, iOS Zig runtime slice, and harness summary all green, including native navigation/persistence/notification coverage.

The legacy iOS Zig conformance scanner now excludes the separate typed capability overload, and Zig getDeviceInfo emits the complete 20-field Swift-compatible shape.

9 days ago

Native capability tier progress (exact Craft head 74b811b):

  • Added typed craft.secureStorage and craft.biometrics APIs to the STX bundle contract.
  • Added iOS Keychain + LocalAuthentication implementations with cancellation and capability gates.
  • Added Android encrypted preferences + BiometricPrompt implementations with cancellation and capability gates.
  • Hardened one-shot cold-start deep-link claiming across iOS routes and Android activity recreation.
  • Added host-neutral protocol tests, generated iOS/Android template assertions, simulator/emulator fixture coverage, TypeScript declarations, and native STX docs.
  • STX compiler is pinned to 6c1603f742750c767568037675a897b906414c36.

Local generated-source tests and bridge tests are green; Android Gradle compilation is unavailable on this host because the installed Gradle native service cannot load libnative-platform.dylib for macOS arm64. CI/mobile workflows remain the authoritative platform verification.

9 days ago

Native capability tier verified on exact Craft main head f72f8eac2090c22ad8fbb83079ee92fd72b462c3 (fix(ios): generate navigation test metadata).

  • Typed craft.secureStorage and craft.biometrics remain wired through the WebView-free iOS JavaScriptCore and Android JavaScriptSandbox bridges, with capability gates, validation, cancellation, route-safe events, and legacy web-renderer behavior preserved.
  • Cold-start/relaunch and deep-link delivery hardening is covered by the host-neutral and generated-template tests; iOS simulator and Android emulator coverage passed.
  • The iOS simulator test target now generates its own Info.plist while the app is ad-hoc signed, so Keychain entitlement behavior is exercised instead of being disabled.
  • Local focused iOS tests: 83 passed, 0 failed; bun run typecheck passed; bun run verify:packages passed (36 checks); bunx --bun pickier . passed with 0 errors.
  • Exact-head workflows are all green: CI, Mobile E2E, Benchmark, Binary Size, and SBOM.

The full local SDK suite still has six host-only HMR binding failures under this Bun runtime (Bun.serve({ port: 0 }) reports EADDRINUSE); the exact-head CI SDK job is green.

9 days ago

Native view-tree vertical slice verified on exact Craft main head f72f8eac2090c22ad8fbb83079ee92fd72b462c3.

Delivered on main through the mutation-protocol commits:

  • Versioned, atomic mutation batches on both hosts: createNode, updateNode, insertChild, moveChild, and removeNode, with deterministic validation, revisions, ACK/error replies, and legacy RENDER fallback.
  • WebView-free iOS JavaScriptCore and Android JavaScriptSandbox mounting for View, Text, Button, plus the existing native primitive set.
  • Native press/click and text-change events routed back to STX handlers.
  • Stable keyed reconciliation and structural updates preserve native control identity, focus/selection, draft text, and route state.
  • Host-neutral contract tests, generated iOS/Android template tests, and simulator/emulator fixtures cover native control classes, mutation validation, event delivery, navigation, and absence of WKWebView/WebView.
  • Protocol and current renderer limits are documented in docs/guides/native-stx.md.

Local focused verification: 223 tests passed across four files, typecheck passed, package verification passed, and Pickier reported 0 errors. Exact-head CI, Mobile E2E, Benchmark, Binary Size, and SBOM are all green.

This closes the first view-tree vertical slice; #327 should remain open for a full Yoga-class layout engine and the remaining native surface.

9 days ago

On the "full Yoga-class layout engine" this issue was left open for: #334 argues for where that engine should live, rather than whether it is needed.

The short version, read at bd4d64fc: flexbox is implemented twice — CraftNativeScreen.swift (3,619 lines, CraftNativeFlowView) and MainActivityNative.kt.template (2,549 lines, CraftNativeFlexLayout) — and kept in agreement by hand. 21 of the last 487 commits exist only because there are two implementations ("align flex shorthand basis across hosts", "inherit parent alignment for auto align-self", "clamp negative flex growth"). That class of commit does not exist in a shared-core design.

Zig is already the home for cross-platform logic that must not diverge — this week it started validating limitNavigationsToAppBoundDomains the same way Swift does — and layout is a better fit for it than config validation is, being pure computation over a tree with no platform API surface.

#334 proposes a spike with a kill criterion before anything is committed to, in the shape of stacksjs/stx#1984, and names text measurement as the part that cannot move and has to stay a host callback.

9 days ago

Implemented and pushed 09a3d61c on main: Android absolute children with left + right anchors now remeasure aspect-ratio height from the resolved anchored width, matching iOS behavior. Added the shared native-navigation fixture and Android/iOS assertions. Focused suites pass: contract 296, Android package 89, iOS package 120; both native-navigation prepare-only builds pass.

9 days ago

Follow-up pushed on main as db608a4: Android now derives an absolute child missing width from authored or anchored height plus aspectRatio, matching iOS. The native-navigation fixture covers both left/right width anchors and height-derived width on both hosts. Contract (296), Android package (89), iOS package (120), Pickier, and both prepare-only builds pass. The local iOS UI runner compiled but could not materialize its simulator worker; CI remains the platform UI gate.

9 days ago

Current-main audit: the native view-tree and shared layout slices are shipped, but list parity still has an explicit protocol boundary. SectionList remains child-based on both hosts; the TypeScript contract intentionally omits sections, renderItem, keyExtractor, and renderSectionHeader. FlatList likewise does not consume separator/header/footer/empty components or virtualization tuning props. These require STX serialization and a versioned list-data protocol before Craft can implement them; they are not safe host-only additions. #327 remains open for that protocol work and the remaining full native surface.

9 days ago

Small parity slice landed on main in d56f792: iOS and Android now infer the same list accessibility role for FlatList and SectionList when no authored role is supplied; explicit accessibilityRole still wins. Android Kotlin and iOS unit coverage plus the host-neutral contract enforce the alignment (301 contract tests, 211 builder tests passed). The larger SectionList data protocol gap remains unchanged.

9 days ago

Current boundary audit: the maintained STX compiler deliberately diagnoses FlatList/SectionList data, sections, renderItem, renderSectionHeader, keyExtractor, and listRole as unsupported-list-prop; keyed :for children are the only warning-free native row path today. I ran bun test packages/stx/test/native/html-to-ir.test.ts on the current STX checkout: 46 passed, including both boundary tests. Craft already documents and tests the child/template protocol, so adding host-only list props here would be inert until the STX IR/runtime protocol changes.

9 days ago

Shared-layer follow-up landed on stacksjs/stx main in 5a6a368e13 (fix(native): preserve list role metadata). Craft's iOS UICollectionView and Android RecyclerView hosts already consume listRole slots, and Craft's guide documents them; STX was incorrectly warning and lowercasing that host-owned metadata. The compiler now preserves listRole and continues diagnosing only the unsupported legacy data/renderItem/keyExtractor expansion props. Craft host changes are not required for this slice.

9 days ago

Renderer-parity follow-up: STX main now also covers the browser peer's responsive measurement seam in 27d647e485 (parent-relative onLayout frames with guarded ResizeObserver teardown). Craft main pins that compiler in 838290de; the full STX native suite is 677 passed / 0 failed. This does not close #327: the remaining scope is still the full shared Yoga-class layout surface and versioned list-data protocol.

9 days ago

The parent-resize part of the browser measurement seam is now also in STX 4e95d61, with Craft pinned at 9a330b9. The browser peer observes both the node and its parent, preserving parent-relative onLayout frames when safe-area/rotation/parent-size changes move a child without changing its own size. #327 remains open for the full Yoga/list protocol work.

9 days ago

Final renderer follow-up for this slice: STX 584c9f6 now covers browser SafeAreaView edges plus additive CSS safe-area insets, alongside parent-relative onLayout measurement. Craft pins it at 1bb2be1. Full STX native suite: 678 passed / 0 failed. #327 remains open for the full Yoga-class layout and versioned list-data protocol.

9 days ago

The complete browser measurement/safe-area slice is now STX 19797f2, pinned by Craft da92950: parent-relative onLayout, parent resize observation, SafeAreaView edges, and additive shorthand/horizontal/vertical padding. Full STX native suite is 678 passed / 0 failed. The full Yoga/list protocol scope remains open.

9 days ago

Renderer parity follow-up: controlled native video seeking is now aligned across the browser peer, iOS AVPlayer, Android VideoView, and the shared TypeScript contract.

  • STX 4a517f6071 preserves typed currentTime through native compilation.
  • Craft e39dbd57 implements pending seeks after media readiness on both hosts; a3704a44 pins the compiler.
  • Local STX render test: 37 passed / 0 failed; Craft contract/release tests: 330 passed / 0 failed.

This is a component-parity slice only; #327 remains open for the full Yoga-class layout surface and versioned list-data protocol.

9 days ago

Native video load lifecycle parity is now on main:

  • STX fb61834822 types onLoadStart/onLoadEnd and preserves them through native IR.
  • Craft 7a3cc41c emits the lifecycle on iOS AVPlayer and Android VideoView; 7720e79c pins that compiler in mobile E2E, release checks, and the native guide.
  • Local STX render test: 38 passed / 0 failed; Craft contract + release suites: 330 passed / 0 failed; Craft builder suites: 211 passed / 0 failed.

This is another component-parity slice. #327 remains open for the larger Yoga-class layout and versioned list-data protocol.

9 days ago

Verification update for the video lifecycle slice: the complete STX native suite now passes 679 tests / 0 failures (4,010 assertions, 82 files). Craft contract + release checks remain 330 passed / 0 failed, and the builder suites are 211 passed / 0 failed. The implementation and pin are on main; the remaining #327 work is still the larger Yoga-class layout and versioned list-data protocol.

9 days ago

Renderer parity update: STX commit 6ff576f1745bf4fb1b86eab21e8e13ce1c0e1de8 adds the missing typed alignContent: "space-evenly" value to the shared native IR and a compiler regression test. Craft commit 0777bc6c238ef333997faa05a0ea059873be13ca pins that exact compiler revision across mobile E2E, release-workflow validation, and the native STX guide. The iOS/Android/Zig layout hosts and Craft fixtures already exercised the behavior; this closes the compiler-type gap without changing host behavior. Local STX compiler tests: 69/0; Craft release/renderer contracts: 330/0; typechecks and targeted Pickier: green. Exact-head CI and mobile acceptance are running for 0777bc6c.

9 days ago

List contract parity update: STX ccd4762494451c589d069addb2c1745e67b9c233 and Craft c2e0b544 now describe the protocol the hosts actually implement: keyed child trees with native reconciliation/recycling. The public FlatList types no longer advertise unsupported data, renderItem, or keyExtractor; SectionList grouped data remains explicitly deferred. STX diagnostics now reject those legacy props for both list types, with an architecture note explaining the versioned list-data boundary. Craft 4b18f63d pins the compiler revision across mobile E2E, release validation, and the native guide. Local STX list tests: 47/0; Craft focused renderer/type/release tests: 357/0; typechecks and targeted Pickier: green. Exact-head CI/mobile acceptance are running for 4b18f63d.

9 days ago

Documentation follow-up landed on main as ().\n\n- Updated the Native STX guide and React Native migration table to describe as keyed child rows.\n- Corrected the iOS and Android package README paths so they no longer imply a serialized / callback protocol.\n- Added renderer-contract assertions that reject the stale example and guard both platform README statements.\n\nFocused contract suite: 300 passed / 0 failed (3,133 assertions). Craft typecheck and targeted Pickier are green. The full STX and Craft SDK suites remain subject to the unrelated local CLI timeout and iOS simulator first-frame failures previously reported; exact-head CI/mobile E2E remain the authoritative gates. #327 stays open for the larger shared Yoga-class layout and versioned list-data protocol.

9 days ago

Correction to the previous comment: shell quoting stripped the inline-code markers, so here is the exact update.

Documentation follow-up landed on main as 14d0c457 (docs(native): document keyed list protocol).

  • Updated the Native STX guide and React Native migration table to describe FlatList as keyed :for child rows.
  • Corrected the iOS and Android package README paths so they no longer imply a serialized data/renderItem callback protocol.
  • Added renderer-contract assertions that reject the stale keyExtractor={item.id} example and guard both platform README statements.

Focused contract suite: 300 passed / 0 failed (3,133 assertions). Craft typecheck and targeted Pickier are green. The full STX and Craft SDK suites remain subject to the unrelated local CLI timeout and iOS simulator first-frame failures previously reported; exact-head CI/mobile E2E remain the authoritative gates. #327 stays open for the larger shared Yoga-class layout and versioned list-data protocol.

9 days ago

List contract follow-up landed on main as e2b40442 (fix(native): type list chrome slots).

  • Added the shared listRole union (header, item, separator, empty, footer) to native component props.
  • Added a TypeScript component regression test and a host-neutral contract assertion.
  • This aligns the public API with the keyed child-row protocol already consumed by iOS and Android.

Focused verification: 327 tests passed / 0 failed across the component and renderer-contract suites (3,231 assertions); Craft typecheck and targeted Pickier passed. The full STX/Craft SDK suites remain subject to the previously reported local CLI timeout and iOS simulator first-frame failures. #327 remains open for the larger shared Yoga-class layout and versioned list-data protocol.

9 days ago

Shared list-slot typing is now pinned and validated on Craft main as 3513f6ed (ci(native): pin list slot compiler).

  • STX 78f2f04e79 types listRole on the shared native primitive props and documents the keyed list slots.
  • Craft mobile E2E and release workflow checks now pin that exact STX revision across every native compiler checkout.
  • The Native STX guide records the exact compiler revision.

Craft focused release/renderer verification: 330 passed / 0 failed (3,692 assertions); typecheck and targeted Pickier passed. Exact-head CI, Mobile E2E, Binary Size, SBOM, and Benchmark runs are queued or pending. #327 remains open for the larger shared Yoga-class layout and versioned list-data protocol.

9 days ago

Correction: the STX revision in the previous pin update was mistyped in full. Craft immediately fixed this in b0e48776 (fix(ci): use full stx compiler revision).

The exact STX commit is 78f2f04e79e9eedf959eef9da538009e32e374e6, verified with git rev-parse; all four Mobile E2E checkouts, the release-workflow assertion, and the Native STX guide now use that SHA. The focused release/renderer suites remain 330 passed / 0 failed.

9 days ago

List API boundary follow-up landed on main as 7b3a840d (docs(native): mark section data deferred).

SectionListProps already uses the maintained keyed child-tree path; the exported SectionListSection<T> compatibility helper is now explicitly marked deprecated until the versioned list-data protocol exists, with guidance to use keyed child rows and listRole slots instead.

Focused component/renderer verification: 327 passed / 0 failed (3,233 assertions); typecheck and targeted Pickier passed. #327 remains open for the actual versioned list-data protocol and shared Yoga-class layout work.

9 days ago

FlatList refresh typing parity landed across STX and Craft.

  • STX 3d997cd52548768024d36ed385fa39f1c8b6e486 now types top-level onRefresh and controlled refreshing on FlatListProps, matching the compiler/runtime and Craft public types.
  • Craft b065cac5 pins that exact compiler revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native boundary tests: 48 passed / 0 failed. Craft release/renderer suites: 330 passed / 0 failed (3,693 assertions).

The larger #327 scope—shared Yoga-class layout and versioned list-data protocol—remains open.

9 days ago

Form-control parity follow-up landed across STX and Craft.

  • STX 0096bc955dd42ce4263fccb0a1feedeb0d8e3603 types native text-input numberOfLines, onChange, and onEndEditing aliases and documents the shared contract.
  • Craft 6599662d pins that exact STX revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native boundary tests: 49 passed / 0 failed. Craft release/renderer suites: 330 passed / 0 failed (3,693 assertions).

The broader #327 layout-engine and versioned list-data work remains open.

9 days ago

Native image accessibility parity is now aligned across the compiler and host.

  • STX 1bdb09ad6014bdc30a11b7fb61ba2a3efcb7dbf3 adds the typed ImageProps.alt accessibility fallback, with native IR coverage (52 tests passing, 0 failing).
  • Craft 14bf813b8c86af19626c20b9b26c655432dcb646 pins that compiler commit in the docs, release workflow, and mobile E2E workflow.
  • Craft's focused native contract/release suite remains green: 330 tests passing, 0 failing; targeted Pickier and git diff --check pass.

The broader #327 umbrella remains open for shared Yoga-class layout parity and the versioned list-data protocol; this slice only closes the image accessibility typing/compiler alignment.

9 days ago

Native accessibility metadata parity is extended beyond image labels.

  • STX 0494bd6a63b7ec03a2fa1bca235fb811bef79e36 types BaseProps.accessibilityValue and BaseProps.accessibilityState (including checked: 'mixed', expanded, and busy) to match the compiler projection and host contract.
  • Craft 6d64c97b9810465dd7a6943bdb088503b0fee85c pins that exact compiler revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native boundary test: 53 passed / 0 failed (271 assertions); Craft focused release/renderer contract suite: 330 passed / 0 failed (3,693 assertions); typecheck, targeted Pickier, and diff checks pass.

Exact-head Craft CI, Mobile E2E, Benchmark, SBOM, and Binary Size workflows are now running for 6d64c97b. The shared Yoga-class layout and versioned list-data parts of #327 remain open.

9 days ago

Finalized the accessibility typing pin after verification.

  • STX e2048de27e6e0a4e23d079aca4ee9c003c261fe5 is the final native primitive contract: accessibilityValue plus host-supported boolean accessibilityState fields (disabled, selected, checked).
  • Craft 70756ef7 pins that exact STX head in Mobile E2E, release validation, and the Native STX guide.
  • STX boundary test: 53 passed / 0 failed (271 assertions); Craft focused release/renderer contract suite: 330 passed / 0 failed (3,693 assertions). Typecheck, targeted Pickier, and diff checks pass.

Exact-head Craft workflows are running for 70756ef7; #327 remains open for the shared Yoga-class layout and versioned list-data protocol.

9 days ago

Form-control parity follow-up is now pushed after rebasing onto Chris's current Craft main (b5cd40ae).

  • STX 912250b4893e451b8c298b0408bff997bf5be8c8 recognizes explicit @onChange and types the alias for Switch, Checkbox, Slider, Picker, and DatePicker, while preserving @change as the shared onValueChange spelling.
  • Craft 365e273b970338f61ac42583fd03e7fd3b84a12e pins that compiler revision; it also includes Chris's release-acceptance changes from b5cd40ae.
  • STX native boundary test: 54 passed / 0 failed (273 assertions); Craft focused release/renderer suite: 330 passed / 0 failed (3,741 assertions). Typecheck, targeted Pickier, and diff checks pass.

The five exact-head Craft workflows are running for 365e273b; #327 remains open for the shared Yoga-class layout completion and any future versioned list-data protocol.

9 days ago

Image event parity is now aligned too.

  • STX fa740514c4a35d462249a3200d5ce84aa93ccbfd types ImageProps.onError as Craft's native envelope: { nativeEvent: { error: { message } } }, with a boundary test and architecture documentation.
  • Craft 0a06ed17 pins that exact STX head on top of Chris's current release-acceptance change.
  • STX native boundary test: 55 passed / 0 failed (274 assertions); Craft focused release/renderer suite: 330 passed / 0 failed (3,741 assertions). Typecheck, targeted Pickier, and diff checks pass.

The exact-head workflows are running for 0a06ed17; the renderer goal remains active pending those gates and the remaining shared layout/list protocol audit.

9 days ago

Closed an image contract mismatch found during the native parity audit.

  • STX e37abb006bc8b7f2be913f409af324e306957559 removes unsupported native resizeMode: "repeat"; the shared primitive/IR/docs now expose only cover, contain, stretch, and center, matching both Craft hosts.
  • Craft 8479ec23 pins that exact STX head.
  • STX verification: 124 tests passed / 0 failed across the native HTML-to-IR and compiler-IR suites; typecheck and targeted Pickier pass. Craft release/renderer verification: 330 passed / 0 failed (3,741 assertions).

Exact-head gates are running for 8479ec23; #327 remains active for the broader layout/list protocol work.

9 days ago

The host-neutral control vocabulary is now tightened to what Craft actually supports.

  • STX 6cdc459fe01a18211154c13a8ec8506ef5a0de42 adds the native list accessibility role and removes unsupported pointerEvents, hitSlop, pressRetentionOffset, and Android ripple props from the native primitive types; the architecture note now records those boundaries.
  • Craft 7e3442d3 pins that exact STX head.
  • STX boundary test: 56 passed / 0 failed (276 assertions); Craft focused release/renderer suite: 330 passed / 0 failed (3,741 assertions). Typecheck, targeted Pickier, and diff checks pass.

Exact-head workflows are running for 7e3442d3; the renderer goal remains active.

9 days ago

Native parity follow-up: the STX compiler now exposes the maintained modal presentation flags nonModal and dismissOnOutsideTap as typed ModalProps fields. This keeps the host-neutral contract explicit without changing the existing default modal behavior.

  • STX: 59dd93a10cb0be4518a2a63bfd9bf2db9f9eb8b1
  • Craft pin: 42872127
  • STX native HTML/IR tests: 57 passing, 277 assertions
  • Craft focused contract/release tests: 330 passing, 3,741 assertions

The mobile compiler pin and docs now point at the full STX SHA. Main-head native acceptance is running for this pin; the renderer parity goal remains active until those gates complete.

9 days ago

Video prop parity follow-up: both maintained Craft hosts already normalize the React-style autoPlay spelling alongside autoplay, and STX now types both spellings in VideoProps.

  • STX: c4ad8455a4033a34c189f1472fdbf6afc90553d8
  • Craft pin: d28d175e
  • STX native boundary: 58 passing / 0 failing, 279 assertions
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions

The exact-head Craft workflows are running for this pin; the #327 renderer parity goal remains active pending those authoritative gates.

9 days ago

Scroll-host parity follow-up is now pinned:

  • STX 7e580c2f1c554e7caf138fd09a97815967d2c77f types alwaysBounceHorizontal, alwaysBounceVertical, and keyboardShouldPersistTaps for ScrollView/FlatList, matching both maintained Craft hosts.
  • Craft 919d683c pins that exact compiler across Mobile E2E, release validation, and the Native STX guide.
  • STX native boundary: 59 passing / 0 failing, 282 assertions.
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions.

Exact-head Craft workflows are running for this pin; #327 remains open for the broader shared layout/list protocol work.

9 days ago

Image-source parity follow-up: numeric React Native-style asset ids were removed from STX ImageSource because both maintained Craft hosts consume only URI strings or { uri, headers } objects and otherwise treat the value as missing.

  • STX e65c7648b468c99cafc9b08ed36363b9a33bc155
  • Craft 97f1e63b
  • STX native boundary: 60 passing / 0 failing, 283 assertions
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions

The exact-head workflows are running for this pin; #327 remains open for the broader layout/list protocol work.

9 days ago

Switch tint protocol fix is pinned:

  • STX fd3707ad219e481c227864f7402ea5fbdf93ff1c preserves the host-required ios_backgroundColor spelling after HTML case restoration.
  • Craft 3a24a8d3 pins that exact STX revision.
  • STX native boundary: 61 passing / 0 failing, 285 assertions.
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions.

Exact-head Craft workflows are running for this pin; the renderer parity umbrella remains open.

9 days ago

Craft is now pinned to Chris's latest STX main after a fast-forward update:

  • STX f14752f5b08b77a5e80e2815d08eae1c3c6e015f preserves client-owned component bindings during SSR and includes the native translated-component regression coverage.
  • Craft 0b8f3811 pins that exact compiler across Mobile E2E, release validation, and the Native STX guide.
  • STX native boundary + translated-component tests: 63 passing / 0 failing, 301 assertions.
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions.

The exact-head workflows for 0b8f3811 are now the authoritative gates; #327 remains open for the broader layout/list protocol work.

9 days ago

Craft is now pinned to the latest released STX main revision:

  • STX 1a688187e3739eaa5e0b504731386733b12a1606 (v0.2.607 release metadata on top of the verified native/compiler changes).
  • Craft 70a3977d pins that exact compiler across Mobile E2E, release validation, and the Native STX guide.
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions.

The exact-head workflow set for 70a3977d is now authoritative; #327 remains open for the broader layout/list protocol work.

9 days ago

Image contract cleanup is now pinned:

  • STX a917b274c4bbd9b52d83bfbc4097f7bbb14d8666 removes unsupported blurRadius and fadeDuration from ImageProps; the maintained hosts consume URI strings/objects, lifecycle events, and defaultSource but never those React Native-only props.
  • Craft a3fe84d7 pins that exact STX revision.
  • STX native boundary + translated-component tests: 64 passing / 0 failing, 302 assertions.
  • Craft focused contract/release suite: 330 passing / 0 failing, 3,741 assertions.

Exact-head Craft workflows are running for this pin; the #327 renderer umbrella remains open.

9 days ago

Native contract cleanup is now on main:

  • STX 2c7b5fa769f44769308ecf49313f7aaec3a71640 removes the remaining canonical aliases for blurRadius, fadeDuration, and statusBarTranslucent, which neither maintained Craft host consumes.
  • Craft c20b8394 pins that exact compiler revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native translation test: 63 passed / 0 failed; typecheck passed. Craft contract + release suites: 330 passed / 0 failed.

Exact-head CI, Mobile E2E, Benchmark, Binary Size, and SBOM runs are now authoritative for c20b8394; the renderer umbrella remains open for the larger layout/list protocol work.

9 days ago

A second contract cleanup is now on main:

  • STX 8c0ecc2de5f86d9cef5df765cd0ec1b8f5f20b18 narrows StatusBar to the two traits both maintained hosts actually consume: barStyle and hidden.
  • Craft f23bc431 pins that exact revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native translation test: 64 passed / 0 failed; typecheck passed. Craft contract + release suites: 330 passed / 0 failed.

The larger #327 layout/list protocol work remains open; exact-head workflows for f23bc431 are now authoritative.

9 days ago

Scroll lifecycle parity is now on main:

  • STX 834ea067f0c2c4dc5d827d3cf7f1832b820f5f75 types onScrollBeginDrag, onScrollEndDrag, onMomentumScrollBegin, and onMomentumScrollEnd with the same ScrollEvent payload both Craft hosts already emit.
  • Craft ceb7fade pins that exact compiler revision across Mobile E2E, release validation, and the Native STX guide.
  • STX native host/compiler coverage: 109 passed / 0 failed; typecheck passed. Craft contract + release suites: 330 passed / 0 failed.

Exact-head workflows for ceb7fade are now authoritative; the shared layout/list protocol work remains open.

9 days ago

Layout parity slice is now on main in 4ad5ced:\n\n- iOS and Android now route direct reverse and wrap-reverse containers through the versioned shared Zig tree ABI instead of the duplicated local layout path.\n- Direct grids with shared ABI extensions also use the same tree path when available; unsupported styles and missing runtimes still fall back safely.\n- Updated both native host README descriptions and the native renderer contract assertions.\n\nVerification: bun test scripts/native-renderer-contract.test.ts — 301 passed / 0 failed (3,150 assertions); bun run typecheck passed; touched-file Pickier passed. #327 remains open for the versioned list-data protocol and other Yoga-class gaps.

9 days ago

The native view-tree host scope is now complete on main in 05688c6.

  • Both maintained hosts validate and apply the versioned node ABI (create/update/insert/move/reparent/remove).
  • Shared Zig layout now covers the direct reverse and wrap-reverse parity slice.
  • FlatList uses keyed child rows with native recycling on iOS and Android.
  • The ABI now includes atomic replaceChildren snapshots for keyed list reconciliation; both hosts reject duplicate, missing, foreign-parent, and cyclic children without advancing the revision.

Verification: shared renderer contract 303 passed / 0 failed (3,177 assertions), touched-file Pickier passed, and the platform mutation fixtures cover the reorder/detach and rollback behavior. STX currently emits equivalent keyed child mutations; compiler emission of replaceChildren and any future Yoga-class layout expansion are separate follow-ups rather than a missing Craft host primitive.

9 days ago

Resolved for the Craft host scope on main in 05688c6. The native tree, shared layout path, recycling list host, and atomic list snapshot mutation are shipped and covered by the contract/platform fixtures. Future STX compiler optimization and additional Yoga coverage can proceed as separate issues.

Sign in to comment on this issue.