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
59 changes: 20 additions & 39 deletions flock.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
setFlockReference as setFlockSensing,
} from "./api/sensing";
import { translate } from "./main/translation.js";
import { handleError, dismissBanner } from "./ui/notifications.js";

import {
enableSceneDescription,
Expand Down Expand Up @@ -414,7 +415,6 @@
}

flock.havokAbortHandled = true;
console.error(translate("physics_out_of_memory_log"), error);

try {
if (flock._renderLoop) {
Expand All @@ -436,30 +436,7 @@
);
}

const doc = flock.document;
if (!doc?.body) return;

const warningId = "havok-oom-warning";
if (doc.getElementById(warningId)) return;

const banner = doc.createElement("div");
banner.id = warningId;
banner.textContent = translate("physics_out_of_memory_banner_ui");
banner.style.position = "fixed";
banner.style.top = "0";
banner.style.left = "0";
banner.style.right = "0";
banner.style.padding = "12px";
banner.style.background = "#3b0b0b";
banner.style.color = "#ffb3b3";
banner.style.fontSize = "16px";
banner.style.fontFamily = "'Asap', sans-serif";
banner.style.zIndex = "10000";
banner.style.textAlign = "center";
banner.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.4)";
banner.style.borderBottom = "2px solid #d33";

doc.body.prepend(banner);
handleError(error, { source: "physics-oom", fatal: true });
},
validateCode(code) {
if (typeof code !== "string") {
Expand Down Expand Up @@ -896,15 +873,6 @@
const enhancedError = this.createEnhancedError?.(error, code) ?? error;
console.error("Enhanced error details:", enhancedError);

this.printText?.({
text: translate("runtime_error_message").replace(
"{message}",
error.message,
),
duration: 5,
color: "#ff0000",
});

try {
this.audioContext?.close?.();
this.engine?.stopRenderLoop?.();
Expand Down Expand Up @@ -1270,7 +1238,11 @@
manifoldMeshInstance: manifoldWasm.Mesh,
});
} catch (error) {
console.error("Error initializing CSG2:", error);
// CSG2 powers only boolean mesh blocks; the rest of the app still works.
console.warn(
"CSG2 unavailable; mesh boolean blocks are disabled.",
error,
);
}

flock.canvas.addEventListener(
Expand Down Expand Up @@ -1537,6 +1509,13 @@
lockstepMaxSteps: 4,
});

flock.engine.onContextLostObservable.add(() => {
handleError(new Error("WebGL context lost"), {
source: "webgl-lost",
fatal: true,
});
});

flock.engine.enableOfflineSupport = false;
flock.engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
},
Expand All @@ -1546,7 +1525,7 @@
if (flock.memoryDebug)
if(flock.hk)
{
const [result, stats] = flock.hk._hknp.HP_GetStatistics();

Check failure on line 1528 in flock.js

View workflow job for this annotation

GitHub Actions / eslint

'result' is assigned a value but never used. Allowed unused vars must match /^_/u

const [
numBodies,
Expand Down Expand Up @@ -1587,15 +1566,15 @@
md.heightmapBody._pluginData.hpBodyId,
);
}
} catch (e) {

Check failure on line 1569 in flock.js

View workflow job for this annotation

GitHub Actions / eslint

'e' is defined but never used
/* ignore */
}
try {
md.heightmapBody?.dispose();
} catch {}

Check failure on line 1574 in flock.js

View workflow job for this annotation

GitHub Actions / eslint

Empty block statement
try {
md.heightmapShape?.dispose();
} catch {}

Check failure on line 1577 in flock.js

View workflow job for this annotation

GitHub Actions / eslint

Empty block statement
md.heightmapBody = null;
md.heightmapShape = null;
}
Expand Down Expand Up @@ -1956,9 +1935,9 @@
flock.havokAbortHandled = false;
flock.disposed = false;

const existingOomBanner =
flock.document?.getElementById("havok-oom-warning");
existingOomBanner?.remove?.();
// Clear any error banner from a previous run now that we're starting fresh.
dismissBanner("physics-oom");
dismissBanner("project-run");

// Create the new scene
flock.scene = new flock.BABYLON.Scene(flock.engine);
Expand Down Expand Up @@ -2023,7 +2002,9 @@
flock.handlePhysicsOutOfMemory(error);
return;
}
throw error;
// Stop the loop so a crash doesn't re-fire every frame.
flock.engine?.stopRenderLoop(flock._renderLoop);
handleError(error, { source: "project-run", fatal: false });
}
};

