widgetWindow
Create and manage desktop widget windows. Each window hosts a UI script and supports drag, snap, transparency, background images, animations, context menus, and events. UI scripts communicate via IPC.
import { widgetWindow } from "novadesk";Availability
Available in the Main script only.
Table of Contents
Constructor
Creates and shows a new desktop widget window.
If id is provided and a widget with the same id already exists, the existing widget is silently removed before the new one is created. If id matches a previously saved widget, the saved position and size are loaded as defaults (explicitly provided x, y, width, height override them). If no saved state exists yet, the initial position is automatically saved after the first successful creation.
Options:
| Option | Type | Default | Description |
|---|---|---|---|
id | string | "" | Unique identifier. Saved position/size are loaded by this ID on creation. |
width | number | — | Window width in pixels. |
height | number | — | Window height in pixels. |
x | number | — | Horizontal screen position in pixels. |
y | number | — | Vertical screen position in pixels. |
script | string | — | Path to the UI script. Must end with .ui.js (e.g. "ui/clock.ui.js"). Relative paths resolve from the entry script directory. |
backgroundColor | string | "rgba(0,0,0,0)" | Window background color or gradient. Supports rgb(), rgba(), linearGradient(), radialGradient(). |
opacity | number | string | 1 | Master window opacity. Accepts 0.0–1.0, 0–100, 0–255, or a percentage string like "75%". Scales the entire window including all drawn elements. |
draggable | boolean | true | Allow the user to drag the window. |
resizable | boolean | false | Allow the user to resize the window by dragging its edges. |
minWidth | number | 0 | Minimum window width in pixels when resizing. |
minHeight | number | 0 | Minimum window height in pixels when resizing. |
clickThrough | boolean | false | Mouse events pass through the window to whatever is behind it. |
keepOnScreen | boolean | false | Prevent dragging the window off-screen. |
snapEdges | boolean | true | Snap to screen edges and other widgets while dragging. |
show | boolean | true | Show the window immediately after creation. Pass false to create it hidden and call win.show() later. |
showInToolbar | boolean | false | Show in the Windows taskbar. |
toolbarIcon | string | "" | Path to the taskbar icon. |
toolbarTitle | string | "" | Title shown in the Windows taskbar. |
backgroundImage | string | "" | Path to a background image. Supports local files and HTTP/HTTPS URLs. |
backgroundImageFallback | string | "" | Fallback image shown while the main image loads (or if it fails). |
backgroundImageFallbackAspectRatio | string | "stretch" | How the fallback background image is scaled. Values: "stretch", "preserve" / "fit" / "contain", "crop" / "cover". Also accepted as backgroundImageFallbackSize. |
backgroundImageSize | string | object | "cover" | How the image fits. String: "cover", "contain", "stretch". Object: { width, height } for explicit sizing. |
backgroundImagePosition | string | object | "center" | Image position. String: "top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right". Object: { x, y } for pixel offset. |
zPos | string | "normal" | Z-order position. See values below. |
zPos values (case-insensitive):
| Value | Behavior |
|---|---|
"ontopmost" | Always on top of everything, including other topmost windows. |
"ontop" | Above normal windows. |
"normal" | Normal stacking order (default). |
"onbottom" | Behind all app windows. Hidden when "Show Desktop" is triggered. |
"ondesktop" | Sits over the desktop. Ideal for wallpaper-style widgets. |
Script must end with .ui.js
If script does not end with .ui.js, the window is created but the script is not executed. The UI will be blank. Valid examples: "script.ui.js", "ui/clock.ui.js".
opacity vs backgroundColor alpha
opacity sets the Win32 layered window opacity — it scales the entire window including all UI elements. The alpha component of backgroundColor only affects the background fill. Setting opacity: 0 makes everything invisible. Setting backgroundColor: "rgba(0,0,0,0)" only makes the background transparent while UI elements remain visible.
PARAMETERS
import { widgetWindow } from "novadesk";
const win = new widgetWindow({
id: "my-widget",
width: 400,
height: 300,
script: "script.ui.js",
backgroundColor: "rgb(10,10,10)",
draggable: true,
resizable: true,
snapEdges: true,
showInToolbar: true,
toolbarTitle: "My Widget"
});Window State
Shows the widget window. Fires the show event.
widgetWindow The widget instance (chainable).win.show();Hides the widget window. Fires the hide event.
widgetWindow The widget instance (chainable).win.hide();Destroys the widget window and releases all resources. Fires the close and closed events.
win.close();Destroys the widget window immediately without firing the close event. Use close() for normal shutdown; use destroy() when you need to remove the window silently.
win.destroy();Returns whether the window is visible.
boolean true if the window is currently visible.if (!win.isVisible()) win.show();Returns whether the window has keyboard focus.
boolean true if the window currently has keyboard focus.console.log("Focused:", win.isFocused());Returns whether the window has been destroyed. Safe to call even after the window is closed. Check this before calling other methods on a window that may have been closed elsewhere.
boolean true if the window has been destroyed.if (!win.isDestroyed()) {
win.setProperties({ width: 500 });
}Enables or disables window resizing by the user dragging the window edges. When enabled, a thin resize border appears around the window.
Not persisted
The resizable state is not saved to disk. The window will revert to resizable: false on the next launch unless you set it again in the constructor or via setResizable().
PARAMETERS
widgetWindow The widget instance (chainable).win.setResizable(true); // user can now drag edges to resize
win.setResizable(false); // lock the sizeReturns whether the user can resize the window by dragging its edges.
boolean true if the window is currently resizable.console.log("Resizable:", win.isResizable());Returns whether the window is in the process of being resized (user is dragging an edge).
boolean true if the window is currently being resized by the user.win.on("resize", () => {
if (win.isResizing()) {
console.log("User is resizing...");
}
});Sets the minimum width the window can be resized to.
PARAMETERS
widgetWindow The widget instance (chainable).win.setMinWidth(200);Returns the current minimum width.
number The minimum width in pixels.console.log("Min width:", win.getMinWidth());Sets the minimum height the window can be resized to.
PARAMETERS
widgetWindow The widget instance (chainable).win.setMinHeight(150);Returns the current minimum height.
number The minimum height in pixels.console.log("Min height:", win.getMinHeight());Sets both minimum width and height in one call.
PARAMETERS
widgetWindow The widget instance (chainable).win.setMinSize(200, 150);Returns the current minimum size.
object An object with width and height.const min = win.getMinSize();
console.log("Min size:", min.width, "x", min.height);Minimizes the widget window. Fires the minimize event.
win.minimize();Restores a minimized widget window. Fires the unMinimize event.
win.unMinimize();Returns whether the window is minimized.
boolean true if the window is currently minimized.if (win.isMinimized()) {
win.unMinimize();
}Maximizes the widget window to fill the work area.
win.maximize();Restores a maximized window to its previous size and position.
win.restore();Toggles between maximized and normal window state.
win.toggleMaximize();Returns whether the window is maximized.
boolean true if the window is currently maximized.if (!win.isMaximized()) {
win.maximize();
}Gives keyboard focus to the widget window.
win.setFocus();Removes keyboard focus from the widget window.
win.unFocus();Clears all UI elements and re-executes the widget's UI script. Stale ipcRenderer listeners from the previous run are automatically cleaned up before the new script executes.
win.refresh();Background Image
Sets the window background image. The image is drawn behind all UI elements but on top of backgroundColor.
Size modes:
| Mode | Behavior |
|---|---|
"cover" | Image fills the window, cropping if needed to maintain aspect ratio (default). |
"contain" | Image fits inside the window, letterboxing if needed to maintain aspect ratio. |
"stretch" | Image stretches to fill the window exactly, ignoring aspect ratio. |
{ width, height } | Explicit pixel size. Omit one dimension to auto-scale while maintaining aspect ratio. |
Position keywords:
"top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right"
PARAMETERS
widgetWindow The widget instance (chainable).win.setBackgroundImage("./assets/wallpaper.jpg");
win.setBackgroundImage("./assets/bg.png", "contain");
win.setBackgroundImage("./assets/bg.png", "cover", "top-left");
win.setBackgroundImage("./assets/bg.png", { width: 200 }, "center");Returns the current background image path.
string The current background image path, or empty string if none.console.log("BG image:", win.getBackgroundImage());Sets a fallback image that displays while the main backgroundImage is loading (or if it fails to load).
PARAMETERS
widgetWindow The widget instance (chainable).win.setBackgroundImageFallback("./assets/placeholder.png");
win.setBackgroundImage("https://example.com/wallpaper.jpg");Sets the aspect ratio mode for the fallback background image. This controls how the fallback is scaled independently of the main background image size setting.
PARAMETERS
widgetWindow The widget instance (chainable).win.setBackgroundImageFallback("./assets/placeholder.jpg");
win.setBackgroundImageFallbackAspectRatio("preserve"); // show full fallback, letterboxed
win.setBackgroundImage("https://example.com/wallpaper.jpg", "cover");Window Animation
Animates the window's position, size, and opacity using either a simple A-to-B tween or a multi-stop keyframe timeline.
Every call is fire-and-forget — there is no callback when the animation completes. Calling animate() on a window that is already animating immediately replaces the running animation.
Options:
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
duration | number | No | 250 | Duration in milliseconds. |
easing | string | No | "linear" | Easing function name. See easing reference. |
iterationCount | number / "infinite" | No | 1 | How many times to play. Must be ≥ 1 or "infinite". |
to | object | Tween only | — | Target values. See animatable properties below. |
from | object | No | Current state | Starting values. Omit to start from current state. Accepts the same properties as to. |
keyframes | array / object | Keyframe only | — | Multi-stop timeline. Cannot be combined with to/from. |
Animatable properties (in from, to, and each keyframe):
| Property | Type | Description |
|---|---|---|
x | number / string | Horizontal position in pixels, or a screen keyword expression (see below). |
y | number / string | Vertical position in pixels, or a screen keyword expression (see below). |
width | number | Window width in pixels. Alias: w. |
height | number | Window height in pixels. Alias: h. |
opacity | number | Window opacity 0.0–1.0. Alias: alpha. |
backgroundColor | string | Background color to animate to. Alias: bgColor. |
position | string | Screen position preset (see below). Alias: align. |
offsetX | number | Pixel offset applied after resolving position. |
offsetY | number | Pixel offset applied after resolving position. |
Screen position presets (position / align):
| Preset | Aliases | Resolves to |
|---|---|---|
"top-left" | "topleft" | Top-left corner of the work area. |
"top-center" | "top" | Top center of the work area. |
"top-right" | "topright" | Top-right corner of the work area. |
"center-left" | "left" | Left edge, vertically centered. |
"center" | "middle" | Dead center of the work area. |
"center-right" | "right" | Right edge, vertically centered. |
"bottom-left" | "bottomleft" | Bottom-left corner of the work area. |
"bottom-center" | "bottom" | Bottom center of the work area. |
"bottom-right" | "bottomright" | Bottom-right corner of the work area. |
Work area
The "work area" is the portion of the screen excluding the taskbar. Position presets align the window's top-left corner to that screen location.
String expressions for x and y:
Instead of a number, x and y accept a string keyword with an optional pixel offset:
| Keyword | X resolves to | Y resolves to |
|---|---|---|
"left" | Left edge of work area | — |
"center" / "middle" | Horizontally centered | Vertically centered |
"right" | Right edge minus window width | — |
"top" | — | Top edge of work area |
"bottom" | — | Bottom edge minus window height |
"offscreen-left" | Left edge minus window width (hidden) | — |
"offscreen-right" | Right edge (hidden) | — |
"offscreen-top" | — | Top edge minus window height (hidden) |
"offscreen-bottom" | — | Bottom edge (hidden) |
PARAMETERS
widgetWindow The widget instance (chainable).// Slide the window in from off-screen
win.animate({
duration: 500,
easing: "easeOutCubic",
from: { x: -400 },
to: { x: 100 }
});
// Fade in
win.animate({
duration: 300,
from: { opacity: 0 },
to: { opacity: 1 }
});
// Infinite bounce
win.animate({
duration: 700,
iterationCount: "infinite",
from: { y: 100 },
to: { y: 80 }
});
// Keyframe: slide in then settle
win.animate({
duration: 800,
keyframes: [
{ offset: 0, x: -400 },
{ offset: 0.6, x: 120, easing: "easeOutBack" },
{ offset: 1, x: 100 }
]
});
// Animate to a screen position
win.animate({
duration: 400,
easing: "easeOutCubic",
to: { position: "bottom-center" }
});
// Use position with an offset
win.animate({
duration: 300,
to: { position: "top-right", offsetX: -20, offsetY: 20 }
});
// String expression for x/y
win.animate({
duration: 500,
from: { x: "offscreen-left" },
to: { x: "left", y: "center" }
});
// Animate background color
win.animate({
duration: 600,
from: { backgroundColor: "rgb(0,0,0)" },
to: { backgroundColor: "rgb(30,30,60)" }
});Stops all running window animations. The window stays at its current position/size/opacity.
widgetWindow The widget instance (chainable).win.stopAnimation();Properties
Updates one or more window properties at runtime.
PARAMETERS
widgetWindow The widget instance (chainable).win.setProperties({ width: 600, height: 400 });
win.setProperties({ backgroundColor: "rgb(30,30,30)", draggable: false });
win.setProperties({ show: false }); // equivalent to win.hide()Returns the current state of all window properties. Note: zPos is returned as a number (-2 to 2), not a string.
object An object with id, x, y, width, height, draggable, clickThrough, keepOnScreen, snapEdges, showInToolbar, toolbarIcon, toolbarTitle, show (live visibility), windowOpacity (0–255), backgroundColor, zPos (as a number), and script.const props = win.getProperties();
console.log("Position:", props.x, props.y);
console.log("Size:", props.width, "x", props.height);Position and Size
Sets the position and/or size of the window in one call. Throws TypeError if the argument is not an object.
PARAMETERS
widgetWindow The widget instance (chainable).win.setBounds({ x: 100, y: 100, width: 500, height: 400 });
win.setBounds({ width: 600 }); // change only widthReturns the current position and size of the window using screen coordinates.
object An object with x, y, width, and height in screen coordinates. Returns null if the window handle is not available.const b = win.getBounds();
console.log("At:", b.x, b.y, "Size:", b.width, "x", b.height);Sets the window size without changing its position. Throws TypeError if fewer than two number arguments are provided.
PARAMETERS
widgetWindow The widget instance (chainable).win.setSize(800, 600);Returns the current window size.
object An object with width and height. Returns null if the window handle is not available.const { width, height } = win.getSize();
console.log(width, "x", height);Color and Opacity
Sets the window background color or gradient.
PARAMETERS
widgetWindow The widget instance (chainable).win.setBackgroundColor("rgba(20,20,30,0.95)");Returns the current background color.
string The current background color string.console.log("BG:", win.getBackgroundColor());Sets the master window opacity. Scales the entire window including all UI elements. Throws TypeError if the argument is not a number.
| Range | Interpretation |
|---|---|
0.0–1.0 | Fractional opacity (e.g. 0.75 = 75%) |
1.0–100.0 | Percentage (e.g. 75 = 75%) |
100.0–255.0 | Raw byte (e.g. 191 = 75%) |
PARAMETERS
widgetWindow The widget instance (chainable).win.setOpacity(0.75); // 75% opacity
win.setOpacity(128); // ~50% opacityContext Menu
Sets the right-click context menu. Replaces any previous menu and clears all previous action callbacks.
Menu item properties:
| Property | Type | Description |
|---|---|---|
text | string | Label text. |
action | function | Callback invoked when the item is clicked. |
type | string | "separator" inserts a horizontal divider. Separator items ignore all other properties. |
checked | boolean | Shows a checkmark when true. |
items | object[] | Nested sub-menu items (recursively supports the same schema). |
PARAMETERS
widgetWindow The widget instance (chainable).win.setContextMenu([
{ text: "Refresh", action: () => win.refresh() },
{
text: "Tools",
items: [
{ text: "Debug", checked: false, action: () => app.enableDebugging(true) }
]
},
{ type: "separator" },
{ text: "Close", action: () => win.close() }
]);Removes all custom context menu items and clears their registered callbacks.
widgetWindow The widget instance (chainable).win.clearContextMenu();Enables or disables the right-click context menu.
PARAMETERS
widgetWindow The widget instance (chainable).win.disableContextMenu(true); // no right-click menu
win.disableContextMenu(false); // restore menuControls whether built-in Novadesk context menu entries (e.g. Refresh, Close) are shown alongside custom items.
PARAMETERS
widgetWindow The widget instance (chainable).win.showDefaultContextMenuItems(false); // custom items onlyEvents
Registers an event listener on the widget window. Mouse events pass a Mouse Event Object to the callback. Throws TypeError if the callback is not a function or the event name is empty.
Supported events:
| Event | Trigger |
|---|---|
show | Window became visible |
hide | Window was hidden |
focus | Window gained keyboard focus |
unFocus | Window lost keyboard focus |
minimize | Window was minimized |
unMinimize | Window was restored from minimized state |
move | Window position changed |
resize | Window was resized (width or height changed) |
resizeStart | Window resize operation started (user began dragging an edge). Alias: resize-start |
resizeEnd | Window resize operation ended (user released the edge). Alias: resize-end |
refresh | UI script was refreshed |
close | Window is about to close (fired by close(), not by destroy()) |
closed | Window has been fully destroyed |
mouseOver | Mouse entered the window area |
mouseLeave | Mouse left the window area |
mouseMove | Mouse moved over the window |
mouseDown | Any mouse button was pressed |
mouseUp | Any mouse button was released |
click | Left click released on the window |
right-click | Right click released on the window |
double-click | Left button double-clicked |
scroll-up | Mouse wheel scrolled up |
scroll-down | Mouse wheel scrolled down |
PARAMETERS
widgetWindow The widget instance (chainable).win.on("click", (e) => {
console.log("Clicked at:", e.__clientX, e.__clientY);
});
win.on("mouseMove", (e) => {
console.log("Mouse:", e.__clientX, e.__clientY);
});
win.on("close", () => {
console.log("Window closing");
cleanup();
});
win.on("resize", () => {
const { width, height } = win.getSize();
console.log("New size:", width, "x", height);
});
win.on("resizeStart", () => {
console.log("User started resizing");
});
win.on("resizeEnd", () => {
console.log("User finished resizing");
const { width, height } = win.getSize();
console.log("Final size:", width, "x", height);
});Native Interop
Returns the native window handle. Useful when passing to a native addon that needs a parent window.
number The native Windows HWND as a number.const hwnd = win.getHandle();Returns the raw Widget pointer. Useful when passing the widget reference to a native addon.
number The internal native Widget pointer as a number.const ptr = win.getInternalPointer();Returns the current window title.
string The window title string.console.log("Title:", win.getTitle());Runtime Overrides
When the Ctrl key is held down, the runtime temporarily overrides some interaction settings:
- Dragging works even when
draggable: false - Click-through widgets become interactable
- Snap behavior can be bypassed for precise placement
Practical Examples
Basic widget with tray and context menu
import { widgetWindow, tray, app } from "novadesk";
const win = new widgetWindow({
id: "demo",
width: 400,
height: 300,
script: "script.ui.js",
backgroundColor: "rgb(10,10,10)",
snapEdges: true
});
const appTray = new tray(path.join(__dirname, "assets", "icon.ico"));
appTray.setToolTip("My Widget");
appTray.on("click", () => win.show());
win.setContextMenu([
{ text: "Refresh", action: () => win.refresh() },
{ type: "separator" },
{ text: "Exit", action: () => app.exit() }
]);Hidden window revealed on demand
const win = new widgetWindow({
id: "popup",
width: 300,
height: 200,
script: "popup.ui.js",
show: false // start hidden
});
ipcMain.on("show-popup", () => win.show());
ipcMain.on("hide-popup", () => win.hide());Resize window based on content
const win = new widgetWindow({
id: "dynamic",
width: 300,
height: 100,
script: "dynamic.ui.js"
});
ipcMain.on("content-changed", (event, payload) => {
const newHeight = 60 + payload.itemCount * 30;
win.setSize(300, newHeight);
});Dynamic opacity on hover
const win = new widgetWindow({
id: "fade",
width: 300,
height: 200,
script: "fade.ui.js",
opacity: 0.4
});
win.on("mouseOver", () => win.setOpacity(1.0));
win.on("mouseLeave", () => win.setOpacity(0.4));