Skip to content

Latest commit

 

History

History
262 lines (220 loc) · 7.75 KB

README.md

File metadata and controls

262 lines (220 loc) · 7.75 KB

Denog

A fork of Deno with built-in window system integration.

Install

Shell (Mac, Linux):

curl -fsSL https://denogdev.github.io/install.sh | sh

PowerShell (Windows):

irm https://denogdev.github.io/install.ps1 | iex

Getting Started

Try running the hello-triangle example:

denog run --unstable --wsi https://denogdev.github.io/hello-triangle.ts

A red triangle over a green background.

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.

Using Visual Studio Code

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"
}

Window System Integration (WSI)

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.

WebGPU Integration

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.