Rootless

Automate iOS, iPadOS, and macOS using plain JavaScript. Build custom widgets and interact directly with native APIs.

Download on the App Store
Rootless app interface

Plain JavaScript

Supports ES6. Scripts are stored as plain .js files on your disk.

Native APIs & Documentation

Integrate directly with iOS native APIs. Fully documented, available offline.

Siri Shortcuts

Trigger scripts via Siri. Present tables, websites, and custom HTML natively.

System Integration

Run from the Share Sheet, process inputs, and manage local files via Files.app.

x-callback-url

Communicate seamlessly and trigger workflows with other apps on your device.

Customizable & Ready

Tailor the code editor to your liking. Includes several example scripts to start immediately.

Documentation

Also inside the app, or as rootless.json.

Animated

How a node changes between renders

A widget is not running while it is on screen. Its views are rendered in another process, archived, and shown later, so an animation is the difference between two renders and the system plays it. No loops, no timers, nothing longer than two seconds. id and value do different jobs and both are required. id is stable and marks a view as the same one as last render; without it the tree, rebuilt from scratch every run, looks new and gets crossfaded. That is the usual reason a transition appears to be ignored. value is what changed, and is what fires the animation. Animations are switched off on the Always-On display automatically.

Methods

Animated(options)WidgetNode

Wraps a node with { id, value, animation, transition, contentTransition, child } so an update animates instead of crossfading.

  • options Any required
    • id String required

      Stable across runs. Without it the system treats the view as new and crossfades it, which is why a transition seems ignored.

    • value Any required

      What changed. The animation fires when this differs from last render.

    • animation Animation

      Which curve to use.

    • transition Any

      How the view arrives and leaves. Needs id.

    • contentTransition Any

      How a value inside a view that stays changes.

    • child WidgetNode

      The node inside.

Examples

A number ticking over

var total = Storage.get("total") || 0;

Animated({
  id: "total",
  value: total,
  animation: Animation.spring({ duration: 0.3 }),
  contentTransition: ContentTransition.numericText(),
  child: Text(String(total), { font: Font.TITLE }),
})

A row that slides in when it changes

Animated({
  id: "latest:" + item.id,          // changes when the item does
  value: item.id,
  animation: Animation.easeInOut({ duration: 0.4 }),
  transition: Transition.push(Edge.bottom),
  child: Text(item.title),
})