PageSourceSearch

https://www.vzome.com/modules/vzome-worker-static.js

js vzome.com collected 2026-09-24 20:35:49 UTC 21,384 bytes, 521 lines download raw bytes

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.