A fork of Deno with built-in window system integration.
Shell (Mac, Linux):
curl -fsSL https://denogdev.github.io/install.sh | sh
PowerShell (Windows):
irm https://denogdev.github.io/install.ps1 | iex
Try running the hello-triangle example:
denog run --unstable --wsi https://denogdev.github.io/hello-triangle.ts
Denog is based on Deno and provides most of the same functionality. You can learn more about Deno from its manual.
Deno's complete API reference is available at the runtime documentation. Denog's additions to this API are documented below.
Denog is compatible with the
vscode_deno
extension. Once both Denog and the extension are installed, you can enable the
extension and point it at Denog instead of Deno in your Visual Studio Code
settings.json
:
{
"deno.enable": true,
"deno.unstable": true,
"deno.path": "C:/Users/<USERNAME>/.deno/bin/denog.exe"
// Or for macOS: "/Users/<USERNAME>/.deno/bin/denog"
// Or for Linux: "/home/<USERNAME>/.deno/bin/denog"
}
Denog enhances Deno by adding built-in support for window system integration
(WSI) which can be enabled using the optional --wsi
flag. It's currently only
available to the denog run
subcommand and requires the --unstable
flag as
well. Example:
denog run --unstable --wsi https://denogdev.github.io/hello-triangle.ts
Denog's window system integration uses the Rust
winit
library under the hood and
provides much of the same functionality.
To create a window, use Deno.wsi.createWindow
:
createWindow(options?: WSICreateWindowOptions): WSIWindow
WSICreateWindowOptions
provides most of the same options as
winit::window::WindowBuilder
:
declare interface WSICreateWindowOptions {
active?: boolean;
contentProtected?: boolean;
decorated?: boolean;
enabledButtons?: WSIWindowButtons;
fullscreen?: boolean;
position?: [number, number];
innerSize?: [number, number];
minInnerSize?: [number, number];
maxInnerSize?: [number, number];
level?: WSIWindowLevel;
maximized?: boolean;
resizable?: boolean;
resizeIncrements?: [number, number];
theme?: WSIWindowTheme;
title?: string;
transparent?: boolean;
visible?: boolean;
}
You can read and/or modify more properties after a window has been created:
declare class WSIWindow {
setContentProtected(contentProtected?: boolean): void;
setCursorGrabMode(mode: WSICursorGrabMode): void;
setCursorHitTestEnabled(enabled?: boolean): void;
setCursorIcon(icon: WSICursorIcon): void;
setCursorPosition(position: [number, number]): void;
setCursorPosition(x: number, y: number): void;
setCursorVisible(visible?: boolean): void;
isDecorated(): boolean;
setDecorated(decorated?: boolean): void;
getEnabledButtons(): WSIWindowButtons;
setEnabledButtons(buttons: WSIWindowButtons): void;
hasFocus(): boolean;
takeFocus(): void;
isFullscreen(): boolean;
setFullscreen(fullscreen?: boolean): void;
getGPUSurface(): GPUSurface;
setIMEAllowed(allowed?: boolean): void;
setIMEPosition(position: [number, number]): void;
setIMEPosition(x: number, y: number): void;
setIMEPurpose(purpose: WSIIMEPurpose): void;
getInnerPosition(): [number, number];
getOuterPosition(): [number, number];
setOuterPosition(position: [number, number]): void;
setOuterPosition(x: number, y: number): void;
getInnerSize(): [number, number];
getOuterSize(): [number, number];
setInnerSize(size: [number, number]): void;
setInnerSize(width: number, height: number): void;
setMinInnerSize(size: [number, number] | null): void;
setMinInnerSize(width: number, height: number): void;
setMaxInnerSize(size: [number, number] | null): void;
setMaxInnerSize(width: number, height: number): void;
setLevel(level: WSIWindowLevel): void;
isMinimized(): boolean | null;
setMinimized(minimized?: boolean): void;
isMaximized(): boolean;
setMaximized(maximized?: boolean): void;
isResizable(): boolean;
setResizable(resizable?: boolean): void;
getResizeIncrements(): [number, number] | null;
setResizeIncrements(size: [number, number] | null): void;
setResizeIncrements(width: number, height: number): void;
getScaleFactor(): number;
getTheme(): WSIWindowTheme | null;
setTheme(theme: WSIWindowTheme | null): void;
getTitle(): string;
setTitle(title: string): void;
setTransparent(transparent?: boolean): void;
isVisible(): boolean | null;
setVisible(visible?: boolean): void;
beginDragMove(): void;
beginDragResize(direction: WSIResizeDirection): void;
requestRedraw(): void;
requestUserAttention(type: WSIUserAttentionType | null): void;
destroy(): void;
}
After creating a window, you generally want to call Deno.wsi.nextEvent
in an
event loop.
nextEvent(): Promise<WSIEvent>
Example:
Deno.wsi.createWindow();
eventLoop:
while (true) {
const event = await Deno.wsi.nextEvent();
switch (event.type) {
case "close-requested": {
break eventLoop;
}
}
}
WSIEvent
is a discriminated union. Each WSIEvent.type
corresponds to a
different event type from
winit::event::Event
.
The properties of each event type are listed in
lib.deno.wsi.d.ts along with links to the
corresponding winit
events.
You can render to a WSIWindow
using the
WebGPU API. Unlike standard WebGPU which uses
GPUCanvasContext
to render to
an
HTMLCanvasElement
,
Denog provides the non-standard GPUSurface
class for rendering to a
WSIWindow
directly. Its interface is much closer to the
wgpu::Surface
interface from the Rust wgpu
library that Deno and Denog use under-the-hood.
declare class GPUSurface {
getCapabilities(adapter: GPUAdapter): GPUSurfaceCapabilities;
configure(device: GPUDevice, config: GPUSurfaceConfiguration): void;
getCurrentTexture(): GPUSurfaceTexture;
}
declare interface GPUSurfaceCapabilities {
formats: GPUTextureFormat[];
presentModes: GPUSurfacePresentMode[];
alphaModes: GPUSurfaceAlphaMode[];
}
declare type GPUSurfacePresentMode =
| "auto-vsync"
| "auto-no-vsync"
| "fifo"
| "fifo-relaxed"
| "immediate"
| "mailbox";
declare type GPUSurfaceAlphaMode =
| "auto"
| "opaque"
| "pre-multiplied"
| "post-multiplied"
| "inherit";
declare interface GPUSurfaceConfiguration {
usage?: GPUTextureUsageFlags;
format: GPUTextureFormat;
size: GPUExtent3D;
presentMode?: GPUSurfacePresentMode;
alphaMode?: GPUSurfaceAlphaMode;
viewFormats?: GPUTextureFormat[];
}
declare class GPUSurfaceTexture extends GPUTexture {
readonly isSuboptimal: boolean;
present(): void;
}
Denog also adds a non-standard compatibleSurface
property to
GPURequestAdapterOptions
:
declare interface GPURequestAdapterOptions {
powerPreference?: GPUPowerPreference;
forceFallbackAdapter?: boolean;
compatibleSurface?: GPUSurface;
}
See examples/hello-triangle for a complete example of using WSI and WebGPU together.