Skip to content

Three.js Parity API

The */three subpaths expose a Three-like authoring surface on top of PolyCSS. Use them when you are porting a Three.js scene, writing docs for coding agents, or want familiar PerspectiveCamera, Object3D, Vector3, lookAt, and radian-based mesh transforms.

This is still PolyCSS: it renders DOM polygon leaves with CSS transforms. It does not run Three.js at runtime, and it does not use WebGL. The parity API matches Three’s parameter surface closely enough that the same scene math frames the same object with the same projection, orientation, depth ordering, and light direction.

PackageImportUse
Core math@layoutit/polycss-core/threeThree-like classes and coordinate transforms
Vanilla@layoutit/polycss/threeCore parity surface plus scene mounting, mesh loading, and geometry helpers
React@layoutit/polycss-react/threeReact components and parity classes
Vue@layoutit/polycss-vue/threeVue components and parity classes

The native PolyCSS API uses PolyCSS conventions: Z-up scene math, camera rotations in degrees, and zoom as CSS pixels per world unit.

The */three subpaths intentionally use Three-style conventions:

Value*/three convention
CoordinatesY-up authoring space
Mesh rotationsRadians, XYZ Euler
CamerasThree-like PerspectiveCamera(fov, aspect, near, far) and OrthographicCamera(left, right, top, bottom, near, far)
Camera targetingcamera.position.set(...) + camera.lookAt(...)
Directional lightsThree.js source vector: light.target.positionlight.position
Point lightslight.position in Three/Y-up space
Vanilla lighting defaultmountPolyThreeScene(...) defaults to textureLighting: "baked"

Internally, geometry is converted into PolyCSS space with transformPolygonsToPoly. The axis conversion is right-handed, so polygon winding and Lambert lighting stay correct.

Polygon arrays passed to transformPolygonsToPoly or <PolyThreeMesh> are interpreted as Three/Y-up coordinates. If you already have native PolyCSS polygons with their own native transform, render them with the native API instead of converting them again.

For Three parity, use baked lighting as the baseline. It computes the final Lambert face color through the same directional/ambient intensity surface used by the Three-like light adapters. Dynamic lighting is still available by passing textureLighting: "dynamic", but it is a live CSS-lighting path for interactive light changes, not the strict conformance mode.

@layoutit/polycss/three is the smallest path for plain JavaScript demos, tests, CLIs, and agent-generated snippets. The scene below is authored with Three-like camera and transform objects, then mounted into a DOM host by PolyCSS.

import {
AmbientLight,
DirectionalLight,
Object3D,
PerspectiveCamera,
boxPolygons,
mountPolyThreeScene,
transformPolygonsToPoly,
} from "@layoutit/polycss/three";
const host = document.querySelector("#scene")!;
const camera = new PerspectiveCamera(50, 16 / 9, 0.1, 100);
camera.position.set(3, 2, 5);
camera.lookAt(0, 0, 0);
const object = new Object3D();
object.position.set(0, 0.5, 0);
object.rotation.set(0, Math.PI / 4, 0);
object.scale.set(1, 1, 1);
const sun = new DirectionalLight("#ffffff", 1);
sun.position.set(3, 5, 4);
sun.target.position.set(0, 0, 0);
const polygons = transformPolygonsToPoly(
boxPolygons({ size: 1, color: "#66aaff" }),
object,
);
mountPolyThreeScene(host, {
camera,
cameraOptions: { viewportHeight: 420 },
polygons,
ambientLight: new AmbientLight("#ffffff", 0.35).toPolyAmbientLight(),
directionalLight: sun.toPolyDirectionalLight(),
});

The React parity components wrap the normal <PolyScene>. Keep the scene and controls from @layoutit/polycss-react, and import the Three-like cameras / meshes from @layoutit/polycss-react/three.

import { PolyOrbitControls, PolyScene } from "@layoutit/polycss-react";
import {
DirectionalLight,
PolyThreeMesh,
PolyThreePerspectiveCamera,
} from "@layoutit/polycss-react/three";
const sun = new DirectionalLight("#ffffff", 1);
sun.position.set(3, 5, 4);
sun.target.position.set(0, 0, 0);
export function App() {
return (
<PolyThreePerspectiveCamera
fov={50}
aspect={16 / 9}
position={[3, 2, 5]}
lookAt={[0, 0, 0]}
>
<PolyScene
ambientLight={{ intensity: 0.35 }}
directionalLight={sun.toPolyDirectionalLight()}
>
<PolyOrbitControls drag wheel />
<PolyThreeMesh
src="/models/cube.glb"
position={[0, 0.5, 0]}
rotation={[0, Math.PI / 4, 0]}
/>
</PolyScene>
</PolyThreePerspectiveCamera>
);
}

<PolyThreeMesh> accepts polygons or src like the native <PolyMesh>. It also supports scene mesh options such as castShadow, receiveShadow, texture options, meshResolution, and merge.

Vue mirrors the React parity surface.

<script setup lang="ts">
import { PolyOrbitControls, PolyScene } from "@layoutit/polycss-vue";
import {
DirectionalLight,
PolyThreeMesh,
PolyThreePerspectiveCamera,
} from "@layoutit/polycss-vue/three";
const sun = new DirectionalLight("#ffffff", 1);
sun.position.set(3, 5, 4);
sun.target.position.set(0, 0, 0);
</script>
<template>
<PolyThreePerspectiveCamera
:fov="50"
:aspect="16 / 9"
:position="[3, 2, 5]"
:look-at="[0, 0, 0]"
>
<PolyScene
:ambient-light="{ intensity: 0.35 }"
:directional-light="sun.toPolyDirectionalLight()"
>
<PolyOrbitControls drag wheel />
<PolyThreeMesh
src="/models/cube.glb"
:position="[0, 0.5, 0]"
:rotation="[0, Math.PI / 4, 0]"
/>
</PolyScene>
</PolyThreePerspectiveCamera>
</template>

All */three subpaths share these core exports:

ExportPurpose
Vector3Minimal Three-like vector class used by cameras, objects, and lights
EulerXYZ Euler rotation in radians
Object3Dposition, rotation, scale, up, lookAt, and localToWorld
PerspectiveCameraThree-like perspective camera that PolyCSS can render with
OrthographicCameraThree-like orthographic camera that PolyCSS can render with
DirectionalLightThree-like positioned light with target, convertible to PolyCSS light options
PointLightThree-like point light, convertible to PolyCSS point-light options
AmbientLightAmbient light helper, convertible to PolyCSS light options
threeToPolyPoint / polyToThreePointConvert individual points between coordinate spaces
threeToPolyDirection / polyToThreeDirectionConvert direction vectors between coordinate spaces
transformPointToPolyApply an Object3D transform to one point and convert it
transformPolygonsToPolyApply an Object3D transform to a Polygon[] and convert it

Use the native API when you are building PolyCSS-first scenes, DOM inspection demos, builder output, or examples where degree-based rotX / rotY camera controls are more direct. The parity API is for Three-shaped scene authoring and ports; it is not a replacement for native PolyCSS controls or custom elements.