Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3661bbd
Redundancy and connection updates
tracygardner Mar 28, 2026
5fab575
Addressed issues with CSG materials tests failing
tracygardner Mar 28, 2026
39ae21e
rotateAnim didn't handle 0 duration
tracygardner Mar 28, 2026
f00bd19
Updated sound tests
tracygardner Mar 28, 2026
83db6e7
Update physics shape on instate rotation
tracygardner Mar 28, 2026
f169e85
Add tests for printText
tracygardner Mar 28, 2026
2a07510
Added missing UI component tests
tracygardner Mar 28, 2026
5f63bae
Added UI control tests
tracygardner Mar 28, 2026
5ff1e23
Added missing scene tests
tracygardner Mar 28, 2026
17b259a
Added events tests
tracygardner Mar 28, 2026
c79946f
Added missing physics tests
tracygardner Mar 28, 2026
93f59c6
Added missing movement tests
tracygardner Mar 28, 2026
2a1ee1f
Add mesh hierarchy tests for parentChild, removeParent, makeFollow, s…
tracygardner Mar 28, 2026
a717021
Add missing effects API tests: getMainLight, lightColor, startParticl…
tracygardner Mar 28, 2026
cd3ed53
Add math API tests: createVector3, randomInteger, seededRandom
tracygardner Mar 28, 2026
bf34455
Add shapes API tests (createCapsule, createPlane, create3DText) and a…
tracygardner Mar 28, 2026
06ba09e
Add sensing API tests: keyPressed, setActionKey, actionPressed, getTime
tracygardner Mar 28, 2026
6c0da09
Add material API tests: randomColour, changeColorMesh, changeMaterial
tracygardner Mar 28, 2026
80d6e49
Add physics API tests: setPhysicsShape, showPhysics
tracygardner Mar 28, 2026
b1e7f73
Add sound2 tests for setBPM and speak
tracygardner Mar 28, 2026
febc0ab
Add camera API tests for cameraControl, attachCamera, canvasControls
tracygardner Mar 28, 2026
563f52b
Add rotateToObject and positionAtSingleCoordinate tests
tracygardner Mar 28, 2026
4e6a7b7
Remove createGround — superseded by createMap
tracygardner Mar 28, 2026
5dfaf67
Add control API tests for waitUntil and safeLoop
tracygardner Mar 28, 2026
ce23268
Remove rumble methods; add XR tests for setCameraBackground and setXR…
tracygardner Mar 28, 2026
167a8f3
Add createModel tests using Flock.glb
tracygardner Mar 29, 2026
9313e83
Add initialize and createEngine tests to scene tests
tracygardner Mar 29, 2026
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
27 changes: 24 additions & 3 deletions api/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
const updateCapsuleShapeForAnimation = (
physicsMesh,
animationName,
{ fallYOffset = -0.4 } = {},

Check failure on line 21 in api/animate.js

View workflow job for this annotation

GitHub Actions / eslint

'fallYOffset' is assigned a value but never used
) => {
if (
!physicsMesh ||
Expand Down Expand Up @@ -136,10 +136,10 @@
easing = "Linear",
} = {},
) {
const rawDuration = Number(duration);
duration =
Number.isFinite(Number(duration)) && Number(duration) > 0
? Number(duration)
: 1;
Number.isFinite(rawDuration) && rawDuration > 0 ? rawDuration : 1;
const instant = Number.isFinite(rawDuration) && rawDuration === 0;
x = Number.isFinite(Number(x)) ? Number(x) : 0;
y = Number.isFinite(Number(y)) ? Number(y) : 0;
z = Number.isFinite(Number(z)) ? Number(z) : 0;
Expand All @@ -151,6 +151,27 @@
return;
}