Expand Down
8 changes: 8 additions & 0 deletions locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,14 @@ export default {
physics_out_of_memory_banner_ui:
"Physics engine ran out of memory. Try reducing the number of physics objects or reloading your project.",
runtime_error_message: "Error: {message}",
error_startup: "Flock couldn't start up. Try reloading the page.",
error_project_crash:
"Your project hit a problem. Press Stop, check your blocks, then press Play again.",
error_webgl_lost: "The 3D view stopped working. Try reloading the page.",
error_physics_oom:
"Your project ran out of memory. Try reloading the page and using fewer blocks.",
banner_reload: "Reload",
banner_dismiss: "Dismiss",
xr_mode_message: "XR Mode!",
fly_camera_instructions: "ℹ️ Fly camera, use arrow keys and page up/down",
select_mesh_delete_prompt: "ℹ️ Click an object to delete it.",
Expand Down
9 changes: 9 additions & 0 deletions locale/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,15 @@ export default {
physics_out_of_memory_banner_ui:
"El motor de física se quedó sin memoria. Intenta reducir el número de objetos físicos o recargar el proyecto.", // human
runtime_error_message: "Error: {mensaje}", // human
error_startup: "Flock no se pudo iniciar. Intenta recargar la página.", // human
error_project_crash:
"Tu proyecto tuvo un problema. Pulsa Detener, revisa tus bloques y pulsa Reproducir otra vez.", // human
error_webgl_lost:
"La vista 3D dejó de funcionar. Intenta recargar la página.", // human
error_physics_oom:
"Tu proyecto se quedó sin memoria. Recarga la página e intenta usar menos bloques.", // human
banner_reload: "Recargar", // human
banner_dismiss: "Cerrar", // human
xr_mode_message: "¡Modo XR!", // human
fly_camera_instructions: "ℹ️ Cámara en vuelo, usa las flechas y Page Up/Down", // human
select_mesh_delete_prompt: "ℹ️ Haz clic en un objeto para eliminarlo.", // Google translate
Expand Down
17 changes: 2 additions & 15 deletions main/execution.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { flock } from "../flock.js";
import { currentView, isNarrowScreen, showCanvasView } from "./view.js";
import { fetchProjectJson, loadWorkspaceAndExecute } from "./files.js";
import { handleError } from "../ui/notifications.js";
import { setGizmoManager, disposeGizmoManager } from "../ui/gizmos.js";
import { javascriptGenerator } from "blockly/javascript";
import { workspace } from "./blocklyinit.js";
Expand Down Expand Up @@ -46,21 +46,8 @@ export async function executeCode(options = {}) {
console.log(code);
await flock.runCode(code, options);
} catch (error) {
console.error("Error executing Blockly code:", error);
isExecuting = false; // Reset the flag if there's an error

// Load the starter project if execution fails
const starter = "examples/starter.flock";
fetchProjectJson(starter)
.then((json) => {
loadWorkspaceAndExecute(json, workspace, executeCode);
})
.catch((loadError) => {
console.error(
"Error loading starter project after execution failure:",
loadError,
);
});
handleError(error, { source: "project-run", fatal: false });
return; // Exit after handling the error
}

Expand Down
13 changes: 10 additions & 3 deletions main/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ import { AUTOSAVE_KEY } from "../config.js";

// Function to save the current workspace state
export function saveWorkspace(workspace) {
const state = Blockly.serialization.workspaces.save(workspace);
const key = AUTOSAVE_KEY;
localStorage.setItem(key, JSON.stringify(state));
try {
if (!workspace || !workspace.getAllBlocks) return;
const state = Blockly.serialization.workspaces.save(workspace);
// Never overwrite a good autosave with an empty/transient workspace —
// the error banner's Reload action restores the project from this entry.
if (!state || !state.blocks || !state.blocks.blocks?.length) return;
localStorage.setItem(AUTOSAVE_KEY, JSON.stringify(state));
} catch (error) {
console.warn("Autosave failed; keeping previous saved state.", error);
}
}

function validateBlocklyJson(json) {
Expand Down
23 changes: 17 additions & 6 deletions main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import "@babylonjs/inspector";
import { flock } from "../flock.js";
import { initializeVariableIndexes } from "../blocks/blocks";
import { enableGizmos } from "../ui/gizmos.js";
import {
handleError,
installGlobalErrorHandlers,
} from "../ui/notifications.js";
import { executeCode, stopCode } from "./execution.js";
import "../ui/addmeshes.js";
import "../ui/colourpicker.js";
Expand Down Expand Up @@ -1038,6 +1042,8 @@ function initializeApp() {
}

window.onload = async function () {
installGlobalErrorHandlers();

const blocklyContainer = document.getElementById("blocklyDiv");
if (!blocklyContainer) {
const standaloneScript = document.getElementById("flock");
Expand All @@ -1063,9 +1069,10 @@ window.onload = async function () {

createBlocklyWorkspace();
if (!workspace) {
console.error(
"Blockly workspace failed to initialize; aborting editor setup.",
);
handleError(new Error("Blockly workspace failed to initialize"), {
source: "startup",
fatal: true,
});
return;
}

Expand All @@ -1085,10 +1092,14 @@ window.onload = async function () {
}, 30000);

(async () => {
await flock.initialize();
try {
await flock.initialize();

// Hide loading screen once Flock is fully initialized
setTimeout(hideLoadingScreen, 500);
// Hide loading screen once Flock is fully initialized
setTimeout(hideLoadingScreen, 500);
} catch (error) {
handleError(error, { source: "startup", fatal: true });
}
})();
Comment thread
tracygardner marked this conversation as resolved.

//workspace.getToolbox().setVisible(false);
Expand Down
82 changes: 82 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
/* Shadow Colors */
--color-shadow: rgba(0, 0, 0, 0.1);
--color-shadow-medium: rgba(0, 0, 0, 0.2);

/* Error banner */
--color-error-bg: #b3261e;
--color-error-text: #ffffff;
--color-error-border: #7a1812;
}

/* Dark theme */
Expand Down Expand Up @@ -116,6 +121,11 @@

/* Scroll buttons */
--color-scroll-button-bg: rgba(0, 0, 0, 0.5);

/* Error banner */
--color-error-bg: #7a1812;
--color-error-text: #ffffff;
--color-error-border: #e0584f;
}

/* Dark high-contrast theme */
Expand Down Expand Up @@ -178,6 +188,11 @@

/* Scroll buttons */
--color-scroll-button-bg: rgba(0, 0, 0, 0.5);

/* Error banner */
--color-error-bg: #8b0000;
--color-error-text: #ffffff;
--color-error-border: #ff5252;
}

/* High‑contrast theme */
Expand Down Expand Up @@ -232,6 +247,11 @@
/* Shadow Colors */
--color-shadow: rgba(0, 0, 0, 0.1);
--color-shadow-medium: rgba(0, 0, 0, 0.2);

/* Error banner */
--color-error-bg: #c20000;
--color-error-text: #ffffff;
--color-error-border: #ffffff;
}

/* Low-vision theme */
Expand All @@ -256,6 +276,11 @@
--color-menu-hover: #2a2a2a;
--color-focus-ring: #e0e0e0;
--color-outline-focus: #e0e0e0;

/* Error banner */
--color-error-bg: #8b0000;
--color-error-text: #ffffff;
--color-error-border: #ffb4ab;
}


