Skip to content

PolyScene

The scene is the root of every PolyCSS render tree. It applies scene-level lighting and atlas options, then renders its children (typically meshes or individual polygons) in 3D space. <poly-scene> / PolyScene must always be nested inside a camera element (<poly-camera> / PolyCamera or the perspective variant): the camera owns the projection and orbital state.

It’s available as a custom element (<poly-scene>), via the imperative createPolyScene(host, opts) API, and as React / Vue components (<PolyScene>).

(React / Vue prop names use camelCase; the <poly-scene> custom element accepts the kebab-case form, e.g. textureQualitytexture-quality.)

The React/Vue components and createPolyScene() support the full table. The <poly-scene> custom element supports directional-*, ambient-*, texture-lighting, texture-quality, auto-center, and implicit camera attributes; use the imperative API for options such as shadow, seamBleed, and strategies in vanilla.

PropTypeDefaultDescription
directionalLightPolyDirectionalLightNoneDirectional light source.
ambientLightPolyAmbientLightNoneAmbient fill light.
textureLighting"baked" | "dynamic""baked"Whether texture lighting is rasterized into atlases or computed with CSS variables.
textureQualitynumber | "auto""auto"Atlas bitmap budget and compositor sprite size. Auto caps large runtime bitmaps and uses a larger desktop sprite to avoid Safari/Firefox flattening artifacts; lower numeric values reduce texture memory and detail.
seamBleednumber | "auto"1.5Solid-primitive overscan for detected shared seam edges. "auto" fits each edge from the polygon plan; numbers clamp the CSS-pixel amount.
strategies{ disable?: ("b" | "i" | "u")[] }NoneDiagnostic override for render strategy selection. Disabled solid strategies fall through to <s> atlas slices; <s> cannot be disabled.
autoCenterbooleanfalseRotate around the content bbox center instead of world origin. Polygon data is not mutated.
centerPolygonsPolygon[]None(Framework only.) Bbox source for autoCenter when renderable polygons live inside child meshes.
shadow{ color?, opacity?, lift?, maxExtend? }{ color:"#000000", opacity:0.25, lift:0.05, maxExtend:2000 }Appearance and SVG extent cap for cast shadows emitted by meshes with castShadow.
polygonsPolygon[]None(Framework only.) Flat array of polygon objects rendered as direct children. Composes with JSX/slot children.
childrenNoneNoneMeshes, polygons, controls, helpers, selection wrappers, and transform controls.

Camera state and input are set on the wrapping camera element (<poly-camera> / PolyCamera): rot-x, rot-y, zoom, distance. <poly-scene> carries no camera attributes. Add a child <poly-orbit-controls> / <PolyOrbitControls> to enable drag, wheel, or autorotate: see PolyOrbitControls.

React/Vue <PolyMesh> supports the full table. The <poly-mesh> custom element currently supports src, mtl, mesh-resolution, position, scale, rotation, and auto-center; use scene.add(result, opts) for advanced vanilla mesh options such as castShadow.

PropTypeDescription
idstringStable mesh identifier. Reflected as data-poly-mesh-id and exposed on mesh handles for selection / transform tools.
srcstringURL to .obj, .glb, .gltf, or .vox.
polygonsPolygon[]Pre-parsed polygons (alternative to src). Framework only.
positionVec3[x, y, z] offset in scene space.
scalenumber | Vec3Uniform or per-axis scale.
rotationVec3Euler rotation in degrees [x, y, z].
textureLighting"baked" | "dynamic"Per-mesh lighting mode override. Defaults to the scene value.
textureQualitynumber | "auto"Atlas bitmap budget and compositor sprite size. React / Vue only; vanilla meshes inherit the scene’s texture-quality.
seamBleednumber | "auto"Per-mesh solid seam overscan. React / Vue only; vanilla meshes inherit the scene setting.
atomicAtlasbooleanHold the previous atlas frame until the next frame is decoded, then swap atomically. React / Vue only.
onFrameReady() => voidFires when an atomic atlas frame swaps to a ready one. React / Vue only.
autoCenterbooleanShift the loaded mesh so its bounding-box center sits at the local origin before applying position. Useful when assets aren’t centered in their file coordinates.
mtlstringCompanion .mtl URL for OBJ models.
parseOptionsUseMeshOptionsParser options forwarded to loadMesh; meshResolution defaults to "lossy".
meshResolution"lossless" | "lossy"Top-level optimizer intent. Wins over parseOptions.meshResolution; defaults to "lossy".
castShadowbooleanEmit SVG cast shadows in both lighting modes; projections update when light, ground, or mesh geometry changes.
fallbackReactNodeRendered while src is loading. (React / Vue only.)
errorFallback(error: Error) => ReactNodeRendered if parse fails. (React / Vue only.)
children(polygon, index) => ReactNodePer-polygon render prop / scoped slot. (React / Vue only.)

