API Docs

hs.canvas

A low-level, absolutely-positioned drawing surface

hs.canvas mirrors v1 Hammerspoon's hs.canvas module: elements are plain JS objects (mirroring v1's Lua tables) describing shapes (rectangle, circle, oval, text) with a fill/stroke/strokeAndFill/clip/build/skip action pipeline. This is a different tool from hs.ui, which is a SwiftUI stack/layout builder for app-like interfaces -- reach for hs.canvas when you need absolute positioning, clipped/composited shapes, or direct window-level/Spaces control.

Coordinate systems -- read this before positioning elements

A canvas's window position (create({x, y, w, h}), and any later x/y you compare it against, e.g. from hs.screen) uses unflipped AppKit screen coordinates: y = 0 is the bottom of the screen, and y increases upward. This matches hs.ui.window.

But element content positioned inside a canvas -- every frame, center, and coordinates value you pass to appendElements() and friends -- is drawn top-down: y = 0 is the top of the canvas, and y increases downward. These two coordinate senses are independent of each other and easy to conflate, especially when a script computes an element's position from the same screen geometry it used for the window's own placement. If a shape appears vertically mirrored from where you expect, this mismatch is the first thing to check.

Example: a rounded screen corner overlay

const radius = 12
const corner = hs.canvas.create({x: 0, y: 0, w: radius, h: radius})
corner.appendElements([
    { action: "build", type: "rectangle" },
    { action: "clip", type: "circle", center: {x: radius, y: radius}, radius: radius, reversePath: true },
    { action: "fill", type: "rectangle", fillColor: { alpha: 1 } },
    { type: "resetClip" }
])
corner.levelValue(hs.canvas.windowLevels.screenSaver + 1)
corner.behavior("canJoinAllSpaces")
corner.show()

Types

This module provides the following types:

Properties

hs.canvas.windowLevels

{[key: string]: number}
Named window levels, exposed as raw numeric values (not opaque strings) so scripts can do arithmetic on them, matching v1 behavior.

hs.canvas.windowBehaviors

{[key: string]: number}
Named window Spaces/Exposé collection behaviors, exposed as raw numeric bit values.

hs.canvas.compositeTypes

{[key: string]: string}
Named compositing/blend rules usable as an element's `compositeRule` attribute.

Methods

hs.canvas.create(rect) -> HSCanvas

Create a new canvas Named `create()` rather than v1's `new()` -- `new` cannot be used as a JavaScriptCore-exported method name (it collides with the JS `new` operator keyword at the bridging layer), and this codebase's conventions additionally forbid method names starting with `new`/`alloc`/`copy` (an ARC/ObjC hazard).
hs.canvas.create(rect) -> HSCanvas
Name Type Description
rect {[key: string]: any} A `{x, y, w, h}` dictionary describing the canvas window's frame
HSCanvas
A new HSCanvas, not yet shown
const c = hs.canvas.create({x: 100, y: 100, w: 200, h: 200})