@layoutit/polycss-vue 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,188 +1,199 @@
1
- > **Status: pre-1.0. APIs may still change before a stable 1.0 release.**
1
+ # PolyCSS
2
2
 
3
- # @layoutit/polycss-vue
3
+ A CSS polygon mesh library. A 3D engine for the DOM. Renders OBJ/MTL, GLB and VOX as real HTML elements transformed with CSS `matrix3d(...)`. Supports colors, textures, lighting, shadows, shapes and animations. Works with React, Vue or plain JavaScript.
4
4
 
5
- Native Vue 3 components for CSS-based polygon mesh rendering. Loads OBJ, glTF, GLB, and MagicaVoxel `.vox` files; renders each polygon as a real DOM element (atlas-backed `<i>` for both textured and flat-color faces) positioned with `transform: matrix3d(...)`. No WebGL, no canvas-as-scene.
5
+ Visit [polycss.com](https://polycss.com) for docs and model examples.
6
6
 
7
- ## Install
7
+ <img width="1600" height="300" alt="PolyCSS primitives banner" src="https://github.com/user-attachments/assets/b05e2204-9323-4f83-8d1b-01ea0dd000db" />
8
+
9
+ ## Installation
8
10
 
9
11
  ```bash
12
+
13
+ # Vanilla
14
+ npm install @layoutit/polycss
15
+
16
+ # React
17
+ npm install @layoutit/polycss-react
18
+
19
+ # Vue
10
20
  npm install @layoutit/polycss-vue
21
+
11
22
  ```
12
23
 
13
- Requires Vue 3 as a peer dependency.
14
24
 
15
- ## Quickstart
25
+ You can also load PolyCSS directly from a CDN. Here is a minimal custom-element scene:
16
26
 
17
- ```vue
18
- <template>
19
- <PolyCamera :rot-x="65" :rot-y="45" :perspective="1000">
20
- <PolyScene>
21
- <PolyMesh src="/cottage.glb" />
22
- </PolyScene>
23
- </PolyCamera>
24
- </template>
27
+ ```html
28
+ <script type="module" src="https://esm.sh/@layoutit/polycss/elements"></script>
25
29
 
26
- <script setup lang="ts">
27
- import { PolyCamera, PolyScene, PolyMesh } from "@layoutit/polycss-vue";
28
- </script>
30
+ <poly-camera rot-x="65" rot-y="45">
31
+ <poly-scene>
32
+ <poly-orbit-controls drag wheel></poly-orbit-controls>
33
+ <poly-box size="100" color="#ffd166"></poly-box>
34
+ </poly-scene>
35
+ </poly-camera>
29
36
  ```
30
37
 
31
- ## Component reference
38
+ <img width="2500" height="1145" alt="PolyCSS intro" src="https://github.com/user-attachments/assets/0e5df0d8-04a8-4e50-8e3a-1097a96ce42f" />
39
+
40
+ ## Framework Components
32
41
 
33
- ### `<PolyScene>`
42
+ React and Vue expose the same component model. `<PolyCamera>` owns the viewpoint, `<PolyScene>` owns lighting and atlas options, and `<PolyMesh>` loads or receives polygon data.
34
43
 
35
- Root of every Vue polycss render tree. Renders polygons and meshes inside a `<PolyCamera>` context, and owns scene-level lighting and atlas options.
44
+ ```tsx
45
+ import { PolyCamera, PolyScene, PolyOrbitControls, PolyMesh } from "@layoutit/polycss-react";
36
46
 
37
- | Prop | Type | Default | Description |
38
- |---|---|---|---|
39
- | `directional-light` | `PolyDirectionalLight` | None | Directional light config |
40
- | `ambient-light` | `PolyAmbientLight` | None | Ambient light config |
41
- | `texture-lighting` | `"baked" \| "dynamic"` | `"baked"` | Texture lighting mode |
42
- | `atlas-scale` | `number \| "auto"` | `"auto"` | Atlas bitmap budget and compositor sprite size |
43
- | `polygons` | `Polygon[]` | None | Static polygon array (composes with slot) |
47
+ export default function App() {
48
+ return (
49
+ <PolyCamera rotX={65} rotY={45}>
50
+ <PolyScene textureLighting="dynamic">
51
+ <PolyOrbitControls drag wheel />
52
+ <PolyMesh src="/gallery/obj/cottage.obj" mtl="/gallery/obj/cottage.mtl" />
53
+ </PolyScene>
54
+ </PolyCamera>
55
+ );
56
+ }
57
+ ```
44
58
 
45
- For pointer drag, wheel zoom, and autorotate, mount `<PolyOrbitControls>` (or `<PolyMapControls>` for pan-first map-style input) inside `<PolyCamera>`: it receives the camera context. Mirrors Three.js's split between camera state and input.
59
+ ## API Reference
46
60
 
47
- ### `<PolyMesh>`
61
+ ### PolyCamera
48
62
 
49
- Loads a mesh from a URL and renders its polygons. Manages blob-URL lifecycle automatically.
63
+ - `rotX`, `rotY` control the orbit angle in degrees.
64
+ - `zoom` scales the projected scene.
65
+ - `target` pans the camera target in world coordinates.
66
+ - `distance` adds dolly pull-back.
67
+ - `PolyCamera` is the orthographic default. Use `PolyPerspectiveCamera` when you want perspective depth.
50
68
 
51
- | Prop | Type | Description |
52
- |---|---|---|
53
- | `src` | `string` | URL to `.obj`, `.glb`, `.gltf`, or `.vox` |
54
- | `polygons` | `Polygon[]` | Pre-parsed polygons (alternative to `src`) |
55
- | `position` | `Vec3` | `[x, y, z]` offset in scene space |
56
- | `scale` | `number \| Vec3` | Uniform or per-axis scale |
57
- | `rotation` | `Vec3` | Euler angles in degrees `[x, y, z]` |
58
- | `atlas-scale` | `number \| "auto"` | Atlas bitmap budget and compositor sprite size |
59
- | `auto-center` | `boolean` | Shift mesh so its bbox center is at origin |
60
- | `mtl` | `string` | Companion `.mtl` URL for OBJ models |
69
+ ### PolyScene
61
70
 
62
- Named slot: `#polygon="{ polygon, index }"`: per-polygon scoped slot for rendering overrides. The default slot is for static children inside the mesh wrapper.
71
+ - `polygons` renders a static `Polygon[]` directly.
72
+ - `directionalLight` and `ambientLight` control scene lighting.
73
+ - `textureLighting` chooses `"baked"` or `"dynamic"`.
74
+ - `textureQuality` controls atlas raster budget.
75
+ - Solid seam bleed is automatic on detected shared solid edges.
76
+ - `strategies` can disable selected render strategies for diagnostics.
77
+ - `autoCenter` rotates around the rendered mesh bounds instead of world origin.
63
78
 
64
- ### `<Poly>`
79
+ ### PolyMesh
65
80
 
66
- Single polygon. Renders one atlas-backed `<i>` for UV-textured and flat-color faces. Accepts standard Vue event bindings and class/style.
81
+ - `src` loads `.obj`, `.gltf`, `.glb`, or `.vox` files.
82
+ - `mtl` loads companion OBJ materials.
83
+ - `polygons` accepts pre-parsed geometry.
84
+ - `position`, `scale`, and `rotation` transform the mesh wrapper.
85
+ - `autoCenter` shifts the mesh bbox center to local origin.
86
+ - `meshResolution` chooses `"lossy"` (default) or `"lossless"` optimization.
87
+ - `castShadow` emits CSS-projected shadows in dynamic lighting mode.
67
88
 
68
- | Prop | Type | Description |
69
- |---|---|---|
70
- | `vertices` | `Vec3[]` | Required: 3+ `[x, y, z]` points |
71
- | `color` | `string` | CSS color; used when no texture is set |
72
- | `texture` | `string` | Image URL for UV-mapped rendering |
73
- | `uvs` | `Vec2[]` | UV coordinates, one per vertex |
74
- | `data` | `Record<string, string \| number \| boolean>` | Reflected as `data-*` DOM attributes |
75
- | `position` | `Vec3` | Local offset |
76
- | `scale` | `number \| Vec3` | Scale |
77
- | `rotation` | `Vec3` | Euler rotation in degrees |
78
- | `atlas-scale` | `number \| "auto"` | Atlas bitmap budget and compositor sprite size |
89
+ ### Controls
79
90
 
80
- ### `<PolyCamera>`
91
+ - `<PolyOrbitControls>` adds drag orbit, shift-drag pan, wheel zoom, and optional auto-rotate.
92
+ - `<PolyMapControls>` uses pan-first map-style input.
93
+ - `<PolyFirstPersonControls>` provides keyboard and pointer-look navigation.
94
+ - `<PolyTransformControls>` adds translate/rotate gizmos for selected mesh handles.
81
95
 
82
- Camera wrapper for perspective, rotation, zoom, target, and dolly distance. Vue scenes must render inside `<PolyCamera>` (or `<PolyPerspectiveCamera>` / `<PolyOrthographicCamera>`) so controls and scenes share camera state.
96
+ ### Polygon Data Model
83
97
 
84
- ### Composables
98
+ Each polygon describes one renderable face:
85
99
 
86
- | Composable | Description |
87
- |---|---|
88
- | `usePolyCamera(options)` | Internal camera integration composable |
89
- | `usePolySceneContext(polygons, options)` | Lower-level hook for custom scene wrappers |
90
- | `usePolyMesh(srcRef, options?)` | Reactive mesh loader. Returns reactive `{ polygons, loading, error, warnings, dispose }`. |
100
+ ```ts
101
+ const polygons = [
102
+ {
103
+ vertices: [[0, 0, 0], [60, 0, 0], [0, 60, 0]],
104
+ color: "#f97316",
105
+ },
106
+ {
107
+ vertices: [[0, 0, 0], [60, 0, 0], [60, 60, 0], [0, 60, 0]],
108
+ texture: "/texture.png",
109
+ uvs: [[0, 0], [1, 0], [1, 1], [0, 1]],
110
+ },
111
+ ];
112
+ ```
91
113
 
92
- ### Utility
114
+ Render polygons directly when you need per-face DOM events or custom styling:
93
115
 
94
- | Export | Description |
95
- |---|---|
96
- | `injectPolyBaseStyles(doc?)` | Inject polycss base CSS into the document. Idempotent. |
116
+ ```tsx
117
+ <PolyCamera>
118
+ <PolyScene>
119
+ {polygons.map((polygon, index) => (
120
+ <Poly
121
+ key={index}
122
+ {...polygon}
123
+ onClick={() => console.log("clicked polygon", index)}
124
+ className="my-polygon"
125
+ />
126
+ ))}
127
+ </PolyScene>
128
+ </PolyCamera>
129
+ ```
97
130
 
98
- ## Re-exports from `@layoutit/polycss-core`
131
+ ## Loading Mesh Files
99
132
 
100
- All types and core functions are re-exported:
133
+ Use `loadMesh()` to parse supported model formats:
101
134
 
102
135
  ```ts
103
- import type { Polygon, Vec2, Vec3, PolyDirectionalLight, PolyAmbientLight, ParseResult } from "@layoutit/polycss-vue";
104
- import { parseObj, parseGltf, parseVox, loadMesh, normalizePolygons, mergePolygons } from "@layoutit/polycss-vue";
136
+ import { createPolyCamera, createPolyScene, loadMesh } from "@layoutit/polycss";
137
+
138
+ const host = document.getElementById("polycss")!;
139
+ const camera = createPolyCamera({ rotX: 65, rotY: 45 });
140
+ const scene = createPolyScene(host, { camera });
141
+
142
+ const mesh = await loadMesh("https://polycss.com/gallery/obj/cottage.obj", {
143
+ mtlUrl: "https://polycss.com/gallery/obj/cottage.mtl",
144
+ });
145
+
146
+ scene.add(mesh);
105
147
  ```
106
148
 
107
- ## Examples
149
+ Supported formats:
108
150
 
109
- ### With lighting and multiple meshes
151
+ - OBJ + MTL, including `map_Kd` textures and UV coordinates.
152
+ - glTF / GLB, including embedded images and `TEXCOORD_0`.
153
+ - MagicaVoxel `.vox`, with direct voxel fast paths when eligible.
154
+ - Generated primitives: box, plane, ring, sphere, torus, cylinder, cone, and Platonic solids.
110
155
 
111
- ```vue
112
- <template>
113
- <PolyCamera :rot-x="65" :rot-y="45">
114
- <PolyScene :directional-light="light">
115
- <PolyMesh src="/cottage.glb" />
116
- <PolyMesh src="/tree.glb" :position="[8, 0, 0]" :scale="0.5" />
117
- </PolyScene>
118
- </PolyCamera>
119
- </template>
156
+ ## Performance
120
157
 
121
- <script setup lang="ts">
122
- import { PolyCamera, PolyScene, PolyMesh } from "@layoutit/polycss-vue";
123
- const light = { direction: [0.5, -0.7, 0.6] as [number, number, number], color: "#ffe4a8" };
124
- </script>
125
- ```
158
+ PolyCSS renders in the DOM, so performance is mostly determined by how many polygons are mounted and how much texture atlas area they consume. The renderer uses several CSS strategies so simple surfaces stay cheap and textured or irregular surfaces fall back to atlas slices.
126
159
 
127
- ### Per-polygon interactive
160
+ - One visible polygon becomes one leaf DOM element.
161
+ - Flat rectangles and stable quads use solid CSS leaves.
162
+ - Textured polygons are packed into generated texture atlases.
163
+ - Dynamic lighting runs through CSS custom properties instead of per-frame JavaScript.
164
+ - Voxel-shaped meshes mount only camera-facing leaves when the mesh is eligible.
165
+ - `meshResolution: "lossy"` merges compatible polygons, then may spend a small split budget to repair high-risk seams.
128
166
 
129
- ```vue
130
- <template>
131
- <PolyCamera :rot-x="65" :rot-y="45">
132
- <PolyScene>
133
- <Poly
134
- v-for="(p, i) in polygons"
135
- :key="i"
136
- v-bind="p"
137
- @click="() => alert(`clicked polygon ${i}`)"
138
- @mouseenter="hoveredId = i"
139
- @mouseleave="hoveredId = null"
140
- :class="{ highlight: hoveredId === i }"
141
- />
142
- </PolyScene>
143
- </PolyCamera>
144
- </template>
145
-
146
- <script setup lang="ts">
147
- import { ref } from "vue";
148
- import { PolyCamera, PolyScene, Poly } from "@layoutit/polycss-vue";
149
- import type { Polygon } from "@layoutit/polycss-vue";
150
-
151
- defineProps<{ polygons: Polygon[] }>();
152
- const hoveredId = ref<number | null>(null);
153
- </script>
154
-
155
- <style>
156
- .highlight { filter: brightness(1.5); }
157
- </style>
158
- ```
167
+ Renderer internals:
159
168
 
160
- ### `PolyMesh` with scoped slot
161
-
162
- ```vue
163
- <template>
164
- <PolyCamera :rot-x="65" :rot-y="45">
165
- <PolyScene>
166
- <PolyMesh src="/character.glb" :position="[5, 0, 0]" :scale="2">
167
- <template #polygon="{ polygon, index }">
168
- <Poly
169
- v-bind="polygon"
170
- @click="selected = index"
171
- :class="{ outlined: selected === index }"
172
- />
173
- </template>
174
- </PolyMesh>
175
- </PolyScene>
176
- </PolyCamera>
177
- </template>
178
-
179
- <script setup lang="ts">
180
- import { ref } from "vue";
181
- import { PolyCamera, PolyScene, PolyMesh, Poly } from "@layoutit/polycss-vue";
182
- const selected = ref<number | null>(null);
183
- </script>
184
- ```
169
+ Each visible polygon is emitted as one leaf element; the renderer chooses the least expensive CSS primitive that can represent the polygon, then uses `matrix3d(...)` to place that primitive in 3D space.
170
+
171
+ - `<b>` uses `background: currentColor` on a fixed box for solid rectangles and stable quads.
172
+ - `<u>` uses `corner-shape` for stable triangles and beveled-corner solids, with a `border-width` triangle fallback when needed.
173
+ - `<i>` clips solid polygons with `border-shape: polygon(...)` when the browser supports it.
174
+ - `<s>` maps a packed texture-atlas slice with `background-image`, and is the fallback for textured or unsupported shapes.
175
+
176
+ ## Packages
177
+
178
+ | Package | Description |
179
+ |---|---|
180
+ | `@layoutit/polycss-core` | Pure math, parsers, lighting, camera helpers, mesh optimization. Zero browser globals. |
181
+ | `@layoutit/polycss` | Vanilla custom elements and imperative `createPolyScene` API. |
182
+ | `@layoutit/polycss-react` | React components, hooks, controls, and core re-exports. |
183
+ | `@layoutit/polycss-vue` | Vue 3 components, composables, controls, and core re-exports. |
184
+
185
+ ## Made with PolyCSS
186
+
187
+ [Layoutit Voxels](https://voxels.layoutit.com)
188
+ -> A CSS Voxel editor
189
+
190
+ <img width="1000" height="600" alt="layoutit-voxels" src="https://polycss.com/layoutit-voxels.png" />
191
+
192
+ [Layoutit Terra](https://terra.layoutit.com)
193
+ -> A CSS Terrain Generator
194
+
195
+ <img width="1000" height="601" alt="layoutit-terra" src="https://polycss.com/layoutit-terra.png" />
185
196
 
186
- ## Docs
197
+ ## License
187
198
 
188
- Full documentation at [polycss.com](https://polycss.com).
199
+ MIT.