PolyGround is a React/Vue convenience component for a flat shadow-receiving plane.

PropTypeDefaultDescription
sizenumber6Side length in world units.
znumber0World-space floor height.
center[number, number][0,0]Ground center in world X/Y.
colorstring"#7d848e"Ground fill color.
className / classstringNoneAdditional CSS class.
interface PolyDirectionalLight {
direction: [number, number, number]; // Direction the light shines toward
color?: string; // Light color (default: "#ffffff")
intensity?: number; // Directional intensity (default: 1)
}
interface PolyAmbientLight {
color?: string; // Ambient tint (default: "#ffffff")
intensity?: number; // Ambient intensity (default: 0.4)
}

Helpers render as ordinary scene children and are available in vanilla custom elements plus React/Vue components.

HelperPropsDescription
<poly-axes-helper> / PolyAxesHelpersize, thickness, negative, xColor, yColor, zColorDraws red/green/blue world axes from the origin.
<poly-directional-light-helper> / PolyDirectionalLightHelperReact/Vue: light, target, distance, size, color. Vanilla: direction, target, distance, size, color.Draws a small marker along a directional light vector.

A scene with a dodecahedron at default camera angle.

<script type="module" src="https://esm.sh/@layoutit/polycss/elements"></script>
<poly-camera rot-x="65" rot-y="45">
<poly-scene>
<poly-dodecahedron size="100" color="#a78bfa"></poly-dodecahedron>
</poly-scene>
</poly-camera>
import { PolyPerspectiveCamera, PolyScene, PolyTorus, PolyBox } from "@layoutit/polycss-react";
<PolyPerspectiveCamera perspective={1000} rotX={65} rotY={45}>
<PolyScene
directionalLight={{ direction: [0.5, -0.7, 0.6], color: "#ffe4a8" }}
ambientLight={{ intensity: 0.4 }}
>
<PolyTorus color="#4ecdc4" position={[0, 0, 0]} />
<PolyBox size={60} color="#ffd166" position={[8, 0, 0]} />
</PolyScene>
</PolyPerspectiveCamera>

Shadows are SVG-projected surfaces. They work in both lighting modes; textureLighting controls surface shading, while shadow geometry reprojects when the light or scene geometry changes.

import { PolyCamera, PolyScene, PolyGround, PolyMesh } from "@layoutit/polycss-react";
<PolyCamera rotX={65} rotY={45}>
<PolyScene
textureLighting="dynamic"
directionalLight={{ direction: [0.4, -0.6, 1], intensity: 1 }}
shadow={{ opacity: 0.28, lift: 0.04 }}
>
<PolyGround size={8} color="#d8d2c7" />
<PolyMesh src="/model.glb" castShadow />
</PolyScene>
</PolyCamera>

Use strategies.disable when you need to compare paths or isolate browser rendering issues.

<PolyScene strategies={{ disable: ["b", "i", "u"] }}>
<PolyMesh src="/model.glb" />
</PolyScene>
<PolyCamera rotX={65} rotY={45}>
<PolyScene>
<PolyIcosahedron size={80} color="#ff6644" position={[0, 0, 0]} />
<PolyBox size={60} color="#7dd3fc" position={[10, 0, 0]} />
</PolyScene>
</PolyCamera>

Pass a polygons array directly to render static geometry without a file loader.

const polygons: Polygon[] = [
{ vertices: [[0,0,0],[1,0,0],[0,1,0]], color: "#f00" },
{ vertices: [[2,0,0],[3,0,0],[2,1,0]], color: "#00f" },
];
<PolyCamera>
<PolyScene polygons={polygons} />
</PolyCamera>