Skip to content

Latest commit

ย 

History

165 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ScriptWidget ๐ŸŽจ

Website: https://xnu.app/scriptwidget/

โœจ Build iPhone, iPad, and Mac widgets in ScriptWidget Studioโ€”without writing Swift.


๐ŸŽฏ What is ScriptWidget?

ScriptWidget is an open-source widget development platform for building native WidgetKit experiences with JavaScript and JSX-like syntax. Write once, preview on Mac, and run the same package on iPhone, iPad, and Macโ€”without requiring Swift for widget authoring.

It combines a JavaScriptCore runtime, native SwiftUI rendering, a desktop development environment, secure package sharing, AI-assisted generation, and a GitHub-backed community catalog.

ScriptWidget template gallery


โœจ Features

Feature Description
๐Ÿ–ฅ๏ธ Cross-Platform One codebase for iOS and macOS widgets
๐ŸŽจ JSX Support Declarative UI with JavaScript XML syntax
โšก Native Rendering JSX elements are rendered as native SwiftUI views
๐Ÿ”ง Versioned Runtime API Storage, files, networking, device, location, health, system, and data sources
๐Ÿ“ฑ Interactive Widgets Links, buttons, toggles, App Intents, Live Activities, and Control Widgets
๐ŸŽจ Custom Styling Full control over appearance
๐Ÿ“ฆ Template Gallery Pre-built templates to get started
๐ŸŒ Community Gallery Verified, one-click Widget and AI Skill installs
๐Ÿงฐ ScriptWidget Studio Build on Mac with CodeMirror, diagnostics, console, and multi-size preview
โœจ AI Generation Generate, run, diagnose, and refine widgets with an OpenAI-compatible model
๐Ÿง  Skills 1.0 Import, author, export, and share focused AI instructions
๐Ÿ“ฆ Package 2.0 Versioned widget.json, permissions, host allowlists, migration, and hardened imports
๐Ÿ”Œ Data Source Plugins Declarative third-party API connectors with a Mac request lab

ScriptWidget Studio for Mac

Studio is the primary place to build widgets:

  • project file tree with multiple JavaScript/JSON files and package resources;
  • CodeMirror 6 editing, schema completions, diagnostics, formatting, autosave, and crash recovery;
  • live preview for one or every supported widget family, plus runtime console and timing information;
  • Config panel for widget.json, families, permissions, network domains, plugins, and preview parameters;
  • AI generation with provider profiles, iterative run/diagnose/refine, and reusable Skills;
  • verified Widget & Skills Gallery and a Data Source Lab for testing plugin operations.

The first-launch guide can create a complete tutorial widget and walk a new user from editing through adding it to the desktop in about five minutes.


๐Ÿš€ Quick Start

1. Download

# Clone the repository
git clone https://github.com/everettjf/ScriptWidget.git
cd ScriptWidget

2. Open in Xcode

# iOS app + widget + share extension
open iOS/ScriptWidget.xcodeproj

# macOS app + widget
open macOS/ScriptWidgetMac.xcodeproj

3. Run & Explore

  1. Select a scheme (ScriptWidget / ScriptWidgetWidget for iOS, ScriptWidgetMac for macOS)
  2. Enable the iCloud.ScriptWidget container and group.everettjf.scriptwidget app group so script storage works
  3. Press Cmd + R to build and run
  4. Browse the bundled example scripts under Shared/ScriptWidgetRuntime/Resource/Script.bundle/ (api/, component/, template/)

๐Ÿ“ Project Structure

