Custom domains and a mobile remote
This week Contrast and SootSim merged into a single account and a single paid plan, Pro. The mobile companion grew from a chat app into a real remote for your projects, with a floating picture-in-picture preview, a live React Native runtime, and over-the-air updates. And a deep engine push made SootSim scroll and animate far closer to a real device, while a wave of native fidelity work brought its menus, sheets, and libraries in line with iOS.
Platform
One account, one plan under Pro
Your Soot projects and your SootSim repos and builds now live under a single account with one billing relationship, whether that account is personal or shared with a team. There is one paid tier, Pro: 20 dollars a month for 1,000 included credits, with a prepaid top-up balance and monthly and daily usage caps you set. A credit is worth two cents, a build costs one, and a walkthrough, AI preview, or test run costs two. When you run low you can buy another 1,000 credits from billing in one step, and auto top-up is opt-in and only ever kicks in once you have actually run past your included credits.
Billing also moved out of the old cramped pricing modal into a proper settings area with a sidebar, a running ledger that shows exactly where your credits went, and a clean balance overview. The account menu was rebuilt around an active account: it shows the current organization with avatars, lets you switch organizations from a nested menu, and scopes creating a project, forking, and the project switcher to whichever account is active, so moving between personal and team accounts shows the right projects and the right bill. Getting the paid tier now sends a welcome email summarizing what it unlocks, and usage and invoice emails send exactly once per event.
Your projects, live from your phone
The Soot mobile app became a full remote for your work. It is now organized into Chat, Factory, Preview, and Projects, and the Factory tab shows the same factory-floor scene as the web with a live view of your build agents: the top half is a read-only feed of a selected agent’s real conversation, and tapping an agent on the floor switches which thread you are watching, so you can follow exactly what your build agents are doing. Chat renders code with real syntax highlighting, autolinks bare URLs, and the composer wears the same frosted Liquid Glass material as the rest of the shell with a drag-down gesture that dismisses the keyboard with soft haptic taps along the way.
The embedded preview is now a real web plus iOS deck: both stay mounted with the inactive one peeking out behind the active one, and you tap the sliver to flip which is in front. It can float as a draggable picture-in-picture window that snaps to any corner, tucks partway off-screen, pops back with a tap, and lifts above the keyboard when docked at the bottom. Fullscreen was redesigned with a frosted control bar and, for web previews, an address bar with back, forward, and reload, and a swipe in from the left edge interactively shrinks fullscreen back into the floating window mid-gesture without stealing horizontal swipes from carousels inside the app you are previewing. The app opens instantly from a saved local copy, shows a live sync dot instead of a fake perpetual loading pill, recovers on its own when the preview stalls or iOS kills its web view under memory pressure, and now updates itself over the air, checking on launch and foreground and prompting a one-tap reload. You can grab it from the homepage through an App Store styled button that points at the public TestFlight invite.
Bring your own domain, secrets, and integrations
Project Settings gained three real config surfaces. You can attach your own domain to any live web deploy instead of a Soot subdomain: a flow shows the DNS record to point at us, tracks SSL issuance live so you can watch the certificate go valid, and keeps the domain attached across every redeploy, as a 5 dollar a month add-on. You can add your own API keys and secrets, which Soot encrypts at rest and injects into both the app runtime and the deploy, keeping the deployed worker in sync so deleting a secret in Soot removes it from the live worker rather than stranding it. And a new Integrations panel connects Cloudflare, PostHog, GitHub, Stripe, Slack, Linear, Resend, RevenueCat, Anthropic, OpenAI, and OpenRouter, verifying each connection the moment you add it so a bad key shows a clear status instead of failing silently later. Your AI agent can read secret metadata and recommend and verify an integration itself, so you never paste secrets into chat and it never sees the values.
Describe a test in plain English
Describe a test the way you would say it out loud, “tap the login button and verify the welcome screen,” and SootSim reads the current screen, turns your words into taps, waits, and assertions, runs them, and saves a replayable recording. These hosted runs now show up on your organization’s dashboard in a new Runs tab, each with pass or fail status, the repo it ran against, how long it took, and a link to replay. Preview recordings also gained a full trace docked beside the phone: a scrubbable strip of everything that happened, per-step timing with rendered thumbnails, which components re-rendered and why, and an agent-drive section listing every action an AI agent took with its duration and any timeouts. You can export a saved preview share as a Maestro flow, and test flows now wait on the simulator’s real settled state instead of fixed sleeps, cutting dead time without losing the guarantee that catches a half-finished transition.
Agents can research the web while they build
Agents building your app can now fetch pages and run web searches to look up real documentation or verify a fact instead of guessing, with safeguards on what the fetch tool is allowed to reach.
A guided tour of your whole workspace
First-time users can now be led through the workspace step by step by Lux: the Lux chat, the Overview screen and its dock, and each of the Dev, Plan, Factory, Deploy, and Prod panes, with Lux explaining what each area does and pointing at the controls that matter through a redesigned speech bubble. The pointer aims at the center of its target with a subtle drift, respects reduced-motion, and closing the tour early shows a toast telling you how to restart it, with Lux poofing into particles at the end. Redeeming a private beta code now plays a short animated introduction to the stack Soot is built on, each piece paired with its logo, around the actual code redemption and login.
SootSim moves closer to real iOS
SootSim’s simulated iOS got noticeably closer to a real device across many places at once. Dark-mode blur materials match real colors, alert buttons are fully rounded pills, bottom and fit sheets stay content-sized instead of stretching, and a sheet’s floating footer keeps its inset when content scrolls. Drilling into a nested context menu now takes 240ms with a full-velocity ease-out so a second drill does not feel heavier than the menu that opened it, a fast tap on the tab bar no longer leaves the selection indicator glitching, text renders with SF Pro’s real variable-weight axes, and a horizontal drag that starts on a home-screen icon now promotes into the same page swipe a real iPhone uses. On compatibility, react-native-device-info, react-native-mmkv, and react-native-permissions gained the native pieces the Rainbow wallet demo needs, and the inspector now tells you when a blocking Alert or ActionSheet is covering the screen so a tap that seems to do nothing gets explained.
Long-press context menus, the kind you get from a message bubble or app icon, now render pixel-faithful to real iOS and distinct from ordinary tap dropdowns: a dimming scrim behind an undimmed cutout of the pressed item that lifts and scales above it, a panel that flips above or below the source depending on where it sits, and hairline separators between rows, with every measurement recalibrated against real iOS captures. Regular native menus, action sheets, and the developer menu were brought to conformance too, menus now open on a plain tap again, the dev menu is a real native action sheet, and modal sheets dim and stack exactly like iOS 26 with a flat 20 percent black dim and a 37.5pt corner radius. Apps built on react-native-bottom-tabs now run the real library through a genuine native seam covering roughly 95 percent of the tab API, so a widely used tab bar previews correctly with no app-specific stand-in, and because a simulator cannot buzz your hand, haptics now show as a visible pulse in the Dynamic Island that scales with the impact.
Ship an exported app to a real iPhone
Taking an exported app all the way to a real iPhone and TestFlight surfaced and fixed a chain of breaks. Templates now ship the native build settings needed to compile in Xcode, custom-named projects build cleanly at pod install, App Store Connect key registration signs its tokens with a method the cloud runtime actually supports, and a deploy’s build trigger is kept alive to completion instead of being killed the instant the response returns, which had left deploys stuck building forever. Native sign-in works on device now that a leftover session cookie no longer trips the anti-CSRF check and an auth header is no longer dropped by a later request rewrite. The Production pane shows your place in the build queue and a submission-readiness checklist before you can send to Apple, each item with a concrete fix. Creating a project from the CLI and exporting a project to a tarball, both of which had been failing in production because the cloud runtime has no filesystem, now read their template inputs from cloud storage, with each deploy verifying a real multi-megabyte archive comes back before it is called healthy.
Report a bug from inside the sim
Reporting an issue from SootSim’s devtools used to just log to stderr while nothing was kept. Now a report with a screenshot, your note, your last 50 logs, and version info is durably saved, the team gets an email when one lands, and operators get an inbox to triage each one. A public Reporting Issues guide spells out exactly what is captured and the privacy posture, and the onboarding privacy pane is now accurate with a real crash-reporting opt-out that is honored everywhere, including crashes from your previewed app. A new telemetry command sets the same preference from the CLI, and DO_NOT_TRACK still forces it off.
Link your GitHub and email into one account
You can now link a GitHub identity to an existing email-based account and the reverse from Settings, so signing in a different way no longer strands you with two separate accounts. It is backed by a full merge that safely moves every project, thread, deployment, billing record, and API key onto the surviving account, renaming any projects that would collide on the same URL.
A cleaner SootSim site
The SootSim site dropped the preview’s fake macOS menu bar as its navigation for one real, auth-aware header that spans the homepage, marketing, and every dashboard page, with an org and repo breadcrumb and an avatar account menu. The homepage was reworked so media sits inside framed stage panels, and a bar chart shows real wall-clock numbers for driving the same Bluesky login-and-scroll flow: SootSim finishes it in 25.95 seconds against 37.01 for an agent driving a real device with iOS capture and 30.40 for Maestro, all measured by the same capture wrapper. The download page’s engine card now leads with verifiable claims, the top 500 native packages all load and run and the top 100 score 93 percent in a pixel-diff against a real iPhone, and the interactive 3D phone case that had looked dark and dull was brought to life with studio softbox lighting once the root cause turned out to be the near-black environment it was reflecting, not the materials.
Tech
The Cloudflare deploy stack, extracted into a reusable package
Across eighteen sequential parity-checked commits, Soot’s 4,241-line cloudflareDoDeploy.ts monolith was decomposed into a new app-neutral orez-cf-deploy package: worker-source shims, wrangler-config generation, migration-module building, worker pruning, the Cloudflare bundlers, and the readiness smoke check, all built on already-lifted orez engine pieces. Soot passes its own token prefix and re-exports the package as a drop-in facade, so no callers changed and the emitted worker bytes stay byte-identical to the old inline definitions, guarded by a parity test in the new package. A same-day dependency-range mismatch in the new package briefly red’d the prod deploy gate and was fixed by realigning the ranges. The package also gained WASM bundling, so consumer-declared .wasm modules are copied next to the worker and rewritten as CompiledWasm externals, and cross-worker cron forwarding, so a per-minute cron can fire authenticated posts at an app worker over a service binding.
The bug that emptied shared accounts
Drizzle’s table-level composite-primary-key helper was being silently dropped when the schema parser generated DDL for the Cloudflare Durable Object SQL layer, handled by neither the inline-column path nor the index parser. Two tables, one for account membership and one for repo build config, shipped to prod with no unique constraint at all, so every upsert against them silently no-oped. That was the concrete cause of prod showing accounts with zero member rows and team and billing provisioning quietly doing nothing. The fix emits a synthetic unique index alongside a composite primary key so the Durable Object has a real upsert target, followed by an admin-token-gated recover endpoint that idempotently re-runs just the access-restoring steps to backfill the already-affected prod data, since DO deploys apply DDL straight from the schema and skip the migration loop that would have moved the data.
Postgres-only SQL that silently breaks on Cloudflare’s SQLite
A LEFT JOIN LATERAL in the preview-upload account lookup was returning 500 on every GitHub-app branch build and flow-preview upload on Cloudflare’s Durable Object SQLite backend, which has no LATERAL keyword, and the pg-to-sqlite compatibility layer passed it through unchanged so the static check never caught it. It was rewritten as a correlated scalar subquery, and the same audit found two more Postgres-only constructs that compile clean but fail at runtime on DO SQLite. A new static check now scans raw SQL in the API layer for all three. Separately, drizzle’s typed SELECT path indexes rows positionally, but the DO Postgres shim returned column-keyed objects, so any typed query with a timestamp, json, or numeric column threw, now fixed by projecting object rows into arrays in column order when array row mode is requested.
Anonymous identity is now a server-signed cookie
Anonymous identity was previously a guessable random string set directly from client JS as an unsigned cookie, so anyone who learned another visitor’s anon id, for instance leaked in a share URL, could impersonate that anonymous workspace by setting the cookie themselves. Now the bootstrap endpoint mints the cookie server-side, HMAC’d with the app secret, HttpOnly, SameSite Lax, and Secure on HTTPS, and every consumer verifies the signature before trusting the id: request-principal resolution, anon-to-user migration on login, sync push and pull, branch creation, collaboration, and iOS auth. An unsigned or tampered cookie now resolves as unauthenticated rather than as that anon identity, closing the residual flagged open in the June security audit.
Rate limiting the sync push endpoint
A rate limiter now sits in front of the sync push endpoint, backed by Cloudflare Durable Object storage with an in-memory fallback for dev and test. Ordinary mutations are capped at 1,200 a minute per scope, per user or per anonymous IP, and heavier actions get their own budgets: project creates at 3 a minute and 30 a day, deploys at 3 per 10 minutes and 20 a day, plus a per-project cap of 2 deploys per 10 minutes. The limiter parses each push body to classify the mutations inside it, so the heavy-action budgets still apply even when a project create or deployment is buried in a batched custom-mutation push.
SootSim scroll and animation, rebuilt
A deep dive into WebKit frame timings found the renderer repainting every open app on a single home-screen clock tick, decode-related GPU format info read once per sample instead of once per context, and oversized auto-retained content wrappers that kept scroll rows from ever qualifying for raster caching. The fixes scope dirty-marking to just the surfaces a value actually changed, double the glyph-atlas budget so scroll text stops re-decoding, read GPU format info once per context, let oversized wrappers yield raster retention to their children, and promote expensive scroll-row content into cached raster images. On a real feed scroll, average frame time went from the 13.7 to 17.2ms range down to 4.2ms, p95 from 21 to 35ms down to 5.1ms, and jank from 17 to 52 percent down to 2 percent. The raster caching exposed correctness gaps that were fixed in the same window, including a backdrop-sampling seam under partial-damage clips and a swiped row whose cached raster was not invalidated on non-composited style writes.
No more keyboard-open jank from a GPU blur readback
The iOS frosted-glass material behind the keyboard, Alert, ActionSheet, and app-switcher cards was doing a synchronous GPU-to-CPU pixel readback and re-upload roughly 15 times a second on the single shell paint thread the whole time any blur surface was open, each a 12 to 30ms stall eating into the keyboard-slide’s frame budget while the render worker sat about 96 percent idle. Three gates fixed it: skip the readback during an active animation or transition, skip it unless the app surface actually repainted since the last capture, and downsample the capture to logical resolution for about 9 times less GPU memory. Open-slide captures dropped from 7 to 1 and the settled-open rate fell from about 15 to 6.5 a second with pixel-identical output. That incidentally removed a repaint a rounded glass corner relied on, closed with a decoupled readback-free repaint for a bounded tail after any change under the glass.
One shared Yoga layout pass over a SharedArrayBuffer
The tenant worker now runs the only Yoga layout pass and publishes each node’s geometry into a SharedArrayBuffer-backed layout table, and the shell worker adopts that geometry directly on every paint instead of re-running a second Yoga pass on its own mirror tree. This kills both the two-Yogas-drift bug class and the mid-fling relayout cost, and shell-side worklet measure calls now read committed tenant geometry straight from the table. It falls back to the old dual-Yoga path when cross-origin isolation, and therefore SharedArrayBuffer, is unavailable, with a stress test proving the adopted geometry stays identical under continuous scroll.
The real Reanimated driver, in dev and production
SootSim’s own native-styled UI and the react-native-gesture-handler Swipeable that tenant apps use now animate through the actual Reanimated driver instead of a simplified JS animation, so spring and gesture-driven UI times and feels like it does on a device, verified with 54 of 54 conformance passes and about 40 percent less flakiness under load. Getting there took real engine work, including pairing the UI-runtime kind with the worklet global upstream’s installer sets, and fixing a scroll-damage bug that double-counted a swiping row’s own translation and left paint trails. Worklets built through the bundle-mode transform, used for production and OTA bundles, were also broken two ways: bundle mode omits the init-data source the dispatcher relied on, recovered now via a toString fallback, and Reanimated 4 outlines nested worklets into separate modules loaded through Metro’s require, which does not exist in the shell worker, fixed by recursively inlining the outlined factory at serialize time. Reanimated now behaves identically in dev and bundled previews.
A self-hosted OTA pipeline that won’t ship JS the binary can’t run
The mobile app now ships JS updates over the air from a self-hosted Expo Updates server, a Cloudflare Worker backed by an R2 bucket speaking the Expo Updates v1 protocol, replacing an earlier third-party dependency. A publish script builds the iOS bundle exactly the way Xcode’s own phase does. Adding haptics meant shipping a native module, and an early OTA pushed the haptics-dependent JS to TestFlight binaries that predated the native pod, crashing on launch. The durable fix computes a native fingerprint from podfile checksums plus the new-architecture flag at publish time, recording a baseline on the first publish per runtime and hard-failing later publishes on drift, so an update can never ship JS a device’s binary cannot run. TestFlight build linking now also blocks orphaned mismatched-runtime builds.
Local dev and CI on real embedded Postgres
Orez’s local-dev and CI backend now runs a real embedded Postgres cluster instead of WASM-based PGlite, so zero-cache syncs over its actual production logical-replication path, a genuine pgoutput replication slot, instead of a faked pg-wire proxy, serializing mutex, and change-tracking trigger log. This removes the vacuum and checkpoint timer overhead that was spiking machine load during concurrent agent-factory waves, validated end to end with a real slot tracking WAL in lockstep across 62 migrated tables. The dependency bump briefly broke Cloudflare worker builds by pulling seven unused per-platform Postgres binaries into the bundle graph, fixed same-day by loading the backend through createRequire rather than a static import.
Production AI chat on Cloudflare Workers AI
Soot’s default production model now calls Cloudflare Workers AI’s OpenAI-compatible endpoint directly and bills against Soot’s Cloudflare AI credits, instead of routing through OpenRouter, while local dev and CI keep the OpenRouter path so they do not need Workers AI credentials. The direct route trades a smaller context window, 262k against 1.05M tokens, for a larger max output, 262k against 131k tokens.
SootSim
- Sibling views that swap stacking order now repaint in the new order, and continuous squircle corners now actually work in app code where they were silently ignored.
- An image that finishes loading after first paint repaints its correct region instead of staying partly blank, and custom fonts that load a moment late trigger a repaint so text leaves the fallback.
- Scrolling comes back immediately after an iOS edge swipe back instead of going dead, and an animation path degrades to a static reference under memory pressure instead of crashing the dispatch.
- Fixed crashes for apps that deep-import Apple’s Liquid Glass view, that read custom values off their Expo config, and that open a native bottom-tab screen, where the router and tab library each bundled their own copy of the navigation theme context.
- The inspector and accessibility overlay now clip an element’s reported geometry to its nearest scrolling container, and test lookups no longer misreport a dense list tiled edge to edge by its own rows as hidden.
- A custom map marker with child content now projects its real coordinate onto the map and draws your view there instead of falling back to a generic pin.
- A parked react-native-webview can show its real live web content via a dev-menu toggle, and a backgrounded WebView parks behind a tap-to-load placeholder rather than a throttled offscreen frame that never finishes loading.
- The dock now fetches a slow dev server’s manifest out of band and republishes the entry with the real name and icon instead of a bare port number.
- A Safari-only tap misfire right after the home and app screens swapped is fixed, gradient swatches in the devtools rail clip to a clean circle, several blank SF Symbol tab icons draw again, and an oversized tab-bar search icon was reverted to its calibrated size with a regression test.
- Home-screen chrome tuning: a restyled background gradient and ambient rings, adjusted bezel padding and metallic ring shading, and a subtle text shadow on app labels.
Mobile app
- Faster, calmer preview boot with real staged progress and a lifted command bar, booting only the surface you are looking at instead of both in-browser runtimes at once.
- The floating preview card deck tracks your finger on both axes with real parallax, interpolates directly between docked and picture-in-picture layouts, and reshuffles on a quick flick away from the edge.
- Mobile inspect draws a selection rectangle around the element you pick, matching the desktop inspector, and out-of-credits mid-chat shows a clear notice instead of the conversation going blank.
- Scroll views pad their content by the tab bar’s real height plus the safe-area inset so the last row no longer tucks under the floating tab bar.
- Fixed the app icon’s white border, the settings gear that silently did nothing because the screen was never declared as a route, and chat that never got past Connecting after being pointed at a sync host the edge router rejects.
- Softened the device-preview drop shadow and fixed the stacked-card fan geometry and picture-in-picture scaling so iOS content keeps its aspect ratio.
- Live React Native runner: your own signed-in project’s iOS preview can switch from the simulated canvas to a real, live React Native runtime with real native views and gestures, early and experimental.
Editor and IDE
- Opening Overview now keeps your current section in place while the panes rearrange into and out of the overview layout, instead of jumping to a separate page.
- The element picker is now a compact input that appears where you click: type a message, press Enter, and it attaches the picked element’s snapshot and sends it to chat in one step.
- Inspect mode can open the exact source file and line for a React Native element in your editor, opt-in via a small Babel plugin that tags your own JSX.
- DevTools stays reachable from the section overview across native and web dev panes, and the Inspect quick action disables itself unless a dev pane is focused.
- Repo owners get a settings gear pinned in the dashboard header with build controls: whether a preview builds on every push, which platforms build, which branches always auto-build, and whether build and share links are public or unlisted.
- Repository settings became a sidebar-navigated dialog with focused panes, shared preview links can be set private or public, and the org dashboard now lists repos connected purely for preview, not just editor projects.
- Branch review’s diff pane got readable, sized text and working scroll with its redundant nested panels flattened, and keyboard navigation polish: a persistent focus ring, left and right arrows moving between columns, and a clearer focused-pane glow.
- Fixed press-popovers staying stuck open when focus moves into a preview, the nav dropdown silently reopening after a click, and the native preview’s letterbox flashing opaque on a light-dark system flip.
Auth and onboarding
- Fixed two real data-loss bugs when an anonymous project becomes a signed-in one: the seeded welcome message made every anonymous project look already-edited so the migration’s cleanup never ran, and a stale reference to your old anonymous account could bounce you out of the project you just signed into.
- Magic-link sign-in now times out after 30 seconds with a clear message instead of hanging, stale errors clear when you retype or switch methods, and a real delivery failure surfaces as an error instead of a false check-your-email.
- A failed GitHub OAuth callback lands on the login screen with the specific error and a retry instead of the marketing page, and the sign-in popup closes itself on success.
- The login and success screens share dark, grain-textured chrome with the mascot reacting to state, plus a watchdog with a retry so a stuck OAuth redirect does not strand you.
- Account and team invite links route to the correct join destination for each invite type, and a brief centered Welcome chip appears after you sign in on a lightweight notice tier.
- Cleaned up pre-launch splash dead-ends: already-signed-in visitors go straight in, signing out returns to the real app entry point, and the top bar always shows a Login state while your session is still resolving.
- A shared onboarding link that skips the welcome screen now fires reliably instead of hardcoding the wrong home path, and a broken tour step pointing at a stale target was removed.
Website and marketing
- The homepage hero’s animated dithered background is now a pre-baked texture with lightweight CSS drift, and about a dozen below-the-fold cards pause while off-screen, dropping measured hero CPU from 52 to 14 percent.
- The homepage no longer plays its entrance animations twice, now that a lazily loaded chunk hydrates in place instead of discarding and remounting the server-rendered page.
- CTAs on the changelog, compat, legal, and pricing pages plus the team page’s nav buttons now navigate instantly instead of quietly falling back to a full browser reload.
- SootSim theme now follows the right source everywhere: marketing, docs, and share pages stay dark, signed-in pages follow your OS, and a leftover saved preference from a removed toggle is cleared automatically.
- The compatibility directory gained real numbered page jumps that stay compact past 50 pages, and the SootSim home demo gained a slim phone-side sidebar that reopens the intro and shows a launched app’s name and description.
- Fixed a white flash on the embedded test-drive’s first load on Safari, restored the platform-detected desktop download buttons after a regression, put the wordmark’s phone glyph back between the words, and cropped the wordmark’s baked-in padding so it renders at the height you ask for.
- Flattened the devtools dock, widened the signed-in dashboard, reorganized the account menu to lead with your dashboard, and fixed a duplicate title tag on production app pages.
- Marketing visual and copy polish across both sites, and a round of hero, footer, and mascot-anchoring tuning.
Previews and sharing
- The shared preview page’s share button works again after a nested-button bug had made it dead for every visitor, and it hides for signed-out viewers.
- The replay cursor now tracks the video’s own clock instead of lagging up to about 5 seconds behind, and the recorded video is cached immutably and pre-warmed as the page’s metadata loads.
- GitHub PR-preview links are openable by reviewers again after a private-by-default change had broken them, while your own manual shares still default to private.
- App Store screenshot review resolves through the public build list so it works without a signed-in session and picks the right branch’s build, with one shared Save and Cancel pair per source mode and a fixed 3D phone mockup.
- Any gallery listing backed by a source project can now be forked into your own workspace, labeled Fork app or Fork template to match.
CLI
- SootSim setup went npx-first: the download page shows a single copyable command, and setup asks which package manager you use, checks for pinned Node versions, and scaffolds a plain JS config for JS apps instead of forcing TypeScript.
- New
contrast link --createpublishes a project you built locally as a fresh cloud project, and newsootsim linkjumps straight to a route or deep link inside a running simulator. - Installing an agent skill now symlinks it to the source so edits go live with no re-install, and the sootsim CLI’s one-off commands were merged into single verb groups.
- Reload and reconnect reliability: open, list, and reload now read bridge port and shell URL from one source of truth, reload compares a build fingerprint so long-lived sim tabs pick up a rebuilt engine, and the post-reload reconnect budget went from 10 to 30 seconds.
- The on-canvas prompt bar routes through to a claimed CLI agent session, and driving a browser tab’s navigation through attach no longer hangs to its 90-second timeout by awaiting the mutation’s server-durability ack before reloading.
Templates and examples
- A deep visual-quality sweep across the finance, travel, pet game, and RPG starters: killed a flash of unstyled content, fixed pale text and wrong-colored buttons, gave login and CTA buttons solid high-contrast fills, upgraded the hero to a high-res golden-hour photo with a theme-aware edge fade, and added a crash-recovery screen.
- A mobile-web sweep fixed containers collapsing to zero height, missing safe-area insets under tab bars and floating buttons, a broken login button order, a silently-failing guest login, truncated trip titles, and a mispositioned map caption, with marketplace screenshots refreshed to match.
- The travel and finance landing heroes fade their photo in cleanly on web and native via a real cross-platform mask, and the travel hero swapped fake floating chips for a real interactive mini-map with numbered stop pins.
- Standalone clones and exports build again after several templates leaned on a monorepo-only clipboard stub instead of declaring the real dependency, and native iOS builds no longer fail on a custom app name.
- Broader template polish: accent-themed buttons, a real favicon in every template, removed stray link underlines, and a WebGPU pet-game scene that mounts instead of hanging on a layout gate.
Docs
- A sweeping accuracy pass on the SootSim docs: broken cross-site links resolve, the CLI reference matches the real commands, and a pile of fabricated defaults, a nonexistent test API, and two imaginary testing sections were replaced with the real ones, plus real explanations of the engine’s cross-worker native-driver mirror, damage-rect compositor, and Fabric self-identification.
- Restructured the docs site: the old Concepts section folded into a tighter Essentials guide, with new Apps and Launch sections, a subtitle-cards sidebar, and better search, every command and price re-verified against the shipping CLI and UI.
- A new Troubleshooting guide walks through version, upgrade, runtime, diagnosis, and compat checks, cross-linked with the Reporting Issues guide.
- The pricing page now spells out the open-source boundary, the CLI, engine, and conformance suite free for non-commercial use against the paid app and cloud features, and Terms and Privacy were finalized for public beta.
Explore, chat, and design
- A brand-new chat’s starting-point picker offers App, Game, Website, and map-itinerary starter cards, and the project-creation agent can search the public app catalog to match your idea to an existing forkable app.
- Curated app listings now reconcile on every seed so a caretaker’s edits to a listing’s title, icon, tags, or supported runtimes actually reach the site, with a freshness check to catch drift.
- Swapped the hand-drawn pixel icons for Phosphor icons across chat, marketplace, docs, the editor, billing, and the factory chrome, pasted URLs in chat render as safe clickable links, and a two-tap bug on styled buttons under the animation driver now takes the first tap.
- The in-app terminal writes directly and batches redraws so a heavy stream stays smooth, and native modules that are genuinely absent now read as undefined instead of a fabricated permissive stand-in.
Tech (smaller wins)
- Root-caused why the containerized recording runner failed on real walkthroughs: with no GPU it falls back to SwiftShader and starves capture and CanvasKit for CPU. A GPU-backed cloud runner renders the same WebGL2 workload at 60.4fps against single-digit fps on SwiftShader, at roughly 0.2 to 1.3 cents of GPU compute per recording.
- Continuing last week’s in-place Zero resync, that approach was found to leave long-running authenticated tabs half-broken when the fresh client also failed, so recovery now clears both local stores and does a single gated reload, unified across web and mobile through one hook that also teaches the native SQLite client to auto-recover from a finalized-statement crash.
- Closed sync races: the client blocks on the anonymous bootstrap promise before mutating, and the home-to-IDE handoff updates state in place instead of remounting the sync client and flashing a fresh anonymous user.
- Moved client-side stale-storage recovery and cleanup into on-zero, thinning the client wrapper, after restoring the mobile template’s native resync-burst guard that an earlier deletion had wrongly assumed was covered.
- The AI build factory can run headless build waves inside a Cloudflare container and Durable Object instance, after shipping the headless route into the deployed worker’s allowlist and switching wave-stop to actually destroy the container.
- Faster preview boot by spawning and initializing the local-database worker during an idle pre-gate window, then adopting it once the real boot starts, since the DB worker and initial sync handshake dominate startup over SQL setup.
- Halved home-screen idle CPU by wrapping the live Clock icon’s 60 static tick marks in a repaint boundary, dropping the idle tree walk from about 88 to 42 node visits a frame, and fixed a node-registry memory leak by switching to weak references with explicit cleanup at every real discard site.
- Debounced idle-preview message thrash between tenant and host, where a flip-flopping vsync-demand flag was posting about 100 messages a second, with a 250ms hysteresis window while rising edges still post immediately.
- GitHub avatars are copied into Soot’s own storage on sign-in instead of hotlinking GitHub’s CDN, crash reports keep tenant app and session attribution, and new auth-lifecycle telemetry reuses the session cookie so a failed login is one joinable journey.
- PR-preview pipeline hardening: recordings judge trimmed visible duration so a slow runner does not get a legitimate take rejected, the cold-boot replay clears storage and skips gates whose target is confirmed missing, failures report their real cause, and unrecorded bundle-origin images serve a transparent placeholder instead of flooding the console.
- Forge TestFlight builds are no longer silently canceled by sharing the deploy workflow’s concurrency group, backstopped by a skip-gated 30-minute scheduled build.
- Reused a CanvasKit paint object for liquid-glass blur, coalesced rapid shell pointer-move events, and switched two native-stub-detection helpers back to a static import so the bundler keeps them in the caller’s chunk.
- Registered react-native-enriched-markdown with real Fabric host components so Streamdown’s renderer runs unmodified, and guarded the native-only bottom-tabs package out of web builds after moving generated apps onto it.
- Gesture-handler conformance: touch events carry the numeric shape apps read, a cancelled pointer drives the recognizer to cancelled, coordinates are view-relative, and a detector keeps its handler tag across config-only re-renders.
- Pruned the Cloudflare apex worker under budget by moving the native-bundle build pipeline behind a dynamic import, and bumped one to fix a Metro socket bug that queued every Zero sync handshake behind an unanswered upgrade in exported apps.
Fixes & polish
Beyond the headline work, 447 fixes and 21 performance improvements landed this week. A few worth calling out: two onboarding data-loss bugs are fixed so signing into an anonymous project no longer silently drops your work or bounces you out of it; any app using native bottom tabs no longer crashes with “Couldn’t find a theme” the moment a tabbed screen opens; and creating a project from the CLI and exporting a project to a tarball work in production again after the cloud runtime’s missing filesystem had been failing both.