Expand Down Expand Up @@ -1728,3 +1753,60 @@ kbd {
#shortcuts-table {
margin-bottom: 1.5em;
}

/* Error notification banner */
.flock-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 20000;
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
font-family: "Asap", sans-serif;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove quotes around the font family name.

The font family name "Asap" should not be quoted according to CSS conventions for single-word font names.

📝 Proposed fix
-  font-family: "Asap", sans-serif;
+  font-family: Asap, sans-serif;

As per coding guidelines, stylelint flagged: Expected no quotes around "Asap".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
font-family: "Asap", sans-serif;
font-family: Asap, sans-serif;
🧰 Tools
🪛 GitHub Actions: Prettier / prettier

[warning] Prettier reported formatting issues.

🪛 Stylelint (17.11.1)

[error] 1768-1768: Expected no quotes around "Asap" (font-family-name-quotes)

(font-family-name-quotes)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@style.css` at line 1768, The font-family declaration uses quoted single-word
family name "Asap"; update the CSS rule containing the font-family property
(font-family: "Asap", sans-serif;) to remove the quotes so it reads font-family:
Asap, sans-serif; ensuring the change is made where the font-family property is
defined in the stylesheet.

font-size: 16px;
box-shadow: 0 2px 4px var(--color-shadow-medium);
}

.flock-banner--error {
background: var(--color-error-bg);
color: var(--color-error-text);
border-bottom: 2px solid var(--color-error-border);
}

.flock-banner__message {
flex: 1;
}

.flock-banner__action,
.flock-banner__close {
flex: none;
font-family: inherit;
color: var(--color-error-text);
background: transparent;
border: 1px solid var(--color-error-text);
border-radius: 4px;
cursor: pointer;
}

.flock-banner__action {
padding: 4px 12px;
font-size: 15px;
}

.flock-banner__close {
width: 28px;
height: 28px;
font-size: 18px;
line-height: 1;
}

.flock-banner__action:hover,
.flock-banner__close:hover,
.flock-banner__action:focus-visible,
.flock-banner__close:focus-visible {
background: var(--color-error-text);
color: var(--color-error-bg);
}
Loading
Loading