create-substrate 0.1.4 → 0.1.5

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.
@@ -3,6 +3,7 @@ export const scene3d = {
3
3
  "toolbar",
4
4
  "panel",
5
5
  "pane",
6
+ "action",
6
7
  "slider",
7
8
  "number-input",
8
9
  "colour-picker",
@@ -16,9 +17,10 @@ export const scene3d = {
16
17
  extraDevDeps: {
17
18
  "@types/three": "^0.172.0",
18
19
  },
19
- app: () => `import { useState, useRef } from "react"
20
+ app: () => `import { useEffect, useRef, useState } from "react"
21
+ import type { Mesh } from "three"
20
22
  import { Canvas } from "@react-three/fiber"
21
- import { OrbitControls, Grid, Environment } from "@react-three/drei"
23
+ import { Grid, OrbitControls, TransformControls } from "@react-three/drei"
22
24
  import {
23
25
  Toolbar,
24
26
  ToolbarToggleGroup,
@@ -30,150 +32,495 @@ import {
30
32
  Pane,
31
33
  PaneHeader,
32
34
  PaneLabel,
35
+ PaneAction,
33
36
  PaneContent,
34
37
  } from "@/components/substrate/pane"
38
+ import { Action, ActionLabel, ActionControls } from "@/components/substrate/action"
35
39
  import { NumberInput } from "@/components/substrate/number-input"
36
40
  import { Slider } from "@/components/substrate/slider"
37
41
  import { ColourPicker } from "@/components/substrate/colour-picker"
38
- import { StatusBar, StatusBarSection, StatusBarItem } from "@/components/substrate/status-bar"
39
42
  import {
43
+ StatusBar,
44
+ StatusBarSection,
45
+ StatusBarItem,
46
+ StatusBarSeparator,
47
+ } from "@/components/substrate/status-bar"
48
+ import {
49
+ RiBox3Line,
40
50
  RiCursorLine,
51
+ RiDeleteBinLine,
41
52
  RiDragMoveLine,
42
- RiRefreshLine,
43
53
  RiExpandDiagonal2Line,
54
+ RiGlobeLine,
55
+ RiRefreshLine,
44
56
  } from "@remixicon/react"
45
57
 
58
+ type Vec3 = [number, number, number]
59
+ type Mode = "select" | "translate" | "rotate" | "scale"
60
+ type Shape = "box" | "sphere"
61
+
46
62
  interface SceneObject {
47
63
  id: string
48
- type: "box" | "sphere"
49
- position: [number, number, number]
64
+ name: string
65
+ shape: Shape
66
+ position: Vec3
67
+ rotation: Vec3
68
+ scale: Vec3
50
69
  colour: string
51
70
  roughness: number
71
+ metalness: number
52
72
  }
53
73
 
74
+ const MODES: Mode[] = ["select", "translate", "rotate", "scale"]
75
+ const MODE_KEYS: Record<string, Mode> = {
76
+ v: "select",
77
+ g: "translate",
78
+ r: "rotate",
79
+ s: "scale",
80
+ }
81
+ const AXES = ["X", "Y", "Z"] as const
82
+ const COLOURS = ["#6366f1", "#f43f5e", "#10b981", "#f59e0b", "#0ea5e9"]
83
+
54
84
  const INITIAL_OBJECTS: SceneObject[] = [
55
- { id: "box-1", type: "box", position: [-1.5, 0.5, 0], colour: "#6366f1", roughness: 0.4 },
56
- { id: "sphere-1", type: "sphere", position: [1.5, 0.6, 0], colour: "#f43f5e", roughness: 0.2 },
85
+ {
86
+ id: "box-1",
87
+ name: "Box 1",
88
+ shape: "box",
89
+ position: [-1.5, 0.5, 0],
90
+ rotation: [0, 0, 0],
91
+ scale: [1, 1, 1],
92
+ colour: "#6366f1",
93
+ roughness: 0.4,
94
+ metalness: 0.1,
95
+ },
96
+ {
97
+ id: "sphere-1",
98
+ name: "Sphere 1",
99
+ shape: "sphere",
100
+ position: [1.5, 0.6, 0],
101
+ rotation: [0, 0, 0],
102
+ scale: [1, 1, 1],
103
+ colour: "#f43f5e",
104
+ roughness: 0.2,
105
+ metalness: 0.1,
106
+ },
57
107
  ]
58
108
 
109
+ const toolbarButton =
110
+ "inline-flex h-7 min-w-7 items-center justify-center rounded-md px-2 outline-none transition-all hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
111
+
112
+ function isMode(value: string): value is Mode {
113
+ return MODES.some((mode) => mode === value)
114
+ }
115
+
116
+ function toDegrees(radians: number) {
117
+ return (radians * 180) / Math.PI
118
+ }
119
+
120
+ function toRadians(degrees: number) {
121
+ return (degrees * Math.PI) / 180
122
+ }
123
+
124
+ function withAxis(vector: Vec3, axis: number, value: number): Vec3 {
125
+ const next: Vec3 = [vector[0], vector[1], vector[2]]
126
+ next[axis] = value
127
+ return next
128
+ }
129
+
59
130
  function SceneMesh({
60
131
  object,
61
132
  selected,
133
+ mode,
62
134
  onSelect,
135
+ onTransform,
63
136
  }: {
64
137
  object: SceneObject
65
138
  selected: boolean
139
+ mode: Mode
66
140
  onSelect: () => void
141
+ onTransform: (patch: Pick<SceneObject, "position" | "rotation" | "scale">) => void
67
142
  }) {
143
+ const [mesh, setMesh] = useState<Mesh | null>(null)
144
+
68
145
  return (
69
- <mesh position={object.position} onClick={onSelect}>
70
- {object.type === "box" ? (
71
- <boxGeometry args={[1, 1, 1]} />
72
- ) : (
73
- <sphereGeometry args={[0.6, 32, 32]} />
146
+ <>
147
+ <mesh
148
+ ref={setMesh}
149
+ position={object.position}
150
+ rotation={object.rotation}
151
+ scale={object.scale}
152
+ onClick={(event) => {
153
+ event.stopPropagation()
154
+ onSelect()
155
+ }}
156
+ >
157
+ {object.shape === "box" ? (
158
+ <boxGeometry args={[1, 1, 1]} />
159
+ ) : (
160
+ <sphereGeometry args={[0.6, 32, 32]} />
161
+ )}
162
+ <meshStandardMaterial
163
+ color={object.colour}
164
+ roughness={object.roughness}
165
+ metalness={object.metalness}
166
+ emissive={selected ? "#ffffff" : "#000000"}
167
+ emissiveIntensity={selected ? 0.08 : 0}
168
+ />
169
+ </mesh>
170
+ {mesh && selected && mode !== "select" && (
171
+ <TransformControls
172
+ object={mesh}
173
+ mode={mode}
174
+ onObjectChange={() =>
175
+ onTransform({
176
+ position: [mesh.position.x, mesh.position.y, mesh.position.z],
177
+ rotation: [mesh.rotation.x, mesh.rotation.y, mesh.rotation.z],
178
+ scale: [mesh.scale.x, mesh.scale.y, mesh.scale.z],
179
+ })
180
+ }
181
+ />
74
182
  )}
75
- <meshStandardMaterial
76
- color={object.colour}
77
- roughness={object.roughness}
78
- emissive={selected ? "#ffffff" : "#000000"}
79
- emissiveIntensity={selected ? 0.05 : 0}
80
- />
81
- </mesh>
183
+ </>
82
184
  )
83
185
  }
84
186
 
85
187
  export default function App() {
86
- const [mode, setMode] = useState("select")
188
+ const [mode, setMode] = useState<Mode>("select")
87
189
  const [objects, setObjects] = useState(INITIAL_OBJECTS)
88
- const [selectedId, setSelectedId] = useState<string | null>(null)
190
+ const [selectedId, setSelectedId] = useState<string | null>("box-1")
191
+ const [lightIntensity, setLightIntensity] = useState(1.5)
192
+ const nextIndex = useRef(INITIAL_OBJECTS.length + 1)
89
193
 
90
- const selected = objects.find((o) => o.id === selectedId) ?? null
194
+ const selected = objects.find((object) => object.id === selectedId) ?? null
91
195
 
92
- function updateSelected(patch: Partial<SceneObject>) {
93
- if (!selectedId) return
196
+ function updateObject(id: string, patch: Partial<SceneObject>) {
94
197
  setObjects((prev) =>
95
- prev.map((o) => (o.id === selectedId ? { ...o, ...patch } : o))
198
+ prev.map((object) => (object.id === id ? { ...object, ...patch } : object)),
96
199
  )
97
200
  }
98
201
 
202
+ function addObject(shape: Shape) {
203
+ const index = nextIndex.current++
204
+ const object: SceneObject = {
205
+ id: \`\${shape}-\${index}\`,
206
+ name: \`\${shape === "box" ? "Box" : "Sphere"} \${index}\`,
207
+ shape,
208
+ position: [(index % 5) - 2, shape === "box" ? 0.5 : 0.6, 1.5],
209
+ rotation: [0, 0, 0],
210
+ scale: [1, 1, 1],
211
+ colour: COLOURS[index % COLOURS.length],
212
+ roughness: 0.4,
213
+ metalness: 0.1,
214
+ }
215
+ setObjects((prev) => [...prev, object])
216
+ setSelectedId(object.id)
217
+ }
218
+
219
+ function removeObject(id: string) {
220
+ setObjects((prev) => prev.filter((object) => object.id !== id))
221
+ setSelectedId((current) => (current === id ? null : current))
222
+ }
223
+
224
+ useEffect(() => {
225
+ function handleKeyDown(event: KeyboardEvent) {
226
+ const target = event.target
227
+ if (
228
+ target instanceof HTMLElement &&
229
+ (target.isContentEditable || target.tagName === "INPUT" || target.tagName === "TEXTAREA")
230
+ ) {
231
+ return
232
+ }
233
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey) return
234
+
235
+ const nextMode = MODE_KEYS[event.key.toLowerCase()]
236
+ if (nextMode) {
237
+ setMode(nextMode)
238
+ } else if (event.key === "Escape") {
239
+ setSelectedId(null)
240
+ } else if ((event.key === "Delete" || event.key === "Backspace") && selectedId) {
241
+ removeObject(selectedId)
242
+ }
243
+ }
244
+
245
+ window.addEventListener("keydown", handleKeyDown)
246
+ return () => window.removeEventListener("keydown", handleKeyDown)
247
+ }, [selectedId])
248
+
99
249
  return (
100
250
  <div className="flex h-screen flex-col bg-background text-foreground">
101
- <div className="relative flex flex-1 overflow-hidden">
102
- <div className="flex-1 bg-canvas">
103
- <Canvas camera={{ position: [4, 3, 4], fov: 50 }}>
104
- <ambientLight intensity={0.4} />
105
- <directionalLight position={[5, 8, 5]} intensity={1} />
106
- <Environment preset="studio" />
107
- <Grid infiniteGrid fadeDistance={20} cellColor="#333" sectionColor="#555" />
251
+ <div className="flex min-h-0 flex-1">
252
+ <div className="relative min-w-0 flex-1 bg-canvas">
253
+ <Canvas
254
+ camera={{ position: [4, 3, 5], fov: 50 }}
255
+ onPointerMissed={() => {
256
+ if (mode === "select") setSelectedId(null)
257
+ }}
258
+ >
259
+ <ambientLight intensity={0.6} />
260
+ <hemisphereLight args={["#ffffff", "#444444", 0.6]} />
261
+ <directionalLight position={[5, 8, 5]} intensity={lightIntensity} />
262
+ <Grid infiniteGrid fadeDistance={25} cellColor="#333333" sectionColor="#555555" />
108
263
  <OrbitControls makeDefault />
109
- {objects.map((obj) => (
264
+ {objects.map((object) => (
110
265
  <SceneMesh
111
- key={obj.id}
112
- object={obj}
113
- selected={obj.id === selectedId}
114
- onSelect={() => setSelectedId(obj.id)}
266
+ key={object.id}
267
+ object={object}
268
+ selected={object.id === selectedId}
269
+ mode={mode}
270
+ onSelect={() => setSelectedId(object.id)}
271
+ onTransform={(patch) => updateObject(object.id, patch)}
115
272
  />
116
273
  ))}
117
274
  </Canvas>
275
+
276
+ <Toolbar className="absolute bottom-4">
277
+ <ToolbarToggleGroup
278
+ value={mode}
279
+ onValueChange={(value) => {
280
+ if (isMode(value)) setMode(value)
281
+ }}
282
+ >
283
+ <ToolbarToggle value="select" tooltip="Select" shortcut="V">
284
+ <RiCursorLine className="size-4" />
285
+ </ToolbarToggle>
286
+ <ToolbarSeparator />
287
+ <ToolbarToggle value="translate" tooltip="Move" shortcut="G">
288
+ <RiDragMoveLine className="size-4" />
289
+ </ToolbarToggle>
290
+ <ToolbarToggle value="rotate" tooltip="Rotate" shortcut="R">
291
+ <RiRefreshLine className="size-4" />
292
+ </ToolbarToggle>
293
+ <ToolbarToggle value="scale" tooltip="Scale" shortcut="S">
294
+ <RiExpandDiagonal2Line className="size-4" />
295
+ </ToolbarToggle>
296
+ </ToolbarToggleGroup>
297
+ <ToolbarSeparator />
298
+ <div className="flex items-center gap-1">
299
+ <button
300
+ type="button"
301
+ aria-label="Add box"
302
+ title="Add box"
303
+ className={toolbarButton}
304
+ onClick={() => addObject("box")}
305
+ >
306
+ <RiBox3Line className="size-4" />
307
+ </button>
308
+ <button
309
+ type="button"
310
+ aria-label="Add sphere"
311
+ title="Add sphere"
312
+ className={toolbarButton}
313
+ onClick={() => addObject("sphere")}
314
+ >
315
+ <RiGlobeLine className="size-4" />
316
+ </button>
317
+ <button
318
+ type="button"
319
+ aria-label="Delete selected"
320
+ title="Delete selected"
321
+ className={toolbarButton}
322
+ disabled={!selected}
323
+ onClick={() => {
324
+ if (selected) removeObject(selected.id)
325
+ }}
326
+ >
327
+ <RiDeleteBinLine className="size-4" />
328
+ </button>
329
+ </div>
330
+ </Toolbar>
118
331
  </div>
119
332
 
120
333
  <Panel position="right">
334
+ <Pane>
335
+ <PaneHeader>
336
+ <PaneLabel>Scene</PaneLabel>
337
+ </PaneHeader>
338
+ <PaneContent className="space-y-1">
339
+ {objects.length === 0 && (
340
+ <p className="text-xs text-muted-foreground">
341
+ No objects. Add one from the toolbar.
342
+ </p>
343
+ )}
344
+ {objects.map((object) => (
345
+ <button
346
+ key={object.id}
347
+ type="button"
348
+ onClick={() => setSelectedId(object.id)}
349
+ className={
350
+ object.id === selectedId
351
+ ? "flex h-7 w-full items-center gap-2 rounded-md bg-accent px-2 text-xs text-accent-foreground"
352
+ : "flex h-7 w-full items-center gap-2 rounded-md px-2 text-xs hover:bg-accent/50"
353
+ }
354
+ >
355
+ <span
356
+ className="size-2.5 rounded-full"
357
+ style={{ backgroundColor: object.colour }}
358
+ />
359
+ {object.name}
360
+ </button>
361
+ ))}
362
+ </PaneContent>
363
+ </Pane>
364
+
365
+ <Pane>
366
+ <PaneHeader>
367
+ <PaneLabel>Lighting</PaneLabel>
368
+ </PaneHeader>
369
+ <PaneContent>
370
+ <Action>
371
+ <ActionLabel>Intensity</ActionLabel>
372
+ <ActionControls>
373
+ <Slider
374
+ min={0}
375
+ max={4}
376
+ step={0.05}
377
+ value={[lightIntensity]}
378
+ onValueChange={([value]) => setLightIntensity(value)}
379
+ />
380
+ </ActionControls>
381
+ </Action>
382
+ </PaneContent>
383
+ </Pane>
384
+
121
385
  {selected ? (
122
386
  <>
123
387
  <Pane>
124
388
  <PaneHeader>
125
- <PaneLabel>Position</PaneLabel>
389
+ <PaneLabel>Transform</PaneLabel>
390
+ <PaneAction
391
+ aria-label="Reset transform"
392
+ title="Reset transform"
393
+ onClick={() =>
394
+ updateObject(selected.id, { rotation: [0, 0, 0], scale: [1, 1, 1] })
395
+ }
396
+ >
397
+ <RiRefreshLine />
398
+ </PaneAction>
126
399
  </PaneHeader>
127
- <PaneContent>
400
+ <PaneContent className="space-y-2">
401
+ <div className="text-xs text-muted-foreground">Position</div>
402
+ <div className="grid grid-cols-3 gap-2">
403
+ {AXES.map((axis, index) => (
404
+ <NumberInput
405
+ key={axis}
406
+ label={axis}
407
+ step={0.1}
408
+ value={selected.position[index]}
409
+ onChange={(value) =>
410
+ updateObject(selected.id, {
411
+ position: withAxis(selected.position, index, value),
412
+ })
413
+ }
414
+ />
415
+ ))}
416
+ </div>
417
+ <div className="text-xs text-muted-foreground">Rotation</div>
418
+ <div className="grid grid-cols-3 gap-2">
419
+ {AXES.map((axis, index) => (
420
+ <NumberInput
421
+ key={axis}
422
+ label={axis}
423
+ step={1}
424
+ precision={1}
425
+ value={toDegrees(selected.rotation[index])}
426
+ onChange={(value) =>
427
+ updateObject(selected.id, {
428
+ rotation: withAxis(selected.rotation, index, toRadians(value)),
429
+ })
430
+ }
431
+ />
432
+ ))}
433
+ </div>
434
+ <div className="text-xs text-muted-foreground">Scale</div>
128
435
  <div className="grid grid-cols-3 gap-2">
129
- <NumberInput label="X" value={selected.position[0]} step={0.1} onChange={(v) => updateSelected({ position: [v, selected.position[1], selected.position[2]] })} />
130
- <NumberInput label="Y" value={selected.position[1]} step={0.1} onChange={(v) => updateSelected({ position: [selected.position[0], v, selected.position[2]] })} />
131
- <NumberInput label="Z" value={selected.position[2]} step={0.1} onChange={(v) => updateSelected({ position: [selected.position[0], selected.position[1], v] })} />
436
+ {AXES.map((axis, index) => (
437
+ <NumberInput
438
+ key={axis}
439
+ label={axis}
440
+ step={0.1}
441
+ min={0.01}
442
+ value={selected.scale[index]}
443
+ onChange={(value) =>
444
+ updateObject(selected.id, {
445
+ scale: withAxis(selected.scale, index, value),
446
+ })
447
+ }
448
+ />
449
+ ))}
132
450
  </div>
133
451
  </PaneContent>
134
452
  </Pane>
453
+
135
454
  <Pane>
136
455
  <PaneHeader>
137
456
  <PaneLabel>Material</PaneLabel>
138
457
  </PaneHeader>
139
- <PaneContent className="space-y-3">
140
- <ColourPicker value={selected.colour} onChange={(c) => updateSelected({ colour: c })} />
141
- <Slider label="Roughness" min={0} max={1} step={0.01} value={[selected.roughness]} onValueChange={([v]) => updateSelected({ roughness: v })} />
458
+ <PaneContent className="space-y-2">
459
+ <Action>
460
+ <ActionLabel>Colour</ActionLabel>
461
+ <ActionControls>
462
+ <ColourPicker
463
+ value={selected.colour}
464
+ onChange={(colour) => updateObject(selected.id, { colour })}
465
+ />
466
+ <span className="font-mono text-xs text-muted-foreground">
467
+ {selected.colour}
468
+ </span>
469
+ </ActionControls>
470
+ </Action>
471
+ <Action>
472
+ <ActionLabel>Roughness</ActionLabel>
473
+ <ActionControls>
474
+ <Slider
475
+ min={0}
476
+ max={1}
477
+ step={0.01}
478
+ value={[selected.roughness]}
479
+ onValueChange={([value]) =>
480
+ updateObject(selected.id, { roughness: value })
481
+ }
482
+ />
483
+ </ActionControls>
484
+ </Action>
485
+ <Action>
486
+ <ActionLabel>Metalness</ActionLabel>
487
+ <ActionControls>
488
+ <Slider
489
+ min={0}
490
+ max={1}
491
+ step={0.01}
492
+ value={[selected.metalness]}
493
+ onValueChange={([value]) =>
494
+ updateObject(selected.id, { metalness: value })
495
+ }
496
+ />
497
+ </ActionControls>
498
+ </Action>
142
499
  </PaneContent>
143
500
  </Pane>
144
501
  </>
145
502
  ) : (
146
503
  <Pane>
147
504
  <PaneContent>
148
- <p className="text-sm text-muted-foreground">Click an object to inspect</p>
505
+ <p className="text-xs text-muted-foreground">
506
+ Click an object to inspect it.
507
+ </p>
149
508
  </PaneContent>
150
509
  </Pane>
151
510
  )}
152
511
  </Panel>
153
512
  </div>
154
513
 
155
- <Toolbar>
156
- <ToolbarToggleGroup value={mode} onValueChange={setMode}>
157
- <ToolbarToggle value="select" tooltip="Select" shortcut="V">
158
- <RiCursorLine className="size-4" />
159
- </ToolbarToggle>
160
- <ToolbarSeparator />
161
- <ToolbarToggle value="translate" tooltip="Translate" shortcut="G">
162
- <RiDragMoveLine className="size-4" />
163
- </ToolbarToggle>
164
- <ToolbarToggle value="rotate" tooltip="Rotate" shortcut="R">
165
- <RiRefreshLine className="size-4" />
166
- </ToolbarToggle>
167
- <ToolbarToggle value="scale" tooltip="Scale" shortcut="S">
168
- <RiExpandDiagonal2Line className="size-4" />
169
- </ToolbarToggle>
170
- </ToolbarToggleGroup>
171
- </Toolbar>
172
-
173
514
  <StatusBar>
174
- <StatusBarSection>
515
+ <StatusBarSection align="left">
175
516
  <StatusBarItem>Mode: {mode}</StatusBarItem>
176
- {selected && <StatusBarItem>Selected: {selected.id}</StatusBarItem>}
517
+ <StatusBarSeparator />
518
+ <StatusBarItem>
519
+ {objects.length} {objects.length === 1 ? "object" : "objects"}
520
+ </StatusBarItem>
521
+ </StatusBarSection>
522
+ <StatusBarSection align="right">
523
+ <StatusBarItem>{selected ? selected.name : "Nothing selected"}</StatusBarItem>
177
524
  </StatusBarSection>
178
525
  </StatusBar>
179
526
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"3d-scene.js","sourceRoot":"","sources":["../../src/surfaces/3d-scene.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,eAAe;QACf,YAAY;KACb;IACD,SAAS,EAAE;QACT,KAAK,EAAE,UAAU;QACjB,oBAAoB,EAAE,QAAQ;QAC9B,mBAAmB,EAAE,SAAS;KAC/B;IACD,YAAY,EAAE;QACZ,cAAc,EAAE,UAAU;KAC3B;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmKZ;CACA,CAAA"}
1
+ {"version":3,"file":"3d-scene.js","sourceRoot":"","sources":["../../src/surfaces/3d-scene.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,cAAc;QACd,eAAe;QACf,YAAY;KACb;IACD,SAAS,EAAE;QACT,KAAK,EAAE,UAAU;QACjB,oBAAoB,EAAE,QAAQ;QAC9B,mBAAmB,EAAE,SAAS;KAC/B;IACD,YAAY,EAAE;QACZ,cAAc,EAAE,UAAU;KAC3B;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6fZ;CACA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../../src/surfaces/animation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,SAAS,EAAE,aAoNvB,CAAA"}
1
+ {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../../src/surfaces/animation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,SAAS,EAAE,aA4MvB,CAAA"}