Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ import
.deprecated

# Static
static
static

# Test coverage
coverage
3,637 changes: 3,407 additions & 230 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
"build-lib": "tsc && vite build",
"build-static": "node scripts/generate-story-args.js && storybook build -o static && typedoc",
"lint": "eslint .",
"storybook": "node scripts/generate-story-args.js && storybook dev -p 6006"
"storybook": "node scripts/generate-story-args.js && storybook dev -p 6006",
"test": "jest --coverage",
"test:watch": "jest --watchAll --coverage"
},
"dependencies": {
"@react-three/drei": "^9.121.4",
Expand Down Expand Up @@ -80,6 +82,7 @@
"@types/d3-path": "^3.1.0",
"@types/d3-scale": "^4.0.8",
"@types/d3-selection": "^3.0.11",
"@types/jest": "^29.5.14",
"@types/lodash.filter": "^4.6.9",
"@types/node": "^22.12.0",
"@types/proj4": "^2.5.5",
Expand All @@ -94,11 +97,14 @@
"eslint-plugin-react-refresh": "^0.4.18",
"eslint-plugin-storybook": "^0.11.2",
"globals": "^15.14.0",
"jest": "^29.7.0",
"jest-cli": "^29.7.0",
"minimist": "^1.2.8",
"r3f-perf": "^7.2.1",
"rimraf": "^6.0.1",
"sass": "^1.83.1",
"storybook": "^8.5.5",
"ts-jest": "^29.2.6",
"typedoc": "^0.27.6",
"typescript": "^5.2.2",
"typescript-eslint": "^8.18.2",
Expand All @@ -114,5 +120,11 @@
"react": ">=18 <19",
"react-dom": ">=18 <19",
"three": ">=0.169"
},
"jest": {
"transform": {
".(ts|tsx)": "ts-jest"
},
"testRegex": "(/tests/.*|(\\.|/)test)\\.ts$"
}
}
3 changes: 3 additions & 0 deletions src/sdk/utils/numbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export function remap(
}

