minecraft-renderer 0.1.0
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 +297 -0
- package/dist/index.html +83 -0
- package/dist/static/image/arrow.6f27b59f.png +0 -0
- package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
- package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
- package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
- package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
- package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
- package/dist/static/js/365.f05233ab.js +8462 -0
- package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
- package/dist/static/js/async/738.efa27644.js +1 -0
- package/dist/static/js/index.092ec5be.js +56 -0
- package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
- package/dist/static/js/lib-react.5c9129e0.js +2 -0
- package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
- package/package.json +104 -0
- package/src/assets/destroy_stage_0.png +0 -0
- package/src/assets/destroy_stage_1.png +0 -0
- package/src/assets/destroy_stage_2.png +0 -0
- package/src/assets/destroy_stage_3.png +0 -0
- package/src/assets/destroy_stage_4.png +0 -0
- package/src/assets/destroy_stage_5.png +0 -0
- package/src/assets/destroy_stage_6.png +0 -0
- package/src/assets/destroy_stage_7.png +0 -0
- package/src/assets/destroy_stage_8.png +0 -0
- package/src/assets/destroy_stage_9.png +0 -0
- package/src/examples/README.md +146 -0
- package/src/examples/appViewerExample.ts +205 -0
- package/src/examples/initialMenuStart.ts +161 -0
- package/src/graphicsBackend/appViewer.ts +297 -0
- package/src/graphicsBackend/config.ts +119 -0
- package/src/graphicsBackend/index.ts +10 -0
- package/src/graphicsBackend/playerState.ts +61 -0
- package/src/graphicsBackend/types.ts +143 -0
- package/src/index.ts +97 -0
- package/src/lib/DebugGui.ts +190 -0
- package/src/lib/animationController.ts +85 -0
- package/src/lib/buildSharedConfig.mjs +1 -0
- package/src/lib/cameraBobbing.ts +94 -0
- package/src/lib/canvas2DOverlay.example.ts +361 -0
- package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
- package/src/lib/canvas2DOverlay.ts +381 -0
- package/src/lib/cleanupDecorator.ts +29 -0
- package/src/lib/createPlayerObject.ts +55 -0
- package/src/lib/frameTimingCollector.ts +164 -0
- package/src/lib/guiRenderer.ts +283 -0
- package/src/lib/items.ts +140 -0
- package/src/lib/mesherlogReader.ts +131 -0
- package/src/lib/moreBlockDataGenerated.json +714 -0
- package/src/lib/preflatMap.json +1741 -0
- package/src/lib/simpleUtils.ts +40 -0
- package/src/lib/smoothSwitcher.ts +168 -0
- package/src/lib/spiral.ts +29 -0
- package/src/lib/ui/newStats.ts +120 -0
- package/src/lib/utils/proxy.ts +23 -0
- package/src/lib/utils/skins.ts +63 -0
- package/src/lib/utils.ts +76 -0
- package/src/lib/workerProxy.ts +342 -0
- package/src/lib/worldrendererCommon.ts +1088 -0
- package/src/mesher/mesher.ts +253 -0
- package/src/mesher/models.ts +769 -0
- package/src/mesher/modelsGeometryCommon.ts +142 -0
- package/src/mesher/shared.ts +80 -0
- package/src/mesher/standaloneRenderer.ts +270 -0
- package/src/mesher/test/a.ts +3 -0
- package/src/mesher/test/mesherTester.ts +76 -0
- package/src/mesher/test/playground.ts +19 -0
- package/src/mesher/test/test-perf.ts +74 -0
- package/src/mesher/test/tests.test.ts +56 -0
- package/src/mesher/world.ts +294 -0
- package/src/mesher/worldConstants.ts +1 -0
- package/src/modules/index.ts +11 -0
- package/src/modules/starfield.ts +313 -0
- package/src/modules/types.ts +110 -0
- package/src/playerState/playerState.ts +78 -0
- package/src/playerState/types.ts +36 -0
- package/src/playground/allEntitiesDebug.ts +170 -0
- package/src/playground/baseScene.ts +587 -0
- package/src/playground/mobileControls.tsx +268 -0
- package/src/playground/playground.html +83 -0
- package/src/playground/playground.ts +11 -0
- package/src/playground/playgroundUi.tsx +140 -0
- package/src/playground/reactUtils.ts +71 -0
- package/src/playground/scenes/allEntities.ts +13 -0
- package/src/playground/scenes/entities.ts +37 -0
- package/src/playground/scenes/floorRandom.ts +33 -0
- package/src/playground/scenes/frequentUpdates.ts +148 -0
- package/src/playground/scenes/geometryExport.ts +142 -0
- package/src/playground/scenes/index.ts +12 -0
- package/src/playground/scenes/lightingStarfield.ts +40 -0
- package/src/playground/scenes/main.ts +313 -0
- package/src/playground/scenes/railsCobweb.ts +14 -0
- package/src/playground/scenes/rotationIssue.ts +7 -0
- package/src/playground/scenes/slabsOptimization.ts +16 -0
- package/src/playground/scenes/transparencyIssue.ts +11 -0
- package/src/playground/shared.ts +79 -0
- package/src/resourcesManager/index.ts +5 -0
- package/src/resourcesManager/resourcesManager.ts +314 -0
- package/src/shims/minecraftData.ts +41 -0
- package/src/sign-renderer/index.html +21 -0
- package/src/sign-renderer/index.ts +216 -0
- package/src/sign-renderer/noop.js +1 -0
- package/src/sign-renderer/playground.ts +38 -0
- package/src/sign-renderer/tests.test.ts +69 -0
- package/src/sign-renderer/vite.config.ts +10 -0
- package/src/three/appShared.ts +75 -0
- package/src/three/bannerRenderer.ts +275 -0
- package/src/three/cameraShake.ts +120 -0
- package/src/three/cinimaticScript.ts +350 -0
- package/src/three/documentRenderer.ts +491 -0
- package/src/three/entities.ts +1580 -0
- package/src/three/entity/EntityMesh.ts +707 -0
- package/src/three/entity/animations.js +171 -0
- package/src/three/entity/armorModels.json +204 -0
- package/src/three/entity/armorModels.ts +36 -0
- package/src/three/entity/entities.json +6230 -0
- package/src/three/entity/exportedModels.js +38 -0
- package/src/three/entity/externalTextures.json +1 -0
- package/src/three/entity/models/allay.obj +325 -0
- package/src/three/entity/models/arrow.obj +60 -0
- package/src/three/entity/models/axolotl.obj +509 -0
- package/src/three/entity/models/blaze.obj +601 -0
- package/src/three/entity/models/boat.obj +417 -0
- package/src/three/entity/models/camel.obj +1061 -0
- package/src/three/entity/models/cat.obj +509 -0
- package/src/three/entity/models/chicken.obj +371 -0
- package/src/three/entity/models/cod.obj +371 -0
- package/src/three/entity/models/creeper.obj +279 -0
- package/src/three/entity/models/dolphin.obj +371 -0
- package/src/three/entity/models/ender_dragon.obj +2993 -0
- package/src/three/entity/models/enderman.obj +325 -0
- package/src/three/entity/models/endermite.obj +187 -0
- package/src/three/entity/models/fox.obj +463 -0
- package/src/three/entity/models/frog.obj +739 -0
- package/src/three/entity/models/ghast.obj +463 -0
- package/src/three/entity/models/goat.obj +601 -0
- package/src/three/entity/models/guardian.obj +1015 -0
- package/src/three/entity/models/horse.obj +1061 -0
- package/src/three/entity/models/llama.obj +509 -0
- package/src/three/entity/models/minecart.obj +233 -0
- package/src/three/entity/models/parrot.obj +509 -0
- package/src/three/entity/models/piglin.obj +739 -0
- package/src/three/entity/models/pillager.obj +371 -0
- package/src/three/entity/models/rabbit.obj +555 -0
- package/src/three/entity/models/sheep.obj +555 -0
- package/src/three/entity/models/shulker.obj +141 -0
- package/src/three/entity/models/sniffer.obj +693 -0
- package/src/three/entity/models/spider.obj +509 -0
- package/src/three/entity/models/tadpole.obj +95 -0
- package/src/three/entity/models/turtle.obj +371 -0
- package/src/three/entity/models/vex.obj +325 -0
- package/src/three/entity/models/villager.obj +509 -0
- package/src/three/entity/models/warden.obj +463 -0
- package/src/three/entity/models/witch.obj +647 -0
- package/src/three/entity/models/wolf.obj +509 -0
- package/src/three/entity/models/zombie_villager.obj +463 -0
- package/src/three/entity/objModels.js +1 -0
- package/src/three/fireworks.ts +661 -0
- package/src/three/fireworksRenderer.ts +434 -0
- package/src/three/globals.d.ts +7 -0
- package/src/three/graphicsBackend.ts +274 -0
- package/src/three/graphicsBackendOffThread.ts +107 -0
- package/src/three/hand.ts +89 -0
- package/src/three/holdingBlock.ts +926 -0
- package/src/three/index.ts +20 -0
- package/src/three/itemMesh.ts +427 -0
- package/src/three/modules.d.ts +14 -0
- package/src/three/panorama.ts +308 -0
- package/src/three/panoramaShared.ts +1 -0
- package/src/three/renderSlot.ts +82 -0
- package/src/three/skyboxRenderer.ts +406 -0
- package/src/three/starField.ts +13 -0
- package/src/three/threeJsMedia.ts +731 -0
- package/src/three/threeJsMethods.ts +15 -0
- package/src/three/threeJsParticles.ts +160 -0
- package/src/three/threeJsSound.ts +95 -0
- package/src/three/threeJsUtils.ts +90 -0
- package/src/three/waypointSprite.ts +435 -0
- package/src/three/waypoints.ts +163 -0
- package/src/three/world/cursorBlock.ts +172 -0
- package/src/three/world/vr.ts +257 -0
- package/src/three/worldGeometryExport.ts +259 -0
- package/src/three/worldGeometryHandler.ts +279 -0
- package/src/three/worldRendererThree.ts +1381 -0
- package/src/worldView/index.ts +6 -0
- package/src/worldView/types.ts +66 -0
- package/src/worldView/worldView.ts +424 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import * as tweenJs from '@tweenjs/tween.js'
|
|
3
|
+
import { Vec3 } from 'vec3'
|
|
4
|
+
import { WorldRendererThree } from './worldRendererThree'
|
|
5
|
+
|
|
6
|
+
export interface CinimaticPoint {
|
|
7
|
+
x: number
|
|
8
|
+
y: number
|
|
9
|
+
z: number
|
|
10
|
+
yaw: number
|
|
11
|
+
pitch: number
|
|
12
|
+
duration: number // Time to reach this point from the previous one
|
|
13
|
+
easing?: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'smoothstep' | 'bounce'
|
|
14
|
+
lookAt?: { x: number, y: number, z: number } // Optional: override rotation to look at this point
|
|
15
|
+
fov?: number // Optional: change field of view
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CinimaticScript {
|
|
19
|
+
name?: string
|
|
20
|
+
points: CinimaticPoint[]
|
|
21
|
+
loop?: boolean
|
|
22
|
+
onComplete?: () => void
|
|
23
|
+
onPointReached?: (pointIndex: number, point: CinimaticPoint) => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class CinimaticScriptRunner {
|
|
27
|
+
private isRunning = false
|
|
28
|
+
private currentScript: CinimaticScript | null = null
|
|
29
|
+
private currentPointIndex = 0
|
|
30
|
+
private currentTweens: Array<tweenJs.Tween<any>> = []
|
|
31
|
+
private startTime = 0
|
|
32
|
+
private totalDuration = 0
|
|
33
|
+
|
|
34
|
+
// Camera state
|
|
35
|
+
private currentPosition = { x: 0, y: 0, z: 0 }
|
|
36
|
+
private currentRotation = { yaw: 0, pitch: 0 }
|
|
37
|
+
private currentFov = 75
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
private readonly worldRenderer: WorldRendererThree,
|
|
41
|
+
private readonly updateCamera: (pos: Vec3, yaw: number, pitch: number) => void,
|
|
42
|
+
private readonly updateFov: (fov: number) => void,
|
|
43
|
+
private readonly getInitialState: () => { position: Vec3, yaw: number, pitch: number, fov: number }
|
|
44
|
+
) { }
|
|
45
|
+
|
|
46
|
+
startScript(script: CinimaticScript): boolean {
|
|
47
|
+
if (this.isRunning) {
|
|
48
|
+
console.warn('Cinematic script already running. Stop current script first.')
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!script.points || script.points.length === 0) {
|
|
53
|
+
console.warn('Cinematic script has no points')
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.currentScript = script
|
|
58
|
+
this.isRunning = true
|
|
59
|
+
this.currentPointIndex = 0
|
|
60
|
+
this.startTime = performance.now()
|
|
61
|
+
|
|
62
|
+
// Calculate total duration
|
|
63
|
+
this.totalDuration = script.points.reduce((sum, point) => sum + point.duration, 0)
|
|
64
|
+
|
|
65
|
+
// Get initial state
|
|
66
|
+
const initialState = this.getInitialState()
|
|
67
|
+
this.currentPosition = {
|
|
68
|
+
x: initialState.position.x,
|
|
69
|
+
y: initialState.position.y,
|
|
70
|
+
z: initialState.position.z
|
|
71
|
+
}
|
|
72
|
+
this.currentRotation = {
|
|
73
|
+
yaw: initialState.yaw,
|
|
74
|
+
pitch: initialState.pitch
|
|
75
|
+
}
|
|
76
|
+
this.currentFov = initialState.fov
|
|
77
|
+
|
|
78
|
+
console.log(`Starting cinematic script: ${script.name || 'Unnamed'} (${this.totalDuration}ms)`)
|
|
79
|
+
|
|
80
|
+
// Start from first point
|
|
81
|
+
this.moveToPoint(0)
|
|
82
|
+
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
stopScript(): void {
|
|
87
|
+
if (!this.isRunning) return
|
|
88
|
+
|
|
89
|
+
// Stop all active tweens
|
|
90
|
+
for (const tween of this.currentTweens) tween.stop()
|
|
91
|
+
this.currentTweens = []
|
|
92
|
+
|
|
93
|
+
this.isRunning = false
|
|
94
|
+
this.currentScript = null
|
|
95
|
+
this.currentPointIndex = 0
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
runExampleScripts(index: number) {
|
|
99
|
+
const { cameraObject } = this.worldRenderer
|
|
100
|
+
const playerPos = new Vec3(cameraObject.position.x, cameraObject.position.y, cameraObject.position.z)
|
|
101
|
+
|
|
102
|
+
// Circular flyby around current position
|
|
103
|
+
const circular = CinimaticScriptRunner.createCircularFlyby(playerPos, 30, 20, 15_000)
|
|
104
|
+
|
|
105
|
+
// Spiral descent from high above to current position
|
|
106
|
+
const spiral = CinimaticScriptRunner.createSpiralDescent(
|
|
107
|
+
playerPos.offset(0, 50, 0),
|
|
108
|
+
playerPos,
|
|
109
|
+
3, // 3 spirals
|
|
110
|
+
12_000 // 12 seconds
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
// Building tour example
|
|
114
|
+
const buildingTour = CinimaticScriptRunner.createBuildingTour([
|
|
115
|
+
{ pos: playerPos.offset(-20, 10, -20), lookAt: playerPos, duration: 3000 },
|
|
116
|
+
{ pos: playerPos.offset(20, 15, -20), lookAt: playerPos, duration: 3000 },
|
|
117
|
+
{ pos: playerPos.offset(20, 20, 20), lookAt: playerPos, duration: 3000 },
|
|
118
|
+
{ pos: playerPos.offset(-20, 25, 20), lookAt: playerPos, duration: 3000 },
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
const scripts = [circular, spiral, buildingTour]
|
|
122
|
+
this.startScript(scripts[index])
|
|
123
|
+
|
|
124
|
+
return { circular, spiral, buildingTour }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private moveToPoint(pointIndex: number): void {
|
|
128
|
+
if (!this.currentScript || pointIndex >= this.currentScript.points.length) {
|
|
129
|
+
this.handleScriptComplete()
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const point = this.currentScript.points[pointIndex]
|
|
134
|
+
const { duration } = point
|
|
135
|
+
|
|
136
|
+
// Create target state
|
|
137
|
+
const targetPosition = { x: point.x, y: point.y, z: point.z }
|
|
138
|
+
const targetRotation = { yaw: point.yaw, pitch: point.pitch }
|
|
139
|
+
const targetFov = point.fov ?? this.currentFov
|
|
140
|
+
|
|
141
|
+
// Handle lookAt override
|
|
142
|
+
if (point.lookAt) {
|
|
143
|
+
const lookAtVec = new THREE.Vector3(point.lookAt.x, point.lookAt.y, point.lookAt.z)
|
|
144
|
+
const fromVec = new THREE.Vector3(point.x, point.y, point.z)
|
|
145
|
+
const direction = lookAtVec.sub(fromVec).normalize()
|
|
146
|
+
|
|
147
|
+
// Convert direction to yaw/pitch
|
|
148
|
+
targetRotation.yaw = Math.atan2(-direction.x, -direction.z)
|
|
149
|
+
targetRotation.pitch = Math.asin(direction.y)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Get easing function
|
|
153
|
+
const easingFn = this.getEasingFunction(point.easing || 'easeInOut')
|
|
154
|
+
|
|
155
|
+
// Create position tween
|
|
156
|
+
const positionTween = new tweenJs.Tween(this.currentPosition)
|
|
157
|
+
.to(targetPosition, duration)
|
|
158
|
+
.easing(easingFn)
|
|
159
|
+
.onUpdate(() => {
|
|
160
|
+
this.updateCamera(
|
|
161
|
+
new Vec3(this.currentPosition.x, this.currentPosition.y, this.currentPosition.z),
|
|
162
|
+
this.currentRotation.yaw,
|
|
163
|
+
this.currentRotation.pitch
|
|
164
|
+
)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// Create rotation tween (handle wrapping)
|
|
168
|
+
const rotationTween = new tweenJs.Tween(this.currentRotation)
|
|
169
|
+
.to(this.wrapRotation(targetRotation), duration)
|
|
170
|
+
.easing(easingFn)
|
|
171
|
+
.onUpdate(() => {
|
|
172
|
+
this.updateCamera(
|
|
173
|
+
new Vec3(this.currentPosition.x, this.currentPosition.y, this.currentPosition.z),
|
|
174
|
+
this.currentRotation.yaw,
|
|
175
|
+
this.currentRotation.pitch
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Create FOV tween if needed
|
|
180
|
+
let fovTween: tweenJs.Tween<any> | null = null
|
|
181
|
+
if (Math.abs(targetFov - this.currentFov) > 0.1) {
|
|
182
|
+
const fovState = { fov: this.currentFov }
|
|
183
|
+
fovTween = new tweenJs.Tween(fovState)
|
|
184
|
+
.to({ fov: targetFov }, duration)
|
|
185
|
+
.easing(easingFn)
|
|
186
|
+
.onUpdate(() => {
|
|
187
|
+
this.currentFov = fovState.fov
|
|
188
|
+
this.updateFov(this.currentFov)
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Start tweens
|
|
193
|
+
this.currentTweens = [positionTween, rotationTween]
|
|
194
|
+
if (fovTween) this.currentTweens.push(fovTween)
|
|
195
|
+
|
|
196
|
+
positionTween.start()
|
|
197
|
+
rotationTween.start()
|
|
198
|
+
fovTween?.start()
|
|
199
|
+
|
|
200
|
+
// Handle completion
|
|
201
|
+
positionTween.onComplete(() => {
|
|
202
|
+
this.currentPointIndex++
|
|
203
|
+
|
|
204
|
+
// Call point reached callback
|
|
205
|
+
this.currentScript?.onPointReached?.(pointIndex, point)
|
|
206
|
+
|
|
207
|
+
// Move to next point
|
|
208
|
+
if (this.isRunning) {
|
|
209
|
+
this.moveToPoint(this.currentPointIndex)
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private wrapRotation(target: { yaw: number, pitch: number }): { yaw: number, pitch: number } {
|
|
215
|
+
// Handle yaw wrapping to take shortest path
|
|
216
|
+
let targetYaw = target.yaw
|
|
217
|
+
const yawDiff = targetYaw - this.currentRotation.yaw
|
|
218
|
+
|
|
219
|
+
if (yawDiff > Math.PI) {
|
|
220
|
+
targetYaw -= 2 * Math.PI
|
|
221
|
+
} else if (yawDiff < -Math.PI) {
|
|
222
|
+
targetYaw += 2 * Math.PI
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Clamp pitch to avoid gimbal lock
|
|
226
|
+
const targetPitch = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, target.pitch))
|
|
227
|
+
|
|
228
|
+
return { yaw: targetYaw, pitch: targetPitch }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private getEasingFunction(easing: string): (t: number) => number {
|
|
232
|
+
switch (easing) {
|
|
233
|
+
case 'linear': return tweenJs.Easing.Linear.None
|
|
234
|
+
case 'easeIn': return tweenJs.Easing.Quadratic.In
|
|
235
|
+
case 'easeOut': return tweenJs.Easing.Quadratic.Out
|
|
236
|
+
case 'easeInOut': return tweenJs.Easing.Quadratic.InOut
|
|
237
|
+
case 'smoothstep': return tweenJs.Easing.Cubic.InOut
|
|
238
|
+
case 'bounce': return tweenJs.Easing.Bounce.Out
|
|
239
|
+
default: return tweenJs.Easing.Quadratic.InOut
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private handleScriptComplete(): void {
|
|
244
|
+
if (!this.currentScript) return
|
|
245
|
+
|
|
246
|
+
const script = this.currentScript
|
|
247
|
+
|
|
248
|
+
if (script.loop) {
|
|
249
|
+
// Restart from beginning
|
|
250
|
+
this.currentPointIndex = 0
|
|
251
|
+
this.moveToPoint(0)
|
|
252
|
+
} else {
|
|
253
|
+
// Script finished
|
|
254
|
+
console.log(`Cinematic script completed: ${script.name || 'Unnamed'}`)
|
|
255
|
+
script.onComplete?.()
|
|
256
|
+
this.stopScript()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Public getters
|
|
261
|
+
get running(): boolean {
|
|
262
|
+
return this.isRunning
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
get progress(): number {
|
|
266
|
+
if (!this.isRunning || this.totalDuration === 0) return 0
|
|
267
|
+
const elapsed = performance.now() - this.startTime
|
|
268
|
+
return Math.min(elapsed / this.totalDuration, 1)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
get currentScriptName(): string | undefined {
|
|
272
|
+
return this.currentScript?.name
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Static helper methods for creating common scripts
|
|
276
|
+
static createCircularFlyby(center: Vec3, radius: number, height: number, duration: number): CinimaticScript {
|
|
277
|
+
const points: CinimaticPoint[] = []
|
|
278
|
+
const numPoints = 8
|
|
279
|
+
|
|
280
|
+
for (let i = 0; i <= numPoints; i++) {
|
|
281
|
+
const angle = (i / numPoints) * Math.PI * 2
|
|
282
|
+
const x = center.x + Math.cos(angle) * radius
|
|
283
|
+
const z = center.z + Math.sin(angle) * radius
|
|
284
|
+
const y = center.y + height
|
|
285
|
+
|
|
286
|
+
points.push({
|
|
287
|
+
x, y, z,
|
|
288
|
+
yaw: angle + Math.PI / 2, // Look tangent to circle
|
|
289
|
+
pitch: -0.2, // Look slightly down
|
|
290
|
+
duration: duration / numPoints,
|
|
291
|
+
easing: 'smoothstep',
|
|
292
|
+
lookAt: { x: center.x, y: center.y, z: center.z }
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
name: 'Circular Flyby',
|
|
298
|
+
points,
|
|
299
|
+
loop: false
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
static createSpiralDescent(start: Vec3, end: Vec3, spirals: number, duration: number): CinimaticScript {
|
|
304
|
+
const points: CinimaticPoint[] = []
|
|
305
|
+
const numPoints = spirals * 8
|
|
306
|
+
const radius = 20
|
|
307
|
+
|
|
308
|
+
for (let i = 0; i <= numPoints; i++) {
|
|
309
|
+
const t = i / numPoints
|
|
310
|
+
const angle = t * spirals * Math.PI * 2
|
|
311
|
+
|
|
312
|
+
const x = THREE.MathUtils.lerp(start.x, end.x, t) + Math.cos(angle) * radius * (1 - t)
|
|
313
|
+
const z = THREE.MathUtils.lerp(start.z, end.z, t) + Math.sin(angle) * radius * (1 - t)
|
|
314
|
+
const y = THREE.MathUtils.lerp(start.y, end.y, t)
|
|
315
|
+
|
|
316
|
+
points.push({
|
|
317
|
+
x, y, z,
|
|
318
|
+
yaw: angle + Math.PI / 2,
|
|
319
|
+
pitch: -0.3 * t, // Gradually look more down
|
|
320
|
+
duration: duration / numPoints,
|
|
321
|
+
easing: 'easeInOut'
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
name: 'Spiral Descent',
|
|
327
|
+
points,
|
|
328
|
+
loop: false
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static createBuildingTour(waypoints: Array<{ pos: Vec3, lookAt?: Vec3, duration?: number }>): CinimaticScript {
|
|
333
|
+
const points: CinimaticPoint[] = waypoints.map((wp, i) => ({
|
|
334
|
+
x: wp.pos.x,
|
|
335
|
+
y: wp.pos.y,
|
|
336
|
+
z: wp.pos.z,
|
|
337
|
+
yaw: 0, // Will be overridden by lookAt if provided
|
|
338
|
+
pitch: 0,
|
|
339
|
+
duration: wp.duration || 3000,
|
|
340
|
+
easing: 'smoothstep',
|
|
341
|
+
lookAt: wp.lookAt ? { x: wp.lookAt.x, y: wp.lookAt.y, z: wp.lookAt.z } : undefined
|
|
342
|
+
}))
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
name: 'Building Tour',
|
|
346
|
+
points,
|
|
347
|
+
loop: false
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|