1import { 2 assemblePartsList, 3 commitToGitHub, 4 createPartsList, 5 normalizePreview 6} from "./chunk-RIUXEPIU.js"; 7import { 8 importLegacy, 9 importZomic, 10 resourceIndex 11} from "./chunk-YWNSTGG6.js"; 12import "./chunk-JSBRDJBE.js"; 13 14// src/worker/vzome-worker-static.js 15var WORKER_ENTRY_FILE_URL = import.meta.url; 16var baseURL; 17var design = {}; 18var IDENTITY_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; 19var DEFAULT_SNAPSHOT = -1; 20var prepareSceneResponse = (design2, snapshot) => { 21 const { embedding, polygons, snapshots, orientations, instances } = design2.rendered; 22 const snapshotInstances = snapshot === DEFAULT_SNAPSHOT ? instances : snapshots[snapshot]; 23 const shapes = {}; 24 for (const instance of snapshotInstances) { 25 const rotation = [...orientations[instance.orientation] || IDENTITY_MATRIX]; 26 if (!shapes[instance.shapeId]) { 27 shapes[instance.shapeId] = { ...design2.rendered.shapes[instance.shapeId], instances: [] }; 28 } 29 shapes[instance.shapeId].instances.push({ ...instance, rotation }); 30 } 31 const symmController = design2.wrapper?.controller?.symmController; 32 const parts = createPartsList(shapes, symmController); 33 const orbitSource = symmController?.getOrbitSource?.(); 34 const symmetryId = orbitSource ? `${orbitSource.getSymmetry().getField().getName()}:${orbitSource.getName()}` : void 0; 35 return { shapes, embedding, polygons, parts, orientations, symmetryId }; 36}; 37var prepareEditSceneResponse = (design2, edit, before) => { 38 let sceneInstances = design2.wrapper.getScene(edit, before); 39 if (!sceneInstances) { 40 edit = design2.wrapper.interpretToBreakpoint(edit, before); 41 sceneInstances = design2.wrapper.getScene(edit, before); 42 } 43 sceneInstances = { ...sceneInstances }; 44 const { polygons, orientations } = design2.rendered; 45 const shapes = {}; 46 for (const instance of Object.values(sceneInstances)) { 47 const rotation = [...orientations[instance.orientation] || IDENTITY_MATRIX]; 48 if (!shapes[instance.shapeId]) { 49 shapes[instance.shapeId] = { ...design2.rendered.shapes[instance.shapeId], instances: [] }; 50 } 51 shapes[instance.shapeId].instances.push({ ...instance, rotation }); 52 } 53 return { scene: { shapes, polygons, orientations }, edit }; 54}; 55var fetchUrlText = async (url) => { 56 let response; 57 try { 58 response = await fetch(url); 59 } catch (error) { 60 console.log(`Fetching ${url} failed with "${error}"; trying cors-anywhere`); 61 response = await fetch("https://cors-anywhere.herokuapp.com/" + url); 62 } 63 if (!response.ok) { 64 throw new Error(`Failed to fetch "${url}": ${response.statusText}`); 65 } 66 return response.text(); 67}; 68var fetchFileText = (selected) => { 69 const temporaryFileReader = new FileReader(); 70 return new Promise((resolve, reject) => { 71 temporaryFileReader.onerror = () => { 72 temporaryFileReader.abort(); 73 reject(temporaryFileReader.error); 74 }; 75 temporaryFileReader.onload = () => { 76 resolve(temporaryFileReader.result); 77 }; 78 temporaryFileReader.readAsText(selected); 79 }); 80}; 81var parts_catalog_url = "https://zometool.github.io/vzome-sharing/metadata/zometool-parts.json"; 82var partsPromise = fetch(parts_catalog_url).then((response) => response.text()).then((text) => JSON.parse(text)); 83var clientEvents = (report) => { 84 const sceneChanged = (scene, edit = "--START--") => report({ type: "SCENE_RENDERED", payload: { scene, edit } }); 85 const shapeDefined = (shape) => report({ type: "SHAPE_DEFINED", payload: shape }); 86 const instanceAdded = (instance) => report({ type: "INSTANCE_ADDED", payload: instance }); 87 const latestBallAdded = (instance) => report({ type: "LAST_BALL_CREATED", payload: instance }); 88 const instanceRemoved = (shapeId, id) => report({ type: "INSTANCE_REMOVED", payload: { shapeId, id } }); 89 const selectionToggled = (shapeId, id, selected) => report({ type: "SELECTION_TOGGLED", payload: { shapeId, id, selected } }); 90 const symmetryChanged = (details) => report({ type: "SYMMETRY_CHANGED", payload: details }); 91 const xmlParsed = (xmlTree) => report({ type: "DESIGN_XML_PARSED", payload: xmlTree }); 92 const propertyChanged = (controllerPath, name, value) => report({ type: "CONTROLLER_PROPERTY_CHANGED", payload: { controllerPath, name, value } }); 93 const errorReported = (message) => report({ type: "ALERT_RAISED", payload: message }); 94 const scenesDiscovered = (s) => report({ type: "SCENES_DISCOVERED", payload: s }); 95 const snapshotCaptured = (s) => report({ type: "SNAPSHOT_CAPTURED", payload: s }); 96 const textExported = (action2, text) => report({ type: "TEXT_EXPORTED", payload: { action: action2, text } }); 97 const buildPlaneSelected = (center, diskZone, hingeZone) => report({ type: "PLANE_CHANGED", payload: { center, diskZone, hingeZone } }); 98 return { 99 sceneChanged, 100 shapeDefined, 101 instanceAdded, 102 instanceRemoved, 103 selectionToggled, 104 symmetryChanged, 105 latestBallAdded, 106 xmlParsed, 107 scenesDiscovered, 108 snapshotCaptured, 109 propertyChanged, 110 errorReported, 111 textExported, 112 buildPlaneSelected 113 }; 114}; 115var createDesign = async (report, fieldName) => { 116 report({ type: "FETCH_STARTED", payload: { name: "untitled.vZome", preview: false } }); 117 try { 118 const legacy = await importLegacy(); 119 design = await legacy.newDesign(fieldName, clientEvents(report)); 120 report({ type: "CONTROLLER_CREATED" }); 121 reportDefaultScene(report); 122 } catch (error) { 123 console.log(`createDesign failure: ${error.message}`); 124 report({ type: "ALERT_RAISED", payload: "Failed to create vZome model." }); 125 return false;
126 } 127}; 128var resourcesPromise = null; 129var whenResourcesLoaded = async () => { 130 if (resourcesPromise === null) { 131 const legacy = await importLegacy(); 132 resourcesPromise = Promise.all(resourceIndex.map((path) => legacy.loadAndInjectResource(path, new URL(`/app/classic/resources/${path}`, baseURL)))); 133 } 134 return resourcesPromise; 135}; 136var openDesign = async (xmlLoading, name, report, debug, polygons, shapshot = DEFAULT_SNAPSHOT) => { 137 const events = clientEvents(report); 138 return Promise.all([importLegacy(), xmlLoading]).then(async ([legacy, xml]) => { 139 if (!xml) { 140 report({ type: "ALERT_RAISED", payload: "Unable to load .vZome content" }); 141 return; 142 } 143 const doLoad = async () => { 144 design = await legacy.loadDesign(xml, debug, polygons, events); 145 report({ type: "CONTROLLER_CREATED" }); 146 events.sceneChanged(prepareSceneResponse(design, shapshot)); 147 report({ type: "TEXT_FETCHED", payload: { text: xml, name } }); 148 }; 149 if (xml.includes("Zomic")) { 150 importZomic().then(async (zomic) => { 151 const api = await legacy.initialize(); 152 const field = api.getField("golden"); 153 field.setInterpreterModule(zomic); 154 doLoad().catch((error) => { 155 console.log(`openDesign failure: ${error.message}`); 156 report({ type: "ALERT_RAISED", payload: `Failed to load vZome model: ${error.message}` }); 157 }); 158 }).catch((error) => { 159 console.log(`openDesign failure: ${error.message}`); 160 report({ type: "ALERT_RAISED", payload: `Failed to load vZome model: ${error.message}` }); 161 }); 162 } else 163 doLoad().catch((error) => { 164 console.log(`openDesign failure: ${error.message}`); 165 report({ type: "ALERT_RAISED", payload: `Failed to load vZome model: ${error.message}` }); 166 }); 167 }).catch((error) => { 168 console.log(`openDesign failure: ${error.message}`); 169 report({ type: "ALERT_RAISED", payload: `Failed to load vZome model: ${error.message}` }); 170 }); 171}; 172var exportPreview = (camera, lighting, scenes) => { 173 const { snapshots: allShapshots, ...rest } = design.rendered; 174 const usedInScene = (snapshot) => scenes.some((scene) => Number(scene.snapshot) === snapshot); 175 const snapshots = allShapshots.map((snapshot, i) => usedInScene(i) ? snapshot : []); 176 scenes[0].camera = camera; 177 const rendered = { format: "online", ...rest, snapshots, scenes, lighting }; 178 return JSON.stringify(rendered, null, 2); 179}; 180var SCENE_UIS = { 181 "indexed": "indexed", 182 "indexed-camera": "indexed (load-camera)", 183 "titled": "menu (named)", 184 "all": "menu (all)", 185 "zometool": "zometool", 186 "none": "none" 187}; 188var shareToGitHub = async (target, config, data, report) => { 189 const { orgName, repoName, branchName } = target; 190 const { title, description, blog, publish, style, originalDate } = config; 191 const { name, camera, lighting, image, scenes } = data; 192 const preview = exportPreview(camera, lighting, scenes); 193 Promise.all([importLegacy(), whenResourcesLoaded()]).then(([module]) => { 194 const xml = design.wrapper.serializeVZomeXml(lighting, camera, scenes); 195 const creation = (originalDate || /* @__PURE__ */ new Date()).toISOString(); 196 const date = creation.substring(0, 10); 197 const time = creation.substring(11).replaceAll(":", "-").replaceAll(".", "-"); 198 const shareData = new module.GitHubShare(title, date, time, xml, image, preview); 199 const uploads = []; 200 shareData.setEntryHandler({ addEntry: (path, data2, encoding) => { 201 data2 && uploads.push({ path, encoding, data: data2 }); 202 } }); 203 const gitUrl = shareData.generateContent(orgName, repoName, branchName, title, description, blog, publish, SCENE_UIS[style]); 204 commitToGitHub(target, uploads, `Online share - ${name}`).then(() => { 205 report({ type: "SHARE_SUCCESS", payload: gitUrl }); 206 }).catch(({ message, status }) => { 207 report({ type: "SHARE_FAILURE", payload: { message, status } }); 208 }); 209 }); 210}; 211var textLoader = (report, payload) => { 212 const { name, contents } = payload; 213 const xmlLoading = new Promise((resolve) => resolve(contents)); 214 openDesign(xmlLoading, name, report, false, true); 215}; 216var fileLoader = (report, payload) => { 217 const { file, debug = false, polygons = true } = payload; 218 const { name } = file; 219 report({ type: "FETCH_STARTED", payload: { name, preview: false } }); 220 console.log(`%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% editing ${name}`); 221 const xmlLoading = fetchFileText(file); 222 xmlLoading.then((text) => report({ type: "TEXT_FETCHED", payload: { text } })); 223 openDesign(xmlLoading, name, report, debug, polygons); 224}; 225var doImport = (text, format, report) => { 226 const action2 = IMPORT_ACTIONS[format]; 227 try { 228 design.wrapper.doAction("", action2, { vef: text }); 229 reportDefaultScene(report); 230 } catch (error) { 231 console.log(`${action2} actionPerformed error: ${error.message}`); 232 report({ type: "ALERT_RAISED", payload: `Failed to perform action: ${action2}` }); 233 } 234}; 235var importDesign = async (report, url, format) => { 236 report({ type: "FETCH_STARTED", payload: { name: "untitled.vZome", preview: false } }); 237 try { 238 const text = await fetchUrlText(url); 239 let fieldName = "golden"; 240 if (format !== "vef") { 241 const json = JSON.parse(text); 242 fieldName = json.field || fieldName; 243 } 244 const legacy = await importLegacy(); 245 design = await legacy.newDesign(fieldName, clientEvents(report)); 246 report({ type: "CONTROLLER_CREATED" }); 247 doImport(text, format, report); 248 } catch (error) { 249 console.log(`importDesign failure: ${error.message}`); 250 report({ type: "ALERT_RAISED", payload: "Failed to import vZome model." }); 251 return false;
252 } 253}; 254var fileImporter = (report, payload) => { 255 const { file, format } = payload; 256 fetchFileText(file).then((text) => doImport(text, format, report)).catch((error) => { 257 console.log(error.message); 258 console.log("Import failed"); 259 }); 260}; 261var IMPORT_ACTIONS = { 262 "mesh": "ImportSimpleMeshJson", 263 "cmesh": "ImportColoredMeshJson", 264 "vef": "LoadVEF" 265}; 266var IMPORT_FORMATS = { 267 ".mesh.json": "mesh", 268 ".cmesh.json": "cmesh", 269 ".vef": "vef" 270}; 271var importFormat = (url) => { 272 const normalized = url.split(/[?#]/, 1)[0].toLowerCase(); 273 for (const extension of Object.keys(IMPORT_FORMATS)) { 274 if (normalized.endsWith(extension)) { 275 return IMPORT_FORMATS[extension]; 276 } 277 } 278 return void 0; 279}; 280var defaultLoad = { design: true, bom: false }; 281var urlLoader = async (report, payload) => { 282 const { url, config } = payload; 283 const { preview = false, debug = false, polygons = true, showScenes = "none", snapshot = DEFAULT_SNAPSHOT, load = defaultLoad, source = true } = config; 284 if (!url) { 285 throw new Error("No url field in URL_PROVIDED event payload"); 286 } 287 const name = url.split("\\").pop().split("/").pop(); 288 const format = importFormat(url); 289 if (!!format) { 290 return importDesign(report, url, format); 291 } 292 report({ type: "FETCH_STARTED", payload }); 293 console.log(`%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ${preview ? "previewing" : "interpreting "} ${url}`); 294 const xmlLoading = source && fetchUrlText(url); 295 source && xmlLoading.then((text) => report({ type: "TEXT_FETCHED", payload: { text, url } })); 296 const events = clientEvents(report); 297 if (preview) { 298 const previewUrl = url.substring(0, url.length - 6).concat(".shapes.json"); 299 return fetchUrlText(previewUrl).then((text) => JSON.parse(text)).then((preview2) => { 300 const { lighting, scenes, ...rendered } = preview2.format === "online" ? preview2 : normalizePreview(preview2); 301 if (Object.keys(rendered.shapes).length === 0) { 302 console.error(`No shapes in preview ${previewUrl}`); 303 console.log("Preview failed, falling back to vZome XML"); 304 openDesign(xmlLoading, name, report, debug, polygons, snapshot); 305 return; 306 } 307 if ((showScenes !== "none" || snapshot >= 0) && rendered.snapshots.length === 0) { 308 console.log(`No snapshots in preview ${previewUrl}`); 309 console.log("Preview failed, falling back to vZome XML"); 310 openDesign(xmlLoading, name, report, debug, polygons, snapshot); 311 return; 312 } 313 events.scenesDiscovered({ lighting, scenes }); 314 design.rendered = { ...rendered }; 315 events.sceneChanged(prepareSceneResponse(design, snapshot)); 316 }).catch((error) => { 317 console.log(error.message); 318 console.log("Preview failed, falling back to vZome XML"); 319 openDesign(xmlLoading, name, report, debug, polygons, snapshot); 320 }); 321 } else { 322 openDesign(xmlLoading, name, report, debug, polygons, snapshot); 323 } 324}; 325var reportDefaultScene = (report) => { 326 const { shapes, embedding, parts } = prepareSceneResponse(design, DEFAULT_SNAPSHOT); 327 clientEvents(report).sceneChanged({ shapes, embedding, polygons: true, parts }); 328}; 329onmessage = ({ data }) => { 330 const { type, payload, requestId, isInspector } = data; 331 if (typeof payload === "object") { 332 payload.polygons = !isInspector; 333 if (typeof payload.config === "object") { 334 payload.config.polygons = !isInspector; 335 } 336 } 337 const responseLogger = (message) => { 338 console.dir(message); 339 postMessage(message); 340 }; 341 let sendToClient = postMessage; 342 if (!!requestId) { 343 sendToClient = (message) => { 344 message.requestId = requestId; 345 postMessage(message); 346 }; 347 } 348 try { 349 switch (type) { 350 case "WORKER_PROBE": 351 sendToClient({ type: "WORKER_READY" }); 352 break; 353 case "WINDOW_LOCATION": 354 baseURL = payload; 355 break; 356 case "URL_PROVIDED": 357 urlLoader(sendToClient, payload); 358 break; 359 case "TEXT_PROVIDED": 360 textLoader(sendToClient, payload); 361 break; 362 case "FILE_PROVIDED": 363 fileLoader(sendToClient, payload); 364 break; 365 case "MESH_FILE_PROVIDED": 366 fileImporter(sendToClient, payload); 367 break; 368 case "SNAPSHOT_SELECTED": { 369 if (!design?.rendered?.snapshots) 370 break; 371 const { snapshot } = payload; 372 const scene = prepareSceneResponse(design, snapshot); 373 sendToClient({ type: "SCENE_RENDERED", payload: { scene } }); 374 break; 375 } 376 case "BOM_REQUESTED": { 377 partsPromise.then(({ colors }) => { 378 const bom = assemblePartsList(design.rendered, colors, payload); 379 sendToClient({ type: "BOM_CHANGED", payload: bom }); 380 }); 381 break; 382 } 383 case "EDIT_SELECTED": { 384 const { before, after } = payload; 385 const edit = before || after; 386 try { 387 const response = prepareEditSceneResponse(design, edit, !!before); 388 sendToClient({ type: "SCENE_RENDERED", payload: response }); 389 } catch (error) { 390 console.log(`EDIT_SELECTED error: ${error.message}`); 391 sendToClient({ type: "ALERT_RAISED", payload: error.message }); 392 } 393 break; 394 } 395 case "MACRO_TRIGGERED": { 396 try { 397 for (const actionData of payload) { 398 const { controllerPath, action: action2, parameters } = actionData; 399 design.wrapper.doAction(controllerPath, action2, parameters); 400 } 401 reportDefaultScene(sendToClient); 402 } catch (error) { 403 console.log(`Macro error: ${error.message}`); 404 sendToClient({ type: "ALERT_RAISED", payload: `Failed to complete macro.` }); 405 } 406 break; 407 } 408 case "EXPORT_TRIGGERED": { 409 const { format, camera, lighting, scenes } = payload; 410 if (format === "shapes") { 411 const preview = exportPreview(camera, lighting, scenes); 412 clientEvents(sendToClient).textExported("exportText", preview); 413 return; 414 } 415 if (!design?.wrapper) { 416 sendToClient({ type: "ALERT_RAISED", payload: `No design loaded; cannot export as ${format}.` }); 417 return; 418 } 419 if (format === "vZome") {
420 const xml = design.wrapper.serializeVZomeXml(lighting, camera, scenes); 421 clientEvents(sendToClient).textExported("exportText", xml); 422 return; 423 } 424 Promise.all([whenResourcesLoaded(), import("./exporters-QN2V3JA4.js")]).then(([, exporters]) => { 425 design.wrapper.doAction("", "exportText", { ...payload, exporters }); 426 }); 427 break; 428 } 429 case "ACTION_TRIGGERED": { 430 const { controllerPath, action: action2, parameters, polygons } = payload; 431 try { 432 if (action2 === "shareToGitHub") { 433 const { target, config, data: data2 } = parameters; 434 shareToGitHub(target, config, data2, sendToClient); 435 return; 436 } 437 if (action2 === "captureSnapshot") { 438 const { snapshots, instances } = design.rendered; 439 const snapshot = snapshots.length; 440 snapshots.push([...instances]); 441 design.wrapper.doAction(controllerPath, "Snapshot", { id: snapshot }); 442 clientEvents(sendToClient).snapshotCaptured(snapshot); 443 return; 444 } 445 if (action2 === "snapCamera") { 446 const symmController = design.wrapper.getControllerByPath(controllerPath); 447 const { up, lookDir } = parameters; 448 const result = design.wrapper.snapCamera(symmController.controller, up, lookDir); 449 sendToClient({ type: "CAMERA_SNAPPED", payload: { up: result.up, lookDir: result.lookDir } }); 450 return; 451 } 452 design.wrapper.doAction(controllerPath, action2, parameters); 453 reportDefaultScene(sendToClient); 454 } catch (error) { 455 console.log(`${action2} actionPerformed error: ${error.message}`); 456 sendToClient({ type: "ALERT_RAISED", payload: `Failed to perform action: ${action2}` }); 457 } 458 break; 459 } 460 case "PROPERTY_SET": { 461 const { controllerPath, name, value } = payload; 462 try { 463 design.wrapper.setProperty(controllerPath, name, value); 464 } catch (error) { 465 console.log(`${action} setProperty error: ${error.message}`); 466 sendToClient({ type: "ALERT_RAISED", payload: `Failed to set property: ${name}` }); 467 } 468 break; 469 } 470 case "PROPERTY_REQUESTED": { 471 const { controllerPath, propName, changeName, isList } = payload; 472 design.wrapper.registerPropertyInterest(controllerPath, propName, changeName, isList); 473 break; 474 } 475 case "NEW_DESIGN_STARTED": 476 const { field } = payload; 477 createDesign(sendToClient, field); 478 break; 479 case "STRUT_CREATION_TRIGGERED": 480 case "JOIN_BALLS_TRIGGERED": { 481 design.wrapper.doAction("buildPlane", type, payload); 482 reportDefaultScene(sendToClient); 483 break; 484 } 485 case "HINGE_STRUT_SELECTED": { 486 design.wrapper.doAction("buildPlane", type, payload); 487 break; 488 } 489 case "PREVIEW_STRUT_START": { 490 const { ballId, direction } = payload; 491 design.wrapper.startPreviewStrut(ballId, direction); 492 break; 493 } 494 case "PREVIEW_STRUT_MOVE": { 495 const { direction } = payload; 496 design.wrapper.movePreviewStrut(direction); 497 break; 498 } 499 case "PREVIEW_STRUT_SCALE": { 500 const { increment } = payload; 501 design.wrapper.scalePreviewStrut(increment); 502 break; 503 } 504 case "PREVIEW_STRUT_END": { 505 design.wrapper.endPreviewStrut(); 506 reportDefaultScene(sendToClient); 507 break; 508 } 509 default: 510 console.log("action not handled:", data, type, payload); 511 } 512 } catch (error) { 513 console.log(`${type} onmessage error: ${error.message}`); 514 sendToClient({ type: "ALERT_RAISED", payload: `Failed to perform action: ${type}` }); 515 } 516}; 517export { 518 DEFAULT_SNAPSHOT, 519 WORKER_ENTRY_FILE_URL, 520 whenResourcesLoaded 521};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.