SwiftUI-powered widget builder that lets anyone author widgets with JavaScript + JSX and run them directly on iOS, iPadOS, macOS, widgets, Live Activities, and Dynamic Island surfaces. ScriptWidget is the multi-platform predecessor to JSWidget and remains useful for contributors exploring or extending the original runtime.
Docs, gallery, and FAQ live at xnu.app/scriptwidget
- Highlights
- Architecture
- Quick Start
- Repository Layout
- Writing Widgets
- Development Tips
- Contributing
- Roadmap
- Community & Support
- License
- JavaScript + JSX workflow – Build widgets with
$render(<stack>)and Babel-transpiled JSX primitives that map directly to SwiftUI components. - Runtime helper APIs – JavaScriptCore host injects
$fetch,$file,$location,$dynamic_island,$preferences, and environment getters for widget size/parameters. - Multi-target – One codebase powers the iOS/iPadOS app, WidgetKit extension (AppIntents, Live Activity, Dynamic Island surfaces), macOS app, and share extension.
- Offline-first storage – Scripts are stored under iCloud (
iCloud.ScriptWidget) when available and fall back to the shared app group to keep data in sync. - Open editor workflow – React + CodeMirror web editor mirrors the native experience for rapid iteration and previewing.
ScriptWidget is split across Swift and JavaScript targets while sharing the ScriptWidgetRuntime core.
| Area | Location | What it does |
|---|---|---|
| iOS/iPadOS app | iOS/ScriptWidget |
Script explorer/editor, gallery, import/export, photo picker, and settings. |
| Widget extension | iOS/ScriptWidgetWidget |
WidgetKit timelines plus Live Activity + Dynamic Island views backed by the runtime. |
| Share extension | iOS/ScriptWidgetShare |
Receives script bundles/assets from Safari, Files, and other apps. |
| macOS app + widget | macOS/ScriptWidgetMac* |
Desktop shell that reuses the shared runtime/resources. |
| Shared runtime | Shared/ScriptWidgetRuntime |
JavaScriptCore host, Babel preset, SwiftUI renderer, AppIntent glue, storage helpers. |
| Web editor | Editor/editorfe |
Create React App + CodeMirror 6 frontend for writing scripts. |
| Assets | Resource/ |
App Store marketing artwork, screenshots, and promo material. |
- Xcode 14+ with SwiftUI, WidgetKit, ActivityKit, and the
iCloud.ScriptWidgetcontainer enabled. - Node.js 16+ / npm for the React editor.
- No CocoaPods required — dependencies are vendored via Swift Package Manager.
git clone https://github.com/everettjf/ScriptWidget.git
cd ScriptWidget- Open
iOS/ScriptWidget.xcodeprojin Xcode. - Choose one of the schemes:
ScriptWidget– main appScriptWidgetWidget– widget extension + Live ActivitiesScriptWidgetShare– share extension
- Enable the
iCloud.ScriptWidgetcontainer and thegroup.everettjf.scriptwidgetapp group so script storage works on-device.
- Open
macOS/ScriptWidgetMac.xcodeproj. - Select
ScriptWidgetMac(app) orScriptWidgetMacWidget(widget) scheme and build/run. - macOS targets reuse
Shared/ScriptWidgetRuntime, so changes here automatically benefit every platform.
cd Editor/editorfe
npm install
npm start # Local dev server at http://localhost:3000
npm run build # Optional production build for embedding/distributionShared/ScriptWidgetRuntime/ # JavaScriptCore host, JSX renderer, runtime APIs
iOS/ScriptWidget* # App, widget, and share extensions for iOS/iPadOS
macOS/ScriptWidgetMac* # macOS app + widget sources
Editor/editorfe/ # React + CodeMirror editor frontend
Resource/ # Screenshots, marketing assets, icons
Scripts/ # (runtime) user-created widget packages, synced via iCloud/app group
Use $render with JSX components inside Scripts/<PackageName>/main.jsx packages. Runtime helpers such as $getenv("widget-size"), $getenv("widget-param"), $preferences, $file, $fetch, $location, and $dynamic_island are injected automatically.
const widgetSize = $getenv("widget-size");
const widgetParam = $getenv("widget-param");
const beijingDate = new Date().toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
const sanJoseDate = new Date().toLocaleString("zh-CN", { timeZone: "America/Los_Angeles" });
const newYorkDate = new Date().toLocaleString("zh-CN", { timeZone: "America/New_York" });
const sydneyDate = new Date().toLocaleString("zh-CN", { timeZone: "Australia/Sydney" });
$render(
<hstack frame="max">
<vstack alignment="leading">
<text font="title3" color="blue" font="custom,Unispaced">World Clock</text>
<text font="title3" color="green" font="custom,Unispaced">Beijing: {beijingDate}</text>
<text font="title3" color="orange" font="custom,Unispaced">San Jose: {sanJoseDate}</text>
<text font="title3" color="secondary" font="custom,Unispaced">New York: {newYorkDate}</text>
<text font="title3" color="purple" font="custom,Unispaced">Sydney: {sydneyDate}</text>
</vstack>
</hstack>
);- Keep user scripts under
Scripts/<PackageName>;ScriptManagermigrates them toiCloud.ScriptWidgetviamoveSandboxFilesToICloud()once the container is available. - Touching runtime or storage logic? Run the iOS/macOS app + widget schemes to confirm scripts render, Live Activity/Dynamic Island surfaces update, and migrations succeed.
- For editor changes, run
npm testinsideEditor/editorfe, smoke-test save/export, and rebuild before shipping. - Marketing assets live under
Resource/; refresh screenshots/icons if user-facing UI changes.
We welcome issues and pull requests! Before landing breaking runtime changes, please open an issue so we can discuss migration plans. Helpful areas right now:
- ScriptWidgetRuntime unit tests that cover JSX ➜ SwiftUI conversion and error reporting.
- React editor modernization (React 18, Vite/Vitest, TypeScript typings for runtime APIs).
- Documentation refreshes (per-target onboarding, localization, screenshots) and CI automation for
xcodebuild+npm test.
When submitting PRs:
- Reference the GitHub issue (or open one) describing the problem.
- Include repro steps or screenshots where applicable.
- Verify builds/tests for the targets you touched (see Development Tips).
| Item | Status | Notes |
|---|---|---|
| Documentation refresh (README, AGENTS) | ✅ Done | High-level overview + contributor guidance landed. |
| AI-generated Widget Builder | ⏳ Planned | Prompt-based assistant that writes starter widget scripts automatically. |
| AI-generated Widget Template Library | ⏳ Planned | Auto-generate ready-to-use widget variations for each size and style. |
| AI-generated Widget Guardrails | ⏳ Planned | Sandboxing + linting to keep AI-authored scripts safe to run. |
| AI-generated Widget Editor Integration | ⏳ Planned | Surface AI suggestions directly inside the React editor for instant inserts. |
| AI-generated Widget Distribution Pipeline | ⏳ Planned | Publish AI-generated widgets to a shared catalog with one-click import. |
- App Store: ScriptWidget
- Docs, gallery, FAQ: xnu.app/scriptwidget
- Issues & discussions: GitHub Issues/Discussions on this repository
MIT License – see LICENSE.