if (instant) {
const targetRotation = new flock.BABYLON.Vector3(
x * (Math.PI / 180),
y * (Math.PI / 180),
z * (Math.PI / 180),
);
mesh.rotation = targetRotation;
mesh.computeWorldMatrix(true);

if (mesh.physics && mesh.physics._pluginData?.hpBodyId) {
mesh.physics.setTargetTransform(
mesh.absolutePosition,
mesh.absoluteRotationQuaternion ||
flock.BABYLON.Quaternion.FromEulerVector(mesh.rotation),
);
}

resolve();
return;
}

const children = mesh.getChildMeshes();

const childData = children.map((c) => ({
Expand Down Expand Up @@ -253,7 +274,7 @@
y = Number.isFinite(Number(y)) ? Number(y) : 0;
}

return new Promise(async (resolve) => {

Check failure on line 277 in api/animate.js

View workflow job for this annotation

GitHub Actions / eslint

Promise executor functions should not be async
await flock.whenModelReady(meshName, async function (mesh) {
if (mesh) {
const groundLevelSentinel = -999999;
Expand Down Expand Up @@ -375,7 +396,7 @@
easing = "Linear",
} = {},
) {
return new Promise(async (resolve) => {

Check failure on line 399 in api/animate.js

View workflow job for this annotation

GitHub Actions / eslint

Promise executor functions should not be async
await flock.whenModelReady(meshName1, async function (mesh1) {
if (!mesh1) {
resolve();
Expand Down Expand Up @@ -447,7 +468,7 @@
easing = "Linear",
} = {},
) {
return new Promise(async (resolve) => {

Check failure on line 471 in api/animate.js

View workflow job for this annotation

GitHub Actions / eslint

Promise executor functions should not be async
await flock.whenModelReady(meshName1, async function (mesh1) {
if (!mesh1) {
resolve();
Expand Down
2 changes: 1 addition & 1 deletion api/csg.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export const flockCSG = {
mergedMesh.metadata.blockKey = blockId;
mergedMesh.metadata.sharedMaterial = false;

return mergedMesh;
return modelId;
}

const originalMaterial = referenceMesh.material;
Expand Down
116 changes: 0 additions & 116 deletions api/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,6 @@ export const flockUI = {
button.height = `${size}px`;
button.color = color;
button.background = "transparent";
button.thickness = 0;
button.fontSize = `${40 * flock.displayScale}px`;
button.fontFamily = fontFamily;

Expand Down Expand Up @@ -374,11 +373,6 @@ export const flockUI = {
grid.height = `${160 * flock.displayScale}px`;
grid.horizontalAlignment = flock.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
grid.verticalAlignment = flock.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;

// Position it slightly away from the screen edge
grid.left = "20px";
grid.top = "-20px";

grid.addRowDefinition(1);
grid.addRowDefinition(1);
grid.addColumnDefinition(1);
Expand All @@ -396,14 +390,6 @@ export const flockUI = {
color,
);

// Add padding so buttons don't overlap touch areas
[upButton, downButton, leftButton, rightButton].forEach((b) => {
b.paddingTop = "4px";
b.paddingBottom = "4px";
b.paddingLeft = "4px";
b.paddingRight = "4px";
});

grid.addControl(upButton, 0, 1);
grid.addControl(leftButton, 1, 0);
grid.addControl(downButton, 1, 1);
Expand All @@ -418,11 +404,6 @@ export const flockUI = {
rightGrid.horizontalAlignment =
flock.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
rightGrid.verticalAlignment = flock.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;

// Position it away from the edge
rightGrid.left = "-20px";
rightGrid.top = "-20px";

rightGrid.addRowDefinition(1);
rightGrid.addRowDefinition(1);
rightGrid.addColumnDefinition(1);
Expand All @@ -435,103 +416,6 @@ export const flockUI = {
const button3 = flock.createSmallButton("③", "f", color);
const button4 = flock.createSmallButton("④", " ", color);

[button1, button2, button3, button4].forEach((b) => {
b.paddingTop = "4px";
b.paddingBottom = "4px";
b.paddingLeft = "4px";
b.paddingRight = "4px";
});

rightGrid.addControl(button1, 0, 0);
rightGrid.addControl(button2, 0, 1);
rightGrid.addControl(button3, 1, 0);
rightGrid.addControl(button4, 1, 1);
},
createSmallButton(text, keys, color) {
if (!flock.controlsTexture) return;

const keyList = Array.isArray(keys) ? keys : [keys];

const buttonId = `small-${text}-${Math.random().toString(36).slice(2)}`;
const button = flock.GUI.Button.CreateSimpleButton(buttonId, text);
button.width = `${70 * flock.displayScale}px`;
button.height = `${70 * flock.displayScale}px`;
button.color = color;
button.background = "transparent";
button.fontSize = `${40 * flock.displayScale}px`;

button.fontFamily = fontFamily;

button.onPointerDownObservable.add(() => {
keyList.forEach((key) => {
if (key == null) return;
flock.canvas.pressedButtons.add(key);
flock.gridKeyPressObservable.notifyObservers(key);
});
});

const releaseAction = () => {
keyList.forEach((key) => {
if (key == null) return;
flock.canvas.pressedButtons.delete(key);
flock.gridKeyReleaseObservable.notifyObservers(key);
});
};

button.onPointerUpObservable.add(releaseAction);
button.onPointerOutObservable.add(releaseAction);

return button;
},
createArrowControls(color) {
if (!flock.controlsTexture) return;

const grid = new flock.GUI.Grid();
grid.width = `${240 * flock.displayScale}px`;
grid.height = `${160 * flock.displayScale}px`;
grid.horizontalAlignment = flock.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
grid.verticalAlignment = flock.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
grid.addRowDefinition(1);
grid.addRowDefinition(1);
grid.addColumnDefinition(1);
grid.addColumnDefinition(1);
grid.addColumnDefinition(1);
flock.controlsTexture.addControl(grid);

const upButton = flock.createSmallButton("△", ["w", "ArrowUp"], color);
const downButton = flock.createSmallButton("▽", ["s", "ArrowDown"], color);
const leftButton = flock.createSmallButton("◁", ["a", "ArrowLeft"], color);
const rightButton = flock.createSmallButton(
"▷",
["d", "ArrowRight"],
color,
);

grid.addControl(upButton, 0, 1);
grid.addControl(leftButton, 1, 0);
grid.addControl(downButton, 1, 1);
grid.addControl(rightButton, 1, 2);
},
createButtonControls(color) {
if (!flock.controlsTexture) return;

const rightGrid = new flock.GUI.Grid();
rightGrid.width = `${160 * flock.displayScale}px`;
rightGrid.height = `${160 * flock.displayScale}px`;
rightGrid.horizontalAlignment =
flock.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
rightGrid.verticalAlignment = flock.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
rightGrid.addRowDefinition(1);
rightGrid.addRowDefinition(1);
rightGrid.addColumnDefinition(1);
rightGrid.addColumnDefinition(1);
flock.controlsTexture.addControl(rightGrid);

const button1 = flock.createSmallButton("①", "e", color);
const button2 = flock.createSmallButton("②", "r", color);
const button3 = flock.createSmallButton("③", "f", color);
const button4 = flock.createSmallButton("④", " ", color);

rightGrid.addControl(button1, 0, 0);
rightGrid.addControl(button2, 0, 1);
rightGrid.addControl(button3, 1, 0);
Expand Down
113 changes: 0 additions & 113 deletions api/xr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,6 @@ export function setFlockReference(ref) {
flock = ref;
}

const rumblePatterns = {
objectGrab: [
{ duration: 40, weakMagnitude: 0.1, strongMagnitude: 0.8, pauseAfter: 30 },
{ duration: 25, weakMagnitude: 0.1, strongMagnitude: 0.4, pauseAfter: 0 },
],
objectDrop: [
{ duration: 60, weakMagnitude: 0.3, strongMagnitude: 1.0, pauseAfter: 20 },
{ duration: 30, weakMagnitude: 0.1, strongMagnitude: 0.4, pauseAfter: 0 },
],
smallCollision: [
{ duration: 30, weakMagnitude: 0.5, strongMagnitude: 0.2, pauseAfter: 40 },
{ duration: 20, weakMagnitude: 0.2, strongMagnitude: 0.1, pauseAfter: 0 },
],
heavyCollision: [
{ duration: 100, weakMagnitude: 0.5, strongMagnitude: 1.0, pauseAfter: 30 },
{ duration: 60, weakMagnitude: 0.3, strongMagnitude: 0.7, pauseAfter: 40 },
{ duration: 30, weakMagnitude: 0.1, strongMagnitude: 0.3, pauseAfter: 0 },
],
snapToGrid: [
{ duration: 20, weakMagnitude: 0.0, strongMagnitude: 0.9, pauseAfter: 25 },
{ duration: 20, weakMagnitude: 0.0, strongMagnitude: 0.9, pauseAfter: 0 },
],
errorInvalid: [
{ duration: 50, weakMagnitude: 0.9, strongMagnitude: 0.1, pauseAfter: 25 },
{ duration: 40, weakMagnitude: 0.7, strongMagnitude: 0.1, pauseAfter: 20 },
{ duration: 50, weakMagnitude: 0.9, strongMagnitude: 0.1, pauseAfter: 30 },
{ duration: 30, weakMagnitude: 0.5, strongMagnitude: 0.0, pauseAfter: 0 },
],
successConfirmation: [
{ duration: 30, weakMagnitude: 0.1, strongMagnitude: 0.3, pauseAfter: 40 },
{ duration: 40, weakMagnitude: 0.2, strongMagnitude: 0.6, pauseAfter: 40 },
{ duration: 50, weakMagnitude: 0.3, strongMagnitude: 0.9, pauseAfter: 0 },
],
slidingGravel: [
{ duration: 40, weakMagnitude: 0.6, strongMagnitude: 0.2, pauseAfter: 25 },
{ duration: 25, weakMagnitude: 0.4, strongMagnitude: 0.1, pauseAfter: 20 },
{ duration: 50, weakMagnitude: 0.7, strongMagnitude: 0.3, pauseAfter: 30 },
{ duration: 30, weakMagnitude: 0.4, strongMagnitude: 0.1, pauseAfter: 20 },
{ duration: 45, weakMagnitude: 0.6, strongMagnitude: 0.2, pauseAfter: 0 },
],
slidingMetal: [
{ duration: 90, weakMagnitude: 0.05, strongMagnitude: 0.4, pauseAfter: 25 },
{ duration: 70, weakMagnitude: 0.05, strongMagnitude: 0.25, pauseAfter: 0 },
],
machineRunning: [
{ duration: 60, weakMagnitude: 0.2, strongMagnitude: 0.5, pauseAfter: 30 },
{ duration: 60, weakMagnitude: 0.2, strongMagnitude: 0.5, pauseAfter: 30 },
{ duration: 60, weakMagnitude: 0.2, strongMagnitude: 0.5, pauseAfter: 30 },
{ duration: 60, weakMagnitude: 0.2, strongMagnitude: 0.5, pauseAfter: 0 },
],
explosion: [
{ duration: 120, weakMagnitude: 0.8, strongMagnitude: 1.0, pauseAfter: 20 },
{ duration: 80, weakMagnitude: 0.6, strongMagnitude: 0.8, pauseAfter: 30 },
{ duration: 60, weakMagnitude: 0.3, strongMagnitude: 0.5, pauseAfter: 40 },
{ duration: 40, weakMagnitude: 0.1, strongMagnitude: 0.2, pauseAfter: 0 },
],
teleport: [
{ duration: 30, weakMagnitude: 0.1, strongMagnitude: 0.2, pauseAfter: 20 },
{ duration: 50, weakMagnitude: 0.3, strongMagnitude: 0.5, pauseAfter: 20 },
{ duration: 70, weakMagnitude: 0.5, strongMagnitude: 0.9, pauseAfter: 20 },
{ duration: 50, weakMagnitude: 0.3, strongMagnitude: 0.5, pauseAfter: 20 },
{ duration: 30, weakMagnitude: 0.1, strongMagnitude: 0.2, pauseAfter: 0 },
],
};

export const flockXR = {
/*
Category: Scene>XR
Expand Down Expand Up @@ -106,54 +41,6 @@ export const flockXR = {
},
);
},
controllerRumble(motor, strength, duration) {
const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
for (const gamepad of gamepads) {
if (!gamepad || !gamepad.vibrationActuator) continue;
const weakMagnitude = motor === "left" ? 0 : strength;
const strongMagnitude = motor === "right" ? 0 : strength;
gamepad.vibrationActuator.playEffect("dual-rumble", {
startDelay: 0,
duration: duration,
weakMagnitude: weakMagnitude,
strongMagnitude: strongMagnitude,
});
}
},
controllerRumblePattern(motor, strength, onDuration, offDuration, repeats) {
const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
for (const gamepad of gamepads) {
if (!gamepad || !gamepad.vibrationActuator) continue;
const weakMagnitude = motor === "left" ? 0 : strength;
const strongMagnitude = motor === "right" ? 0 : strength;
for (let i = 0; i < repeats; i++) {
gamepad.vibrationActuator.playEffect("dual-rumble", {
startDelay: i * (onDuration + offDuration),
duration: onDuration,
weakMagnitude: weakMagnitude,
strongMagnitude: strongMagnitude,
});
}
}
},
playRumblePattern(patternName) {
const pattern = rumblePatterns[patternName];
if (!pattern) return;
const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
for (const gamepad of gamepads) {
if (!gamepad || !gamepad.vibrationActuator) continue;
let startDelay = 0;
for (const pulse of pattern) {
gamepad.vibrationActuator.playEffect("dual-rumble", {
startDelay,
duration: pulse.duration,
weakMagnitude: pulse.weakMagnitude,
strongMagnitude: pulse.strongMagnitude,
});
startDelay += pulse.duration + pulse.pauseAfter;
}
}
},
async setXRMode(mode) {
await flock.initializeXR(mode);
flock.printText({
Expand Down
4 changes: 0 additions & 4 deletions flock.js
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,6 @@ export const flock = {
makeFollow: this.makeFollow?.bind(this),
stopFollow: this.stopFollow?.bind(this),
removeParent: this.removeParent?.bind(this),
createGround: this.createGround?.bind(this),
createMap: this.createMap?.bind(this),
setSky: this.setSky?.bind(this),
lightIntensity: this.lightIntensity?.bind(this),
Expand All @@ -988,9 +987,6 @@ export const flock = {
cameraControl: this.cameraControl?.bind(this),
setCameraBackground: this.setCameraBackground?.bind(this),
setXRMode: this.setXRMode?.bind(this),
controllerRumble: this.controllerRumble?.bind(this),
controllerRumblePattern: this.controllerRumblePattern?.bind(this),
playRumblePattern: this.playRumblePattern?.bind(this),
applyForce: this.applyForce?.bind(this),
moveByVector: this.moveByVector?.bind(this),
glideTo: this.glideTo?.bind(this),
Expand Down
4 changes: 2 additions & 2 deletions playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineConfig({
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
baseURL: "http://localhost:5173",
baseURL: "http://127.0.0.1:5173",
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "retain-on-failure",
Expand All @@ -22,7 +22,7 @@ export default defineConfig({
],
webServer: {
command: "npm run dev",
port: 5173,
url: "http://127.0.0.1:5173",
reuseExistingServer: !process.env.CI,
},
});
Loading
Loading