export const toRGB = (v: number) => {
if (v < 0) return [0, 0, 0]
if (v > 1677.215) return [255, 255, 255]

const m = Math.round(v * 1000)
const r = Math.floor(m / 65536)
const g = Math.floor(m / 256) - r * 256
Expand Down
30 changes: 20 additions & 10 deletions src/sdk/utils/vector-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export function negateVec3(vec: Vec3) {
vec[0] = -vec[0]
vec[1] = -vec[1]
vec[2] = -vec[2]

return vec
}

Expand Down Expand Up @@ -87,20 +86,20 @@ export function angleVec3(v1: Vec3, v2: Vec3): number {
}

export function rotateVec3(vector: Vec3, axis: Vec3 = [0, 1, 0], angle = 0) : Vec3 {
const c = Math.cos(angle);
const s = Math.sin(angle);
const c = Math.cos(angle)
const s = Math.sin(angle)

const t = 1 - c;

const vx = vector[0];
const vy = vector[1];
const vz = vector[2];
const vx = vector[0]
const vy = vector[1]
const vz = vector[2]

const ax = axis[0];
const ay = axis[1];
const az = axis[2];
const ax = axis[0]
const ay = axis[1]
const az = axis[2]

const tx = t * ax, ty = t * ay;
const tx = t * ax, ty = t * ay

return [
(tx * ax + c) * vx + (tx * ay - s * az) * vy + (tx * az + s * ay) * vz,
Expand All @@ -111,6 +110,10 @@ export function rotateVec3(vector: Vec3, axis: Vec3 = [0, 1, 0], angle = 0) : Ve


// Vec2
export function getVec2(buffer: number[], id: number): Vec2 {
return [buffer[id], buffer[id + 1]]
}

export function setVec2(buffer: number[], id: number, value: Vec2): void {
buffer[id] = value[0]
buffer[id + 1] = value[1]
Expand All @@ -131,6 +134,13 @@ export function subVec2(v1: Vec2, v2: Vec2): Vec2 {
return [v1[0] - v2[0], v1[1] - v2[1]]
}

export function negateVec2(vec: Vec2) {
vec[0] = -vec[0]
vec[1] = -vec[1]

return vec
}

export function scaleVec2(vec: Vec2, factor: number): Vec2 {
vec[0] = vec[0] * factor
vec[1] = vec[1] * factor
Expand Down
44 changes: 44 additions & 0 deletions tests/numbers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { clamp, inverseLerp, lerp, remap, toRGB } from '../src/sdk/utils/numbers'

describe('numbers', () => {
test('should clamp to min max', () => {
expect(clamp(1.1)).toBe(1)
expect(clamp(-0.1)).toBe(0)
expect(clamp(0.1)).toBe(0.1)
expect(clamp(2.4, 1, 2)).toBe(2)
expect(clamp(2.4, 1, 3)).toBe(2.4)
expect(clamp(2.4, 3, 10)).toBe(3)
})

test('should linearly interpolate between two numbers', () => {
expect(lerp(0, 1, 0)).toBe(0)
expect(lerp(0, 1, 0.5)).toBe(0.5)
expect(lerp(0, 1, 1)).toBe(1)
expect(lerp(0, 1, -1)).toBe(0)
expect(lerp(0, 1, 1.2)).toBe(1)
})

test('should find interpolation position (t) given a value along with min and max', () => {
expect(inverseLerp(0, 0, 1)).toBe(0)
expect(inverseLerp(0.5, 0, 1)).toBe(0.5)
expect(inverseLerp(1, 0, 1)).toBe(1)
expect(inverseLerp(1.5, 0, 1)).toBe(1.5)
expect(inverseLerp(-1, 0, 1)).toBe(-1)
expect(inverseLerp(125, 0, 200)).toBe(0.625)
})

test('should be able to remap a value from one range to another', () => {
expect(remap(50, 0, 100, 0, 1)).toBe(0.5)
expect(remap(0.5, 0, 1, 0, 100)).toBe(50)
})

test('should be able to map a positive float value (in the range 0-16777.215) to an array of rgb colors (0-255)', () => {
expect(toRGB(0)).toEqual([0, 0, 0])
expect(toRGB(1000)).toEqual([15, 66, 64])
expect(toRGB(1000.21)).toEqual([15, 67, 18])
expect(toRGB(16777.215)).toEqual([255, 255, 255])
expect(toRGB(-1)).toEqual([0, 0, 0])
expect(toRGB(16777.216)).toEqual([255, 255, 255])

})
})
25 changes: 25 additions & 0 deletions tests/trigonometry.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { edgeOfRectangle } from '../src/sdk/utils/trigonometry'

describe('trigonometry', () => {
test('should be able to find coordinates of closest edge given a rectangle dimensions and an angle', () => {
let edge = edgeOfRectangle([100, 50], Math.PI)
expect(edge[0]).toBeCloseTo(-50)
expect(edge[1]).toBeCloseTo(0)

edge = edgeOfRectangle([100, 50], Math.PI / 2)
expect(edge[0]).toBeCloseTo(0)
expect(edge[1]).toBeCloseTo(-25)

edge = edgeOfRectangle([100, 50], -Math.PI * 2)
expect(edge[0]).toBeCloseTo(50)
expect(edge[1]).toBeCloseTo(0)

edge = edgeOfRectangle([100, 50], Math.PI * 2)
expect(edge[0]).toBeCloseTo(50)
expect(edge[1]).toBeCloseTo(0)

edge = edgeOfRectangle([100, 50], -Math.PI / 2)
expect(edge[0]).toBeCloseTo(0)
expect(edge[1]).toBeCloseTo(25)
})
})
104 changes: 104 additions & 0 deletions tests/vector-operations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Vec3 } from '../src/sdk/types/common'
import { addVec2, addVec3, angleVec3, copyVec3, crossVec3, dotVec3, getVec2, getVec3, lengthVec2, lengthVec3, mixVec2, mixVec3, negateVec2, negateVec3, normalizeVec2, normalizeVec3, rotateVec3, scaleVec2, scaleVec3, setVec2, setVec3, subVec2, subVec3 } from '../src/sdk/utils/vector-operations'

describe('vector operations', () => {
test('should negate vectors', () => {
expect(negateVec2([1, -2])).toEqual([-1, 2])
expect(negateVec3([1, -2, 3])).toEqual([-1, 2, -3])
expect(negateVec2([0, 0])).toEqual([-0, -0])
})

test('should get vector from an array of numbers starting from specified index', () => {
const buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
expect(getVec3(buffer, 0)).toEqual([0, 1, 2])
expect(getVec3(buffer, 1)).toEqual([1, 2, 3])
expect(getVec3(buffer, 9)).toEqual([9, 10, undefined])
expect(getVec2(buffer, 9)).toEqual([9, 10])
})

test('should be able to update values of an array of numbers using vectors', () => {
const buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

setVec3(buffer, 3, [1, 1, 1])
expect(buffer).toEqual([0, 1, 2, 1, 1, 1, 6, 7, 8, 9, 10])

setVec2(buffer, 9, [0, 0])
expect(buffer).toEqual([0, 1, 2, 1, 1, 1, 6, 7, 8, 0, 0])
})

test('should be able to add vectors', () => {
expect(addVec2([1, 2], [-2, 0])).toEqual([-1, 2])
expect(addVec3([2, 1, 2], [3, -2, 0])).toEqual([5, -1, 2])
expect(addVec2([0, 0], [0, 0])).toEqual([0, 0])
expect(addVec2([1, 0], [0, 0])).toEqual([1, 0])
})

test('should be able to subtract vectors', () => {
expect(subVec2([1, 2], [-2, 0])).toEqual([3, 2])
expect(subVec3([2, 1, 2], [3, -2, 0])).toEqual([-1, 3, 2])
expect(subVec2([0, 0], [0, 0])).toEqual([0, 0])
expect(subVec2([1, 0], [0, 0])).toEqual([1, 0])
})

test('should be able to scale vectors', () => {
expect(scaleVec2([1, 2], 3)).toEqual([3, 6])
expect(scaleVec3([1, 2, 3], -1)).toEqual([-1, -2, -3])
expect(scaleVec3([1, 2, 3], 0)).toEqual([0, 0, 0])
})

test('should be able to calculate length of vectors', () => {
expect(lengthVec2([1, 0])).toBe(1)
expect(lengthVec2([0, 0])).toBe(0)
expect(lengthVec3([1, 0, 0])).toBe(1)
expect(lengthVec3([0, 0, 0])).toBe(0)
})

test('should be able to calculate cross product', () => {
expect(crossVec3([1, 0, 0], [0, 1, 0])).toEqual([0, 0, 1])
expect(crossVec3([0, 1, 0], [0, 1, 0])).toEqual([0, 0, 0])
})

test('should be able to calculate dot product', () => {
expect(dotVec3([1, 2, 0], [-1, 1, 0])).toEqual(1)
expect(dotVec3([0, 1, 0], [0, 1, 0])).toEqual(1)
expect(dotVec3([15, 2, -3], [1, 2, 5])).toEqual(4)
expect(dotVec3([1, 2, 5], [15, 2, -3])).toEqual(4)
})

test('should be able to normalize vectors', () => {
expect(normalizeVec2([10, 0])).toEqual([1, 0])
expect(normalizeVec2([0.1, 0])).toEqual([1, 0])
expect(normalizeVec3([10, 0, 0])).toEqual([1, 0, 0])
expect(normalizeVec3([0.1, 0, 0])).toEqual([1, 0, 0])
})

test('should be able to linearly mix vectors', () => {
expect(mixVec2([0, 1], [1, 0], 0)).toEqual([0, 1])
expect(mixVec2([0, 1], [1, 0], 1)).toEqual([1, 0])
expect(mixVec2([0, 1], [1, 0])).toEqual([0.5, 0.5])

expect(mixVec3([0, 1, 0], [1, 0, 10], 0)).toEqual([0, 1, 0])
expect(mixVec3([0, 1, 0], [1, 0, 10], 1)).toEqual([1, 0, 10])
expect(mixVec3([0, 1, 0], [1, 0, 10])).toEqual([0.5, 0.5, 5])
})

test('should be able to determine angle between vectors', () => {
expect(angleVec3([0, 1, 0], [1, 0, 0])).toBeCloseTo(Math.PI / 2, 7)
expect(angleVec3([0, 1, 0], [-1, 0, 0])).toBeCloseTo(Math.PI / 2, 7)
expect(angleVec3([1, 0, 0], [-1, 0, 0])).toBeCloseTo(Math.PI, 7)
expect(angleVec3([1, 0, 0], [0, 0, 0])).toBeCloseTo(Math.PI / 2)
})

test('should be able to rotate a vector around an axis', () => {
expect(rotateVec3([1, 0, 0])).toEqual([1, 0, 0])
expect(rotateVec3([1, 0, 0], [1, 0, 0], Math.PI / 4)).toEqual([1, 0, 0])
expect(rotateVec3([1, 0, 0], [0, 1, 0], Math.PI / 4)).toEqual([0.7071067811865476, 0, -0.7071067811865475])
})

test('should be able to copy a vector', () => {
const v: Vec3 = [1, 2, 3]
const copy = copyVec3(v)
expect(v).toEqual(copy)
expect(v).not.toBe(copy)
})
})
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["vite-plugin-glsl/ext"],
"types": ["vite-plugin-glsl/ext", "jest"],

/* Linting */
"strict": true,
Expand Down