Skip to content

feat: Add Grid extra and rebuild the Grid script on it - #9808

Merged
kpal81xd merged 7 commits into
mainfrom
feat/grid
Oct 21, 2026
Merged

kpal81xd merged 7 commits into
mainfrom
feat/grid

Conversation

@kpal81xd

@kpal81xd kpal81xd commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds a Grid extra for drawing an anti-aliased reference grid, and rebuilds the Grid ESM script (scripts/esm/grid.mjs) on top of it, so the script and the engine share one implementation and every setting is available from both.

  • Levels of lines follow the zoom: zooming out brings in coarser levels and zooming in finer ones, each fading in as its cells grow, so the grid keeps the same density at any distance
  • Lines keep their thickness in CSS pixels, with separate thickness for axis, major and minor lines
  • The plane follows each camera that renders it and fades out with distance (ending inside the camera's far clip), or is sized by its node's scale when not infinite
  • Fades out where the plane is seen nearly edge on, to cut shimmer near the horizon
  • XZ, XY or YZ plane, positioned and rotated by its node; the node's scale sizes a fixed grid but never its cells
  • Theme with axis, major and minor line colors, set through setTheme so presets can be applied in one call
  • Contrast option: lines are drawn black over light parts of the scene and white over dark ones
  • Depth options: depth offset to keep a coplanar floor from hiding the grid, depth test, and depth write with optional dithering, so the grid can hide gaussian splats and transparent meshes drawn after it
  • GLSL and WGSL shaders

Public API changes

New Grid extra:

const grid = new pc.Grid(app.graphicsDevice);
entity.addComponent('render', {
    meshInstances: grid.meshInstances,
    castShadows: false
});

grid.plane = 'xz';                      // 'xz' | 'xy' | 'yz'
grid.spacing = 1;                       // the cell size the levels are scaled from
grid.subdivisions = 10;                 // 1 for a single fixed level
grid.infinite = false;                  // then the node's scale sizes the grid
grid.fadeRange = new pc.Vec2(400, 1000);
grid.showAxes = true;
grid.axisLineThickness = 2;
grid.majorLineThickness = 1.5;
grid.minorLineThickness = 1;
grid.contrast = true;                   // needs camera.renderSceneColorMap = true
grid.depthOffset = 0.001;
grid.depthTest = true;
grid.depthWrite = true;
grid.depthDither = true;
grid.setTheme({ axis: { x: new pc.Color(1, 0, 0) }, major: new pc.Color(0.8, 0.8, 0.8, 0.6) });

Grid script:

// before: a fixed grid sized by the entity's scale
gridEntity.setLocalScale(8, 1, 8);
gridEntity.script.create(Grid, {
    properties: { resolution: Grid.RESOLUTION_HIGH }
});

// after: the scale still sizes the grid once it isn't infinite
gridEntity.setLocalScale(8, 1, 8);
gridEntity.script.create(Grid, {
    properties: { infinite: false, spacing: 1 }
});

Breaking changes:

  • The grid is infinite by default, so a grid sized by its entity's scale needs infinite: false to keep its size
  • resolution and Grid.RESOLUTION_LOW, RESOLUTION_MEDIUM and RESOLUTION_HIGH are deprecated and have no effect, as the levels now follow the zoom; setting resolution warns once
  • The grid no longer writes depth by default
  • Colors are gamma corrected, as the gizmos are
  • The default look changes: lines are a fixed pixel thickness and partly transparent, the grid fades out with distance and has a small depth offset, and the axis lines replace the grid lines under them
  • colorX and colorZ remain; new attributes cover every setting of the extra

Examples

  • New Graphics / Grid example exposing every setting, with Default, Editor and SuperSplat presets
  • The gizmo and editor examples drop the entity scale and the removed resolution control

Manual smoke test

  1. Open Graphics / Grid. Expected: an infinite grid with red and blue axes, fading out towards the horizon, with no errors in the console.
  2. Zoom out with the mouse wheel. Expected: coarser lines fade in and the finest fade out, so the grid density stays about the same; zooming in brings in finer lines.
  3. Turn Infinite off and set Size, which scales the grid entity. Expected: the grid becomes a patch of that size centered on the origin, on whichever plane is selected.
  4. Change Plane to XY and YZ. Expected: the grid moves to that plane, with the matching axis colors.
  5. Set Depth Offset to 0. Expected: the dark plane on the grid hides the lines over it; at the default 0.001 the lines show on it.
  6. Pick the Editor preset. Expected: a fixed 8 × 8 grid of 1 unit cells with black axes, which keeps its size when zooming out.
  7. Pick the SuperSplat preset. Expected: the sphere becomes gaussian splats, and the grid lines cut across their lower half.
  8. Turn on Contrast with Depth Test off. Expected: lines turn dark over the light cube and capsule and stay light over the background.
  9. Switch the device to WebGPU and repeat steps 1 and 2. Expected: the same result.
  10. Open Gizmos / Translate and Misc / Editor. Expected: both show the grid with no errors.

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

Add a Grid extra that draws an anti-aliased reference grid whose levels
of lines follow the zoom, with a theme, plane, spacing, subdivisions,
infinite or fixed extent, distance fade, line thicknesses, contrast
against the scene, and depth offset, test, write and dither options.

The Grid script now wraps the extra and exposes every setting. Its
resolution attribute and RESOLUTION_* constants are removed, and the
entity's scale no longer sizes the grid.

Add a Grid example with presets, and update the examples using the
script.
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2698.0 KB (+15.7 KB, +0.58%) 700.0 KB (+4.0 KB, +0.57%) 542.6 KB (+3.0 KB, +0.55%)
playcanvas.min.mjs 2694.8 KB (+15.7 KB, +0.59%) 698.6 KB (+3.8 KB, +0.55%) 542.4 KB (+3.0 KB, +0.55%)

A grid that isn't infinite is now as large as its node's scale along
the two axes of its plane, replacing the size property, so the Grid
script sized by its entity's scale works as before. The Grid script's
resolution attribute and RESOLUTION_* constants are restored as
deprecated no-ops that warn once.
@github-actions

Copy link
Copy Markdown

Public API report

This PR changes the public API surface (+41 / −0), per the docs' rules (@ignore / @Private / undocumented are excluded).

Show API diff
+Grid.constructor(device: GraphicsDevice)
+Grid.destroy(): void
+Grid.get axisLineThickness(): number
+Grid.get contrast(): boolean
+Grid.get depthDither(): boolean
+Grid.get depthOffset(): number
+Grid.get depthTest(): boolean
+Grid.get depthWrite(): boolean
+Grid.get fadeRange(): Vec2
+Grid.get infinite(): boolean
+Grid.get majorLineThickness(): number
+Grid.get meshInstances(): MeshInstance[]
+Grid.get minorLineThickness(): number
+Grid.get plane(): GridPlane
+Grid.get showAxes(): boolean
+Grid.get spacing(): number
+Grid.get subdivisions(): number
+Grid.get theme(): GridTheme
+Grid.get visible(): boolean
+Grid.set axisLineThickness(value: number)
+Grid.set contrast(value: boolean)
+Grid.set depthDither(value: boolean)
+Grid.set depthOffset(value: number)
+Grid.set depthTest(value: boolean)
+Grid.set depthWrite(value: boolean)
+Grid.set fadeRange(value: Vec2)
+Grid.set infinite(value: boolean)
+Grid.set majorLineThickness(value: number)
+Grid.set minorLineThickness(value: number)
+Grid.set plane(value: GridPlane)
+Grid.set showAxes(value: boolean)
+Grid.set spacing(value: number)
+Grid.set subdivisions(value: number)
+Grid.set visible(value: boolean)
+Grid.setTheme(partial: { axis: Partial<{ x: Color; y: Color; z: Color }>; major: Color; minor: Color }): void
+GridTheme.axis: { x: Color; y: Color; z: Color }
+GridTheme.major: Color
+GridTheme.minor: Color
+class Grid
+interface GridTheme
+type GridPlane = "xz" | "xy" | "yz"

Informational only — this never fails the build.

@kpal81xd
kpal81xd merged commit 82df4fc into main Oct 21, 2026
11 checks passed
@kpal81xd
kpal81xd deleted the feat/grid branch October 21, 2026 13:49

This branch was successfully deployed

2 active deployments
Preview – engine — 39994146 Deployed Oct 21, 2026 by vercel[bot]
Preview – engine-api-docs — 39994146 Deployed Oct 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: examples area: extras area: scripts enhancement Request for a new feature release: next minor Ticket marked for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant