boxels-in-js 0.1.0-alpha.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 +188 -0
- package/dist/lib/animation/animator.d.ts +27 -0
- package/dist/lib/animation/explode.d.ts +10 -0
- package/dist/lib/animation/layer-rotate.d.ts +4 -0
- package/dist/lib/animation/tweens.d.ts +6 -0
- package/dist/lib/boxels.cjs +1 -0
- package/dist/lib/boxels.mjs +1324 -0
- package/dist/lib/core/boolean.d.ts +3 -0
- package/dist/lib/core/edge-fusion.d.ts +4 -0
- package/dist/lib/core/geometry.d.ts +4 -0
- package/dist/lib/core/grid.d.ts +16 -0
- package/dist/lib/core/image-mapper.d.ts +31 -0
- package/dist/lib/core/rotation.d.ts +3 -0
- package/dist/lib/core/style.d.ts +2 -0
- package/dist/lib/core/textures.d.ts +8 -0
- package/dist/lib/index.d.ts +86 -0
- package/dist/lib/presets/styles.d.ts +11 -0
- package/dist/lib/renderers/dom/axes.d.ts +1 -0
- package/dist/lib/renderers/dom/boxel-element.d.ts +7 -0
- package/dist/lib/renderers/dom/dom-renderer.d.ts +34 -0
- package/dist/lib/renderers/dom/edge-borders.d.ts +2 -0
- package/dist/lib/renderers/dom/orbit.d.ts +31 -0
- package/dist/lib/renderers/renderer.d.ts +1 -0
- package/dist/lib/types.d.ts +165 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# boxels
|
|
2
|
+
|
|
3
|
+
A tiny CSS 3D library for composing interactive boxel scenes from DOM divs. Per-face styling, edge fusion, textures, image mapping, click interactions, and spin animation — zero dependencies.
|
|
4
|
+
|
|
5
|
+
**[Live Demo](https://asitparida.github.io/boxels-in-js/)**
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { Boxels } from 'boxels'
|
|
11
|
+
|
|
12
|
+
const b = new Boxels({
|
|
13
|
+
boxelSize: 100,
|
|
14
|
+
gap: 1,
|
|
15
|
+
edgeWidth: 1,
|
|
16
|
+
camera: { rotation: [-25, 35] },
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
b.addBox({ position: [0, 0, 0], size: [2, 2, 2] })
|
|
20
|
+
b.mount(document.getElementById('scene'))
|
|
21
|
+
b.setTexture('glass', 220, 0.70)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
### Textures
|
|
27
|
+
|
|
28
|
+
5 built-in material textures, controlled by hue and opacity:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
b.setTexture('solid', 220, 1.0) // Opaque blocks with visible edges
|
|
32
|
+
b.setTexture('hollow', 220, 1.0) // Wireframe — transparent fill, colored edges
|
|
33
|
+
b.setTexture('glass', 220, 0.7) // Translucent with backdrop blur
|
|
34
|
+
b.setTexture('frosted', 220, 0.8) // Heavy blur, milky
|
|
35
|
+
b.setTexture('neon', 220, 1.0) // Dark blocks with bright glowing edges
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Geometry & Boolean Operations
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
b.addBox({ position: [0, 0, 0], size: [4, 4, 4] })
|
|
42
|
+
b.addSphere({ center: [2, 2, 2], radius: 1.5, mode: 'subtract' })
|
|
43
|
+
b.addLine({ from: [0, 0, 0], to: [5, 5, 5], radius: 1 })
|
|
44
|
+
b.removeBox({ position: [1, 1, 0], size: [2, 2, 1] })
|
|
45
|
+
|
|
46
|
+
// Boolean modes: 'union' (default), 'subtract', 'intersect', 'exclude'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Per-Face Styling
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
b.addBox({
|
|
53
|
+
position: [0, 0, 0],
|
|
54
|
+
size: [3, 3, 3],
|
|
55
|
+
style: {
|
|
56
|
+
front: { fill: '#ff0000', stroke: '#333' },
|
|
57
|
+
back: { fill: '#ff8c00', stroke: '#333' },
|
|
58
|
+
left: { fill: '#00cc00', stroke: '#333' },
|
|
59
|
+
right: { fill: '#0000ff', stroke: '#333' },
|
|
60
|
+
top: { fill: '#ffff00', stroke: '#333' },
|
|
61
|
+
bottom: { fill: '#ffffff', stroke: '#333' },
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Functional Styles
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
b.addBox({
|
|
70
|
+
position: [0, 0, 0],
|
|
71
|
+
size: [6, 6, 6],
|
|
72
|
+
style: {
|
|
73
|
+
default: (x, y, z) => ({
|
|
74
|
+
fill: `oklch(${0.4 + y / 12} 0.15 ${x / 6 * 360})`,
|
|
75
|
+
stroke: 'transparent',
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Image Mapping
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
// One image distributed across all exposed faces
|
|
85
|
+
b.mapImage('landscape.jpg')
|
|
86
|
+
|
|
87
|
+
// Different image per face type
|
|
88
|
+
b.mapImage('icon-x.png', 'front')
|
|
89
|
+
b.mapImage('icon-github.png', 'back')
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Edge Fusion
|
|
93
|
+
|
|
94
|
+
When `gap: 0`, internal faces between adjacent boxels are culled and shared edges merge — only the outer silhouette remains. A 10x10x10 cube (1,000 boxels) renders ~600 faces instead of 6,000.
|
|
95
|
+
|
|
96
|
+
### Animation
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
// Continuous spin
|
|
100
|
+
b.startSpin({ x: true, y: true, speed: 3 })
|
|
101
|
+
b.stopSpin()
|
|
102
|
+
|
|
103
|
+
// Gap animation
|
|
104
|
+
b.animateGap({ from: 0, to: 10, duration: 800 })
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Click Interaction
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
b.enableClick(({ boxel, face }) => {
|
|
111
|
+
console.log(`Clicked ${face} face at [${boxel}]`)
|
|
112
|
+
})
|
|
113
|
+
// Plays a dip animation + active flash on the clicked face
|
|
114
|
+
// Pauses spin during interaction, resumes after
|
|
115
|
+
|
|
116
|
+
b.disableClick()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Axes
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
b.showAxes() // L/R (red), T/B (blue), F/Bk (green) through center
|
|
123
|
+
b.hideAxes()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Positioning
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
// Fixed position on page
|
|
130
|
+
const b = new Boxels({
|
|
131
|
+
position: { x: '50%', y: 100, zIndex: 999, fixed: true }
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Update at runtime
|
|
135
|
+
b.setPosition({ x: 200, y: 300 })
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Camera
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
b.updateTransform(-30, 45) // rotateX, rotateY in degrees
|
|
142
|
+
b.getRotation() // { rotX, rotY }
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Constructor Options
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
new Boxels({
|
|
149
|
+
boxelSize: 50, // Size of each boxel in px
|
|
150
|
+
gap: 0, // Gap between boxels in px
|
|
151
|
+
edgeWidth: 1, // Border width in px
|
|
152
|
+
edgeColor: '#333', // Default border color
|
|
153
|
+
camera: {
|
|
154
|
+
type: 'perspective',
|
|
155
|
+
distance: 1200,
|
|
156
|
+
rotation: [-25, 35], // [rotX, rotY] in degrees
|
|
157
|
+
},
|
|
158
|
+
orbit: true, // Drag to rotate
|
|
159
|
+
zoom: true, // Scroll to zoom
|
|
160
|
+
showBackfaces: false, // Show internal faces for translucent styles
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Project Structure
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
boxels-in-js/
|
|
168
|
+
src/lib/ # The library (zero dependencies)
|
|
169
|
+
core/ # Grid, boolean ops, geometry, style, edge fusion, textures
|
|
170
|
+
renderers/dom/ # CSS 3D renderer, orbit controls, axes
|
|
171
|
+
animation/ # RAF animator, explode, tweens, layer rotation
|
|
172
|
+
presets/ # Built-in style presets
|
|
173
|
+
src/react/ # React 19+ wrapper
|
|
174
|
+
docs/ # Interactive showcase app
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm install
|
|
181
|
+
npm run dev # Docs app at localhost:5173
|
|
182
|
+
npm run build:lib # Build library to dist/lib/
|
|
183
|
+
npm test # Run tests
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AnimationConfig {
|
|
2
|
+
duration: number;
|
|
3
|
+
tick: (t: number) => void;
|
|
4
|
+
onComplete?: () => void;
|
|
5
|
+
easing?: (t: number) => number;
|
|
6
|
+
loop?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface AnimationHandle {
|
|
9
|
+
cancel: () => void;
|
|
10
|
+
readonly done: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const easings: {
|
|
13
|
+
linear: (t: number) => number;
|
|
14
|
+
easeInOut: (t: number) => number;
|
|
15
|
+
easeOut: (t: number) => number;
|
|
16
|
+
easeIn: (t: number) => number;
|
|
17
|
+
bounce: (t: number) => number;
|
|
18
|
+
};
|
|
19
|
+
export declare function parseCubicBezier(str: string): ((t: number) => number) | null;
|
|
20
|
+
export declare class Animator {
|
|
21
|
+
private animations;
|
|
22
|
+
private rafId;
|
|
23
|
+
add(config: AnimationConfig): AnimationHandle;
|
|
24
|
+
cancelAll(): void;
|
|
25
|
+
private start;
|
|
26
|
+
private tick;
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Vec3, BoxelRenderer } from '../types';
|
|
2
|
+
import type { BoxelGrid } from '../core/grid';
|
|
3
|
+
import type { Animator, AnimationHandle } from './animator';
|
|
4
|
+
export declare function computeExplodeOffsets(positions: Vec3[], center: Vec3, factor: number): Vec3[];
|
|
5
|
+
export declare function createExplodeAnimation(grid: BoxelGrid, renderer: BoxelRenderer, animator: Animator, boxelSize: number, options?: {
|
|
6
|
+
factor?: number;
|
|
7
|
+
stagger?: number;
|
|
8
|
+
easing?: string;
|
|
9
|
+
duration?: number;
|
|
10
|
+
}): AnimationHandle;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LayerRotateOptions, BoxelRenderer } from '../types';
|
|
2
|
+
import type { BoxelGrid } from '../core/grid';
|
|
3
|
+
import type { Animator, AnimationHandle } from './animator';
|
|
4
|
+
export declare function createLayerRotateAnimation(grid: BoxelGrid, renderer: BoxelRenderer, animator: Animator, options: LayerRotateOptions, onComplete: () => void): AnimationHandle;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AnimateEachCallback, AnimateEachOptions, TweenOptions, BoxelRenderer } from '../types';
|
|
2
|
+
import type { BoxelGrid } from '../core/grid';
|
|
3
|
+
import type { Animator, AnimationHandle } from './animator';
|
|
4
|
+
export declare function createGapTween(animator: Animator, onGapChange: (gap: number) => void, options: TweenOptions): AnimationHandle;
|
|
5
|
+
export declare function createOpacityTween(animator: Animator, renderer: BoxelRenderer, options: TweenOptions): AnimationHandle;
|
|
6
|
+
export declare function createEachTween(grid: BoxelGrid, renderer: BoxelRenderer, animator: Animator, _boxelSize: number, callback: AnimateEachCallback, options?: AnimateEachOptions): AnimationHandle;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={right:[1,0,0],left:[-1,0,0],top:[0,1,0],bottom:[0,-1,0],front:[0,0,1],back:[0,0,-1]},t=[`top`,`bottom`,`front`,`back`,`left`,`right`];function n(e,t,n){return`${e},${t},${n}`}var r=class{data=new Map;get count(){return this.data.size}hasBoxel(e,t,r){return this.data.has(n(e,t,r))}getBoxel(e,t,r){return this.data.get(n(e,t,r))??null}setBoxel(e,t,r,i){let a=n(e,t,r);i===null?this.data.delete(a):this.data.set(a,i)}getNeighbors(n,r,i){let a={};for(let o of t){let[t,s,c]=e[o];a[o]=this.getBoxel(n+t,r+s,i+c)}return a}getExposure(n,r,i){let a=0;for(let o of t){let[t,s,c]=e[o];this.hasBoxel(n+t,r+s,i+c)||a++}return a}forEach(e){for(let[t,n]of this.data)e(n,t.split(`,`).map(Number))}getBounds(){if(this.data.size===0)return{min:[0,0,0],max:[0,0,0]};let e=1/0,t=1/0,n=1/0,r=-1/0,i=-1/0,a=-1/0;for(let o of this.data.keys()){let[s,c,l]=o.split(`,`).map(Number);s<e&&(e=s),c<t&&(t=c),l<n&&(n=l),s>r&&(r=s),c>i&&(i=c),l>a&&(a=l)}return{min:[e,t,n],max:[r,i,a]}}clear(){this.data.clear()}};function i(e,t,n,r){switch(n){case`union`:for(let[n,i,a]of t)e.setBoxel(n,i,a,{position:[n,i,a],opaque:!0,style:r});break;case`subtract`:for(let[n,r,i]of t)e.setBoxel(n,r,i,null);break;case`intersect`:{let n=new Set(t.map(([e,t,n])=>`${e},${t},${n}`)),r=[];e.forEach((e,t)=>{let i=`${t[0]},${t[1]},${t[2]}`;n.has(i)||r.push(t)});for(let[t,n,i]of r)e.setBoxel(t,n,i,null);break}case`exclude`:for(let[n,i,a]of t)e.hasBoxel(n,i,a)?e.setBoxel(n,i,a,null):e.setBoxel(n,i,a,{position:[n,i,a],opaque:!0,style:r});break}}function a(e,t){let[n,r,i]=e,[a,o,s]=t,c=[];for(let e=n;e<n+a;e++)for(let t=r;t<r+o;t++)for(let n=i;n<i+s;n++)c.push([e,t,n]);return c}function o(e,t){let[n,r,i]=e,a=t,o=[];for(let e=Math.floor(n-a);e<=Math.ceil(n+a);e++)for(let t=Math.floor(r-a);t<=Math.ceil(r+a);t++)for(let s=Math.floor(i-a);s<=Math.ceil(i+a);s++){let c=e-n,l=t-r,u=s-i;c*c+l*l+u*u<=a*a&&o.push([e,t,s])}return o}function s(e,t,n=0){let[r,i,a]=e,[s,c,l]=t,u=s-r,d=c-i,f=l-a,p=Math.max(Math.abs(u),Math.abs(d),Math.abs(f));if(p===0)return n===0?[e]:o(e,n);let m=[],h=new Set;for(let e=0;e<=p;e++){let t=e/p,n=Math.round(r+u*t),o=Math.round(i+d*t),s=Math.round(a+f*t),c=`${n},${o},${s}`;h.has(c)||(h.add(c),m.push([n,o,s]))}if(n===0)return m;let g=new Set,_=[];for(let e of m){let t=o(e,n);for(let e of t){let t=`${e[0]},${e[1]},${e[2]}`;g.has(t)||(g.add(t),_.push(e))}}return _}function c(e,t,n,r){switch(e){case`x`:return[t,-r,n];case`y`:return[r,n,-t];case`z`:return[-n,t,r]}}function l(e,t,n,r=[0,0,0]){let i=(n%4+4)%4;if(i===0)return;let a=[];e.forEach((e,t)=>{a.push([t,e])}),e.clear();for(let[n,o]of a){let a=n[0]-r[0],s=n[1]-r[1],l=n[2]-r[2];for(let e=0;e<i;e++)[a,s,l]=c(t,a,s,l);let u=[Math.round(a+r[0]),Math.round(s+r[1]),Math.round(l+r[2])];e.setBoxel(u[0],u[1],u[2],{...o,position:u})}}var u={right:[1,0,0],left:[-1,0,0],top:[0,1,0],bottom:[0,-1,0],front:[0,0,1],back:[0,0,-1]},d={top:{Left:[-1,0,0],Right:[1,0,0],Top:[0,0,-1],Bottom:[0,0,1]},bottom:{Left:[-1,0,0],Right:[1,0,0],Top:[0,0,1],Bottom:[0,0,-1]},front:{Left:[-1,0,0],Right:[1,0,0],Top:[0,1,0],Bottom:[0,-1,0]},back:{Left:[1,0,0],Right:[-1,0,0],Top:[0,1,0],Bottom:[0,-1,0]},left:{Left:[0,0,1],Right:[0,0,-1],Top:[0,1,0],Bottom:[0,-1,0]},right:{Left:[0,0,-1],Right:[0,0,1],Top:[0,1,0],Bottom:[0,-1,0]}},f=[`top`,`bottom`,`front`,`back`,`left`,`right`];function p(e,t,n,r){let i=[];for(let a of f){let[o,s,c]=u[a];e.hasBoxel(t+o,n+s,r+c)||i.push(a)}return i}function m(e,t,n,r,i){let a=d[i];return{left:!h(e,t,n,r,i,a.Left),right:!h(e,t,n,r,i,a.Right),top:!h(e,t,n,r,i,a.Top),bottom:!h(e,t,n,r,i,a.Bottom)}}function h(e,t,n,r,i,a){let o=t+a[0],s=n+a[1],c=r+a[2];if(!e.hasBoxel(o,s,c))return!1;let l=u[i];return!e.hasBoxel(o+l[0],s+l[1],c+l[2])}function g(e,t,n,r,i,a,o){switch(e){case`front`:return{col:t,row:a-1-n,cols:i,rows:a};case`back`:return{col:i-1-t,row:a-1-n,cols:i,rows:a};case`left`:return{col:r,row:a-1-n,cols:o,rows:a};case`right`:return{col:o-1-r,row:a-1-n,cols:o,rows:a};case`top`:return{col:t,row:r,cols:i,rows:o};case`bottom`:return{col:t,row:o-1-r,cols:i,rows:o}}}function _(e,t,n,r,i,a,o){let{col:s,row:c,cols:l,rows:u}=g(e,t,n,r,i,a,o);return{backgroundSize:`${l*100}% ${u*100}%`,backgroundPosition:`${l>1?s/(l-1)*100:0}% ${u>1?c/(u-1)*100:0}%`}}function v(e,t){let n=[],r=e.getBounds(),i=r.max[0]-r.min[0]+1,a=r.max[1]-r.min[1]+1,o=r.max[2]-r.min[2]+1;return e.forEach((s,c)=>{let[l,u,d]=c,f=p(e,l,u,d);for(let e of f){if(t&&e!==t)continue;let s=_(e,l-r.min[0],u-r.min[1],d-r.min[2],i,a,o);n.push({position:c,face:e,...s})}}),n}var y={fill:`#ddd`,stroke:`#333`,opacity:1};function b(e,t,n,r){return typeof e==`function`?e(t,n,r):e}function x(e,t,n,r){if(e!==void 0)return typeof e==`function`?e(t,n,r):e}function S(e,t,n,r){if(!e)return{};let i={};return e.fill!==void 0&&(i.fill=b(e.fill,t,n,r)),e.stroke!==void 0&&(i.stroke=b(e.stroke,t,n,r)),e.opacity!==void 0&&(i.opacity=e.opacity),e.className!==void 0&&(i.className=e.className),e.backdropFilter!==void 0&&(i.backdropFilter=e.backdropFilter),i}function C(e,t,n,r,i,a){let o={...y};if(a){let i=x(a.default,t,n,r);Object.assign(o,S(i,t,n,r));let s=x(a[e],t,n,r);Object.assign(o,S(s,t,n,r))}if(i){let a=x(i.default,t,n,r);Object.assign(o,S(a,t,n,r));let s=x(i[e],t,n,r);Object.assign(o,S(s,t,n,r))}return o}function w(e,t,n,r){e.style.borderStyle=`solid`,e.style.borderLeftWidth=t.left?`${n}px`:`0`,e.style.borderRightWidth=t.right?`${n}px`:`0`,e.style.borderTopWidth=t.top?`${n}px`:`0`,e.style.borderBottomWidth=t.bottom?`${n}px`:`0`,e.style.borderLeftColor=t.left?r:`transparent`,e.style.borderRightColor=t.right?r:`transparent`,e.style.borderTopColor=t.top?r:`transparent`,e.style.borderBottomColor=t.bottom?r:`transparent`}var T={front:e=>`translateZ(${e/2}px)`,back:e=>`rotateY(180deg) translateZ(${e/2}px)`,left:e=>`rotateY(-90deg) translateZ(${e/2}px)`,right:e=>`rotateY(90deg) translateZ(${e/2}px)`,top:e=>`rotateX(90deg) translateZ(${e/2}px)`,bottom:e=>`rotateX(-90deg) translateZ(${e/2}px)`};function E(e,t,n,r,i,a,o){let s=document.createElement(`div`);return s.dataset.face=e,s.dataset.faceIndex=e,s.style.position=`absolute`,s.style.width=`${t}px`,s.style.height=`${t}px`,s.style.transform=T[e](t),s.style.backfaceVisibility=o?`visible`:`hidden`,s.style.boxSizing=`border-box`,s.style.willChange=`transform`,s.style.contain=`layout style paint`,s.style.backgroundColor=n.fill,s.style.opacity=String(n.opacity),n.backdropFilter&&(s.style.backdropFilter=n.backdropFilter,s.style.webkitBackdropFilter=n.backdropFilter),n.className&&(s.className=n.className),w(s,r,i,n.stroke===`transparent`?a:n.stroke),s}function D(e,t,n,r,i,a,o){let s=document.createElement(`div`);s.dataset.boxel=`${e[0]},${e[1]},${e[2]}`,s.dataset.x=String(e[0]),s.dataset.y=String(e[1]),s.dataset.z=String(e[2]),s.style.position=`absolute`,s.style.width=`${t}px`,s.style.height=`${t}px`,s.style.transformStyle=`preserve-3d`,s.style.willChange=`transform`;let[c,l,u]=e,d=t+n;s.style.transform=`translate3d(${c*d}px, ${-l*d}px, ${u*d}px)`;for(let e of r){let n=E(e.name,t,e.style,e.edges,i,a,o);s.appendChild(n)}return s}var O=class{rotX;rotY;scale;isDragging=!1;lastPointerX=0;lastPointerY=0;onChange;container=null;boundPointerDown=this.onPointerDown.bind(this);boundPointerMove=this.onPointerMove.bind(this);boundPointerUp=this.onPointerUp.bind(this);boundWheel=this.onWheel.bind(this);constructor(e=[-25,35],t){this.rotX=e[0],this.rotY=e[1],this.scale=1,this.onChange=t}attach(e){this.container=e,e.addEventListener(`pointerdown`,this.boundPointerDown),e.addEventListener(`wheel`,this.boundWheel,{passive:!1})}detach(){this.container&&=(this.container.removeEventListener(`pointerdown`,this.boundPointerDown),this.container.removeEventListener(`wheel`,this.boundWheel),document.removeEventListener(`pointermove`,this.boundPointerMove),document.removeEventListener(`pointerup`,this.boundPointerUp),null)}zoomEnabled=!0;disableZoom(){this.zoomEnabled=!1}setState(e,t){this.rotX=e,this.rotY=t}getState(){return{rotX:this.rotX,rotY:this.rotY,scale:this.scale}}onPointerDown(e){e.button===0&&(this.isDragging=!0,this.lastPointerX=e.clientX,this.lastPointerY=e.clientY,document.addEventListener(`pointermove`,this.boundPointerMove),document.addEventListener(`pointerup`,this.boundPointerUp),e.preventDefault())}onPointerMove(e){if(!this.isDragging)return;let t=e.clientX-this.lastPointerX,n=e.clientY-this.lastPointerY;this.lastPointerX=e.clientX,this.lastPointerY=e.clientY,this.rotY+=t*.5,this.rotX-=n*.5,this.onChange({rotX:this.rotX,rotY:this.rotY,scale:this.scale})}onPointerUp(){this.isDragging=!1,document.removeEventListener(`pointermove`,this.boundPointerMove),document.removeEventListener(`pointerup`,this.boundPointerUp)}onWheel(e){if(!this.zoomEnabled)return;e.preventDefault();let t=e.deltaY>0?.95:1.05;this.scale=Math.max(.1,Math.min(5,this.scale*t)),this.onChange({rotX:this.rotX,rotY:this.rotY,scale:this.scale})}},k=class{sceneEl=null;worldEl=null;containerEl=null;orbitControls=null;options;currentRotX=-25;currentRotY=35;constructor(e={}){this.options=e}mount(e){this.containerEl=e,this.sceneEl=document.createElement(`div`),this.sceneEl.style.perspective=`${this.options.cameraDistance??1200}px`,this.sceneEl.style.overflow=`hidden`,this.sceneEl.style.transformStyle=`preserve-3d`;let t=this.options.position;t?(this.sceneEl.style.position=t.fixed?`fixed`:`absolute`,t.x!==void 0&&(this.sceneEl.style.left=typeof t.x==`number`?`${t.x}px`:t.x),t.y!==void 0&&(this.sceneEl.style.top=typeof t.y==`number`?`${t.y}px`:t.y),t.zIndex!==void 0&&(this.sceneEl.style.zIndex=String(t.zIndex)),this.sceneEl.style.width=`auto`,this.sceneEl.style.height=`auto`):(this.sceneEl.style.position=`relative`,this.sceneEl.style.width=`100%`,this.sceneEl.style.height=`100%`),this.worldEl=document.createElement(`div`),this.worldEl.style.position=`absolute`,this.worldEl.style.top=`50%`,this.worldEl.style.left=`50%`,this.worldEl.style.transformStyle=`preserve-3d`,this.worldEl.style.willChange=`transform`;let[n,r]=this.options.cameraRotation??[-25,35];this.currentRotX=n,this.currentRotY=r,this.worldEl.style.transform=`rotateX(${n}deg) rotateY(${r}deg)`,this.sceneEl.appendChild(this.worldEl),e.appendChild(this.sceneEl),this.options.orbit!==!1&&(this.orbitControls=new O(this.options.cameraRotation??[-25,35],e=>{this.currentRotX=e.rotX,this.currentRotY=e.rotY,this.worldEl&&(this.worldEl.style.transform=`rotateX(${e.rotX}deg) rotateY(${e.rotY}deg) scale(${e.scale})`)}),this.options.zoom===!1&&this.orbitControls.disableZoom(),this.orbitControls.attach(this.sceneEl))}unmount(){this.orbitControls&&=(this.orbitControls.detach(),null),this.sceneEl&&this.containerEl&&this.containerEl.removeChild(this.sceneEl),this.sceneEl=null,this.worldEl=null,this.containerEl=null}render(e){if(!this.worldEl)return;this.worldEl.innerHTML=``;let{grid:t,boxelSize:n,gap:r,edgeWidth:i,edgeColor:a,globalStyle:o,showBackfaces:s}=e,c=t.getBounds(),l=n+r,u=n/2,d=(c.min[0]+c.max[0])/2*l+u,f=-(c.min[1]+c.max[1])/2*l+u,h=(c.min[2]+c.max[2])/2*l,g=document.createElement(`div`);g.style.position=`absolute`,g.style.transformStyle=`preserve-3d`,g.style.transform=`translate3d(${-d}px, ${-f}px, ${-h}px)`,this.worldEl.appendChild(g);let _=[`top`,`bottom`,`front`,`back`,`left`,`right`];t.forEach((e,c)=>{let[l,u,d]=c,f=s?_:p(t,l,u,d);if(f.length===0)return;let h=D(c,n,r,f.map(n=>{let i=r===0&&!s?m(t,l,u,d,n):{left:!0,right:!0,top:!0,bottom:!0};return{name:n,style:C(n,l,u,d,e.style,o),edges:i}}),i,a,s);g.appendChild(h)})}updateTransform(e,t){this.currentRotX=e,this.currentRotY=t,this.orbitControls&&this.orbitControls.setState(e,t),this.worldEl&&(this.worldEl.style.transform=`rotateX(${e}deg) rotateY(${t}deg)`)}updateGap(e){}updateOpacity(e){this.worldEl&&this.worldEl.style.setProperty(`--face-opacity`,String(e))}setBoxelTransform(e,t,n,r){if(!this.worldEl)return;let i=this.worldEl.querySelector(`[data-boxel="${e}"]`);if(!i)return;let a=i.style.transform;(t[0]!==0||t[1]!==0||t[2]!==0)&&(i.style.transform=a+` translate3d(${t[0]}px, ${-t[1]}px, ${t[2]}px)`),n!==void 0&&(i.style.transform+=` scale(${n})`),r!==void 0&&(i.style.opacity=String(r))}getWorldContainer(){return this.worldEl}getSceneElement(){return this.sceneEl}getOrbitState(){return{rotX:this.currentRotX,rotY:this.currentRotY,scale:1}}dispose(){this.unmount()}};function A(e,t,n){let r=document.createElement(`div`);return r.className=`boxel-axis-label`,r.textContent=e,r.style.position=`absolute`,r.style.color=t,r.style.fontSize=`16px`,r.style.fontFamily=`monospace`,r.style.fontWeight=`700`,r.style.transform=n,r.style.pointerEvents=`none`,r.style.textShadow=`0 0 16px ${t}, 0 2px 8px rgba(0,0,0,0.9)`,r.style.whiteSpace=`nowrap`,r}function j(e){let t=document.createElement(`div`);t.className=`boxel-axes`,t.style.position=`absolute`,t.style.transformStyle=`preserve-3d`,t.style.pointerEvents=`none`;let n=`rgba(255, 100, 100, 0.9)`,r=`rgba(100, 180, 255, 0.9)`,i=`rgba(100, 255, 160, 0.9)`,a=document.createElement(`div`);a.style.position=`absolute`,a.style.width=`${e*2}px`,a.style.height=`4px`,a.style.background=`linear-gradient(90deg, transparent, ${n} 10%, ${n} 90%, transparent)`,a.style.transform=`translate3d(${-e}px, -2px, 2px)`,t.appendChild(a),t.appendChild(A(`L`,n,`translate3d(${-e-22}px, -10px, 2px)`)),t.appendChild(A(`R`,n,`translate3d(${e+8}px, -10px, 2px)`));let o=document.createElement(`div`);o.style.position=`absolute`,o.style.width=`4px`,o.style.height=`${e*2}px`,o.style.background=`linear-gradient(180deg, transparent, ${r} 10%, ${r} 90%, transparent)`,o.style.transform=`translate3d(-2px, ${-e}px, 2px)`,t.appendChild(o),t.appendChild(A(`T`,r,`translate3d(-10px, ${-e-26}px, 2px)`)),t.appendChild(A(`B`,r,`translate3d(-10px, ${e+8}px, 2px)`));let s=document.createElement(`div`);s.style.position=`absolute`,s.style.width=`${e*2}px`,s.style.height=`4px`,s.style.left=`${-e}px`,s.style.top=`-2px`,s.style.background=`linear-gradient(90deg, transparent, ${i} 10%, ${i} 90%, transparent)`,s.style.transformOrigin=`${e}px 2px`,s.style.transform=`rotateY(90deg)`,t.appendChild(s);let c=document.createElement(`div`);c.style.position=`absolute`,c.style.width=`4px`,c.style.height=`${e*2}px`,c.style.left=`-2px`,c.style.top=`${-e}px`,c.style.background=`linear-gradient(180deg, transparent, ${i} 10%, ${i} 90%, transparent)`,c.style.transformOrigin=`2px ${e}px`,c.style.transform=`rotateX(90deg)`,t.appendChild(c),t.appendChild(A(`F`,i,`translate3d(-8px, -10px, ${e+12}px)`)),t.appendChild(A(`Bk`,i,`translate3d(-12px, -10px, ${-e-28}px)`));let l=document.createElement(`div`);return l.style.position=`absolute`,l.style.width=`10px`,l.style.height=`10px`,l.style.borderRadius=`50%`,l.style.background=`rgba(255,255,255,0.7)`,l.style.boxShadow=`0 0 12px rgba(255,255,255,0.5)`,l.style.transform=`translate3d(-5px, -5px, 2px)`,t.appendChild(l),t}var M={linear:e=>e,easeInOut:e=>e<.5?2*e*e:1-(-2*e+2)**2/2,easeOut:e=>1-(1-e)**3,easeIn:e=>e*e*e,bounce:e=>{let t=7.5625,n=2.75;return e<1/n?t*e*e:e<2/n?t*(e-=1.5/n)*e+.75:e<2.5/n?t*(e-=2.25/n)*e+.9375:t*(e-=2.625/n)*e+.984375}};function N(e){let t=e.match(/cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)/);if(!t)return null;let[,n,r,i,a]=t,o=parseFloat(r),s=parseFloat(a);return e=>{let t=1-e,n=3*t*t*e,r=3*t*e*e,i=e*e*e;return n*o+r*s+i}}var P=class{animations=[];rafId=null;add(e){let t={config:e,startTime:null,cancelled:!1};return this.animations.push(t),this.start(),{cancel:()=>{t.cancelled=!0},get done(){return t.cancelled}}}cancelAll(){for(let e of this.animations)e.cancelled=!0;this.animations=[],this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}start(){this.rafId===null&&(this.rafId=requestAnimationFrame(this.tick))}tick=e=>{let t=[];for(let n=0;n<this.animations.length;n++){let r=this.animations[n];if(r.cancelled){t.push(n);continue}r.startTime===null&&(r.startTime=e);let i=e-r.startTime,a=r.config.duration,o=Math.min(i/a,1);r.config.loop&&o>=1&&(r.startTime=e,o=0);let s=(r.config.easing??M.linear)(o);r.config.tick(s),o>=1&&!r.config.loop&&(r.config.tick(1),r.config.onComplete?.(),t.push(n))}for(let e=t.length-1;e>=0;e--)this.animations.splice(t[e],1);this.animations.length>0?this.rafId=requestAnimationFrame(this.tick):this.rafId=null}};function F(e,t,n){return e.map(([e,r,i])=>{let a=e-t[0],o=r-t[1],s=i-t[2];return[a*n,o*n,s*n]})}function I(e,t,n,r,i={}){let a=i.factor??2,o=i.duration??800,s=[];e.forEach((e,t)=>s.push(t));let c=e.getBounds(),l=F(s,[(c.min[0]+c.max[0])/2,(c.min[1]+c.max[1])/2,(c.min[2]+c.max[2])/2],a),u=M.easeOut;if(i.easing){let e=N(i.easing);e&&(u=e)}return n.add({duration:o,easing:u,tick:e=>{for(let n=0;n<s.length;n++){let[i,a,o]=l[n],c=`${s[n][0]},${s[n][1]},${s[n][2]}`;t.setBoxelTransform(c,[i*e*r,a*e*r,o*e*r])}}})}function L(e,t,n,i,a){let{axis:o,layer:s,direction:c,duration:u=350}=i,d=t.getWorldContainer();if(!d)return{cancel:()=>{},done:!0};let f=o===`x`?0:o===`y`?1:2,p=[];if(e.forEach((e,t)=>{t[f]===s&&p.push(t)}),p.length===0)return{cancel:()=>{},done:!0};let m=document.createElement(`div`);m.style.position=`absolute`,m.style.transformStyle=`preserve-3d`,d.appendChild(m);let h=[];for(let e of p){let t=`${e[0]},${e[1]},${e[2]}`,n=d.querySelector(`[data-boxel="${t}"]`);n&&(h.push(n),m.appendChild(n))}let g=o===`x`?`rotateX`:o===`y`?`rotateY`:`rotateZ`,_=c*90;return n.add({duration:u,easing:M.easeInOut,tick:e=>{m.style.transform=`${g}(${_*e}deg)`},onComplete:()=>{for(let e of h)d.appendChild(e);m.remove();let t=new r;for(let n of p){let r=e.getBoxel(n[0],n[1],n[2]);r&&(t.setBoxel(n[0],n[1],n[2],r),e.setBoxel(n[0],n[1],n[2],null))}l(t,o,c),t.forEach((t,n)=>{e.setBoxel(n[0],n[1],n[2],t)}),a()}})}function R(e){return e?e in M?M[e]:N(e)??M.easeInOut:M.easeInOut}function z(e,t,n){let{from:r,to:i,duration:a=600}=n,o=R(n.easing);return e.add({duration:a,easing:o,tick:e=>{t(r+(i-r)*e)}})}function B(e,t,n){let{from:r,to:i,duration:a=600}=n,o=R(n.easing);return e.add({duration:a,easing:o,tick:e=>{let n=r+(i-r)*e;t.updateOpacity(n)}})}function V(e,t,n,r,i,a={}){let{duration:o=2e3,loop:s=!1}=a,c=R(a.easing);return n.add({duration:o,easing:c,loop:s,tick:n=>{e.forEach((e,r)=>{let a=i(e,r,n),o=`${r[0]},${r[1]},${r[2]}`;t.setBoxelTransform(o,a.translate??[0,0,0],a.scale,a.opacity)})}})}var H={heerich(e,t,n){return{default:(e,t,n)=>{let r=.75+t*.02;return{fill:`oklch(${r} 0.03 80)`,stroke:`oklch(${r-.15} 0.03 80)`}},top:{fill:`oklch(0.85 0.02 80)`,stroke:`oklch(0.65 0.03 80)`}}},rubik(e,t,n){return{default:{fill:`#111`,stroke:`#000`},top:{fill:`#ffff00`,stroke:`#333`},bottom:{fill:`#ffffff`,stroke:`#333`},front:{fill:`#ff0000`,stroke:`#333`},back:{fill:`#ff8c00`,stroke:`#333`},left:{fill:`#00ff00`,stroke:`#333`},right:{fill:`#0000ff`,stroke:`#333`}}},gradient(e,t,n){return{default:(r,i,a)=>{let o=r/Math.max(e,1)*360,s=.4+i/Math.max(t,1)*.4,c=.1+a/Math.max(n,1)*.1;return{fill:`oklch(${s} ${c} ${o})`,stroke:`oklch(${s-.1} ${c} ${o})`}}}},wireframe(e,t,n){return{default:{fill:`transparent`,stroke:`#666`,opacity:1}}},xray(e,t,n){let r=e/2,i=t/2,a=n/2,o=Math.sqrt(r*r+i*i+a*a);return{default:(e,t,n)=>({fill:`oklch(0.7 0.12 220)`,stroke:`oklch(0.5 0.12 220)`,opacity:.1+Math.sqrt((e-r)**2+(t-i)**2+(n-a)**2)/Math.max(o,1)*.6})}},glass(e,t,n){return{default:{fill:`rgba(200, 220, 240, 0.15)`,stroke:`rgba(100, 140, 180, 0.4)`,opacity:.8,backdropFilter:`blur(4px)`}}},marble(e,t,n){return{default:(e,t,n)=>{let r=Math.sin(e*12.9898+t*78.233+n*37.719)*43758.5453,i=.88+(r-Math.floor(r))*.08;return{fill:`oklch(${i} 0.005 90)`,stroke:`oklch(${i-.12} 0.01 90)`}}}},neon(e,t,n){return{default:{fill:`rgba(10, 10, 15, 0.9)`,stroke:`#0ff`,opacity:1}}}},U=[`solid`,`hollow`,`glass`,`frosted`,`neon`];function W(e,t,n=1,r=1,i=1,a=1){let o=n;switch(e){case`solid`:return{default:{fill:`oklch(0.65 0.15 ${t})`,stroke:`oklch(0.45 0.12 ${t})`,opacity:o}};case`hollow`:return{default:{fill:`transparent`,stroke:`oklch(0.7 0.15 ${t})`,opacity:o}};case`glass`:return{default:{fill:`oklch(0.8 0.06 ${t} / ${.15*o})`,stroke:`oklch(0.5 0.08 ${t} / ${.4*o})`,opacity:Math.min(o,.85),backdropFilter:`blur(${Math.round(4*o)}px)`}};case`frosted`:return{default:{fill:`oklch(0.9 0.02 ${t} / ${.4*o})`,stroke:`oklch(0.7 0.04 ${t} / ${.3*o})`,opacity:Math.min(o,.9),backdropFilter:`blur(${Math.round(12*o)}px)`}};case`neon`:return{default:{fill:`oklch(0.15 0.02 ${t} / ${.9*o})`,stroke:`oklch(0.85 0.25 ${t})`,opacity:o}}}}var G=class{static presets=H;static textures=U;grid;renderer;animator;options;globalStyle;listeners=new Map;mounted=!1;eventsBound=!1;constructor(e={}){this.grid=new r,this.animator=new P,this.options={boxelSize:e.boxelSize??50,gap:e.gap??0,edgeWidth:e.edgeWidth??1,edgeColor:e.edgeColor??`#333`,showBackfaces:e.showBackfaces??!1},this.globalStyle=e.style,this.renderer=new k({orbit:e.orbit??!0,zoom:e.zoom??!0,cameraRotation:e.camera?.rotation,cameraDistance:e.camera?.distance,position:e.position}),e.container&&this.mount(e.container)}mount(e){this.renderer.mount(e),this.mounted=!0,this.renderScene()}unmount(){this.animator.cancelAll(),this.renderer.unmount(),this.mounted=!1,this.eventsBound=!1}addBox(e){let t=a(e.position,e.size);i(this.grid,t,e.mode??`union`,e.style),this.renderScene()}removeBox(e){let t=a(e.position,e.size);i(this.grid,t,`subtract`),this.renderScene()}addSphere(e){let t=o(e.center,e.radius);i(this.grid,t,e.mode??`union`,e.style),this.renderScene()}removeSphere(e){let t=o(e.center,e.radius);i(this.grid,t,`subtract`),this.renderScene()}addLine(e){let t=s(e.from,e.to,e.radius);i(this.grid,t,e.mode??`union`,e.style),this.renderScene()}setBoxel(e,t){let[n,r,i]=e;t?this.grid.setBoxel(n,r,i,{position:e,opaque:!0}):this.grid.setBoxel(n,r,i,null),this.renderScene()}hasBoxel(e){return this.grid.hasBoxel(e[0],e[1],e[2])}getBoxel(e){return this.grid.getBoxel(e[0],e[1],e[2])}clear(){this.grid.clear(),this.renderScene()}rotate(e){l(this.grid,e.axis,e.turns,e.center),this.renderScene()}forEach(e){this.grid.forEach(e)}getNeighbors(e){return this.grid.getNeighbors(e[0],e[1],e[2])}getExposure(e){return this.grid.getExposure(e[0],e[1],e[2])}getWorldContainer(){return this.renderer.getWorldContainer()}updateTransform(e,t){this.renderer.updateTransform(e,t)}getRotation(){let e=this.renderer;if(e.getOrbitState){let t=e.getOrbitState();return{rotX:t.rotX,rotY:t.rotY}}return{rotX:-25,rotY:35}}setPosition(e){let t=this.renderer.getSceneElement?.();t&&(t.style.position=e.fixed?`fixed`:`absolute`,e.x!==void 0&&(t.style.left=typeof e.x==`number`?`${e.x}px`:e.x),e.y!==void 0&&(t.style.top=typeof e.y==`number`?`${e.y}px`:e.y),e.zIndex!==void 0&&(t.style.zIndex=String(e.zIndex)))}spinRafId=null;lastSpinOptions=null;startSpin(e={}){this.lastSpinOptions={...e},this.stopSpin();let t=e.x??!1,n=e.y??!0,r=e.xDir??1,i=e.yDir??1,a=(e.speed??1)*.5,o=()=>{let e=this.getRotation(),s=e.rotX,c=e.rotY;t&&(s+=a*r),n&&(c+=a*i),this.updateTransform(s,c),this.spinRafId=requestAnimationFrame(o)};this.spinRafId=requestAnimationFrame(o)}stopSpin(){this.spinRafId!==null&&(cancelAnimationFrame(this.spinRafId),this.spinRafId=null)}showAxes(){this.hideAxes();let e=this.renderer.getWorldContainer();if(!e)return;let t=this.grid.getBounds(),n=Math.max(t.max[0]-t.min[0]+1,t.max[1]-t.min[1]+1,t.max[2]-t.min[2]+1)*(this.options.boxelSize+this.options.gap)*.8;e.appendChild(j(n))}hideAxes(){let e=this.renderer.getWorldContainer();e&&e.querySelectorAll(`.boxel-axes`).forEach(e=>e.remove())}styleBox(e){let t=a(e.position,e.size);for(let[n,r,i]of t){let t=this.grid.getBoxel(n,r,i);t&&this.grid.setBoxel(n,r,i,{...t,style:e.style})}this.renderScene()}setTexture(e,t=220,n=1){let r=this.grid.getBounds();this.globalStyle=W(e,t,n,r.max[0]-r.min[0]+1,r.max[1]-r.min[1]+1,r.max[2]-r.min[2]+1),this.renderScene()}mapImage(e,t){let n=v(this.grid,t),r=this.renderer.getWorldContainer();if(r)for(let t of n){let n=`${t.position[0]},${t.position[1]},${t.position[2]}`,i=r.querySelector(`[data-boxel="${n}"] [data-face="${t.face}"]`);i&&(i.style.backgroundImage=`url(${e})`,i.style.backgroundSize=t.backgroundSize,i.style.backgroundPosition=t.backgroundPosition)}}clearImage(){let e=this.renderer.getWorldContainer();e&&e.querySelectorAll(`[data-face]`).forEach(e=>{e.style.backgroundImage=``,e.style.backgroundSize=``,e.style.backgroundPosition=``})}explode(e={}){I(this.grid,this.renderer,this.animator,this.options.boxelSize,e)}collapse(){this.renderScene()}rotateLayer(e){L(this.grid,this.renderer,this.animator,e,()=>this.renderScene())}animateGap(e){z(this.animator,e=>{this.options.gap=e,this.renderScene()},e)}animateOpacity(e){B(this.animator,this.renderer,e)}animateEach(e,t){V(this.grid,this.renderer,this.animator,this.options.boxelSize,e,t)}clickEnabled=!1;clickHandler=null;boundClickListener=null;enableClick(e){this.disableClick(),this.clickEnabled=!0,this.clickHandler=e;let t=this.renderer.getWorldContainer();t&&(t.style.cursor=`pointer`,this.boundClickListener=e=>{let t=e.target.closest(`[data-face]`);if(!t)return;let n=t.closest(`[data-boxel]`);if(!n)return;let r=n.dataset.boxel.split(`,`).map(Number),i=t.dataset.face,a=this.spinRafId!==null;a&&this.stopSpin();let o=t.style.backgroundColor,s=t.style.borderColor,c=t.style.boxShadow,l=t.style.opacity;t.style.backgroundColor=`rgba(255, 255, 255, 0.9)`,t.style.borderColor=`rgba(255, 255, 255, 0.8)`,t.style.boxShadow=`0 0 20px rgba(255, 255, 255, 0.5), inset 0 0 10px rgba(255, 255, 255, 0.3)`,t.style.opacity=`1`,t.style.transition=`all 0.1s ease-in`;let u=n.style.transform;n.style.transition=`transform 0.15s ease-in`,n.style.transform=u+` scale(0.85)`,setTimeout(()=>{n.style.transition=`transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1)`,n.style.transform=u,t.style.transition=`all 0.3s ease-out`,t.style.backgroundColor=o,t.style.borderColor=s,t.style.boxShadow=c,t.style.opacity=l,setTimeout(()=>{n.style.transition=``,t.style.transition=``,a&&this.startSpin(this.lastSpinOptions??{})},300)},150),this.clickHandler?.({boxel:r,face:i})},t.addEventListener(`click`,this.boundClickListener))}disableClick(){if(!this.clickEnabled)return;let e=this.renderer.getWorldContainer();e&&(e.style.cursor=``,this.boundClickListener&&e.removeEventListener(`click`,this.boundClickListener)),this.clickEnabled=!1,this.clickHandler=null,this.boundClickListener=null}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){this.listeners.get(e)?.delete(t)}renderScene(){this.mounted&&(this.renderer.render({grid:this.grid,boxelSize:this.options.boxelSize,gap:this.options.gap,edgeWidth:this.options.edgeWidth,edgeColor:this.options.edgeColor,globalStyle:this.globalStyle,showBackfaces:this.options.showBackfaces}),this.eventsBound||=(this.setupFaceEvents(),!0),this.emit(`render`,new Event(`render`)))}setupFaceEvents(){let e=this.renderer.getWorldContainer();e&&(e.addEventListener(`click`,e=>{let t=this.buildBoxelEvent(e);t&&this.emit(`boxel:click`,t)}),e.addEventListener(`pointerover`,e=>{let t=this.buildBoxelEvent(e);t&&this.emit(`boxel:hover`,t)}),e.addEventListener(`pointerdown`,e=>{let t=this.buildBoxelEvent(e);t&&this.emit(`boxel:pointerdown`,t)}))}buildBoxelEvent(e){let t=e.target.closest(`[data-face]`);if(!t)return null;let n=t.closest(`[data-boxel]`);if(!n)return null;let r=n.dataset.boxel.split(`,`).map(Number),i=t.dataset.face,a=this.grid.getBoxel(r[0],r[1],r[2]);return a?{boxel:a,position:r,face:i,originalEvent:e}:null}emit(e,t){let n=this.listeners.get(e);if(n)for(let e of n)e(t)}};exports.ALL_TEXTURES=U,exports.Boxels=G;
|