ScriptWidget/
โ”œโ”€โ”€ Shared/
โ”‚   โ””โ”€โ”€ ScriptWidgetRuntime/   # Core runtime: JavaScriptCore host, JSXโ†’SwiftUI
โ”‚       โ”œโ”€โ”€ AI/                # Provider settings, agent loop, evals, Skills
โ”‚       โ”œโ”€โ”€ Common/            # Script storage, Package 2.0, cache & imports
โ”‚       โ”œโ”€โ”€ Gallery/           # Verified GitHub catalog, cache & installer
โ”‚       โ”œโ”€โ”€ Plugin/            # Declarative Data Source Plugin runtime
โ”‚       โ”œโ”€โ”€ Widget/Runtime/    # JS engine setup, Babel transform, execution
โ”‚       โ”œโ”€โ”€ Widget/API/        # JS APIs ($device, $file, $storage, ...)
โ”‚       โ”œโ”€โ”€ Widget/Component/  # Element โ†’ SwiftUI view mapping
โ”‚       โ””โ”€โ”€ Resource/          # Babel bundle + bundled example scripts
โ”œโ”€โ”€ iOS/
โ”‚   โ”œโ”€โ”€ ScriptWidget/          # iOS app (editor, settings)
โ”‚   โ”œโ”€โ”€ ScriptWidgetWidget/    # Widget, Live Activity, Control Widget
โ”‚   โ””โ”€โ”€ ScriptWidgetShare/     # Share extension
โ”œโ”€โ”€ macOS/
โ”‚   โ”œโ”€โ”€ ScriptWidgetMac/       # macOS app
โ”‚   โ””โ”€โ”€ ScriptWidgetMacWidget/ # macOS widget
โ”œโ”€โ”€ Editor/editorfe/           # Vite + CodeMirror 6 editor frontend
โ”œโ”€โ”€ Gallery/                   # Curated Widget & Skills Gallery index
โ”œโ”€โ”€ Tests/                     # Shared runtime, execution, cache & security tests
โ”œโ”€โ”€ docs/                      # User, API, package, Skills & release documentation
โ”œโ”€โ”€ Resource/                  # Marketing assets, screenshots
โ””โ”€โ”€ README.md

๐Ÿ’ป Example Widgets

A script's entry point is the $render(...) call, which takes a JSX tree built from runtime tags (vstack, hstack, zstack, text, image, gauge, chart, ...).

Hello World

$render(
  <vstack frame="max">
    <text font="title">Hello, ScriptWidget! ๐Ÿ‘‹</text>
  </vstack>
);

Fetch remote data

const result = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const model = JSON.parse(result);

$render(
  <vstack>
    <text font="title">{model.title}</text>
  </vstack>
);

Package 2.0 widgets using network access must declare the network permission and matching hosts in widget.json.

Use a Data Source Plugin

const weather = await $dataSource.request(
  "app.scriptwidget.datasource.open-meteo",
  "forecast",
  { latitude: "37.7749", longitude: "-122.4194" }
);

$render(
  <vstack frame="max" padding="16">
    <text font="caption">San Francisco</text>
    <text font="largeTitle">{weather.current.temperature_2m}ยฐ</text>
  </vstack>
);

The package must declare the plugin identifier, network permission, and the plugin host. Plugins are declarative HTTPS request mappingsโ€”not executable native extensions.

Persist values with $storage

$storage.setString("greeting", "Hello ScriptWidget");
const greeting = $storage.getString("greeting");

$render(
  <vstack frame="max" background="#0f172a">
    <text font="caption" color="#94a3b8">Storage</text>
    <text font="title3" color="#e2e8f0">{greeting}</text>
  </vstack>
);

๐Ÿ› ๏ธ Development

Prerequisites

  • Xcode 27+ for the current development branch
  • macOS 26+ for ScriptWidget Studio
  • iOS 16+ (for iOS widgets)

Build from Source

# Clone and setup
git clone https://github.com/everettjf/ScriptWidget.git
cd ScriptWidget

# Open in Xcode (pick the platform you want)
open iOS/ScriptWidget.xcodeproj      # iOS
open macOS/ScriptWidgetMac.xcodeproj # macOS

# Build and run (Cmd + R)

The editor frontend (React + CodeMirror) lives in Editor/editorfe:

cd Editor/editorfe
npm install
npm start   # dev server at http://localhost:3000
npm test
npm run build
npm run release # rebuild and copy StudioEditor.bundle into both apps

Run the same repository gates used by CI:

./Scripts/release-readiness.sh
./Scripts/ipad-icloud-tests.sh

Create Your Own Widget

  1. Open ScriptWidget Studio on Mac (or ScriptWidget on iPhone/iPad) and create a script from a template, AI prompt, or blank project
  2. Write your widget in main.jsx and call $render(...) with a JSX tree
  3. Use the live preview to iterate, then add the widget from the Home Screen

Each widget is stored under Scripts/<PackageName>/ and synced through iCloud/app-group storage. New projects use Package 2.0:

