Per-polygon Interaction
Every polygon rendered by polycss is a real DOM element. You can attach standard event handlers, apply CSS classes, and inspect them in DevTools — that’s true regardless of which entry point you use. The single-polygon primitive is <poly-polygon> (vanilla custom element) / <Poly> (React, Vue).
Live demo — interactive scene
Section titled “Live demo — interactive scene”Loading…
The polygon primitive
Section titled “The polygon primitive”<poly-polygon> (vanilla) and <Poly> (React / Vue) render a single polygon as an atlas-backed <i> for UV-textured and flat-color faces. They forward standard DOM props (onclick, class, style, aria-*, etc.).
<script type="module" src="https://esm.sh/polycss/elements"></script>
<poly-scene> <!-- Vertices are JSON arrays in the `vertices` attribute. --> <poly-polygon vertices='[[0,0,0],[1,0,0],[0,1,0]]' color="#ff0000"></poly-polygon> <poly-polygon vertices='[[0,0,0],[1,0,0],[0,1,0]]' color="#0000ff" texture="/wood.png" uvs='[[0,0],[1,0],[0,1]]'></poly-polygon></poly-scene>import { PolyScene, Poly } from "@polycss/react";
const triangle: Vec3[] = [[0,0,0], [1,0,0], [0,1,0]];
<PolyScene> <Poly vertices={triangle} color="#ff0000" /> <Poly vertices={triangle} color="#0000ff" texture="/wood.png" uvs={[...]} /></PolyScene>Interactive per-polygon example
Section titled “Interactive per-polygon example”<script type="module" src="https://esm.sh/polycss/elements"></script>
<style> .highlight { filter: brightness(1.5); } poly-polygon { transition: filter 0.2s; }</style>
<poly-scene rot-x="65" rot-y="45" id="scene"> <!-- Polygons are appended programmatically. --></poly-scene>
<script type="module"> const scene = document.getElementById("scene"); const polygons = /* Polygon[] from your data source */ [];
for (let i = 0; i < polygons.length; i++) { const p = polygons[i]; const el = document.createElement("poly-polygon"); el.setAttribute("vertices", JSON.stringify(p.vertices)); if (p.color) el.setAttribute("color", p.color); el.addEventListener("click", () => alert(`clicked polygon ${i}`)); el.addEventListener("mouseenter", () => el.classList.add("highlight")); el.addEventListener("mouseleave", () => el.classList.remove("highlight")); scene.appendChild(el); }</script>import { useState } from "react";import { PolyScene, PolyMesh, Poly } from "@polycss/react";import type { Polygon } from "@polycss/react";
export function InteractiveMesh({ polygons }: { polygons: Polygon[] }) { const [hoveredId, setHoveredId] = useState<number | null>(null);
return ( <PolyScene rotX={65} rotY={45}> {polygons.map((p, i) => ( <Poly key={i} {...p} onClick={() => alert(`clicked polygon ${i}`)} onMouseEnter={() => setHoveredId(i)} onMouseLeave={() => setHoveredId(null)} className={hoveredId === i ? "highlight" : ""} style={{ transition: "filter 0.2s" }} /> ))} </PolyScene> );}.highlight { filter: brightness(1.5); }<template> <PolyScene :rot-x="65" :rot-y="45"> <Poly v-for="(p, i) in polygons" :key="i" v-bind="p" @click="onClickPoly(i)" @mouseenter="hoveredId = i" @mouseleave="hoveredId = null" :class="{ highlight: hoveredId === i }" /> </PolyScene></template>
<script setup lang="ts">import { ref } from "vue";import { PolyScene, Poly } from "@polycss/vue";import type { Polygon } from "@polycss/vue";
defineProps<{ polygons: Polygon[] }>();const hoveredId = ref<number | null>(null);const onClickPoly = (i: number) => alert(`clicked polygon ${i}`);</script>
<style>.highlight { filter: brightness(1.5); }</style>Per-polygon override (mesh + custom render)
Section titled “Per-polygon override (mesh + custom render)”To customize specific polygons inside a loaded mesh, use:
- Vanilla: load with
loadMesh, then manually create<poly-polygon>elements in a loop. You stay in full control of which polygons get special handling. - React: the
<PolyMesh>render-prop child. - Vue: the
<PolyMesh>scoped slot.
<script type="module"> import { loadMesh, createPolyScene } from "polycss";
const host = document.getElementById("scene-host"); const scene = createPolyScene(host, { rotX: 65, rotY: 45 });
const result = await loadMesh("/character.glb"); result.polygons.forEach((p, i) => { const el = document.createElement("poly-polygon"); el.setAttribute("vertices", JSON.stringify(p.vertices)); if (p.color) el.setAttribute("color", p.color); el.addEventListener("click", () => el.classList.toggle("outlined")); host.querySelector("poly-scene")?.appendChild(el) ?? host.appendChild(el); });</script>import { useState } from "react";import { PolyScene, PolyMesh, Poly } from "@polycss/react";
export function SelectableMesh() { const [selected, setSelected] = useState<number | null>(null);
return ( <PolyScene rotX={65} rotY={45}> <PolyMesh src="/character.glb" position={[5, 0, 0]} scale={2}> {(polygon, index) => ( <Poly {...polygon} onClick={() => setSelected(index)} className={selected === index ? "outlined" : ""} /> )} </PolyMesh> </PolyScene> );}<template> <PolyScene :rot-x="65" :rot-y="45"> <PolyMesh src="/character.glb" :position="[5, 0, 0]" :scale="2" v-slot="{ polygon, index }"> <Poly v-bind="polygon" @click="selected = index" :class="{ outlined: selected === index }" /> </PolyMesh> </PolyScene></template>
<script setup lang="ts">import { ref } from "vue";import { PolyScene, PolyMesh, Poly } from "@polycss/vue";const selected = ref<number | null>(null);</script>Imperative loading
Section titled “Imperative loading”Load a mesh programmatically when you need control over loading state. The vanilla loadMesh is the universal path; React adds a useMesh hook on top that auto-disposes on unmount.
// Vanilla — works in any framework or no frameworkimport { loadMesh, createPolyScene } from "polycss";
const scene = createPolyScene(document.getElementById("host")!);const { polygons, dispose } = await loadMesh("/cottage.glb");scene.add({ polygons, dispose: () => {} });// ... later:dispose();scene.remove();// Reactimport { PolyScene, Poly, useMesh } from "@polycss/react";
function Viewer() { const { polygons, loading, error } = useMesh("/cottage.glb");
if (loading) return <Spinner />; if (error) return <div>Error: {error}</div>;
return ( <PolyScene> {polygons.map((p, i) => <Poly key={i} {...p} />)} </PolyScene> );}Related
Section titled “Related”- PolyScene — Scene props and polygon data reference.
- Loading Meshes — OBJ, GLB, MTL loading and UV textures.
- Performance — Merge modes and DOM tuning.