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.

Path

Custom shapes, drawn as vectors

A vector outline, drawn by SwiftUI rather than rasterised: it scales with its frame, costs no memory and takes part in layout. viewBox sets your own coordinate space and the outline is fitted to whatever size the widget gives it, so one component serves every family. fit defaults to BoxFit.contain, which keeps the proportions; BoxFit.fill stretches each axis independently. One fill and one stroke per shape: a multi-coloured icon is several Paths in a Stack sharing a viewBox.

Methods

Path(options)WidgetNode

A vector outline, drawn by SwiftUI rather than rasterised.

  • options Any required
    • commands [Any] required

      The outline, as an array. Build it with Path.move, Path.line, Path.curve, Path.quad, Path.arc and Path.close, or all at once with Path.d.

    • viewBox Any

      The coordinate space the commands are written in, as { width, height }. The outline is then fitted to whatever size the widget gives it, so one shape serves every family.

      • width Number required
      • height Number required
    • fit BoxFit

      How the outline fills the space. contain by default, which keeps the proportions; fill stretches each axis on its own, which is what a chart wants.

    • fill Color

      Fill colour.

    • fillGradient LinearGradient

      Gradient fill. Wins over fill.

    • fillRule String

      nonZero (default) or evenOdd, for how overlapping subpaths interact.

    • stroke Color

      Outline colour.

    • strokeWidth Number

      Outline thickness.

    • strokeCap String

      butt (default), round or square, for how a line ends.

    • strokeJoin String

      miter (default), round or bevel, for how two lines meet.

    • dash [Number]

      A dash pattern, as alternating lengths of line and gap.

    • width Any

      A number of points, or a Size.

    • height Any

      A number of points, or a Size.

Path.move(x, y)Any

Starts a new subpath at a point, drawing nothing on the way there.

  • x Number required

    Horizontal position, in viewBox units.

  • y Number required

    Vertical position, in viewBox units.

returns One command.

Path.line(x, y)Any

A straight segment from the current point.

  • x Number required

    Horizontal position, in viewBox units.

  • y Number required

    Vertical position, in viewBox units.

returns One command.

Path.curve(x, y, c1x, c1y, c2x, c2y)Any

A cubic Bezier from the current point. The end point comes first, then the two control points.

  • x Number required

    End point, horizontal.

  • y Number required

    End point, vertical.

  • c1x Number required

    First control point, horizontal. Pulls the curve away from the start.

  • c1y Number required

    First control point, vertical.

  • c2x Number required

    Second control point, horizontal. Pulls it into the end.

  • c2y Number required

    Second control point, vertical.

returns One command.

Path.quad(x, y, cx, cy)Any

A quadratic Bezier from the current point. The end point comes first, then the single control point.

  • x Number required

    End point, horizontal.

  • y Number required

    End point, vertical.

  • cx Number required

    Control point, horizontal.

  • cy Number required

    Control point, vertical.

returns One command.

Path.arc(cx, cy, radius, startDegrees, endDegrees, counterClockwise?)Any

A circular arc. For an elliptical one, write it as SVG and pass it to Path.d.

  • cx Number required

    Centre, horizontal.

  • cy Number required

    Centre, vertical.

  • radius Number required

    In viewBox units.

  • startDegrees Number required

    0 is three o'clock and the angle grows clockwise.

  • endDegrees Number required

    Where it stops. A full circle is 0 to 360.

  • counterClockwise Boolean

    Sweep the other way round. Default false.

returns One command.

Path.close()Any

Closes the current subpath with a straight line back to where it started.

returns One command.

Path.polyline(points)[Any]

A series of points: the first is a move, the rest are lines.

  • points [Any] required

    An array of [x, y] pairs.

returns One command per point.

Path.rect(x, y, width, height)[Any]

A closed rectangle.

  • x Number required

    Left edge.

  • y Number required

    Top edge.

  • width Number required

    In viewBox units.

  • height Number required

    In viewBox units.

returns Five commands: a move, three lines and a close.

Path.circle(cx, cy, radius)[Any]

A closed circle.

  • cx Number required

    Centre, horizontal.

  • cy Number required

    Centre, vertical.

  • radius Number required

    In viewBox units.

returns Two commands: a full arc and a close.

Path.d(data)[Any]

Parses an SVG path data string. Supports M L H V C S Q T A Z, absolute and relative.

  • data String required

    The contents of an SVG <path>'s d attribute. Flags written without separators, as an exporter minifies them, parse the same as spaced ones.

returns One command per segment. Elliptical arcs become one to four cubics each, since nothing below can express an ellipse.

Examples

Sparkline

var values = [3, 7, 4, 9, 6, 11, 8];
var points = values.map(function (v, i) {
  return [i * (100 / (values.length - 1)), 12 - v];
});

Script.setWidget(new Widget({
  padding: EdgeInsets.all(16),
  child: Path({
    viewBox: { width: 100, height: 12 },
    fit: BoxFit.fill,
    commands: Path.polyline(points),
    stroke: Color.blue(),
    strokeWidth: 2,
    strokeCap: "round",
  }),
}));

An icon pasted from a drawing tool

// Copy the `d` attribute out of Figma, Illustrator or an .svg file.
Path({
  viewBox: { width: 24, height: 24 },
  commands: Path.d("M12 2 L22 20 L2 20 Z"),
  fill: Color.orange(),
})