My Widget/
โ”œโ”€โ”€ widget.json
โ”œโ”€โ”€ main.jsx
โ”œโ”€โ”€ lib/
โ”‚   โ””โ”€โ”€ format.js
โ””โ”€โ”€ image/
    โ””โ”€โ”€ background.png

widget.json is the authoritative, versioned manifest. It declares the entry point, supported families, permissions, allowed network hosts, and Data Source Plugins. Legacy main.jsx/meta.json packages remain readable and migrate during supported import/export flows.


๐Ÿ“š Documentation

Start with the documentation hub or build your first widget in ScriptWidget Studio.

Core Concepts

  • Entry point - call $render(<tree/>) to draw the widget
  • Components - vstack, hstack, zstack, text, image, gauge, chart, shapes, ...
  • Styling - element attributes such as font, color, background, frame, padding
  • Widget sizes - read $getenv("widget-size") (small / medium / large / accessoryโ€ฆ)
  • Interactions - buttons and links via App Intents

APIs

API Description
fetch() HTTP requests (fetch/$fetch)
$storage Persisted key/value store (string & JSON)
$file Read/write files in the script package
$device Device info (model, battery, screen, dark mode, โ€ฆ)
$location Location & geocoding
$health HealthKit data (steps, heart rate, โ€ฆ)
$system System info (timezone, app version, โ€ฆ)
$import Import another file from the package
$dataSource Call a declared Data Source Plugin operation
$runtime Runtime API version and enforced resource limits
console Logging (console.log / console.error)

The native JSX component switch is the runtime authority. Studio keeps static completion metadata in scriptWidgetAPI.js, checks it against the native switch, and generates the Runtime API reference from it.

๐Ÿ” Security model

Widget packages, Gallery content, Skills, and Data Source Plugins are treated as untrusted input:

  • Package 2.0 rejects unknown fields and unsupported versions.
  • Archive imports reject traversal, absolute paths, symlinks, encrypted entries, case collisions, malformed ZIP metadata, and oversized payloads.
  • Package file access remains package-relative; storage is package-namespaced and bounded.
  • Package 2.0 networking requires explicit permission and a matching host declaration; generic fetches are limited to public HTTP(S), while Data Source Plugins require HTTPS. Private/local hosts and oversized responses are rejected.
  • Gallery files are restricted to the curated GitHub trust root and verified by exact byte count and SHA-256 before installation.
  • Skills are prompt-only and cannot execute code, access secrets, or grant runtime permissions.
  • Data Source Plugins are declarative request mappings and cannot load arbitrary native code.

See Package 2.0, modern WidgetKit features, Skills 1.0, Gallery, and Data Source Plugins for the complete contracts.


๐ŸŽจ Gallery

Widget Gallery

Sample widgets created with ScriptWidget


๐Ÿ“ฑ Platforms

Platform Support Notes
iOS โœ… Full iOS 16+ (iPhone, iPad)
macOS โœ… Full macOS 26+ (Mac)
watchOS โ€” Not in the current roadmap
visionOS โ€” Not in the current roadmap

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide for details.

Ways to Contribute

  • ๐Ÿ› Report bugs
  • ๐Ÿ’ก Suggest features
  • ๐Ÿ”ง Submit pull requests
  • ๐Ÿ“ Write documentation
  • ๐ŸŽจ Share your widgets
  • ๐Ÿง  Share focused AI Skills

See the public roadmap, governance model, and Gallery submission guide. Every pull request runs the same release-readiness checks used locally.


๐Ÿ“œ License

The source code in this repository is released under the MIT License.

The ScriptWidget name, logos, screenshots, and App Store marketing materials are not licensed under the MIT License. All rights to those brand and marketing assets are reserved by their respective owners.


๐Ÿ™ Acknowledgements

Built with:

Inspired by:


๐Ÿ“ˆ Star History

Star History Chart


๐Ÿ“ž Support

GitHub Issues GitHub Discussions Discord

ๆœ‰้—ฎ้ข˜๏ผŸๅŽป Issues ๆ้—ฎ๏ผ


Made with โค๏ธ by Everett

Project Link: https://github.com/everettjf/ScriptWidget

About

ScriptWidget is an iOS/macOS app that we can create widgets for iOS/macOS using JSX label style in JavaScript.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

276 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages