From 81f01b503217d34867a74cf3af4c4f52fa95deb7 Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:21:14 +0100 Subject: [PATCH 1/8] Change colour of error banners More friendly flock purple --- flock.js | 12 ++++++------ package-lock.json | 11 ++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/flock.js b/flock.js index d62df3bf3..03809da11 100644 --- a/flock.js +++ b/flock.js @@ -422,14 +422,14 @@ export const flock = { banner.style.left = "0"; banner.style.right = "0"; banner.style.padding = "12px"; - banner.style.background = "#3b0b0b"; - banner.style.color = "#ffb3b3"; + banner.style.background = "#511d91"; + banner.style.color = "#ffffff"; banner.style.fontSize = "16px"; banner.style.fontFamily = "'Asap', sans-serif"; banner.style.zIndex = "20000"; banner.style.textAlign = "center"; banner.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.4)"; - banner.style.borderBottom = "2px solid #d33"; + banner.style.borderBottom = "2px solid #3a1568"; doc.body.prepend(banner); }, handlePhysicsOutOfMemory(error) { @@ -708,14 +708,14 @@ export const flock = { banner.style.left = "0"; banner.style.right = "0"; banner.style.padding = "12px"; - banner.style.background = "#3b0b0b"; - banner.style.color = "#ffb3b3"; + banner.style.background = "#511d91"; + banner.style.color = "#ffffff"; banner.style.fontSize = "16px"; banner.style.fontFamily = "'Asap', sans-serif"; banner.style.zIndex = "20000"; banner.style.textAlign = "center"; banner.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.4)"; - banner.style.borderBottom = "2px solid #d33"; + banner.style.borderBottom = "2px solid #3a1568"; banner.style.cursor = "pointer"; banner.title = "Click to dismiss"; banner.addEventListener("click", () => banner.remove()); diff --git a/package-lock.json b/package-lock.json index a81aad09c..f9f12f001 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Flock", - "version": "0.0.0", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Flock", - "version": "0.0.0", + "version": "1.0.0", "dependencies": { "@babylonjs/addons": "^8.56.0", "@babylonjs/core": "^8.56.0", @@ -18,9 +18,11 @@ "@babylonjs/serializers": "^8.56.0", "@blockly/block-dynamic-connection": "^0.8.8", "@blockly/block-plus-minus": "^9.0.9", + "@blockly/block-shareable-procedures": "^6.0.10", "@blockly/field-colour": "^6.0.11", "@blockly/field-grid-dropdown": "^6.0.9", "@blockly/keyboard-navigation": "^3.0.3", + "@blockly/plugin-cross-tab-copy-paste": "^8.0.7", "@blockly/plugin-scroll-options": "^7.0.8", "@blockly/plugin-workspace-search": "^10.1.7", "@blockly/toolbox-search": "^3.1.8", @@ -33,7 +35,6 @@ "babylonjs-serializers": "^8.56.0", "blockly": "^12.3.1", "earcut": "^3.0.2", - "Flock": "file:", "manifold-3d": "^3.4.0", "opentype.js": "^1.3.4", "ses": "^1.15.0", @@ -5515,10 +5516,6 @@ "dev": true, "license": "ISC" }, - "node_modules/Flock": { - "resolved": "", - "link": true - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", From 254bddf2b38f7d48af9f4229f180e4acc7a605cb Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:32:10 +0100 Subject: [PATCH 2/8] Don't show error banners Just log errors to console --- flock.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flock.js b/flock.js index 03809da11..af5142ce5 100644 --- a/flock.js +++ b/flock.js @@ -95,6 +95,7 @@ export const flock = { callbackMode: true, separateAnimations: true, memoryDebug: false, + showErrorBanners: false, memoryMonitorInterval: 5000, materialsDebug: false, meshDebug: false, @@ -696,6 +697,10 @@ export const flock = { }); }, showRuntimeErrorBanner(message) { + if (!flock.showErrorBanners) { + flock.console?.error?.(message); + return; + } const doc = flock.document ?? globalThis.document; if (!doc?.body) return; const bannerId = "runtime-error-banner"; From 3ed4851798e4b2c5c1b9972200b5892aec706a89 Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:46:55 +0100 Subject: [PATCH 3/8] Guard say plane from glow Say plane was turning black when glow was applied --- api/material.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/material.js b/api/material.js index cb9642590..d923cb600 100644 --- a/api/material.js +++ b/api/material.js @@ -204,6 +204,9 @@ export const flockMaterial = { }, glowMesh(mesh, glowColor = null) { const applyGlow = (m) => { + // Don't glow the say plane. + if (m.name === "textPlane" || m.metadata?.isTextPlane) return; + m.metadata = m.metadata || {}; m.metadata.glow = true; From cd523ce7cc3a03f84dd92d8c1725d4293ae39233 Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:50:37 +0100 Subject: [PATCH 4/8] Stringify text colors --- generators/generators-material.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/generators-material.js b/generators/generators-material.js index 1925dad6a..4e890c459 100644 --- a/generators/generators-material.js +++ b/generators/generators-material.js @@ -91,7 +91,7 @@ export function registerMaterialGenerators(javascriptGenerator) { // Hex colour ------------------------------------------------- javascriptGenerator.forBlock["colour_from_string"] = function (block) { const colourValue = block.getFieldValue("COLOR") || "#000000"; - return [`"${colourValue}"`, javascriptGenerator.ORDER_ATOMIC]; + return [JSON.stringify(colourValue), javascriptGenerator.ORDER_ATOMIC]; }; // Set material of object ------------------------------------- From 8f8ac388787d8de240a17a698c789ac63b592c21 Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:07:22 +0100 Subject: [PATCH 5/8] Wrap endowed functions to prevent climbing --- flock.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/flock.js b/flock.js index af5142ce5..03843c41b 100644 --- a/flock.js +++ b/flock.js @@ -774,6 +774,15 @@ export const flock = { sesScript.text = sesText; doc.head.appendChild(sesScript); + // Re-wraps a host-realm fn into this realm; lockdown only tames this + // realm, so a raw host fn would leak the untamed Function via + // `.constructor` (sandbox escape). Must run before lockdown. + const wrapScript = doc.createElement("script"); + wrapScript.type = "text/javascript"; + wrapScript.text = + "window.__flockWrapHostFn = (fn) => (...args) => fn(...args);"; + doc.head.appendChild(wrapScript); + // lockdown the iframe realm win.lockdown(); @@ -806,8 +815,9 @@ export const flock = { for (const [key, value] of Object.entries(whitelist)) { const t = typeof value; if (t === "function") { - // Bind to null so we don't leak host `this` - endowments[key] = value.bind(null); + // Wrap into the iframe realm: a host-realm fn leaks the untamed host + // Function via `.constructor` (sandbox escape). bind(null) drops host `this`. + endowments[key] = win.__flockWrapHostFn(value.bind(null)); } else if (value == null || (t !== "object" && t !== "symbol")) { // primitives only endowments[key] = value; @@ -816,13 +826,15 @@ export const flock = { } } - endowments.performance = { - now: win.performance.now.bind(win.performance), - }; + // win.Object, not a host `{}`: a host literal leaks host Function via + // obj.constructor.constructor. + endowments.performance = new win.Object(); + endowments.performance.now = win.performance.now.bind(win.performance); endowments.requestAnimationFrame = win.requestAnimationFrame.bind(win); - endowments.Date = { now: win.Date.now.bind(win.Date) }; + endowments.Date = new win.Object(); + endowments.Date.now = win.Date.now.bind(win.Date); // Undefine unwanted globals // --- shadow unsafe / unneeded globals --- From 69819589dcef8252cbe5d98218719a74b56cd169 Mon Sep 17 00:00:00 2001 From: Tracy Gardner <14887827+tracygardner@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:14:11 +0100 Subject: [PATCH 6/8] Add overlay and hide gizmos when stopped --- index.html | 25 +++++++++++++++++++++ locale/de.js | 1 + locale/en.js | 1 + locale/es.js | 1 + locale/fr.js | 1 + locale/it.js | 1 + locale/pl.js | 1 + locale/pt.js | 1 + locale/sv.js | 1 + main/execution.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++ main/main.js | 7 ++++++ style.css | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 149 insertions(+) diff --git a/index.html b/index.html index f1da78c69..e2561b4e9 100644 --- a/index.html +++ b/index.html @@ -999,6 +999,31 @@