import {Vector3, EventDispatcher, Object3D, PerspectiveCamera, Quaternion, Euler, AnimationMixer, AnimationClip, VectorKeyframeTrack, QuaternionKeyframeTrack} from "./three.js"; import {TweenMax, gsap as gsap2} from "./gsap.js"; class p { constructor(t) { this.epsilon = 1e-3, this.values = {}, this.targetValues = {}, this.deltaValues = {}, Object.assign(this.values, t.values), Object.assign(this.targetValues, t.values), this.deltaValues = {}; for (const t2 in this.values) this.deltaValues[t2] = 0; this.dampingFactor = t.dampingFactor, t.epsilon && (this.epsilon = t.epsilon), this.hasReached = true; } update() { const t = {}; let e = true; for (const i in this.values) t[i] = this.targetValues[i] - this.values[i], e = e && Math.abs(t[i]) < this.epsilon; if (e) { for (const e2 in this.values) this.deltaValues[e2] = t[e2], this.values[e2] = this.targetValues[e2]; this.hasReached = true; } else for (const e2 in this.values) this.deltaValues[e2] = this.dampingFactor * t[e2], this.values[e2] += this.deltaValues[e2]; } setTarget(t) { for (const e in t) this.targetValues[e] = t[e]; this.hasReached = false; } addToTarget(t, e) { this.targetValues[t] += e, this.hasReached = false; } resetAll(t) { for (const e in this.values) this.targetValues[e] = t, this.values[e] = t, this.deltaValues[e] = 0; this.hasReached = true; } resetData(t) { for (const e in t) this.targetValues[e] = t[e], this.values[e] = t[e], this.deltaValues[e] = 0; this.hasReached = true; } getCurrentValues() { return Object.assign({}, this.values); } getDeltaValues() { return Object.assign({}, this.deltaValues); } reachedTarget() { return this.hasReached; } } var m, u, g; !function(t) { t.Pan = "Pan", t.Tilt = "Tilt", t.Roll = "Roll", t.Truck = "Truck", t.Pedestal = "Pedestal", t.Dolly = "Dolly", t.Zoom = "Zoom"; }(m || (m = {})), function(t) { t.Body = "body", t.Head = "head", t.Eyes = "eyes"; }(u || (u = {})), function(t) { t.X = "x", t.Y = "y", t.Z = "z"; }(g || (g = {})); const b = {[g.X]: new Vector3(1, 0, 0), [g.Y]: new Vector3(0, 1, 0), [g.Z]: new Vector3(0, 0, 1)}, y = {[g.X]: {[m.Pan]: g.X, [m.Tilt]: g.Z, [m.Roll]: g.Y}, [g.Y]: {[m.Pan]: g.Y, [m.Tilt]: g.X, [m.Roll]: g.Z}, [g.Z]: {[m.Pan]: g.Z, [m.Tilt]: g.Y, [m.Roll]: g.X}}; class v extends EventDispatcher { constructor(t, e) { super(), this.inTransit = false, this.upAxis = g.Y, this.actionAxes = y[this.upAxis], this.hasAnimation = false, this.animationTranslationObjectName = "Translation", this.animationRotationObjectName = "Rotation", this.translateAlong = {[m.Tilt]: false, [m.Pan]: true, [m.Roll]: false}, this.camera = t, this.scene = e, this.body = new Object3D(), this.head = new Object3D(), this.eyes = new Object3D(), this.head.name = this.animationRotationObjectName, this.body.name = this.animationTranslationObjectName, this.body.rotation.order = this.getRotationOrder(), this.head.rotation.order = this.getRotationOrder(), this.eyes.rotation.order = this.getRotationOrder(), this.scene.add(this.body.add(this.head.add(this.eyes.add(this.camera)))), this.cameraIsInRig = true, this.unpackTransform(); } getAxisFor(t) { return this.actionAxes[t]; } getAxisVectorFor(t) { return b[this.actionAxes[t]]; } do(t, e, i) { const n = this[i]; switch (t) { case m.Pan: case m.Tilt: case m.Roll: { const i2 = this.getAxisVectorFor(t); n ? n.rotateOnAxis(i2, e) : this.translateAlong[t] ? this.body.rotateOnAxis(i2, e) : this.eyes.rotateOnAxis(i2, e); break; } case m.Truck: { const t2 = this.getAxisVectorFor(m.Tilt); (n || this.body).translateOnAxis(t2, e); break; } case m.Pedestal: { const t2 = this.getAxisVectorFor(m.Pan); (n || this.body).translateOnAxis(t2, e); break; } case m.Dolly: { const t2 = this.getAxisVectorFor(m.Roll); (n || this.body).translateOnAxis(t2, e); break; } case m.Zoom: this.camera instanceof PerspectiveCamera && (this.camera.fov = e, this.camera.updateProjectionMatrix()); } } getWorldCoordinates() { const e = new Vector3(); this.camera.getWorldPosition(e); const i = new Quaternion(); return this.camera.getWorldQuaternion(i), {position: e, quaternion: i}; } setWorldCoordinates({position: t, quaternion: e}) { const i = new Euler().setFromQuaternion(e, this.getRotationOrder()), s = [m.Pan, m.Tilt, m.Roll]; this.eyes.position.set(0, 0, 0), this.eyes.rotation.set(0, 0, 0), this.head.position.set(0, 0, 0), this.head.rotation.set(0, 0, 0), this.body.position.copy(t), s.forEach((t2) => { const e2 = this.getAxisFor(t2); this.translateAlong[t2] ? this.body.rotation[e2] = i[e2] : this.eyes.rotation[e2] = i[e2]; }), this.camera.rotation.set(0, 0, 0), this.camera.position.set(0, 0, 0); } packTransform() { const {position: t, quaternion: e} = this.getWorldCoordinates(); this.body.position.copy(t), this.body.rotation.set(0, 0, 0), this.head.quaternion.copy(e), this.head.position.set(0, 0, 0), this.eyes.position.set(0, 0, 0), this.eyes.rotation.set(0, 0, 0); } unpackTransform() { const {position: t, quaternion: e} = this.getWorldCoordinates(); this.setWorldCoordinates({position: t, quaternion: e}); } disassemble() { this.cameraIsInRig && (this.scene.attach(this.camera), this.cameraIsInRig = false); } assemble() { this.cameraIsInRig || (this.eyes.attach(this.camera), this.unpackTransform(), this.cameraIsInRig = true); } getRotationOrder() { return Object.values(this.actionAxes).join("").toUpperCase(); } isInRig() { return this.cameraIsInRig; } isMoving() { return this.inTransit; } setUpAxis(t) { this.upAxis = t, this.actionAxes = y[this.upAxis], this.body.rotation.order = this.getRotationOrder(); } setAnimationClip(t, e, i) { this.animationClip = t, e && (this.animationTranslationObjectName = e), i && (this.animationRotationObjectName = i), this.hasAnimation = true, this.animationClip.duration += 0.01, this.mixer = new AnimationMixer(this.body); const s = this.mixer.clipAction(this.animationClip); s.clampWhenFinished = true, s.play(); } flyTo(t, e, i = 1, s = "power1", n = true) { if (!this.isMoving()) { const a = this.getWorldCoordinates(), o = {px: a.position.x, py: a.position.y, pz: a.position.z, qx: a.quaternion.x, qy: a.quaternion.y, qz: a.quaternion.z, qw: a.quaternion.w, slerpAmt: 0}, r = {px: t.x, py: t.y, pz: t.z, qx: e.x, qy: e.y, qz: e.z, qw: e.w, slerpAmt: 1}, h = () => { this.inTransit = true, this.packTransform(), this.dispatchEvent({type: "CameraMoveStart"}); }, d = (t2) => { this.body.position.set(o.px, o.py, o.pz), n ? this.head.quaternion.slerp(e, o.slerpAmt) : this.head.quaternion.set(o.qx, o.qy, o.qz, o.qw), this.dispatchEvent({type: "CameraMoveUpdate", progress: t2.progress()}); }, l = () => { this.inTransit = false, this.unpackTransform(), this.dispatchEvent({type: "CameraMoveEnd"}); }; TweenMax.to(o, Object.assign(Object.assign({duration: i, ease: s}, r), {onStart: h, onUpdate: function() { d(this); }, onComplete: l})); } } flyToKeyframe(t, e = 1, i = "power1") { if (this.hasAnimation && !this.isMoving()) { const s = {time: this.mixer.time}, n = {time: this.animationClip.tracks[0].times[t]}, a = () => { this.inTransit = true, this.dispatchEvent({type: "CameraMoveStart"}); }, o = (t2) => { this.mixer.setTime(s.time), this.dispatchEvent({type: "CameraMoveUpdate", progress: t2.progress()}); }, r = () => { this.inTransit = false, this.dispatchEvent({type: "CameraMoveEnd"}); }; TweenMax.to(s, Object.assign(Object.assign({duration: e, ease: i}, n), {onStart: a, onUpdate: function() { o(this); }, onComplete: r})); } } setAnimationPercentage(t) { if (this.hasAnimation) { const e = Math.max(0, Math.min(t * this.animationClip.duration, this.animationClip.duration - 1e-4)); this.mixer.setTime(e); } } setAnimationTime(t) { this.hasAnimation && this.mixer.setTime(t); } setAnimationKeyframe(t) { this.hasAnimation && this.mixer.setTime(this.animationClip.tracks[0].times[t]); } } class x extends EventDispatcher { constructor() { super(); } } const f = {keyMapping: {forward: ["ArrowUp", "w", "W"], backward: ["ArrowDown", "s", "S"], left: ["ArrowLeft", "a", "A"], right: ["ArrowRight", "d", "D"], up: ["u", "U"], down: ["n", "N"]}, dampingFactor: 0.5, incrementor: 1, preventBubbling: true}; class E extends x { constructor(t) { super(), Object.assign(this, f, t); const e = {}; for (const t2 in this.keyMapping) e[t2] = 0; this.damper = new p({values: e, dampingFactor: this.dampingFactor}), this.onKeyUp = this.onKeyUp.bind(this), this.onKeyDown = this.onKeyDown.bind(this); } connect() { document.addEventListener("keyup", this.onKeyUp, true), document.addEventListener("keydown", this.onKeyDown, true), this.connected = true; } disconnect() { document.removeEventListener("keyup", this.onKeyUp, true), document.removeEventListener("keydown", this.onKeyDown, true), this.connected = false; } update() { this.type !== "continuous" || this.damper.reachedTarget() || (this.damper.update(), this.dispatchEvent({type: "update", values: this.damper.getCurrentValues(), deltas: this.damper.getDeltaValues()}), this.damper.reachedTarget() && (this.damper.resetAll(0), this.dispatchEvent({type: "inertiacomplete"}))); } isEnabled() { return this.connected; } onKeyUp(t) { if (this.type === "discrete") { for (const e in this.keyMapping) if (this.keyMapping[e].includes(t.key)) { this.preventBubbling && t.preventDefault(), this.dispatchEvent({type: "trigger", trigger: e}); break; } } } onKeyDown(t) { if (this.type === "continuous") { for (const e in this.keyMapping) if (this.keyMapping[e].includes(t.key)) { this.preventBubbling && t.preventDefault(), this.damper.addToTarget(e, this.incrementor); break; } } } } const w = {domElement: document.body, dampingFactor: 0.5, shouldNormalize: true, normalizeAroundZero: true, multipointerThreshold: 100}; class P extends x { constructor(t) { super(), this.domElement = document.body, this.shouldNormalize = true, this.normalizeAroundZero = true, this.pointerCount = 0, this.recordedPosition = false, this.cache = [], this.lastDownTime = 0, this.lastUpTime = 0, Object.assign(this, w, t), this.damper = new p({values: {x: null, y: null}, dampingFactor: this.dampingFactor}), this.setDimensions(), this.onPointerMove = this.onPointerMove.bind(this), this.onPointerUp = this.onPointerUp.bind(this), this.onPointerDown = this.onPointerDown.bind(this), this.onResize = this.onResize.bind(this); } connect() { this.domElement.addEventListener("pointermove", this.onPointerMove, {passive: true}), this.domElement.addEventListener("pointerdown", this.onPointerDown, {passive: true}), this.domElement.addEventListener("pointerleave", this.onPointerUp, {passive: true}), this.domElement.addEventListener("pointerup", this.onPointerUp, {passive: true}), window.addEventListener("resize", this.onResize), this.connected = true; } disconnect() { this.domElement.removeEventListener("pointermove", this.onPointerMove), this.domElement.removeEventListener("pointerdown", this.onPointerDown), this.domElement.removeEventListener("pointerleave", this.onPointerUp), this.domElement.removeEventListener("pointerup", this.onPointerUp), this.connected = false; } update(t) { this.pointerCount !== this.cache.length && t - this.lastDownTime > this.multipointerThreshold && t - this.lastUpTime > this.multipointerThreshold && (this.pointerCount = this.cache.length, this.pointerCount === 0 ? (this.damper.resetAll(null), this.recordedPosition = false) : (this.damper.resetData(this.getPointerPosition(this.cache[0])), this.recordedPosition = true)), this.damper.reachedTarget() || (this.damper.update(), this.dispatchEvent({type: "update", values: this.shouldNormalize ? this.normalize(this.damper.getCurrentValues(), this.normalizeAroundZero) : this.damper.getCurrentValues(), deltas: this.shouldNormalize ? this.normalize(this.damper.getDeltaValues(), false) : this.damper.getDeltaValues(), pointerCount: this.pointerCount}), this.damper.reachedTarget() && this.dispatchEvent({type: "inertiacomplete"})); } isEnabled() { return this.connected; } setDimensions() { this.width = this.domElement.getBoundingClientRect().width, this.height = this.domElement.getBoundingClientRect().height; } getPointerPosition(t) { return {x: Math.max(0, Math.min(this.width, t.x - this.domElement.offsetLeft)), y: Math.max(0, Math.min(this.height, t.y - this.domElement.offsetTop))}; } normalize(t, e) { let i = t.x / this.width, s = t.y / this.height; return e && (i = 2 * i - 1, s = 2 * s - 1), {x: i, y: s}; } onPointerMove(t) { this.pointerCount === this.cache.length && (this.cache.length === 0 ? this.recordedPosition ? this.damper.setTarget(this.getPointerPosition(t)) : (this.damper.resetData(this.getPointerPosition(t)), this.recordedPosition = true) : t.pointerId === this.cache[0].pointerId && this.damper.setTarget(this.getPointerPosition(t))); } onPointerDown(t) { t.button === 0 && (this.cache.push(t), this.lastDownTime = window.performance.now()); } onPointerUp(t) { if (t.button === 0 || t.type === "pointerleave") { for (let e = 0; e < this.cache.length; e++) if (this.cache[e].pointerId == t.pointerId) { this.cache.splice(e, 1); break; } this.lastUpTime = window.performance.now(); } } onResize() { this.setDimensions(); } } const A = {startOffset: "0px", endOffset: "0px", buffer: 0.1, dampingFactor: 0.5}; class T extends x { constructor(t) { super(), Object.assign(this, A, t), this.lastSeenScrollValue = window.scrollY || -1, this.previousScrollValue = this.lastSeenScrollValue, this.values = {scrollPx: null, scrollPercent: null}, this.damper = new p({values: this.values, dampingFactor: this.dampingFactor}), this.calculateDimensions = this.calculateDimensions.bind(this), this.onScroll = this.onScroll.bind(this), this.resizeObserver = new ResizeObserver(this.calculateDimensions), this.calculateDimensions(); } connect() { window.addEventListener("scroll", this.onScroll, {passive: true}), this.resizeObserver.observe(document.body), this.connected = true; } disconnect() { window.removeEventListener("scroll", this.onScroll), this.resizeObserver.unobserve(document.body), this.connected = false; } update() { if (this.lastSeenScrollValue !== this.previousScrollValue && this.lastSeenScrollValue >= this.bufferedStartPosition && this.lastSeenScrollValue <= this.bufferedEndPosition) { const t = Math.max(0, Math.min(this.distance, this.lastSeenScrollValue - this.startPosition)), e = Math.max(0, Math.min(1, t / this.distance)); this.values = {scrollPx: t, scrollPercent: e}, this.damper.setTarget(this.values), this.previousScrollValue = this.lastSeenScrollValue; } this.damper.reachedTarget() || (this.damper.update(), this.dispatchEvent({type: "update", values: this.values, dampenedValues: this.damper.getCurrentValues()}), this.damper.reachedTarget() && this.dispatchEvent({type: "inertiacomplete"})); } isEnabled() { return this.connected; } parseOffset(t) { let e = 0; return t && (e = parseInt(t), t.indexOf("vh") !== -1 ? e = e * window.innerHeight / 100 : this.distance && t.indexOf("%") !== -1 && (e = e * this.distance / 100)), e; } calculateOffset(t) { return t ? this.calculateOffset(t.offsetParent) + t.offsetTop : 0; } calculateDimensions() { const t = this.scrollElement.clientHeight, e = this.calculateOffset(this.scrollElement); this.startPosition = e - window.innerHeight + this.parseOffset(this.startOffset), this.endPosition = e + t + this.parseOffset(this.endOffset), this.distance = this.endPosition - this.startPosition, this.bufferedStartPosition = Math.max(0, this.startPosition * (1 - this.buffer)), this.bufferedEndPosition = Math.min(this.endPosition * (1 + this.buffer), document.body.getBoundingClientRect().height); } onScroll() { this.lastSeenScrollValue = window.scrollY; } } const C = {domElement: document.body, thresholdX: 60, thresholdY: 60}; class L extends x { constructor(t = {}) { super(), Object.assign(this, C, t), this.onPointerUp = this.onPointerUp.bind(this), this.onPointerDown = this.onPointerDown.bind(this); } connect() { this.domElement.addEventListener("pointerdown", this.onPointerDown, {passive: true}), this.domElement.addEventListener("pointerup", this.onPointerUp, {passive: true}), this.connected = true; } disconnect() { this.domElement.removeEventListener("pointerdown", this.onPointerDown), this.domElement.removeEventListener("pointerup", this.onPointerUp), this.connected = false; } update() { } isEnabled() { return this.connected; } onPointerDown(t) { t.pointerType !== "mouse" && t.isPrimary && (this.startX = t.screenX, this.startY = t.screenY); } onPointerUp(t) { if (t.pointerType !== "mouse" && t.isPrimary) { const e = t.screenX - this.startX, i = t.screenY - this.startY; (Math.abs(e) >= this.thresholdX || Math.abs(i) >= this.thresholdY) && this.dispatchEvent({type: "trigger", x: Math.abs(e) >= this.thresholdX ? Math.sign(e) : 0, y: Math.abs(i) >= this.thresholdY ? Math.sign(-1 * i) : 0}); } } } const S = {dampingFactor: 0.5, thresholdX: 15, thresholdY: 15, debounceDuration: 700}; class F extends x { constructor(t) { super(), this.lastThresholdTrigger = 0, Object.assign(this, S, t), this.damper = new p({values: {x: 0, y: 0}, dampingFactor: this.dampingFactor}), this.onWheel = this.onWheel.bind(this); } connect() { (this.domElement || window).addEventListener("wheel", this.onWheel, {passive: true}), this.connected = true; } disconnect() { (this.domElement || window).removeEventListener("wheel", this.onWheel), this.connected = false; } update() { this.type !== "continuous" || this.damper.reachedTarget() || (this.damper.update(), this.dispatchEvent({type: "update", values: this.damper.getCurrentValues(), deltas: this.damper.getDeltaValues()}), this.damper.reachedTarget() && (this.damper.resetAll(0), this.dispatchEvent({type: "inertiacomplete"}))); } isEnabled() { return this.connected; } onWheel(t) { if (this.type === "continuous") this.damper.addToTarget("x", t.deltaX), this.damper.addToTarget("y", t.deltaY); else if (this.type === "discrete" && (Math.abs(t.deltaX) >= this.thresholdX || Math.abs(t.deltaY) >= this.thresholdY)) { const e = window.performance.now(); e - this.lastThresholdTrigger > this.debounceDuration && (this.lastThresholdTrigger = e, this.dispatchEvent({type: "trigger", x: Math.abs(t.deltaX) >= this.thresholdX ? Math.sign(t.deltaX) : 0, y: Math.abs(t.deltaY) >= this.thresholdY ? Math.sign(t.deltaY) : 0})); } } } const R = {domElement: document.body, pointerDampFactor: 0.3, pointerScaleFactor: 4, keyboardDampFactor: 0.5, keyboardScaleFactor: 0.5, wheelDampFactor: 0.25, wheelScaleFactor: 0.05, panDegreeFactor: Math.PI / 4, tiltDegreeFactor: Math.PI / 10}; class k { constructor(t, e = {}) { this.enabled = false, this.cameraRig = t, this.wheelScaleFactor = e.wheelScaleFactor || R.wheelScaleFactor, this.pointerScaleFactor = e.pointerScaleFactor || R.pointerScaleFactor, this.panDegreeFactor = e.panDegreeFactor || R.panDegreeFactor, this.tiltDegreeFactor = e.tiltDegreeFactor || R.tiltDegreeFactor, this.keyboardAdaptor = new E({type: "continuous", dampingFactor: e.keyboardDampFactor || R.keyboardDampFactor, incrementor: e.keyboardScaleFactor || R.keyboardScaleFactor}), this.wheelAdaptor = new F({type: "continuous", dampingFactor: e.wheelDampFactor || R.wheelDampFactor, domElement: e.domElement || R.domElement}), this.pointerAdaptor = new P({domElement: e.domElement || R.domElement, dampingFactor: e.pointerDampFactor || R.pointerDampFactor}), this.onWheel = this.onWheel.bind(this), this.onKey = this.onKey.bind(this), this.onPointer = this.onPointer.bind(this); } isEnabled() { return this.enabled; } enable() { this.wheelAdaptor.connect(), this.keyboardAdaptor.connect(), this.pointerAdaptor.connect(), this.wheelAdaptor.addEventListener("update", this.onWheel), this.keyboardAdaptor.addEventListener("update", this.onKey), this.pointerAdaptor.addEventListener("update", this.onPointer), this.enabled = true; } disable() { this.wheelAdaptor.disconnect(), this.keyboardAdaptor.disconnect(), this.pointerAdaptor.disconnect(), this.wheelAdaptor.removeEventListener("update", this.onWheel), this.keyboardAdaptor.removeEventListener("update", this.onKey), this.pointerAdaptor.removeEventListener("update", this.onPointer), this.enabled = false; } onWheel(t) { this.cameraRig.do(m.Dolly, t.deltas.y * this.wheelScaleFactor), this.cameraRig.do(m.Truck, t.deltas.x * this.wheelScaleFactor); } onKey(t) { this.cameraRig.do(m.Dolly, t.values.backward - t.values.forward), this.cameraRig.do(m.Truck, t.values.right - t.values.left), this.cameraRig.do(m.Pedestal, t.values.up - t.values.down); } onPointer(t) { switch (t.pointerCount) { case 1: this.cameraRig.do(m.Pan, t.deltas.x * this.panDegreeFactor), this.cameraRig.do(m.Tilt, t.deltas.y * this.tiltDegreeFactor); break; case 2: this.cameraRig.do(m.Dolly, -t.deltas.y * this.pointerScaleFactor), this.cameraRig.do(m.Truck, -t.deltas.x * this.pointerScaleFactor); } } update(t) { this.enabled && (this.keyboardAdaptor.update(), this.wheelAdaptor.update(), this.pointerAdaptor.update(t)); } } const O = {startOffset: "0px", endOffset: "0px", dampingFactor: 1, buffer: 0.1, cameraStart: "0%", cameraEnd: "100%", scrollActions: []}, M = (t, e, i, s, n) => Math.max(s, Math.min(n, (n - s) / (i - e) * (t - e) + s)); class I { constructor(t, e) { this.enabled = false, this.cameraRig = t, this.cameraRig.setAnimationTime(0), this.scrollAdaptor = new T({scrollElement: e.scrollElement, dampingFactor: e.dampingFactor || O.dampingFactor, startOffset: e.startOffset || O.startOffset, endOffset: e.endOffset || O.endOffset, buffer: e.buffer || O.buffer}), this.cameraStart = e.cameraStart || O.cameraStart, this.cameraEnd = e.cameraEnd || O.cameraEnd, this.scrollActions = e.scrollActions || O.scrollActions, this.buffer = e.buffer || O.buffer, this.calculateStops(), this.onScroll = this.onScroll.bind(this); } isEnabled() { return this.enabled; } enable() { this.scrollAdaptor.connect(), this.scrollAdaptor.addEventListener("update", this.onScroll), this.enabled = true; } disable() { this.scrollAdaptor.disconnect(), this.scrollAdaptor.removeEventListener("update", this.onScroll), this.enabled = false; } update() { this.enabled && this.scrollAdaptor.update(); } calculateStops() { this.cameraStartPx = this.scrollAdaptor.parseOffset(this.cameraStart), this.cameraEndPx = this.scrollAdaptor.parseOffset(this.cameraEnd), this.cameraBufferedStartPx = this.cameraStartPx * (1 - this.buffer), this.cameraBufferedEndPx = this.cameraEndPx * (1 + this.buffer), this.scrollActions.forEach((t) => { t.startPx = this.scrollAdaptor.parseOffset(t.start), t.endPx = this.scrollAdaptor.parseOffset(t.end), t.bufferedStartPx = t.startPx * (1 - this.buffer), t.bufferedEndPx = t.endPx * (1 + this.buffer); }); } onScroll(t) { const e = t.dampenedValues.scrollPx; e >= this.cameraBufferedStartPx && e <= this.cameraBufferedEndPx && this.cameraRig.setAnimationPercentage(M(e, this.cameraStartPx, this.cameraEndPx, 0, 1)), this.scrollActions.forEach((t2) => { e >= t2.bufferedStartPx && e <= t2.bufferedEndPx && t2.callback(M(e, t2.startPx, t2.endPx, 0, 1)); }); } } const D = {cycle: false, useKeyboard: true}; class q extends EventDispatcher { constructor(t, e = [], i = {}) { super(), this.currentIndex = null, this.upcomingIndex = null, this.enabled = false, this.cameraRig = t, this.pois = e, Object.assign(this, D, i), this.useKeyboard && (this.keyboardAdaptor = new E({type: "discrete", keyMapping: {next: ["ArrowDown", "ArrowRight"], prev: ["ArrowUp", "ArrowLeft"]}}), this.onKey = this.onKey.bind(this)), this.onCameraStart = this.onCameraStart.bind(this), this.onCameraUpdate = this.onCameraUpdate.bind(this), this.onCameraEnd = this.onCameraEnd.bind(this); } getCurrentIndex() { return this.currentIndex; } nextPOI() { const t = this.currentIndex + 1; t >= this.pois.length && !this.cycle ? this.dispatchEvent({type: "ExitPOIs", exitFrom: "end"}) : this.goToPOI(t % this.pois.length); } prevPOI() { const t = this.currentIndex - 1; t < 0 && !this.cycle ? this.dispatchEvent({type: "ExitPOIs", exitFrom: "start"}) : this.goToPOI((t + this.pois.length) % this.pois.length); } goToPOI(t) { this.upcomingIndex = t; const e = this.pois[this.upcomingIndex]; this.cameraRig.flyTo(e.position, e.quaternion, e.duration, e.ease); } enable() { this.useKeyboard && (this.keyboardAdaptor.connect(), this.keyboardAdaptor.addEventListener("trigger", this.onKey)), this.cameraRig.addEventListener("CameraMoveStart", this.onCameraStart), this.cameraRig.addEventListener("CameraMoveUpdate", this.onCameraUpdate), this.cameraRig.addEventListener("CameraMoveEnd", this.onCameraEnd), this.enabled = true; } disable() { this.useKeyboard && (this.keyboardAdaptor.disconnect(), this.keyboardAdaptor.removeEventListener("trigger", this.onKey)), this.cameraRig.removeEventListener("CameraMoveStart", this.onCameraStart), this.cameraRig.removeEventListener("CameraMoveUpdate", this.onCameraUpdate), this.cameraRig.removeEventListener("CameraMoveEnd", this.onCameraEnd), this.enabled = false; } update() { } isEnabled() { return this.enabled; } updatePois(t) { this.dispatchEvent({type: "update", currentIndex: this.currentIndex, upcomingIndex: this.upcomingIndex, progress: t}); } onCameraStart() { this.updatePois(0); } onCameraUpdate(t) { this.updatePois(t.progress); } onCameraEnd() { this.currentIndex = this.upcomingIndex, this.upcomingIndex = null; } onKey(t) { t.trigger === "next" ? this.nextPOI() : t.trigger === "prev" && this.prevPOI(); } } const z = {wheelThreshold: 15, swipeThreshold: 60, duration: 1, ease: "power1", useKeyboard: true}; class U extends EventDispatcher { constructor(t, e = [], i = {}) { super(), this.currentIndex = 0, this.upcomingIndex = null, this.enabled = false, this.cameraRig = t, this.pois = e, Object.assign(this, z, i), this.wheelAdaptor = new F({type: "discrete", thresholdY: this.wheelThreshold}), this.swipeAdaptor = new L({thresholdY: this.swipeThreshold}), this.useKeyboard && (this.keyboardAdaptor = new E({type: "discrete", keyMapping: {next: ["ArrowDown", "ArrowRight"], prev: ["ArrowUp", "ArrowLeft"]}}), this.onKey = this.onKey.bind(this)), this.onCameraStart = this.onCameraStart.bind(this), this.onCameraUpdate = this.onCameraUpdate.bind(this), this.onCameraEnd = this.onCameraEnd.bind(this), this.onTrigger = this.onTrigger.bind(this); } getCurrentIndex() { return this.currentIndex; } enable() { this.useKeyboard && (this.keyboardAdaptor.addEventListener("trigger", this.onKey), this.keyboardAdaptor.connect()), this.wheelAdaptor.addEventListener("trigger", this.onTrigger), this.swipeAdaptor.addEventListener("trigger", this.onTrigger), this.cameraRig.addEventListener("CameraMoveStart", this.onCameraStart), this.cameraRig.addEventListener("CameraMoveUpdate", this.onCameraUpdate), this.cameraRig.addEventListener("CameraMoveEnd", this.onCameraEnd), this.wheelAdaptor.connect(), this.swipeAdaptor.connect(), this.enabled = true; } disable() { this.useKeyboard && (this.keyboardAdaptor.removeEventListener("trigger", this.onKey), this.keyboardAdaptor.disconnect()), this.wheelAdaptor.removeEventListener("trigger", this.onTrigger), this.swipeAdaptor.removeEventListener("trigger", this.onTrigger), this.cameraRig.removeEventListener("CameraMoveStart", this.onCameraStart), this.cameraRig.removeEventListener("CameraMoveUpdate", this.onCameraUpdate), this.cameraRig.removeEventListener("CameraMoveEnd", this.onCameraEnd), this.wheelAdaptor.disconnect(), this.swipeAdaptor.disconnect(), this.enabled = false; } update() { } isEnabled() { return this.enabled; } onKey(t) { switch (t.trigger) { case "prev": this.onTrigger({y: -1}); break; case "next": this.onTrigger({y: 1}); } } onTrigger(t) { const e = this.currentIndex + t.y; e >= this.pois.length ? this.dispatchEvent({type: "ExitPOIs", exitFrom: "end"}) : e < 0 ? this.dispatchEvent({type: "ExitPOIs", exitFrom: "start"}) : (this.upcomingIndex = e, this.cameraRig.flyToKeyframe(this.pois[this.upcomingIndex].frame, this.duration, this.ease)); } updatePois(t) { this.dispatchEvent({type: "update", currentIndex: this.currentIndex, upcomingIndex: this.upcomingIndex, progress: t}); } onCameraStart() { this.updatePois(0); } onCameraUpdate(t) { this.updatePois(t.progress); } onCameraEnd() { this.currentIndex = this.upcomingIndex, this.upcomingIndex = null; } } const V = {domElement: document.body, panFactor: Math.PI / 20, tiltFactor: Math.PI / 20, truckFactor: 1, pedestalFactor: 1, dampingFactor: 0.7}; class K { constructor(t, e = {}) { this.enabled = false, this.cameraRig = t, Object.assign(this, V, e), this.pointerAdaptor = new P({domElement: e.domElement || V.domElement, dampingFactor: e.dampingFactor || V.dampingFactor}), this.onPointerMove = this.onPointerMove.bind(this); } isEnabled() { return this.enabled; } enable() { this.pointerAdaptor.connect(), this.pointerAdaptor.addEventListener("update", this.onPointerMove), this.enabled = true; } disable() { this.pointerAdaptor.disconnect(), this.pointerAdaptor.removeEventListener("update", this.onPointerMove), this.enabled = false; } update(t) { this.enabled && this.pointerAdaptor.update(t); } onPointerMove(t) { t.pointerCount === 0 && (this.cameraRig.do(m.Pan, -t.deltas.x * this.panFactor, u.Eyes), this.cameraRig.do(m.Tilt, -t.deltas.y * this.tiltFactor, u.Eyes), this.cameraRig.do(m.Truck, t.deltas.x * this.truckFactor, u.Eyes), this.cameraRig.do(m.Pedestal, t.deltas.y * this.pedestalFactor, u.Eyes)); } } !function(t, e) { e === void 0 && (e = {}); var i = e.insertAt; if (t && typeof document != "undefined") { var s = document.head || document.getElementsByTagName("head")[0], n = document.createElement("style"); n.type = "text/css", i === "top" && s.firstChild ? s.insertBefore(n, s.firstChild) : s.appendChild(n), n.styleSheet ? n.styleSheet.cssText = t : n.appendChild(document.createTextNode(t)); } }(".tb-ch {\n width: 350px;\n height: 100%;\n position: fixed;\n top: 0;\n left: 0;\n z-index: 99999;\n background-color: rgba(255, 255, 255, 0.8);\n box-sizing: border-box;\n overflow-x: visible;\n transition: all 0.2s ease-in-out;\n}\n .tb-ch.collapsed {\n left: -350px;\n }\n .tb-ch * {\n box-sizing: border-box;\n }\n .tb-ch button {\n text-transform: capitalize;\n cursor: pointer;\n }\n .tb-ch .btn-round {\n font-size: 1.8rem;\n line-height: 1;\n width: 2.5rem;\n height: 2.5rem;\n position: absolute;\n right: -3rem;\n bottom: 0.5rem;\n }\n .tb-ch .btn-round.collapse {\n bottom: 3.5rem;\n }\n .tb-ch .controls {\n position: absolute;\n bottom: 0;\n height: 185px;\n border-top: 1px solid black;\n padding: 0.5rem;\n width: 100%;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n }\n .tb-ch .btn-text {\n padding: 0.5rem;\n text-align: center;\n width: 100%;\n }\n .tb-ch input[type='range'] {\n width: 100%;\n }\n .tb-ch .pois {\n height: calc(100vh - 185px - 1rem);\n overflow: scroll;\n padding: 1rem 1rem 0;\n }\n .tb-ch .poi {\n margin-bottom: 1rem;\n }\n .tb-ch .poi h2 {\n font-size: 1rem;\n }\n .tb-ch .poi .wrapper {\n display: flex;\n flex-direction: row;\n }\n .tb-ch .poi img {\n display: block;\n max-width: 100%;\n min-width: 0;\n margin-right: 0.5rem;\n }\n .tb-ch .poi .poi-controls {\n display: flex;\n flex-direction: column;\n }\n .tb-ch .poi .poi-controls button {\n padding: 0.5rem;\n width: 2rem;\n height: 2rem;\n margin-bottom: 0.25rem;\n }\n .tb-ch .poi .poi-params {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n width: calc(100% - 2.5rem);\n }\n .tb-ch .poi label,\n .tb-ch .poi input,\n .tb-ch .poi select {\n width: 50%;\n font-size: 0.7rem;\n font-family: monospace;\n margin: 0.25rem 0;\n }\n .tb-ch .poi input {\n text-align: center;\n }\n"); const j = ["none", "power1", "power2", "power3", "power4", "sine", "expo", "circ"], Y = "visit", W = "remove", B = "duration", X = "ease", N = "move-up", Z = "move-down"; class H { constructor(t, e, i, s) { this.useSlerp = true, this.rig = t, this.controls = e, this.canvas = i, this.pois = [], this.currentIndex = null, this.doCapture = false, this.isPlaying = false, this.initUI(s); } capture() { this.doCapture = true; } update(t) { if (this.doCapture) { const t2 = this.canvas.toDataURL(); this.addPoi(t2), this.doCapture = false; } if (this.isPlaying) { this.playStartTime || (this.playStartTime = t, this.controls.disable(), this.rig.packTransform()); const e = (t - this.playStartTime) / 1e3; this.rig.setAnimationTime(e), e > this.animationClip.duration && (this.isPlaying = false, this.playStartTime = null, this.controls.enable(), this.rig.unpackTransform()); } } addPoi(t) { this.pois.push(Object.assign(Object.assign({}, this.rig.getWorldCoordinates()), {duration: 1, ease: "power1", image: t})), this.currentIndex = this.pois.length - 1, this.createClip(), this.render(); } updatePoi(t, e) { this.pois[t] = Object.assign(Object.assign({}, this.pois[t]), e); } movePoi(t, e) { if (t + e >= 0 && t + e < this.pois.length) { const i = this.pois[t]; this.pois[t] = this.pois[t + e], this.pois[t + e] = i, this.render(); } } removePoi(t) { this.pois.splice(t, 1), this.render(); } goToPoi(t) { const e = this.pois[t]; this.rig.flyTo(e.position, e.quaternion, e.duration, e.ease, this.useSlerp); } createClip() { if (this.pois.length > 0) { const e = [], i = [], s = [], a = new Vector3(), o = new Quaternion(), c = 10; let p2 = 0; for (let t = 0; t < this.pois.length - 1; t++) { const n = this.pois[t], r = this.pois[t + 1], h = {px: n.position.x, py: n.position.y, pz: n.position.z, qx: n.quaternion.x, qy: n.quaternion.y, qz: n.quaternion.z, qw: n.quaternion.w, slerpAmount: 0}, d = {px: r.position.x, py: r.position.y, pz: r.position.z, qx: r.quaternion.x, qy: r.quaternion.y, qz: r.quaternion.z, qw: r.quaternion.w, slerpAmount: 1, duration: r.duration, ease: r.ease}, m3 = gsap2.to(h, d); for (let t2 = 0; t2 < c; t2++) { const d2 = r.duration * (t2 / c); e.push(p2 + d2), m3.seek(d2), this.useSlerp ? o.slerpQuaternions(n.quaternion, r.quaternion, h.slerpAmount) : o.set(h.qx, h.qy, h.qz, h.qw), a.set(h.px, h.py, h.pz), o.toArray(s, s.length), a.toArray(i, i.length); } p2 += r.duration; } const m2 = this.pois[this.pois.length - 1]; m2.quaternion.toArray(s, s.length), m2.position.toArray(i, i.length), e.push(p2), this.animationClip = new AnimationClip(null, p2, [new VectorKeyframeTrack("Translation.position", e, i), new QuaternionKeyframeTrack("Rotation.quaternion", e, s)]), this.rig.setAnimationClip(this.animationClip); } } scrubClip(t) { this.pois.length > 0 && this.rig.setAnimationPercentage(t); } playClip() { this.pois.length > 0 && (this.isPlaying = true); } export() { if (this.pois.length > 0) { const t = {}; t.pois = this.pois.map((t2) => ({position: [t2.position.x, t2.position.y, t2.position.z], quaternion: [t2.quaternion.x, t2.quaternion.y, t2.quaternion.z, t2.quaternion.w], duration: t2.duration, ease: t2.ease})), this.animationClip && (t.animationClip = AnimationClip.toJSON(this.animationClip)); const e = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(t)), i = document.createElement("a"); i.href = "data:" + e, i.download = "camera-data.json", document.body.appendChild(i), i.click(), i.remove(); } } exportImages() { const t = document.createElement("a"); document.body.appendChild(t), this.pois.forEach((e, i) => { t.href = e.image, t.download = `camera-poi-${i}.png`, t.click(); }), t.remove(); } initUI(t) { this.drawer = document.createElement("div"), this.drawer.classList.add("tb-ch"); const e = document.createElement("button"); e.classList.add("btn-round", "add"), e.innerText = "+", e.onclick = this.capture.bind(this), this.collapseBtn = document.createElement("button"), this.collapseBtn.classList.add("btn-round", "collapse"), this.collapseBtn.innerText = "<", this.collapseBtn.onclick = this.collapse.bind(this); const i = document.createElement("div"); i.classList.add("controls"); const s = document.createElement("button"); s.classList.add("btn-text", "export"), s.innerText = "export JSON", s.onclick = this.export.bind(this); const n = document.createElement("button"); n.classList.add("btn-text", "export-images"), n.innerHTML = "export images", n.onclick = this.exportImages.bind(this); const a = document.createElement("button"); a.classList.add("btn-text", "play"), a.innerText = "play", a.onclick = this.playClip.bind(this); const o = document.createElement("input"); o.type = "range", o.min = "0", o.max = "1000", o.step = "0.1", o.value = "0"; const r = this.scrubClip.bind(this); o.onmousedown = () => this.rig.packTransform(), o.onmouseup = () => this.rig.unpackTransform(), o.oninput = (t2) => r(parseInt(t2.target.value) / 1e3), this.domList = document.createElement("div"), this.domList.classList.add("pois"), this.domList.onclick = this.handleEvents.bind(this), this.domList.onchange = this.handleEvents.bind(this), i.append(a, o, n, s), this.drawer.append(e, this.collapseBtn, this.domList, i); (t || document.body).append(this.drawer); } handleEvents(t) { const e = t.target.dataset.index; e && (t.target.classList.contains(Y) ? this.goToPoi(parseInt(e)) : t.target.classList.contains(W) ? this.removePoi(parseInt(e)) : t.target.classList.contains(B) ? this.updatePoi(parseInt(e), {duration: parseFloat(t.target.value)}) : t.target.classList.contains(X) ? this.updatePoi(parseInt(e), {ease: t.target.value}) : t.target.classList.contains(N) ? this.movePoi(parseInt(e), -1) : t.target.classList.contains(Z) && this.movePoi(parseInt(e), 1), this.createClip()); } collapse() { this.drawer.classList.contains("collapsed") ? (this.drawer.classList.remove("collapsed"), this.collapseBtn.innerText = "<") : (this.drawer.classList.add("collapsed"), this.collapseBtn.innerText = ">"); } render() { this.domList.innerHTML = "", this.pois.forEach((t, e) => { const i = document.createElement("div"); i.classList.add("poi"); const s = document.createElement("h2"); s.innerText = `${e + 1}.`; const n = document.createElement("div"); n.classList.add("wrapper"); const a = document.createElement("div"); a.classList.add("poi-controls"); const o = document.createElement("div"); o.classList.add("poi-params"); const r = new Image(); r.src = t.image; const h = document.createElement("label"); h.innerText = "Duration"; const d = document.createElement("input"); d.classList.add(B), d.dataset.index = `${e}`, d.type = "number", d.value = String(t.duration); const c = document.createElement("label"); c.innerText = "Easing"; const l = document.createElement("select"); l.classList.add(X), l.dataset.index = `${e}`; const p2 = j.map((e2) => { const i2 = document.createElement("option"); return i2.innerText = e2, i2.value = e2, i2.selected = e2 === t.ease, i2; }); l.append(...p2); const m2 = document.createElement("button"); m2.classList.add(W), m2.title = "Remove", m2.dataset.index = `${e}`, m2.innerText = "x"; const u2 = document.createElement("button"); u2.classList.add(Y), u2.title = "Visit", u2.dataset.index = `${e}`, u2.innerHTML = "→"; const g2 = document.createElement("button"); g2.classList.add(N), g2.title = "Move up", g2.dataset.index = `${e}`, g2.innerHTML = "↑"; const b2 = document.createElement("button"); b2.classList.add(Z), b2.title = "Move down", b2.dataset.index = `${e}`, b2.innerHTML = "↓", a.append(m2, u2, g2, b2), o.append(h, d, c, l), n.append(r, a), i.append(s, n, o), this.domList.appendChild(i); }); } } export {g as Axis, x as BaseAdaptor, m as CameraAction, H as CameraHelper, v as CameraRig, p as Damper, k as FreeMovementControls, E as KeyboardAdaptor, U as PathPointsControls, P as PointerAdaptor, u as RigComponent, T as ScrollAdaptor, I as ScrollControls, q as StoryPointsControls, L as SwipeAdaptor, K as ThreeDOFControls, F as WheelAdaptor}; export default null;