@flighthq/camera-controls 0.3.1-next.975.01aea94 → 0.4.0-edge.1908.751021c
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/dist/cameraShake.d.ts +7 -0
- package/dist/cameraShake.d.ts.map +1 -0
- package/dist/cameraShake.js +77 -0
- package/dist/cameraShake.js.map +1 -0
- package/dist/contract.d.ts +1 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -0
- package/dist/contract.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/cameraShake.test.ts +157 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CameraShake, CameraShakeOffset, CameraShakeOptions } from '@flighthq/types/contract';
|
|
2
|
+
export declare function addCameraShakeTrauma(shake: CameraShake, amount: number): void;
|
|
3
|
+
export declare function createCameraShake(options?: Readonly<CameraShakeOptions>): CameraShake;
|
|
4
|
+
export declare function createCameraShakeOffset(): CameraShakeOffset;
|
|
5
|
+
export declare function resetCameraShake(shake: CameraShake): void;
|
|
6
|
+
export declare function updateCameraShake(shake: CameraShake, dt: number, out: CameraShakeOffset): void;
|
|
7
|
+
//# sourceMappingURL=cameraShake.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cameraShake.d.ts","sourceRoot":"","sources":["../src/cameraShake.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE7E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,WAAW,CASrF;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAGzD;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,IAAI,CA8B9F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createEntity } from '@flighthq/entity/contract';
|
|
2
|
+
import { clamp } from '@flighthq/math/contract';
|
|
3
|
+
export function addCameraShakeTrauma(shake, amount) {
|
|
4
|
+
shake.trauma = clamp(shake.trauma + amount, 0, 1);
|
|
5
|
+
}
|
|
6
|
+
export function createCameraShake(options) {
|
|
7
|
+
return createEntity({
|
|
8
|
+
decay: options?.decay ?? 1.5,
|
|
9
|
+
frequency: options?.frequency ?? 15,
|
|
10
|
+
rotationAmplitude: options?.rotationAmplitude ?? 3,
|
|
11
|
+
time: 0,
|
|
12
|
+
translationAmplitude: options?.translationAmplitude ?? 0.5,
|
|
13
|
+
trauma: 0,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function createCameraShakeOffset() {
|
|
17
|
+
return { rotationX: 0, rotationY: 0, rotationZ: 0, x: 0, y: 0, z: 0 };
|
|
18
|
+
}
|
|
19
|
+
export function resetCameraShake(shake) {
|
|
20
|
+
shake.trauma = 0;
|
|
21
|
+
shake.time = 0;
|
|
22
|
+
}
|
|
23
|
+
// Advances the shake clock by `dt`, decays trauma, and writes the resulting additive offset into
|
|
24
|
+
// `out`. When trauma is zero the output is zeroed and no work is done beyond the decay check.
|
|
25
|
+
// The noise uses three incommensurate sine phases per axis — cheap, deterministic, and smooth.
|
|
26
|
+
export function updateCameraShake(shake, dt, out) {
|
|
27
|
+
shake.time += dt;
|
|
28
|
+
shake.trauma = Math.max(0, shake.trauma - shake.decay * dt);
|
|
29
|
+
if (shake.trauma <= 0) {
|
|
30
|
+
out.x = 0;
|
|
31
|
+
out.y = 0;
|
|
32
|
+
out.z = 0;
|
|
33
|
+
out.rotationX = 0;
|
|
34
|
+
out.rotationY = 0;
|
|
35
|
+
out.rotationZ = 0;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const intensity = shake.trauma * shake.trauma;
|
|
39
|
+
const t = shake.time * shake.frequency;
|
|
40
|
+
const tx = sampleNoise(t, SEED_TX_A, SEED_TX_B, SEED_TX_C);
|
|
41
|
+
const ty = sampleNoise(t, SEED_TY_A, SEED_TY_B, SEED_TY_C);
|
|
42
|
+
const tz = sampleNoise(t, SEED_TZ_A, SEED_TZ_B, SEED_TZ_C);
|
|
43
|
+
const rx = sampleNoise(t, SEED_RX_A, SEED_RX_B, SEED_RX_C);
|
|
44
|
+
const ry = sampleNoise(t, SEED_RY_A, SEED_RY_B, SEED_RY_C);
|
|
45
|
+
const rz = sampleNoise(t, SEED_RZ_A, SEED_RZ_B, SEED_RZ_C);
|
|
46
|
+
out.x = tx * intensity * shake.translationAmplitude;
|
|
47
|
+
out.y = ty * intensity * shake.translationAmplitude;
|
|
48
|
+
out.z = tz * intensity * shake.translationAmplitude;
|
|
49
|
+
out.rotationX = rx * intensity * shake.rotationAmplitude;
|
|
50
|
+
out.rotationY = ry * intensity * shake.rotationAmplitude;
|
|
51
|
+
out.rotationZ = rz * intensity * shake.rotationAmplitude;
|
|
52
|
+
}
|
|
53
|
+
// Three-frequency sine composite in [-1, 1]. The frequencies are incommensurate (prime-ratio
|
|
54
|
+
// multiples) so the combined signal has no visible loop period within any realistic shake duration.
|
|
55
|
+
function sampleNoise(t, seedA, seedB, seedC) {
|
|
56
|
+
return (Math.sin(t * seedA) + Math.sin(t * seedB) + Math.sin(t * seedC)) / 3;
|
|
57
|
+
}
|
|
58
|
+
// Frequency multipliers — irrational-ratio primes keep the combined waveform aperiodic.
|
|
59
|
+
const SEED_TX_A = 1.0;
|
|
60
|
+
const SEED_TX_B = 2.31;
|
|
61
|
+
const SEED_TX_C = 3.53;
|
|
62
|
+
const SEED_TY_A = 1.17;
|
|
63
|
+
const SEED_TY_B = 2.63;
|
|
64
|
+
const SEED_TY_C = 3.89;
|
|
65
|
+
const SEED_TZ_A = 1.37;
|
|
66
|
+
const SEED_TZ_B = 2.41;
|
|
67
|
+
const SEED_TZ_C = 3.71;
|
|
68
|
+
const SEED_RX_A = 1.53;
|
|
69
|
+
const SEED_RX_B = 2.79;
|
|
70
|
+
const SEED_RX_C = 3.47;
|
|
71
|
+
const SEED_RY_A = 1.71;
|
|
72
|
+
const SEED_RY_B = 2.17;
|
|
73
|
+
const SEED_RY_C = 3.91;
|
|
74
|
+
const SEED_RZ_A = 1.89;
|
|
75
|
+
const SEED_RZ_B = 2.53;
|
|
76
|
+
const SEED_RZ_C = 3.29;
|
|
77
|
+
//# sourceMappingURL=cameraShake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cameraShake.js","sourceRoot":"","sources":["../src/cameraShake.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.d.ts
CHANGED
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC"}
|
package/dist/contract.js
CHANGED
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { cloneFlyCameraController, cloneOrbitCameraController, copyFlyCameraController, copyOrbitCameraController, createFlyCameraController, createOrbitCameraController, dollyOrbitCameraController, frameOrbitCameraControllerToSphere, getPerspectiveProjectionFrameDistanceToSphere, lookFlyCameraController, moveFlyCameraController, panOrbitCameraController, panOrbitCameraControllerInViewPlane, resetFlyCameraController, resetOrbitCameraController, rotateOrbitCameraController, setOrthographicProjectionFrameToSphere, snapFlyCameraController, snapOrbitCameraController, updateCamera2DFollow, updateFlyCameraController, updateOrbitCameraController, } from './contract';
|
|
1
|
+
export { addCameraShakeTrauma, cloneFlyCameraController, cloneOrbitCameraController, copyFlyCameraController, copyOrbitCameraController, createCameraShake, createCameraShakeOffset, createFlyCameraController, createOrbitCameraController, dollyOrbitCameraController, frameOrbitCameraControllerToSphere, getPerspectiveProjectionFrameDistanceToSphere, lookFlyCameraController, moveFlyCameraController, panOrbitCameraController, panOrbitCameraControllerInViewPlane, resetCameraShake, resetFlyCameraController, resetOrbitCameraController, rotateOrbitCameraController, setOrthographicProjectionFrameToSphere, snapFlyCameraController, snapOrbitCameraController, updateCamera2DFollow, updateCameraShake, updateFlyCameraController, updateOrbitCameraController, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6CAA6C,EAC7C,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,mCAAmC,EACnC,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,sCAAsC,EACtC,uBAAuB,EACvB,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6CAA6C,EAC7C,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,mCAAmC,EACnC,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,sCAAsC,EACtC,uBAAuB,EACvB,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { cloneFlyCameraController, cloneOrbitCameraController, copyFlyCameraController, copyOrbitCameraController, createFlyCameraController, createOrbitCameraController, dollyOrbitCameraController, frameOrbitCameraControllerToSphere, getPerspectiveProjectionFrameDistanceToSphere, lookFlyCameraController, moveFlyCameraController, panOrbitCameraController, panOrbitCameraControllerInViewPlane, resetFlyCameraController, resetOrbitCameraController, rotateOrbitCameraController, setOrthographicProjectionFrameToSphere, snapFlyCameraController, snapOrbitCameraController, updateCamera2DFollow, updateFlyCameraController, updateOrbitCameraController, } from './contract';
|
|
1
|
+
export { addCameraShakeTrauma, cloneFlyCameraController, cloneOrbitCameraController, copyFlyCameraController, copyOrbitCameraController, createCameraShake, createCameraShakeOffset, createFlyCameraController, createOrbitCameraController, dollyOrbitCameraController, frameOrbitCameraControllerToSphere, getPerspectiveProjectionFrameDistanceToSphere, lookFlyCameraController, moveFlyCameraController, panOrbitCameraController, panOrbitCameraControllerInViewPlane, resetCameraShake, resetFlyCameraController, resetOrbitCameraController, rotateOrbitCameraController, setOrthographicProjectionFrameToSphere, snapFlyCameraController, snapOrbitCameraController, updateCamera2DFollow, updateCameraShake, updateFlyCameraController, updateOrbitCameraController, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6CAA6C,EAC7C,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,mCAAmC,EACnC,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,sCAAsC,EACtC,uBAAuB,EACvB,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6CAA6C,EAC7C,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,mCAAmC,EACnC,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,sCAAsC,EACtC,uBAAuB,EACvB,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,YAAY,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/camera-controls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-edge.1908.751021c",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/camera": "0.
|
|
42
|
-
"@flighthq/entity": "0.
|
|
43
|
-
"@flighthq/geometry": "0.
|
|
44
|
-
"@flighthq/math": "0.
|
|
45
|
-
"@flighthq/types": "0.
|
|
41
|
+
"@flighthq/camera": "0.4.0-edge.1908.751021c",
|
|
42
|
+
"@flighthq/entity": "0.4.0-edge.1908.751021c",
|
|
43
|
+
"@flighthq/geometry": "0.4.0-edge.1908.751021c",
|
|
44
|
+
"@flighthq/math": "0.4.0-edge.1908.751021c",
|
|
45
|
+
"@flighthq/types": "0.4.0-edge.1908.751021c"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"typescript": "^5.3.0"
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
addCameraShakeTrauma,
|
|
5
|
+
createCameraShake,
|
|
6
|
+
createCameraShakeOffset,
|
|
7
|
+
resetCameraShake,
|
|
8
|
+
updateCameraShake,
|
|
9
|
+
} from './cameraShake';
|
|
10
|
+
|
|
11
|
+
describe('addCameraShakeTrauma', () => {
|
|
12
|
+
it('accumulates trauma clamped to 1', () => {
|
|
13
|
+
const shake = createCameraShake();
|
|
14
|
+
addCameraShakeTrauma(shake, 0.3);
|
|
15
|
+
expect(shake.trauma).toBe(0.3);
|
|
16
|
+
addCameraShakeTrauma(shake, 0.5);
|
|
17
|
+
expect(shake.trauma).toBe(0.8);
|
|
18
|
+
addCameraShakeTrauma(shake, 0.5);
|
|
19
|
+
expect(shake.trauma).toBe(1);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('does not go below zero', () => {
|
|
23
|
+
const shake = createCameraShake();
|
|
24
|
+
addCameraShakeTrauma(shake, -1);
|
|
25
|
+
expect(shake.trauma).toBe(0);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('createCameraShake', () => {
|
|
30
|
+
it('creates with default values', () => {
|
|
31
|
+
const shake = createCameraShake();
|
|
32
|
+
expect(shake.trauma).toBe(0);
|
|
33
|
+
expect(shake.decay).toBe(1.5);
|
|
34
|
+
expect(shake.frequency).toBe(15);
|
|
35
|
+
expect(shake.translationAmplitude).toBe(0.5);
|
|
36
|
+
expect(shake.rotationAmplitude).toBe(3);
|
|
37
|
+
expect(shake.time).toBe(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('accepts custom options', () => {
|
|
41
|
+
const shake = createCameraShake({ decay: 2, frequency: 20, translationAmplitude: 1, rotationAmplitude: 5 });
|
|
42
|
+
expect(shake.decay).toBe(2);
|
|
43
|
+
expect(shake.frequency).toBe(20);
|
|
44
|
+
expect(shake.translationAmplitude).toBe(1);
|
|
45
|
+
expect(shake.rotationAmplitude).toBe(5);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('createCameraShakeOffset', () => {
|
|
50
|
+
it('creates a zeroed offset', () => {
|
|
51
|
+
const out = createCameraShakeOffset();
|
|
52
|
+
expect(out.x).toBe(0);
|
|
53
|
+
expect(out.y).toBe(0);
|
|
54
|
+
expect(out.z).toBe(0);
|
|
55
|
+
expect(out.rotationX).toBe(0);
|
|
56
|
+
expect(out.rotationY).toBe(0);
|
|
57
|
+
expect(out.rotationZ).toBe(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('resetCameraShake', () => {
|
|
62
|
+
it('zeros trauma and time', () => {
|
|
63
|
+
const shake = createCameraShake();
|
|
64
|
+
addCameraShakeTrauma(shake, 0.8);
|
|
65
|
+
const out = createCameraShakeOffset();
|
|
66
|
+
updateCameraShake(shake, 0.1, out);
|
|
67
|
+
expect(shake.trauma).toBeGreaterThan(0);
|
|
68
|
+
expect(shake.time).toBeGreaterThan(0);
|
|
69
|
+
resetCameraShake(shake);
|
|
70
|
+
expect(shake.trauma).toBe(0);
|
|
71
|
+
expect(shake.time).toBe(0);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('updateCameraShake', () => {
|
|
76
|
+
it('produces zero offset when trauma is zero', () => {
|
|
77
|
+
const shake = createCameraShake();
|
|
78
|
+
const out = createCameraShakeOffset();
|
|
79
|
+
updateCameraShake(shake, 1 / 60, out);
|
|
80
|
+
expect(out.x).toBe(0);
|
|
81
|
+
expect(out.y).toBe(0);
|
|
82
|
+
expect(out.z).toBe(0);
|
|
83
|
+
expect(out.rotationX).toBe(0);
|
|
84
|
+
expect(out.rotationY).toBe(0);
|
|
85
|
+
expect(out.rotationZ).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('produces non-zero offset when trauma is active', () => {
|
|
89
|
+
const shake = createCameraShake();
|
|
90
|
+
addCameraShakeTrauma(shake, 1);
|
|
91
|
+
const out = createCameraShakeOffset();
|
|
92
|
+
updateCameraShake(shake, 0.05, out);
|
|
93
|
+
const magnitude = Math.hypot(out.x, out.y, out.z);
|
|
94
|
+
expect(magnitude).toBeGreaterThan(0);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('decays trauma over time', () => {
|
|
98
|
+
const shake = createCameraShake({ decay: 2 });
|
|
99
|
+
addCameraShakeTrauma(shake, 1);
|
|
100
|
+
const out = createCameraShakeOffset();
|
|
101
|
+
updateCameraShake(shake, 0.25, out);
|
|
102
|
+
expect(shake.trauma).toBeCloseTo(0.5, 10);
|
|
103
|
+
updateCameraShake(shake, 0.25, out);
|
|
104
|
+
expect(shake.trauma).toBe(0);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('scales offset quadratically with trauma', () => {
|
|
108
|
+
const shake = createCameraShake({ decay: 0 });
|
|
109
|
+
const out = createCameraShakeOffset();
|
|
110
|
+
|
|
111
|
+
shake.trauma = 1;
|
|
112
|
+
shake.time = 0;
|
|
113
|
+
updateCameraShake(shake, 0.1, out);
|
|
114
|
+
const fullX = out.x;
|
|
115
|
+
|
|
116
|
+
shake.trauma = 0.5;
|
|
117
|
+
shake.time = 0;
|
|
118
|
+
updateCameraShake(shake, 0.1, out);
|
|
119
|
+
const halfX = out.x;
|
|
120
|
+
|
|
121
|
+
expect(Math.abs(halfX / fullX)).toBeCloseTo(0.25, 1);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('advances time deterministically', () => {
|
|
125
|
+
const shakeA = createCameraShake({ decay: 0 });
|
|
126
|
+
const shakeB = createCameraShake({ decay: 0 });
|
|
127
|
+
addCameraShakeTrauma(shakeA, 0.7);
|
|
128
|
+
addCameraShakeTrauma(shakeB, 0.7);
|
|
129
|
+
const outA = createCameraShakeOffset();
|
|
130
|
+
const outB = createCameraShakeOffset();
|
|
131
|
+
|
|
132
|
+
updateCameraShake(shakeA, 0.016, outA);
|
|
133
|
+
updateCameraShake(shakeA, 0.016, outA);
|
|
134
|
+
updateCameraShake(shakeB, 0.016, outB);
|
|
135
|
+
updateCameraShake(shakeB, 0.016, outB);
|
|
136
|
+
|
|
137
|
+
expect(outA.x).toBe(outB.x);
|
|
138
|
+
expect(outA.y).toBe(outB.y);
|
|
139
|
+
expect(outA.rotationZ).toBe(outB.rotationZ);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('keeps offsets within amplitude bounds', () => {
|
|
143
|
+
const shake = createCameraShake({ decay: 0, translationAmplitude: 1, rotationAmplitude: 5 });
|
|
144
|
+
addCameraShakeTrauma(shake, 1);
|
|
145
|
+
const out = createCameraShakeOffset();
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < 100; i += 1) {
|
|
148
|
+
updateCameraShake(shake, 0.01, out);
|
|
149
|
+
expect(Math.abs(out.x)).toBeLessThanOrEqual(1);
|
|
150
|
+
expect(Math.abs(out.y)).toBeLessThanOrEqual(1);
|
|
151
|
+
expect(Math.abs(out.z)).toBeLessThanOrEqual(1);
|
|
152
|
+
expect(Math.abs(out.rotationX)).toBeLessThanOrEqual(5);
|
|
153
|
+
expect(Math.abs(out.rotationY)).toBeLessThanOrEqual(5);
|
|
154
|
+
expect(Math.abs(out.rotationZ)).toBeLessThanOrEqual(5);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|