@jscad/web 2.5.11 → 2.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/jscad-web.min.js +62 -59
  3. package/examples/CHANGELOG.md +11 -0
  4. package/examples/README.md +0 -4
  5. package/examples/package.json +1 -1
  6. package/package.json +7 -7
  7. package/postInstall.js +0 -1
  8. package/src/sideEffects/worker/index.js +7 -8
  9. package/src/ui/flow/design.js +10 -305
  10. package/src/ui/flow/reducers.js +304 -0
  11. package/examples/old/benchmark-cag.jscad +0 -27
  12. package/examples/old/benchmark-csg.jscad +0 -29
  13. package/examples/old/benchmark.jscad +0 -25
  14. package/examples/old/bunch-cubes.jscad +0 -17
  15. package/examples/old/complex/example001.jscad +0 -31
  16. package/examples/old/complex/example002.jscad +0 -25
  17. package/examples/old/complex/example003.jscad +0 -25
  18. package/examples/old/complex/example004.jscad +0 -16
  19. package/examples/old/complex/example005.jscad +0 -27
  20. package/examples/old/complex/globe.js +0 -235
  21. package/examples/old/complex/iphone4-case.js +0 -213
  22. package/examples/old/complex/umbilical_torus.js +0 -43
  23. package/examples/old/complex/umbilical_torus.scad +0 -37
  24. package/examples/old/core/cncCutout.js +0 -16
  25. package/examples/old/core/connectors/servo.js +0 -185
  26. package/examples/old/core/extrusions/extrudeLinear.js +0 -24
  27. package/examples/old/core/extrusions/extrudeRectangular.js +0 -21
  28. package/examples/old/core/extrusions/extrudeRotate.js +0 -43
  29. package/examples/old/core/extrusions/slices/four2three-round.js +0 -62
  30. package/examples/old/core/extrusions/slices/four2three.js +0 -53
  31. package/examples/old/core/extrusions/slices/jar-barrel.js +0 -60
  32. package/examples/old/core/extrusions/slices/jar.js +0 -69
  33. package/examples/old/core/extrusions/slices/non-aff.js +0 -72
  34. package/examples/old/core/extrusions/slices/rose.js +0 -52
  35. package/examples/old/core/extrusions/slices/screw.js +0 -34
  36. package/examples/old/core/extrusions/slices/screwDouble.js +0 -34
  37. package/examples/old/core/extrusions/slices/slices.js +0 -43
  38. package/examples/old/core/extrusions/slices/spring.js +0 -41
  39. package/examples/old/core/extrusions/slices/three2four.js +0 -42
  40. package/examples/old/core/extrusions/slices/tor.js +0 -30
  41. package/examples/old/core/hulls/hullChain.js +0 -58
  42. package/examples/old/core/lookup.js +0 -19
  43. package/examples/old/core/platonics/main.jscad +0 -42
  44. package/examples/old/core/platonics/maths_geodesic.jscad +0 -192
  45. package/examples/old/core/platonics/origv07/dualdodeca_difference.stl +0 -1962
  46. package/examples/old/core/platonics/origv07/dualdodeca_intersection.stl +0 -1374
  47. package/examples/old/core/platonics/origv07/dualdodeca_union.stl +0 -1822
  48. package/examples/old/core/platonics/origv07/maths_geodesic.scad +0 -162
  49. package/examples/old/core/platonics/origv07/platonic.scad +0 -483
  50. package/examples/old/core/platonics/origv07/test_platonic.scad +0 -616
  51. package/examples/old/core/platonics/platonic.jscad +0 -528
  52. package/examples/old/core/text/textSimplex.js +0 -625
  53. package/examples/old/core/transforms/transformations.js +0 -29
  54. package/examples/old/echo.jscad +0 -7
  55. package/examples/old/formats/scad/example001.scad +0 -26
  56. package/examples/old/formats/scad/example002.scad +0 -23
  57. package/examples/old/formats/scad/example003.scad +0 -20
  58. package/examples/old/formats/scad/example004.scad +0 -11
  59. package/examples/old/formats/scad/example005.scad +0 -20
  60. package/examples/old/json_logo.json +0 -1
  61. package/examples/old/parameters/axis-coupler.js +0 -149
  62. package/examples/old/parameters/celtic-knot-ring.js +0 -300
  63. package/examples/old/parameters/grille.js +0 -257
  64. package/examples/old/parameters/lamp-shade.js +0 -369
  65. package/examples/old/parameters/name-plate.js +0 -46
  66. package/examples/old/parameters/s-hook.js +0 -131
  67. package/examples/old/parameters/stepper-motor.js +0 -127
  68. package/examples/old/various/logo.js +0 -32
  69. package/examples/old/voxel.json +0 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.5.12](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/web@2.5.11...@jscad/web@2.5.12) (2022-07-17)
7
+
8
+
9
+ ### Performance Improvements
10
+
11
+ * **web:** changed to retain webworker process ([#1110](https://github.com/jscad/OpenJSCAD.org/issues/1110)) ([80a85b0](https://github.com/jscad/OpenJSCAD.org/commit/80a85b018f39b837bfbb5278b180fd2568eef283))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [2.5.11](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/web@2.5.10...@jscad/web@2.5.11) (2022-06-12)
7
18
 
8
19
  **Note:** Version bump only for package @jscad/web
@@ -7,7 +7,7 @@
7
7
  },{}],3:[function(require,module,exports){
8
8
  module.exports={
9
9
  "name": "@jscad/core",
10
- "version": "2.6.1",
10
+ "version": "2.6.2",
11
11
  "description": "Core functionality for JSCAD Applications",
12
12
  "homepage": "https://openjscad.xyz/",
13
13
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -43,9 +43,9 @@ module.exports={
43
43
  "license": "MIT",
44
44
  "dependencies": {
45
45
  "@jscad/array-utils": "2.1.4",
46
- "@jscad/io": "2.4.0",
47
- "@jscad/io-utils": "2.0.20",
48
- "@jscad/modeling": "2.9.5",
46
+ "@jscad/io": "2.4.1",
47
+ "@jscad/io-utils": "2.0.21",
48
+ "@jscad/modeling": "2.9.6",
49
49
  "json5": "2.2.0",
50
50
  "strip-bom": "4.0.0"
51
51
  },
@@ -177,7 +177,7 @@ const zipSync=require("fflate").zipSync,strToU8=require("fflate").strToU8,string
177
177
  },{"xmlchars/xml/1.0/ed5":37,"xmlchars/xml/1.1/ed2":38,"xmlchars/xmlns/1.0/ed3":39}],41:[function(require,module,exports){
178
178
  module.exports={
179
179
  "name": "@jscad/amf-deserializer",
180
- "version": "2.3.0",
180
+ "version": "2.3.1",
181
181
  "description": "AMF Deserializer for JSCAD",
182
182
  "repository": "https://github.com/jscad/OpenJSCAD.org/",
183
183
  "main": "src/index.js",
@@ -208,7 +208,7 @@ module.exports={
208
208
  ],
209
209
  "license": "MIT",
210
210
  "dependencies": {
211
- "@jscad/modeling": "2.9.5",
211
+ "@jscad/modeling": "2.9.6",
212
212
  "saxes": "5.0.1"
213
213
  },
214
214
  "devDependencies": {
@@ -266,7 +266,7 @@ const{geometries:geometries,maths:maths,primitives:primitives}=require("@jscad/m
266
266
  },{"./helpers":54,"@jscad/modeling":207}],57:[function(require,module,exports){
267
267
  module.exports={
268
268
  "name": "@jscad/dxf-deserializer",
269
- "version": "2.3.17",
269
+ "version": "2.3.18",
270
270
  "description": "DXF Deserializer for JSCAD",
271
271
  "homepage": "https://openjscad.xyz/",
272
272
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -294,7 +294,7 @@ module.exports={
294
294
  ],
295
295
  "license": "MIT",
296
296
  "dependencies": {
297
- "@jscad/modeling": "2.9.5"
297
+ "@jscad/modeling": "2.9.6"
298
298
  },
299
299
  "devDependencies": {
300
300
  "ava": "3.15.0",
@@ -350,7 +350,7 @@ const{flatten:flatten,toArray:toArray}=require("@jscad/array-utils"),version=req
350
350
  },{"./package.json":72,"@jscad/array-utils":520}],72:[function(require,module,exports){
351
351
  module.exports={
352
352
  "name": "@jscad/json-deserializer",
353
- "version": "2.0.21",
353
+ "version": "2.0.22",
354
354
  "description": "JSON Deserializer for JSCAD",
355
355
  "homepage": "https://openjscad.xyz/",
356
356
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -381,7 +381,7 @@ module.exports={
381
381
  "@jscad/array-utils": "2.1.4"
382
382
  },
383
383
  "devDependencies": {
384
- "@jscad/modeling": "2.9.5",
384
+ "@jscad/modeling": "2.9.6",
385
385
  "ava": "3.15.0",
386
386
  "nyc": "15.1.0"
387
387
  },
@@ -397,7 +397,7 @@ const{colors:colors,primitives:primitives}=require("@jscad/modeling"),version=re
397
397
  },{"./package.json":75,"@jscad/modeling":207}],75:[function(require,module,exports){
398
398
  module.exports={
399
399
  "name": "@jscad/obj-deserializer",
400
- "version": "2.0.20",
400
+ "version": "2.0.21",
401
401
  "description": "OBJ Deserializer for JSCAD",
402
402
  "homepage": "https://openjscad.xyz/",
403
403
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -429,7 +429,7 @@ module.exports={
429
429
  ],
430
430
  "license": "MIT",
431
431
  "dependencies": {
432
- "@jscad/modeling": "2.9.5"
432
+ "@jscad/modeling": "2.9.6"
433
433
  },
434
434
  "devDependencies": {
435
435
  "ava": "3.15.0",
@@ -447,7 +447,7 @@ const{maths:maths,primitives:primitives}=require("@jscad/modeling"),{BinaryReade
447
447
  },{"./package.json":78,"@jscad/io-utils":65,"@jscad/modeling":207}],78:[function(require,module,exports){
448
448
  module.exports={
449
449
  "name": "@jscad/stl-deserializer",
450
- "version": "2.1.17",
450
+ "version": "2.1.18",
451
451
  "description": "STL Deserializer for JSCAD",
452
452
  "homepage": "https://openjscad.xyz/",
453
453
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -479,8 +479,8 @@ module.exports={
479
479
  ],
480
480
  "license": "MIT",
481
481
  "dependencies": {
482
- "@jscad/io-utils": "2.0.20",
483
- "@jscad/modeling": "2.9.5"
482
+ "@jscad/io-utils": "2.0.21",
483
+ "@jscad/modeling": "2.9.6"
484
484
  },
485
485
  "devDependencies": {
486
486
  "ava": "3.15.0",
@@ -513,7 +513,7 @@ const{geometries:geometries,modifiers:modifiers}=require("@jscad/modeling"),{fla
513
513
  },{"xmlchars/xml/1.0/ed5":82,"xmlchars/xml/1.1/ed2":83,"xmlchars/xmlns/1.0/ed3":84}],86:[function(require,module,exports){
514
514
  module.exports={
515
515
  "name": "@jscad/svg-deserializer",
516
- "version": "2.5.0",
516
+ "version": "2.5.1",
517
517
  "description": "SVG Deserializer for JSCAD",
518
518
  "homepage": "https://openjscad.xyz/",
519
519
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -546,7 +546,7 @@ module.exports={
546
546
  "license": "MIT",
547
547
  "dependencies": {
548
548
  "@jscad/array-utils": "2.1.4",
549
- "@jscad/modeling": "2.9.5",
549
+ "@jscad/modeling": "2.9.6",
550
550
  "saxes": "5.0.1"
551
551
  },
552
552
  "devDependencies": {
@@ -583,7 +583,7 @@ const{geometries:geometries,maths:maths,measurements:measurements,utils:utils}=r
583
583
  },{}],95:[function(require,module,exports){
584
584
  module.exports={
585
585
  "name": "@jscad/svg-serializer",
586
- "version": "2.3.8",
586
+ "version": "2.3.9",
587
587
  "description": "SVG Serializer for JSCAD",
588
588
  "homepage": "https://openjscad.xyz/",
589
589
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -615,7 +615,7 @@ module.exports={
615
615
  ],
616
616
  "license": "MIT",
617
617
  "dependencies": {
618
- "@jscad/modeling": "2.9.5",
618
+ "@jscad/modeling": "2.9.6",
619
619
  "onml": "1.3.0"
620
620
  },
621
621
  "devDependencies": {
@@ -640,7 +640,7 @@ module.exports={
640
640
  },{"xmlchars/xml/1.0/ed5":96,"xmlchars/xml/1.1/ed2":97,"xmlchars/xmlns/1.0/ed3":98}],100:[function(require,module,exports){
641
641
  module.exports={
642
642
  "name": "@jscad/x3d-deserializer",
643
- "version": "2.2.0",
643
+ "version": "2.2.1",
644
644
  "description": "X3D Deserializer for JSCAD",
645
645
  "repository": "https://github.com/jscad/OpenJSCAD.org/",
646
646
  "main": "src/index.js",
@@ -667,7 +667,7 @@ module.exports={
667
667
  },
668
668
  "dependencies": {
669
669
  "@jscad/array-utils": "2.1.4",
670
- "@jscad/modeling": "2.9.5",
670
+ "@jscad/modeling": "2.9.6",
671
671
  "saxes": "5.0.1"
672
672
  },
673
673
  "devDependencies": {
@@ -878,9 +878,9 @@ const vec2=require("../../maths/vec2"),fromPoints=require("./fromPoints"),toPoin
878
878
  const vec2=require("../../maths/vec2"),vec3=require("../../maths/vec2"),appendPoints=require("./appendPoints"),toPoints=require("./toPoints"),appendBezier=(e,t)=>{let{controlPoints:o,segments:r}=Object.assign({},{segments:16},e);if(!Array.isArray(o))throw new Error("controlPoints must be an array of one or more points");if(o.length<1)throw new Error("controlPoints must be an array of one or more points");if(r<4)throw new Error("segments must be four or more");if(t.isClosed)throw new Error("the given geometry cannot be closed");const n=toPoints(t);if(n.length<1)throw new Error("the given path must contain one or more points (as the starting point for the bezier curve)");if(null===(o=o.slice())[0]){if(o.length<2)throw new Error("a null control point must be passed with one more control points");let e=n[n.length-2];if("lastBezierControlPoint"in t&&(e=t.lastBezierControlPoint),!Array.isArray(e))throw new Error("the given path must contain TWO or more points if given a null control point");const r=vec2.scale(vec2.create(),n[n.length-1],2);vec2.subtract(r,r,e),o[0]=r}o.unshift(n[n.length-1]);const s=o.length-1,i=[];let c=1;for(let e=0;e<=s;++e)e>0&&(c*=e),i.push(c);const a=[];for(let e=0;e<=s;++e){const t=i[s]/(i[e]*i[s-e]);a.push(t)}const l=vec2.create(),h=vec2.create(),p=vec3.create(),u=e=>{let t=1,r=Math.pow(1-e,s);const n=1!==e?1/(1-e):1,i=vec2.create();for(let c=0;c<=s;++c){c===s&&(r=1);const h=a[c]*t*r,p=vec2.scale(l,o[c],h);vec2.add(i,i,p),t*=e,r*=n}return i},v=[],f=[],m=s+1;for(let e=0;e<m;++e){const t=e/(m-1),o=u(t);v.push(o),f.push(t)}let g=1;const w=2*Math.PI/r,P=Math.sin(w);for(;g<v.length-1;){const e=vec2.subtract(l,v[g],v[g-1]);vec2.normalize(e,e);const t=vec2.subtract(h,v[g+1],v[g]);vec2.normalize(t,t);const o=vec2.cross(p,e,t);if(Math.abs(o[2])>P){const e=f[g-1],t=f[g+1],o=e+1*(t-e)/3,r=e+2*(t-e)/3,n=u(o),s=u(r);v.splice(g,1,n,s),f.splice(g,1,o,r),--g<1&&(g=1)}else++g}v.shift();const b=appendPoints(v,t);return b.lastBezierControlPoint=o[o.length-2],b};module.exports=appendBezier;
879
879
 
880
880
  },{"../../maths/vec2":305,"./appendPoints":168,"./toPoints":181}],168:[function(require,module,exports){
881
- const fromPoints=require("./fromPoints"),toPoints=require("./toPoints"),appendPoints=(o,t)=>{if(t.isClosed)throw new Error("cannot append points to a closed path");let n=toPoints(t);return n=n.concat(o),fromPoints({},n)};module.exports=appendPoints;
881
+ const concat=require("./concat"),create=require("./create"),appendPoints=(e,c)=>concat(c,create(e));module.exports=appendPoints;
882
882
 
883
- },{"./fromPoints":176,"./toPoints":181}],169:[function(require,module,exports){
883
+ },{"./concat":172,"./create":173}],169:[function(require,module,exports){
884
884
  const mat4=require("../../maths/mat4"),vec2=require("../../maths/vec2"),applyTransforms=r=>mat4.isIdentity(r.transforms)?r:(r.points=r.points.map(s=>vec2.transform(vec2.create(),s,r.transforms)),r.transforms=mat4.create(),r);module.exports=applyTransforms;
885
885
 
886
886
  },{"../../maths/mat4":258,"../../maths/vec2":305}],170:[function(require,module,exports){
@@ -890,7 +890,7 @@ const clone=e=>Object.assign({},e);module.exports=clone;
890
890
  const{EPS:EPS}=require("../../maths/constants"),vec2=require("../../maths/vec2"),clone=require("./clone"),close=e=>{if(e.isClosed)return e;const t=clone(e);if(t.isClosed=!0,t.points.length>1){const e=t.points,n=e[0];let o=e[e.length-1];for(;vec2.distance(n,o)<EPS*EPS&&(e.pop(),1!==e.length);)o=e[e.length-1]}return t};module.exports=close;
891
891
 
892
892
  },{"../../maths/constants":209,"../../maths/vec2":305,"./clone":170}],172:[function(require,module,exports){
893
- const fromPoints=require("./fromPoints"),toPoints=require("./toPoints"),{equals:equals}=require("../../maths/vec2"),concat=(...o)=>{let t=!1;for(const e of o){if(t)throw new Error("Cannot concatenate to a closed path");t=e.isClosed}let e=[];return o.forEach(o=>{const t=toPoints(o);e.length>0&&t.length>0&&equals(t[0],e[e.length-1])&&t.shift(),e=e.concat(t)}),fromPoints({closed:t},e)};module.exports=concat;
893
+ const fromPoints=require("./fromPoints"),toPoints=require("./toPoints"),{equals:equals}=require("../../maths/vec2"),concat=(...t)=>{let o=!1,e=[];return t.forEach((t,n)=>{const s=toPoints(t).slice();if(e.length>0&&s.length>0&&equals(s[0],e[e.length-1])&&s.shift(),s.length>0&&o)throw new Error(`Cannot concatenate to a closed path; check the ${n}th path`);o=t.isClosed,e=e.concat(s)}),fromPoints({closed:o},e)};module.exports=concat;
894
894
 
895
895
  },{"../../maths/vec2":305,"./fromPoints":176,"./toPoints":181}],173:[function(require,module,exports){
896
896
  const mat4=require("../../maths/mat4"),create=e=>(void 0===e&&(e=[]),{points:e,isClosed:!1,transforms:mat4.create()});module.exports=create;
@@ -1769,7 +1769,7 @@ const flatten=require("../../utils/flatten"),measureEpsilon=require("../../measu
1769
1769
  module.exports={generalize:require("./generalize"),snap:require("./snap")};
1770
1770
 
1771
1771
  },{"./generalize":463,"./snap":469}],465:[function(require,module,exports){
1772
- const constants=require("../../maths/constants"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),assert=!1,getTag=e=>`${e}`,addSide=(e,t,n,s,c,r)=>{const l=getTag(s),o=getTag(c);const i=`${l}/${o}`,g=`${o}/${l}`;if(e.has(g))return deleteSide(e,t,n,c,s,null),null;const a={vertex0:s,vertex1:c,polygonindex:r};return e.has(i)?e.get(i).push(a):e.set(i,[a]),l in t?t[l].push(i):t[l]=[i],o in n?n[o].push(i):n[o]=[i],i},deleteSide=(e,t,n,s,c,r)=>{const l=getTag(s),o=getTag(c),i=`${l}/${o}`;let g=-1;const a=e.get(i);for(let e=0;e<a.length;e++){const t=a[e];let n=getTag(t.vertex0);if(n===l&&((n=getTag(t.vertex1))===o&&(null===r||t.polygonindex===r))){g=e;break}}a.splice(g,1),0===a.length&&e.delete(i),g=t[l].indexOf(i),t[l].splice(g,1),0===t[l].length&&delete t[l],g=n[o].indexOf(i),n[o].splice(g,1),0===n[o].length&&delete n[o]},insertTjunctions=e=>{const t=new Map;for(let n=0;n<e.length;n++){const s=e[n],c=s.vertices.length;if(c>=3){let e=s.vertices[0],r=getTag(e);for(let l=0;l<c;l++){let o=l+1;o===c&&(o=0);const i=s.vertices[o],g=getTag(i),a=`${r}/${g}`,v=`${g}/${r}`;if(t.has(v)){const e=t.get(v);e.splice(-1,1),0===e.length&&t.delete(v)}else{const s={vertex0:e,vertex1:i,polygonindex:n};t.has(a)?t.get(a).push(s):t.set(a,[s])}e=i,r=g}}else console.warn("warning: invalid polygon found during insertTjunctions")}if(t.size>0){const n={},s={},c={};for(const[e,r]of t)c[e]=!0,r.forEach(t=>{const c=getTag(t.vertex0),r=getTag(t.vertex1);c in n?n[c].push(e):n[c]=[e],r in s?s[r].push(e):s[r]=[e]});const r=e.slice(0);for(;0!==t.size;){for(const e of t.keys())c[e]=!0;let e=!1;for(;;){const l=Object.keys(c);if(0===l.length)break;const o=l[0];let i=!0;if(t.has(o)){const l=t.get(o);0;const g=l[0];for(let l=0;l<2;l++){const o=0===l?g.vertex0:g.vertex1,a=0===l?g.vertex1:g.vertex0,v=getTag(o),d=getTag(a);let f=[];0===l?v in s&&(f=s[v]):v in n&&(f=n[v]);for(let g=0;g<f.length;g++){const v=f[g],u=t.get(v)[0],x=0===l?u.vertex0:u.vertex1,h=0===l?u.vertex1:u.vertex0,p=getTag(x);getTag(h);if(p===d){deleteSide(t,n,s,o,a,null),deleteSide(t,n,s,a,o,null),i=!1,l=2,e=!0;break}{const g=o,v=a,d=x,f=vec3.subtract(vec3.create(),d,g),h=vec3.dot(vec3.subtract(vec3.create(),v,g),f)/vec3.dot(f,f);if(h>0&&h<1){const o=vec3.scale(vec3.create(),f,h);if(vec3.add(o,o,g),vec3.squaredDistance(o,v)<constants.EPS*constants.EPS){const o=u.polygonindex,g=r[o],v=getTag(u.vertex1);let d=-1;for(let e=0;e<g.vertices.length;e++)if(getTag(g.vertices[e])===v){d=e;break}0;const f=g.vertices.slice(0);f.splice(d,0,a);const x=poly3.create(f);r[o]=x,deleteSide(t,n,s,u.vertex0,u.vertex1,o);const h=addSide(t,n,s,u.vertex0,a,o),p=addSide(t,n,s,a,u.vertex1,o);null!==h&&(c[h]=!0),null!==p&&(c[p]=!0),i=!1,l=2,e=!0;break}}}}}}i&&delete c[o]}if(!e)break}e=r}return t.clear(),e};module.exports=insertTjunctions;
1772
+ const constants=require("../../maths/constants"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),assert=!1,getTag=e=>`${e}`,addSide=(e,t,s,n,r,c)=>{const o=getTag(n),g=getTag(r);const l=`${o}/${g}`,a=`${g}/${o}`;if(e.has(a))return deleteSide(e,t,s,r,n,null),null;const i={vertex0:n,vertex1:r,polygonindex:c};return e.has(l)?e.get(l).push(i):e.set(l,[i]),t.has(o)?t.get(o).push(l):t.set(o,[l]),s.has(g)?s.get(g).push(l):s.set(g,[l]),l},deleteSide=(e,t,s,n,r,c)=>{const o=getTag(n),g=getTag(r),l=`${o}/${g}`;let a=-1;const i=e.get(l);for(let e=0;e<i.length;e++){const t=i[e];let s=getTag(t.vertex0);if(s===o&&((s=getTag(t.vertex1))===g&&(null===c||t.polygonindex===c))){a=e;break}}i.splice(a,1),0===i.length&&e.delete(l),a=t.get(o).indexOf(l),t.get(o).splice(a,1),0===t.get(o).length&&t.delete(o),a=s.get(g).indexOf(l),s.get(g).splice(a,1),0===s.get(g).length&&s.delete(g)},insertTjunctions=e=>{const t=new Map;for(let s=0;s<e.length;s++){const n=e[s],r=n.vertices.length;if(r>=3){let e=n.vertices[0],c=getTag(e);for(let o=0;o<r;o++){let g=o+1;g===r&&(g=0);const l=n.vertices[g],a=getTag(l),i=`${c}/${a}`,v=`${a}/${c}`;if(t.has(v)){const e=t.get(v);e.splice(-1,1),0===e.length&&t.delete(v)}else{const n={vertex0:e,vertex1:l,polygonindex:s};t.has(i)?t.get(i).push(n):t.set(i,[n])}e=l,c=a}}else console.warn("warning: invalid polygon found during insertTjunctions")}if(t.size>0){const s=new Map,n=new Map,r=new Map;for(const[e,c]of t)r.set(e,!0),c.forEach(t=>{const r=getTag(t.vertex0),c=getTag(t.vertex1);s.has(r)?s.get(r).push(e):s.set(r,[e]),n.has(c)?n.get(c).push(e):n.set(c,[e])});const c=e.slice(0);for(;0!==t.size;){for(const e of t.keys())r.set(e,!0);let e=!1;for(;;){const o=Array.from(r.keys());if(0===o.length)break;const g=o[0];let l=!0;if(t.has(g)){const o=t.get(g);0;const a=o[0];for(let o=0;o<2;o++){const g=0===o?a.vertex0:a.vertex1,i=0===o?a.vertex1:a.vertex0,v=getTag(g),d=getTag(i);let h=[];0===o?n.has(v)&&(h=n.get(v)):s.has(v)&&(h=s.get(v));for(let a=0;a<h.length;a++){const v=h[a],f=t.get(v)[0],u=0===o?f.vertex0:f.vertex1,x=0===o?f.vertex1:f.vertex0,p=getTag(u);getTag(x);if(p===d){deleteSide(t,s,n,g,i,null),deleteSide(t,s,n,i,g,null),l=!1,o=2,e=!0;break}{const a=g,v=i,d=u,h=vec3.subtract(vec3.create(),d,a),x=vec3.dot(vec3.subtract(vec3.create(),v,a),h)/vec3.dot(h,h);if(x>0&&x<1){const g=vec3.scale(vec3.create(),h,x);if(vec3.add(g,g,a),vec3.squaredDistance(g,v)<constants.EPS*constants.EPS){const g=f.polygonindex,a=c[g],v=getTag(f.vertex1);let d=-1;for(let e=0;e<a.vertices.length;e++)if(getTag(a.vertices[e])===v){d=e;break}0;const h=a.vertices.slice(0);h.splice(d,0,i);const u=poly3.create(h);c[g]=u,deleteSide(t,s,n,f.vertex0,f.vertex1,g);const x=addSide(t,s,n,f.vertex0,i,g),p=addSide(t,s,n,i,f.vertex1,g);null!==x&&r.set(x,!0),null!==p&&r.set(p,!0),l=!1,o=2,e=!0;break}}}}}}l&&r.delete(g)}if(!e)break}e=c}return t.clear(),e};module.exports=insertTjunctions;
1773
1773
 
1774
1774
  },{"../../geometries/poly3":194,"../../maths/constants":209,"../../maths/vec3":336}],466:[function(require,module,exports){
1775
1775
  const aboutEqualNormals=require("../../maths/utils/aboutEqualNormals"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),createEdges=e=>{const n=poly3.toPoints(e),t=[];for(let e=0;e<n.length;e++){const l=(e+1)%n.length,r={v1:n[e],v2:n[l]};t.push(r)}for(let e=0;e<t.length;e++){const l=(e+1)%n.length;t[e].next=t[l],t[l].prev=t[e]}return t},insertEdge=(e,n)=>{const t=`${n.v1}:${n.v2}`;e.set(t,n)},deleteEdge=(e,n)=>{const t=`${n.v1}:${n.v2}`;e.delete(t)},findOppositeEdge=(e,n)=>{const t=`${n.v2}:${n.v1}`;return e.get(t)},calculateAnglesBetween=(e,n,t)=>{let l=e.prev.v1,r=e.prev.v2,o=n.next.v2;const v=calculateAngle(l,r,o,t);return l=n.prev.v1,r=n.prev.v2,o=e.next.v2,[v,calculateAngle(l,r,o,t)]},v1=vec3.create(),v2=vec3.create(),calculateAngle=(e,n,t,l)=>{const r=vec3.subtract(v1,n,e),o=vec3.subtract(v2,t,n);return vec3.cross(r,r,o),vec3.dot(r,l)},createPolygonAnd=e=>{let n;const t=[];for(;e.next;){const n=e.next;t.push(e.v1),e.v1=null,e.v2=null,e.next=null,e.prev=null,e=n}return t.length>0&&(n=poly3.create(t)),n},mergeCoplanarPolygons=e=>{if(e.length<2)return e;const n=e[0].plane,t=e.slice(),l=new Map;for(;t.length>0;){const e=t.shift(),r=createEdges(e);for(let e=0;e<r.length;e++){const t=r[e],o=findOppositeEdge(l,t);if(o){const e=calculateAnglesBetween(t,o,n);if(e[0]>=0&&e[1]>=0){const n=o.next,r=t.next;t.prev.next=o.next,t.next.prev=o.prev,o.prev.next=t.next,o.next.prev=t.prev,t.v1=null,t.v2=null,t.next=null,t.prev=null,deleteEdge(l,o),o.v1=null,o.v2=null,o.next=null,o.prev=null;const v=(e,n,t)=>{const l={v1:t.v1,v2:n.v2,next:n.next,prev:t.prev};t.prev.next=l,n.next.prev=l,deleteEdge(e,n),n.v1=null,n.v2=null,n.next=null,n.prev=null,deleteEdge(e,t),t.v1=null,t.v2=null,t.next=null,t.prev=null};0===e[0]&&v(l,n,n.prev),0===e[1]&&v(l,r,r.prev)}}else t.next&&insertEdge(l,t)}}const r=[];return l.forEach(e=>{const n=createPolygonAnd(e);n&&r.push(n)}),l.clear(),r},coplanar=(e,n)=>Math.abs(e[3]-n[3])<1.5e-7&&aboutEqualNormals(e,n),mergePolygons=(e,n)=>{const t=[];n.forEach(e=>{const n=t.find(n=>coplanar(n[0],poly3.plane(e)));if(n){n[1].push(e)}else t.push([poly3.plane(e),[e]])});let l=[];return t.forEach(e=>{const n=e[1],t=mergeCoplanarPolygons(n);l=l.concat(t)}),l};module.exports=mergePolygons;
@@ -3079,7 +3079,7 @@ var bundleFn=arguments[3],sources=arguments[4],cache=arguments[5],stringify=JSON
3079
3079
  },{}],782:[function(require,module,exports){
3080
3080
  module.exports={
3081
3081
  "name": "@jscad/web",
3082
- "version": "2.5.11",
3082
+ "version": "2.5.12",
3083
3083
  "description": "Web Application for JSCAD",
3084
3084
  "homepage": "https://openjscad.xyz/",
3085
3085
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -3115,11 +3115,11 @@ module.exports={
3115
3115
  "license": "MIT",
3116
3116
  "dependencies": {
3117
3117
  "@jscad/array-utils": "2.1.4",
3118
- "@jscad/core": "2.6.1",
3119
- "@jscad/examples": "2.4.1",
3120
- "@jscad/io": "2.4.0",
3121
- "@jscad/modeling": "2.9.5",
3122
- "@jscad/regl-renderer": "2.6.1",
3118
+ "@jscad/core": "2.6.2",
3119
+ "@jscad/examples": "2.4.2",
3120
+ "@jscad/io": "2.4.1",
3121
+ "@jscad/modeling": "2.9.6",
3122
+ "@jscad/regl-renderer": "2.6.2",
3123
3123
  "@most/create": "2.0.1",
3124
3124
  "brace": "0.11.1",
3125
3125
  "codemirror": "5.65.2",
@@ -3191,7 +3191,7 @@ const most=require("most"),withLatestFrom=(t,o)=>s=>most.sample(t,s,o,s);module.
3191
3191
  },{"most":739}],796:[function(require,module,exports){
3192
3192
  const{getFileExtensionFromString:getFileExtensionFromString}=require("@jscad/core").utils,callbackToObservable=require("../../most-utils/callbackToObservable"),makeLogger=require("../../utils/logger"),makeDatSideEffect=async e=>{const a=callbackToObservable(),{logging:t}=Object.assign({},{logging:!1},e),n=makeLogger({enabled:t});let r=!0;const i=window.DatArchive;i||(n.error("Dat archives not supported in this environment!"),r=!1);return{source:()=>a.stream.multicast(),sink:e=>{let t,l,o,s=[];e.forEach(e=>{const{type:c,id:d,urls:m,path:u}=e;if(!r)return void a.callback({type:c,id:d,error:new Error("Dat archives not supported in this environment!")});const h={unhandled:()=>{a.callback({type:c,id:d,error:new Error(`Dat: no handler found for command ${c}`)})},read:()=>{m.map(async e=>{e=e.replace(" ","+"),l=e,t=new i(e,{});const n=await t.readdir(u,{recursive:!0,stat:!0}),r=await Promise.all(n.map(async e=>{const a=`${u}/${e.name}`;if(e.stat.isFile()&&e.name.includes("js"))return{content:await t.readFile(a),name:e.name,fullPath:e.name,isFile:!0}})),m=await t.getInfo();o=m.title||"unnamed";const h=r.filter(e=>void 0!==e).map(e=>({name:e.name,ext:getFileExtensionFromString(e.name),source:e.content,fullPath:`/${o}/`+e.fullPath}));s=[{children:h,fullPath:`/${o}`,name:o}],a.callback({type:c,id:d,url:e,data:s}),await t.history()})},write:()=>{n.warning("writing to dat archives is not implemented yet")},watch:()=>{t.watch().addEventListener("changed",async({path:e})=>{const n=await t.readFile(e),r={name:require("path").basename(e),ext:"js",source:n,fullPath:`/${o}`+e},i=s[0].children.findIndex(e=>e.fullPath===r.fullPath);(s=JSON.parse(JSON.stringify(s)))[0].children[i]=r,a.callback({type:"read",id:"loadRemote",url:l,data:s})})}};(h[c]||h.unhandled)()})}}};module.exports=makeDatSideEffect;
3193
3193
 
3194
- },{"../../most-utils/callbackToObservable":791,"../../utils/logger":833,"@jscad/core":19,"path":683}],797:[function(require,module,exports){
3194
+ },{"../../most-utils/callbackToObservable":791,"../../utils/logger":834,"@jscad/core":19,"path":683}],797:[function(require,module,exports){
3195
3195
  const most=require("most"),morph=require("morphdom"),{proxy:proxy}=require("most-proxy"),makeDomSideEffect=({targetEl:e})=>{const{attach:t,stream:r}=proxy(),o=r,s={};return{source:()=>{const t=t=>Array.from(e.querySelectorAll(t));return o.forEach(()=>{Object.keys(s).forEach(e=>{const[r]=e.split("@@"),o=t(r);if(o&&o.length>0){const t=s[e];if(!1===t.live){t.live=!0;const e=o.map(e=>most.fromEvent(t.events,e)),r=most.mergeArray(e);t.observable.attach(r)}}})}),{select:e=>{const r=t(e);let o;return{events:function(t){if(!r||r&&0===r.length){const r=proxy();o=r.stream,s[e+"@@"+t]={observable:r,live:!1}}return s[e+"@@"+t].events=t,o.multicast()}}},element:e}},sink:((e,r)=>{let o;const s=r.take(1).map(t=>{o=t,e.appendChild(o)}),m=r.skip(1).map(e=>{morph(o,e)}),n=most.mergeArray([s,m]).multicast();t(n),n.forEach(e=>e)}).bind(null,e)}};module.exports=makeDomSideEffect;
3196
3196
 
3197
3197
  },{"morphdom":697,"most":739,"most-proxy":700}],798:[function(require,module,exports){
@@ -3203,7 +3203,7 @@ const callbackToObservable=require("../../most-utils/callbackToObservable"),make
3203
3203
  },{"../../most-utils/callbackToObservable":791}],800:[function(require,module,exports){
3204
3204
  const path=require("path"),{getFileExtensionFromString:getFileExtensionFromString}=require("@jscad/core").utils,{formats:formats}=require("@jscad/io/formats"),callbackToObservable=require("../../most-utils/callbackToObservable"),makeLogger=require("../../utils/logger"),proxyUrl="./remote.pl?url=",binaryMimetypes={stl:"application/sla"},makeHttpSideEffect=e=>{const{logging:t}=Object.assign({},{logging:!1},e),r=callbackToObservable(),a=makeLogger({enabled:t});return{source:()=>r.stream.multicast(),sink:e=>{e.forEach(e=>{const{type:t,id:o,urls:n,origin:i,proxy:l}=e,s={read:()=>{let e=[];n.forEach(n=>{const s=e=>{r.callback({type:t,id:o,url:n,error:e}),a.error(e)},c=a=>{e=e.concat(a),r.callback({type:t,id:o,url:n,data:e})};l?readProxy(n,s,e=>{if(e.file){const t=new URL(i),r=new URL(e.file,t);readFile(r.toString(),s,c)}}):readFile(n,s,c)})},write:()=>{a.warning("writing to http is not implemented yet")},watch:()=>{a.warning("watching http is not implemented yet")},unhandled:()=>{r.callback({type:t,id:o,error:new Error(`http: no handler found for command ${t}`)})}};(s[t]||s.unhandled)()})}}},readFile=(e,t,r)=>{const a=getFileExtensionFromString(e),o=void 0!==binaryMimetypes[a];fetch(e).then(e=>{if(e.ok)return o?e.arrayBuffer():e.text();t(new Error(`fetch error: ${e.status} ${e.statusText}`))}).then(t=>{const o=path.basename(e),n=`/${o}`,i=formats[a]?formats[a].mimetype:"";r({name:o,ext:a,mimetype:i,source:t,fullPath:n})}).catch(e=>{t(e)})},readProxy=(e,t,r)=>{fetch(proxyUrl+e).then(e=>{if(e.ok)return e.json();t(new Error(`fetch error: ${e.status} ${e.statusText}`))}).then(e=>{r(e)}).catch(e=>{t(e)})};module.exports=makeHttpSideEffect;
3205
3205
 
3206
- },{"../../most-utils/callbackToObservable":791,"../../utils/logger":833,"@jscad/core":19,"@jscad/io/formats":68,"path":683}],801:[function(require,module,exports){
3206
+ },{"../../most-utils/callbackToObservable":791,"../../utils/logger":834,"@jscad/core":19,"@jscad/io/formats":68,"path":683}],801:[function(require,module,exports){
3207
3207
  const isElectron=require("is-electron"),callBackToStream=require("../../most-utils/callbackToObservable"),longNames={en:"english",de:"german",fr:"french",ja:"japanese",hr:"croatian"},getDefaultLocale=()=>{let a;return isElectron()||(a=navigator.languages&&navigator.languages.length?navigator.languages[0]:navigator.language),a?a.split("-")[0]:""},initTranslations=a=>{const{translations:e}=Object.assign({},{translations:{}},a);return e},i18nImport=require("es2015-i18n-tag"),i18n=i18nImport.default,{i18nConfig:i18nConfig}=i18nImport,makei18nSideEffect=a=>{const e=callBackToStream();let t=initTranslations(a);const n={setAvailableTranslations:a=>{t=a.data},getDefaultLocale:a=>{e.callback({data:getDefaultLocale(),type:a.type})},changeSettings:a=>{const n=a.data;i18nConfig({locales:n,translations:t[n]}),e.callback({data:i18n,type:"changeSettings"})},getAvailableLanguages:a=>{const n=Object.keys(t).map(a=>{let e=longNames[a]?longNames[a]:"placeholder";const n=t[a];return n&&"language"in n&&(e=n.language),{code:a,fullName:e}});e.callback({data:n,type:"getAvailableLanguages"})}};return{sink:a=>{a.forEach(a=>{const e=n[a.type];e&&e(a)})},source:()=>e.stream.multicast()}};module.exports=makei18nSideEffect;
3208
3208
 
3209
3209
  },{"../../most-utils/callbackToObservable":791,"es2015-i18n-tag":694,"is-electron":696}],802:[function(require,module,exports){
@@ -3222,15 +3222,15 @@ const most=require("most"),callbackToObservable=require("../../most-utils/callba
3222
3222
  const most=require("most"),makeTitleBarSideEffect=()=>{return{sink:e=>{e.forEach(e=>{document.title=e})},source:()=>{const e=window.location.href;return most.just(e).filter(e=>void 0!==e).multicast().skipRepeats()}}};module.exports=makeTitleBarSideEffect;
3223
3223
 
3224
3224
  },{"most":739}],807:[function(require,module,exports){
3225
- const WebWorkify=require("webworkify"),callBackToStream=require("../../most-utils/callbackToObservable"),makeWorkerEffect=e=>{const r=callBackToStream();let a=WebWorkify(e);a.onerror=(e=>r.callback({error:e})),a.onmessage=(e=>r.callback(e));return{sink:c=>{c.filter(({cmd:e})=>"cancel"===e).forEach(e=>a.terminate()),c.filter(({cmd:e})=>"cancel"!==e).forEach(c=>{a.terminate(),(a=WebWorkify(e)).onerror=(e=>r.callback({error:e})),a.onmessage=(e=>r.callback(e)),a.postMessage(c)})},source:function(){return r.stream.multicast()}}};module.exports=makeWorkerEffect;
3225
+ const WebWorkify=require("webworkify"),callBackToStream=require("../../most-utils/callbackToObservable"),makeWorkerEffect=e=>{const r=callBackToStream();let a=WebWorkify(e,{});a.onerror=(e=>r.callback({error:e})),a.onmessage=(e=>r.callback(e));return{sink:c=>{c.filter(({cmd:e})=>"cancel"===e).forEach(c=>{a.terminate(),(a=WebWorkify(e)).onerror=(e=>r.callback({error:e})),a.onmessage=(e=>r.callback(e))}),c.filter(({cmd:e})=>"cancel"!==e).forEach(e=>{a.postMessage(e)})},source:function(){return r.stream.multicast()}}};module.exports=makeWorkerEffect;
3226
3226
 
3227
3227
  },{"../../most-utils/callbackToObservable":791,"webworkify":781}],808:[function(require,module,exports){
3228
- const path=require("path"),most=require("most"),{delayFromObservable:delayFromObservable,holdUntil:holdUntil,withLatestFrom:withLatestFrom}=require("../../most-utils"),{applyParameterDefinitions:applyParameterDefinitions,getParameterValuesFromUIControls:getParameterValuesFromUIControls}=require("@jscad/core").parameters,{getDesignEntryPoint:getDesignEntryPoint,getDesignName:getDesignName}=require("@jscad/core").loading.requireDesignUtilsFs,{makeFakeFs:makeFakeFs}=require("@jscad/core").loading,{keep:keep}=require("../../utils/object"),{fetchUriParams:fetchUriParams,getAllUriParams:getAllUriParams}=require("../../utils/urlUtils"),{availableExportFormatsFromSolids:availableExportFormatsFromSolids,exportFilePathFromFormatAndDesign:exportFilePathFromFormatAndDesign}=require("../../core/io/exportUtils"),packageMetadata=require("../../../package.json"),jsonCompare=(e,t)=>JSON.stringify(e)===JSON.stringify(t),designEqualityFields=["parameterDefinitions","parameterValues","mainPath","filesAndFolders","vtreeMode"],serializableFields=["name","mainPath","origin","parameterValues","vtreeMode","autoReload","instantUpdate","solidsTimeOut"],reducers={initialize:e=>{return{design:{name:"",path:"",mainPath:"",origin:void 0,filesAndFolders:[],instantUpdate:!1,autoReload:!1,parameterDefinitions:[],parameterValues:{},parameterDefaults:{},solidsTimeOut:8e4,solids:[],vtreeMode:!1,lookup:{},lookupCounts:{},debug:{startTime:0,endTime:0,totalTime:0}}}},resetDesign:(e,t)=>{const s=Object.assign({},e.design,keep(["name","path","mainPath","origin","filesAndFolders","parameterDefinitions","parameterValues","parameterDefaults","lookup","lookupCounts","debug","solids"],reducers.initialize().design));return s.origin=t,{design:s}},setDesignContent:(e,t)=>{const{filesAndFolders:s}=t,a=makeFakeFs(s),r=s[0].fullPath,i=getDesignEntryPoint(a,r),n=getDesignName(a,r),o=path.dirname(r);let l=e.design;const d=Object.assign({},e.design.debug,{startTime:new Date});return{design:l=Object.assign({},l,{name:n,path:o,mainPath:i,filesAndFolders:s,debug:d}),appTitle:`jscad v ${packageMetadata.version}: ${e.design.name}`,status:Object.assign({},e.status,{busy:!0,error:void 0})}},setDesignSolids:(e,{solids:t,lookup:s,lookupCounts:a})=>{t=t||[],s=s||{},a=a||{};const r=new Date,i=r-e.design.debug.startTime,n=Object.assign({},e.design.debug,{endTime:r,totalTime:i});console.warn("total time for design regeneration",i,(new Date).getSeconds());const o=Object.assign({},e.design,{solids:t,lookup:s,lookupCounts:a,debug:n}),{exportFormat:l,availableExportFormats:d}=availableExportFormatsFromSolids(t),m={exportFormat:l,exportFilePath:exportFilePathFromFormatAndDesign(o,l).exportFilePath,availableExportFormats:d};return{design:o,status:Object.assign({},e.status,{busy:!1}),io:m}},setDesignParameterDefinitions:(e,t)=>{const s=t.parameterDefaults||e.design.parameterDefaults,a=t.parameterDefinitions||e.design.parameterDefinitions;return{design:Object.assign({},e.design,{parameterDefaults:s,parameterDefinitions:a,parametersOrigin:t.origin})}},setDesignParameterValues:(e,t)=>{let s=t.parameterValues;"instantUpdate"!==t.origin||e.design.instantUpdate||(s=e.design.parameterValues),s=s?applyParameterDefinitions(s,e.design.parameterDefinitions):s,s=Object.assign({},e.design.parameterValues,s);let a=Object.assign({},e.design,{parameterValues:s,parametersOrigin:t.origin});const r=Object.assign({},e.design.debug,{startTime:new Date});return{design:a=Object.assign({},a,{debug:r}),status:Object.assign({},e.status,{busy:!0,error:void 0})}},setSettings:(e,{data:t})=>{const{vtreeMode:s,autoReload:a,instantUpdate:r,solidsTimeOut:i}=t;return void 0===s?{design:e.design}:{design:Object.assign({},e.design,{vtreeMode:s,autoReload:a,instantUpdate:r,solidsTimeOut:i})}},requestGeometryRecompute:({design:e},t)=>keep(["mainPath","parameterValues","filesAndFolders","vtreeMode","lookup","lookupCounts"],e),timeoutGeometryRecompute:({status:e},t)=>e.isBusy?Object.assign({},e,{busy:!1,error:new Error("Failed to generate design within an acceptable time, bailing out")}):{status:e},requestWriteCachedGeometry:({design:e},t)=>{const s={};return Object.keys(t).forEach(e=>{s[e]=t[e]}),{path:".solidsCache",options:{isRawData:!0},origin:e.origin}},requestSaveSettings:({design:e})=>keep(serializableFields,e),isDesignValid:e=>e.design&&e.design.name&&""!==e.design.path,isDesignTheSame:(e,t)=>{if(!e.design)return!1;const s=JSON.stringify(keep(designEqualityFields,t.design));return JSON.stringify(keep(designEqualityFields,e.design))===s},isDesignTheSameForSerialization:(e,t)=>{if(!e.design)return!1;const s=JSON.stringify(keep(serializableFields,t.design));return JSON.stringify(keep(serializableFields,e.design))===s},toggleAutoReload:(e,t)=>{return{design:Object.assign({},e.design,{autoReload:t})}},toggleInstantUpdate:(e,t)=>{return{design:Object.assign({},e.design,{instantUpdate:t})}},toggleVtreeMode:(e,t)=>{return{design:Object.assign({},e.design,{vtreeMode:t})}},setSolidsTimeout:(e,t)=>{return{design:Object.assign({},e.design,{solidsTimeOut:t})}}},actions=({sources:e})=>{const t=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>({type:"initializeDesign",state:e,sink:"state"})).multicast(),s=t.map(e=>({sink:"store",key:"design",type:"read"})),a=e.state.filter(reducers.isDesignValid).skipRepeatsWith(reducers.isDesignTheSameForSerialization).thru(holdUntil(e.store.filter(e=>"design"===e.key&&"read"===e.type))).map(reducers.requestSaveSettings).map(e=>Object.assign({},{data:e},{sink:"store",key:"design",type:"write"})).multicast(),r=e.store.filter(e=>"design"===e.key&&"read"===e.type&&void 0!==e.data).thru(withLatestFrom(reducers.setSettings,e.state)).map(e=>({type:"setDesignSettings",state:e,sink:"state"})).multicast(),i=most.mergeArray([e.drops.filter(e=>"fileOrFolder"===e.type).tap(e=>console.log("dropped file",e)).map(({data:e})=>({sink:"fs",data:e,path:"realFs",urls:[]})),e.drops.filter(e=>"url"===e.type).tap(e=>console.log("dropped url",e)).map(e=>{const t=window.location.href,s=e.data,a=new URL(s),r=s?[s]:[],{protocol:i,pathname:n}=a;return{sink:i.replace(":",""),urls:r,origin:t,path:n,proxy:!0}}),e.dom.select(".example").events("click").map(e=>e.target.dataset.path).map(e=>{const t=new URL(e),s=e?[e]:[],{protocol:a,origin:r}=t;return{sink:a.replace(":",""),urls:s,origin:r}}).tap(e=>console.log("load example",e)),e.dom.select("#fileLoader").events("change").tap(e=>console.log("selected directory",e)).filter(e=>e.target.files.length>0).map(e=>{const t=e.target.files,s=[];for(let e=0;e<t.length;e++)s.push(t.item(e));return{sink:"fs",data:s,path:"realFs",urls:[]}}),e.titleBar.filter(e=>void 0!==e).tap(e=>console.log("window href processing",e)).map(e=>{const t=e;let s=fetchUriParams(e,"uri",void 0);if(!s){const t=new URL(e);if(0===t.hash.length)return;s=t.hash.slice(1)}const a=new URL(s),r=[s],{protocol:i,pathname:n}=a;return{sink:i.replace(":",""),urls:r,origin:t,path:n,proxy:!0}})]).filter(e=>void 0!==e).thru(holdUntil(r)).map(e=>({type:"read",id:"loadRemote",urls:e.urls,sink:e.sink,origin:e.origin,path:e.path,data:e.data,proxy:e.proxy})).multicast().skipRepeats(),n=most.mergeArray(Object.values(e).filter(e=>void 0!==e&&"source"in e)).filter(e=>!("loadRemote"!==e.id||"read"!==e.type||"error"in e||"sink"in e)).map(({data:e})=>({filesAndFolders:e})).thru(withLatestFrom(reducers.setDesignContent,e.state)).map(e=>({type:"setDesignContent",state:e,sink:"state"})).multicast(),o=most.mergeArray([e.state.filter(reducers.isDesignValid).map(({design:e})=>{return{id:"watchScript",path:e.mainPath,origin:e.origin,options:{enabled:e.autoReload}}}).skipRepeatsWith(jsonCompare)]).map(e=>Object.assign({},{type:"watch",sink:e.origin},e)).multicast(),l=most.mergeArray([e.state.filter(reducers.isDesignValid).filter(e=>void 0!==e.design.solids).map(e=>e.design.solids).skipRepeatsWith(jsonCompare)]).thru(withLatestFrom(reducers.requestWriteCachedGeometry,e.state)).map(e=>Object.assign({},{type:"write",id:"cachedGeometry",sink:e.origin},e)).multicast(),d=most.mergeArray([i.map(({sink:e})=>e)]).thru(withLatestFrom(reducers.resetDesign,e.state)).map(e=>({type:"resetDesign",state:e,sink:"state"})).multicast(),m=most.mergeArray([e.solidWorker.filter(e=>!("error"in e)&&e.data instanceof Object&&"solids"===e.data.type).map(e=>{const{lookupCounts:t,lookup:s,solids:a}=e.data;return{solids:a,lookup:s,lookupCounts:t}}).multicast(),e.fs.filter(e=>"read"===e.type&&"loadCachedGeometry"===e.id&&e.data).map(e=>{return{solids:void 0,lookupCounts:void 0,lookup:void e.data}}).multicast()]).thru(withLatestFrom(reducers.setDesignSolids,e.state)).map(e=>({type:"setDesignSolids",state:e,sink:"state"})).multicast(),g=e.state.skipRepeatsWith(reducers.isDesignTheSame).filter(reducers.isDesignValid).map(reducers.requestGeometryRecompute).map(e=>Object.assign({},e,{sink:"geometryWorker",cmd:"generate"})).multicast(),u=g.thru(delayFromObservable(e=>e.design.solidsTimeOut,e.state.filter(reducers.isDesignValid))).thru(withLatestFrom(reducers.timeoutGeometryRecompute,e.state)).map(e=>Object.assign({},{state:e},{sink:"state",type:"timeOutDesignGeneration"})).multicast(),p=u.filter(({state:e})=>void 0!==e.status.error).map(e=>Object.assign({},{sink:"geometryWorker",cmd:"cancel"})).multicast(),c=e.solidWorker.filter(e=>!("error"in e)&&e.data instanceof Object&&"params"===e.data.type).map(({data:e})=>({parameterDefaults:e.parameterDefaults,parameterDefinitions:e.parameterDefinitions,origin:"worker"})),h=most.mergeArray([c]).skipRepeatsWith(jsonCompare).thru(holdUntil(e.state.filter(reducers.isDesignValid))).thru(withLatestFrom(reducers.setDesignParameterDefinitions,e.state)).map(e=>({type:"setDesignParameterDefinitions",state:e,sink:"state"})).multicast(),y=()=>Array.from(document.getElementById("paramsTable").getElementsByTagName("input")).concat(Array.from(document.getElementById("paramsTable").getElementsByTagName("select"))).concat(Array.from(document.getElementById("paramsTable").getElementsByClassName("groupTitle"))),k=most.mergeArray([e.dom.select("#updateDesignFromParams").events("click").map(()=>{const e=y();return{parameterValues:getParameterValuesFromUIControls(e),origin:"uiManualUpdate"}}),e.paramChanges.filter(e=>(()=>document.getElementById("instantUpdate").checked)()).map(()=>{try{const e=y();return{parameterValues:getParameterValuesFromUIControls(e),origin:"uiInstantUpdate"}}catch(e){return{error:e,origin:"instantUpdate"}}})]).multicast().debounce(10),f=e.store.filter(e=>"design"===e.key&&"read"===e.type&&void 0!==e.data.parameterValues).map(({data:e})=>({parameterValues:e.parameterValues,origin:"store"})).multicast(),D=e.titleBar.map(e=>getAllUriParams(e)).filter(e=>Object.keys(e).length>0).map(e=>({parameterValues:e,origin:"titleBar"})).multicast(),F=e.state.filter(reducers.isDesignValid).multicast(),b=most.mergeArray([k,f,D,e.dom.select("#resetDesignToParameterDefaults").events("click").thru(withLatestFrom((e,t)=>({parameterValues:e.design.parameterDefaults,origin:"reset"}),e.state))]).skipRepeatsWith(jsonCompare).thru(holdUntil(e.state.filter(reducers.isDesignValid))).thru(holdUntil(F.filter(e=>{return e.design&&Object.keys(e.design.parameterDefinitions).length>0}))).thru(withLatestFrom(reducers.setDesignParameterValues,e.state)).map(e=>({type:"setDesignParameterValues",state:e,sink:"state"})).multicast().delay(10),O=e.solidWorker.filter(e=>e.data instanceof Object&&"errors"===e.data.type).map(({data:e})=>({error:e,origin:"worker"}));return{initialize$:t,requestLoadDesignContent$:i,requestWatchDesign$:o,requestWriteCachedGeometry$:l,resetDesign$:d,setDesignContent$:n,setDesignSolids$:m,setDesignParameterDefinitions$:h,setDesignParameterValues$:b,reportErrorsFromWorker$:most.mergeArray([O]).skipRepeatsWith(jsonCompare).tap(e=>console.log("errors",e)),requestGeometryRecompute$:g,timeoutGeometryRecompute$:u,cancelGeometryRecompute$:p,requestLoadSettings$:s,requestSaveSettings$:a,setDesignSettings$:r,toggleAutoReload$:most.mergeArray([e.dom.select("#toggleAutoReload").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleAutoReload,e.state)).map(e=>({type:"toggleAutoReload",state:e,sink:"state"})),toggleInstantUpdate$:most.mergeArray([e.dom.select("#instantUpdate").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleInstantUpdate,e.state)).map(e=>({type:"toggleInstantUpdate",state:e,sink:"state"})),toggleVTreeMode$:most.mergeArray([e.dom.select("#toggleVtreeMode").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleVtreeMode,e.state)).map(e=>({type:"toggleVtreeMode",state:e,sink:"state"})),setSolidsTimeout$:most.mergeArray([e.dom.select("#solidsTimeout").events("change").map(e=>e.target.value).map(e=>parseFloat(e))]).thru(withLatestFrom(reducers.setSolidsTimeout,e.state)).map(e=>({type:"setSolidsTimeout",state:e,sink:"state"}))}};module.exports=actions;
3228
+ const most=require("most"),{delayFromObservable:delayFromObservable,holdUntil:holdUntil,withLatestFrom:withLatestFrom}=require("../../most-utils"),{getParameterValuesFromUIControls:getParameterValuesFromUIControls}=require("@jscad/core").parameters,{fetchUriParams:fetchUriParams,getAllUriParams:getAllUriParams}=require("../../utils/urlUtils"),reducers=require("./reducers"),jsonCompare=(e,t)=>JSON.stringify(e)===JSON.stringify(t),actions=({sources:e})=>{const t=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>({type:"initializeDesign",state:e,sink:"state"})).multicast(),r=t.map(e=>({sink:"store",key:"design",type:"read"})),s=e.state.filter(reducers.isDesignValid).skipRepeatsWith(reducers.isDesignTheSameForSerialization).thru(holdUntil(e.store.filter(e=>"design"===e.key&&"read"===e.type))).map(reducers.requestSaveSettings).map(e=>Object.assign({},{data:e},{sink:"store",key:"design",type:"write"})).multicast(),a=e.store.filter(e=>"design"===e.key&&"read"===e.type&&void 0!==e.data).thru(withLatestFrom(reducers.setSettings,e.state)).map(e=>({type:"setDesignSettings",state:e,sink:"state"})).multicast(),i=most.mergeArray([e.drops.filter(e=>"fileOrFolder"===e.type).tap(e=>console.log("dropped file",e)).map(({data:e})=>({sink:"fs",data:e,path:"realFs",urls:[]})),e.drops.filter(e=>"url"===e.type).tap(e=>console.log("dropped url",e)).map(e=>{const t=window.location.href,r=e.data,s=new URL(r),a=r?[r]:[],{protocol:i,pathname:o}=s;return{sink:i.replace(":",""),urls:a,origin:t,path:o,proxy:!0}}),e.dom.select(".example").events("click").map(e=>e.target.dataset.path).map(e=>{const t=new URL(e),r=e?[e]:[],{protocol:s,origin:a}=t;return{sink:s.replace(":",""),urls:r,origin:a}}).tap(e=>console.log("load example",e)),e.dom.select("#fileLoader").events("change").tap(e=>console.log("selected directory",e)).filter(e=>e.target.files.length>0).map(e=>{const t=e.target.files,r=[];for(let e=0;e<t.length;e++)r.push(t.item(e));return{sink:"fs",data:r,path:"realFs",urls:[]}}),e.titleBar.filter(e=>void 0!==e).tap(e=>console.log("window href processing",e)).map(e=>{const t=e;let r=fetchUriParams(e,"uri",void 0);if(!r){const t=new URL(e);if(0===t.hash.length)return;r=t.hash.slice(1)}const s=new URL(r),a=[r],{protocol:i,pathname:o}=s;return{sink:i.replace(":",""),urls:a,origin:t,path:o,proxy:!0}})]).filter(e=>void 0!==e).thru(holdUntil(a)).map(e=>({type:"read",id:"loadRemote",urls:e.urls,sink:e.sink,origin:e.origin,path:e.path,data:e.data,proxy:e.proxy})).multicast().skipRepeats(),o=most.mergeArray(Object.values(e).filter(e=>void 0!==e&&"source"in e)).filter(e=>!("loadRemote"!==e.id||"read"!==e.type||"error"in e||"sink"in e)).map(({data:e})=>({filesAndFolders:e})).thru(withLatestFrom(reducers.setDesignContent,e.state)).map(e=>({type:"setDesignContent",state:e,sink:"state"})).multicast(),n=most.mergeArray([e.state.filter(reducers.isDesignValid).map(({design:e})=>{return{id:"watchScript",path:e.mainPath,origin:e.origin,options:{enabled:e.autoReload}}}).skipRepeatsWith(jsonCompare)]).map(e=>Object.assign({},{type:"watch",sink:e.origin},e)).multicast(),l=most.mergeArray([e.state.filter(reducers.isDesignValid).filter(e=>void 0!==e.design.solids).map(e=>e.design.solids).skipRepeatsWith(jsonCompare)]).thru(withLatestFrom(reducers.requestWriteCachedGeometry,e.state)).map(e=>Object.assign({},{type:"write",id:"cachedGeometry",sink:e.origin},e)).multicast(),m=most.mergeArray([i.map(({sink:e})=>e)]).thru(withLatestFrom(reducers.resetDesign,e.state)).map(e=>({type:"resetDesign",state:e,sink:"state"})).multicast(),d=most.mergeArray([e.solidWorker.filter(e=>!("error"in e)&&e.data instanceof Object&&"solids"===e.data.type).map(e=>{const{lookupCounts:t,lookup:r,solids:s}=e.data;return{solids:s,lookup:r,lookupCounts:t}}).multicast(),e.fs.filter(e=>"read"===e.type&&"loadCachedGeometry"===e.id&&e.data).map(e=>{return{solids:void 0,lookupCounts:void 0,lookup:void e.data}}).multicast()]).thru(withLatestFrom(reducers.setDesignSolids,e.state)).map(e=>({type:"setDesignSolids",state:e,sink:"state"})).multicast(),p=e.state.skipRepeatsWith(reducers.isDesignTheSame).filter(reducers.isDesignValid).map(reducers.requestGeometryRecompute).map(e=>Object.assign({},e,{sink:"geometryWorker",cmd:"generate"})).multicast(),u=p.thru(delayFromObservable(e=>e.design.solidsTimeOut,e.state.filter(reducers.isDesignValid))).thru(withLatestFrom(reducers.timeoutGeometryRecompute,e.state)).map(e=>Object.assign({},{state:e},{sink:"state",type:"timeOutDesignGeneration"})).multicast(),c=u.filter(({state:e})=>void 0!==e.status.error).map(e=>Object.assign({},{sink:"geometryWorker",cmd:"cancel"})).multicast(),g=e.solidWorker.filter(e=>!("error"in e)&&e.data instanceof Object&&"params"===e.data.type).map(({data:e})=>({parameterDefaults:e.parameterDefaults,parameterDefinitions:e.parameterDefinitions,origin:"worker"})),h=most.mergeArray([g]).skipRepeatsWith(jsonCompare).thru(holdUntil(e.state.filter(reducers.isDesignValid))).thru(withLatestFrom(reducers.setDesignParameterDefinitions,e.state)).map(e=>({type:"setDesignParameterDefinitions",state:e,sink:"state"})).multicast(),y=()=>Array.from(document.getElementById("paramsTable").getElementsByTagName("input")).concat(Array.from(document.getElementById("paramsTable").getElementsByTagName("select"))).concat(Array.from(document.getElementById("paramsTable").getElementsByClassName("groupTitle"))),k=most.mergeArray([e.dom.select("#updateDesignFromParams").events("click").map(()=>{const e=y();return{parameterValues:getParameterValuesFromUIControls(e),origin:"uiManualUpdate"}}),e.paramChanges.filter(e=>(()=>document.getElementById("instantUpdate").checked)()).map(()=>{try{const e=y();return{parameterValues:getParameterValuesFromUIControls(e),origin:"uiInstantUpdate"}}catch(e){return{error:e,origin:"instantUpdate"}}})]).multicast().debounce(10),f=e.store.filter(e=>"design"===e.key&&"read"===e.type&&void 0!==e.data.parameterValues).map(({data:e})=>({parameterValues:e.parameterValues,origin:"store"})).multicast(),D=e.titleBar.map(e=>getAllUriParams(e)).filter(e=>Object.keys(e).length>0).map(e=>({parameterValues:e,origin:"titleBar"})).multicast(),F=e.state.filter(reducers.isDesignValid).multicast(),w=most.mergeArray([k,f,D,e.dom.select("#resetDesignToParameterDefaults").events("click").thru(withLatestFrom((e,t)=>({parameterValues:e.design.parameterDefaults,origin:"reset"}),e.state))]).skipRepeatsWith(jsonCompare).thru(holdUntil(e.state.filter(reducers.isDesignValid))).thru(holdUntil(F.filter(e=>{return e.design&&Object.keys(e.design.parameterDefinitions).length>0}))).thru(withLatestFrom(reducers.setDesignParameterValues,e.state)).map(e=>({type:"setDesignParameterValues",state:e,sink:"state"})).multicast().delay(10),U=e.solidWorker.filter(e=>e.data instanceof Object&&"errors"===e.data.type).map(({data:e})=>({error:e,origin:"worker"}));return{initialize$:t,requestLoadDesignContent$:i,requestWatchDesign$:n,requestWriteCachedGeometry$:l,resetDesign$:m,setDesignContent$:o,setDesignSolids$:d,setDesignParameterDefinitions$:h,setDesignParameterValues$:w,reportErrorsFromWorker$:most.mergeArray([U]).skipRepeatsWith(jsonCompare).tap(e=>console.log("errors",e)),requestGeometryRecompute$:p,timeoutGeometryRecompute$:u,cancelGeometryRecompute$:c,requestLoadSettings$:r,requestSaveSettings$:s,setDesignSettings$:a,toggleAutoReload$:most.mergeArray([e.dom.select("#toggleAutoReload").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleAutoReload,e.state)).map(e=>({type:"toggleAutoReload",state:e,sink:"state"})),toggleInstantUpdate$:most.mergeArray([e.dom.select("#instantUpdate").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleInstantUpdate,e.state)).map(e=>({type:"toggleInstantUpdate",state:e,sink:"state"})),toggleVTreeMode$:most.mergeArray([e.dom.select("#toggleVtreeMode").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleVtreeMode,e.state)).map(e=>({type:"toggleVtreeMode",state:e,sink:"state"})),setSolidsTimeout$:most.mergeArray([e.dom.select("#solidsTimeout").events("change").map(e=>e.target.value).map(e=>parseFloat(e))]).thru(withLatestFrom(reducers.setSolidsTimeout,e.state)).map(e=>({type:"setSolidsTimeout",state:e,sink:"state"}))}};module.exports=actions;
3229
3229
 
3230
- },{"../../../package.json":782,"../../core/io/exportUtils":783,"../../most-utils":794,"../../utils/object":834,"../../utils/urlUtils":835,"@jscad/core":19,"most":739,"path":683}],809:[function(require,module,exports){
3230
+ },{"../../most-utils":794,"../../utils/urlUtils":836,"./reducers":815,"@jscad/core":19,"most":739}],809:[function(require,module,exports){
3231
3231
  const makeOutput=({sources:e,extras:t})=>e.state.filter(e=>e.design&&e.languages&&e.viewer).skipRepeatsWith((e,t)=>JSON.stringify(e)===JSON.stringify(t)).combine((e,a)=>require("../views/main")(e,a,t.paramsCallbacktoStream,t.editorCallbackToStream),e.i18n.filter(e=>"changeSettings"===e.type).map(e=>e.data));module.exports=makeOutput;
3232
3232
 
3233
- },{"../views/main":824}],810:[function(require,module,exports){
3233
+ },{"../views/main":825}],810:[function(require,module,exports){
3234
3234
  const most=require("most"),{withLatestFrom:withLatestFrom}=require("../../most-utils"),reducers={setErrors:(r,t)=>{const{error:s}=t;return{status:Object.assign({},r.status,{error:s,busy:!1})}},clearErrors:(r,t)=>{return{status:Object.assign({},r.status,{error:void 0,busy:!1})}}},actions=({sources:r})=>{return{setErrors$:most.mergeArray(Object.values(r).filter(r=>void 0!==r&&"source"in r)).filter(r=>{try{return"error"in r}catch(r){return!1}}).thru(withLatestFrom(reducers.setErrors,r.state)).map(r=>Object.assign({},{type:"setErrors",sink:"state"},{state:r})),clearErrors$:most.never().thru(withLatestFrom(reducers.clearErrors,r.state)).map(r=>Object.assign({},{type:"clearErrors",sink:"state"},{state:r}))}};module.exports=actions;
3235
3235
 
3236
3236
  },{"../../most-utils":794,"most":739}],811:[function(require,module,exports){
@@ -3239,25 +3239,28 @@ const most=require("most"),{solidsAsBlob:solidsAsBlob}=require("@jscad/io"),{wit
3239
3239
  },{"../../core/io/exportUtils":783,"../../most-utils":794,"@jscad/io":69,"file-saver":695,"most":739}],812:[function(require,module,exports){
3240
3240
  const most=require("most"),{flatten:flatten}=require("@jscad/array-utils"),{proxy:proxy}=require("most-proxy"),makeActions=e=>{const{attach:r,stream:s}=proxy();e.actions=s.skipRepeatsWith((e,r)=>JSON.stringify(e)===JSON.stringify(r)).multicast();const t=require("./tools")({sources:e}),i=require("./viewer")({sources:e}),o=require("./themes")({sources:e}),u=require("./languages")({sources:e}),a=require("./shortcuts")({sources:e}),c=require("./errors")({sources:e}),n=require("./exports")({sources:e}),m=[c,require("./design")({sources:e}),n,t,o,i,u,a],l=most.mergeArray(flatten(m.map(e=>Object.values(e)))).skipRepeatsWith((e,r)=>JSON.stringify(e)===JSON.stringify(r)).multicast().filter(e=>void 0!==e);return r(l),l};module.exports=makeActions;
3241
3241
 
3242
- },{"./design":808,"./errors":810,"./exports":811,"./languages":814,"./shortcuts":815,"./themes":816,"./tools":817,"./viewer":818,"@jscad/array-utils":520,"most":739,"most-proxy":700}],813:[function(require,module,exports){
3242
+ },{"./design":808,"./errors":810,"./exports":811,"./languages":814,"./shortcuts":816,"./themes":817,"./tools":818,"./viewer":819,"@jscad/array-utils":520,"most":739,"most-proxy":700}],813:[function(require,module,exports){
3243
3243
  const makeReactions=i=>{const{sinks:s,outputs$:t}=i,{store:n,fs:e,http:k,https:r,i18n:o,dom:f,solidWorker:l,state:a,dat:d}=s;f(require("./dom")(i)),o(t.filter(i=>"sink"in i&&"i18n"===i.sink)),n(t.filter(i=>"sink"in i&&"store"===i.sink)),k(t.filter(i=>"sink"in i&&"http"===i.sink)),r(t.filter(i=>"sink"in i&&"https"===i.sink)),e(t.filter(i=>"sink"in i&&"fs"===i.sink)),l(t.filter(i=>"sink"in i&&"geometryWorker"===i.sink)),a(t.filter(i=>"sink"in i&&"state"===i.sink)),d(t.filter(i=>"sink"in i&&"dat"===i.sink))};module.exports=makeReactions;
3244
3244
 
3245
3245
  },{"./dom":809}],814:[function(require,module,exports){
3246
3246
  const most=require("most"),{holdUntil:holdUntil,withLatestFrom:withLatestFrom}=require("../../most-utils"),reducers={initialize:e=>{return{languages:{active:void 0,available:[]}}},setLanguage:(e,a)=>{return{languages:Object.assign({},e.languages,{active:a})}},setAvailableLanguages:(e,a)=>{return{languages:Object.assign({},e.languages,{available:a})}},requestSaveSettings:e=>({active:e.active})},actions=({sources:e})=>{const a=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>Object.assign({},{type:"initializeLanguages",sink:"state"},{state:e})),t=a.map(e=>({type:"getAvailableLanguages",sink:"i18n"})),s=t.map(e=>({type:"getDefaultLocale",sink:"i18n"})),i=e.state.filter(e=>e.languages&&void 0!==e.languages.active).map(e=>e.languages.active).skipRepeatsWith((e,a)=>JSON.stringify(e)===JSON.stringify(a)).map(e=>({type:"changeSettings",data:e,sink:"i18n"})),g=most.mergeArray([e.i18n.filter(e=>"getAvailableLanguages"===e.type).map(e=>e.data)]).thru(withLatestFrom(reducers.setAvailableLanguages,e.state)).map(e=>Object.assign({},{type:"setAvailableLanguages",sink:"state"},{state:e})).multicast(),n=a.map(e=>({sink:"store",key:"languages",type:"read"})),l=e.i18n.thru(holdUntil(g)).filter(e=>"getDefaultLocale"===e.type).map(e=>e.data).multicast().delay(1),r=e.store.filter(e=>"languages"===e.key&&"read"===e.type).thru(holdUntil(l)).map(e=>e.data.active).filter(e=>void 0!==e);return{initialize$:a,requestGetAvailableLanguages$:t,requestGetDefaultLanguage$:s,requestGetLanguageData$:i,setLanguage$:most.mergeArray([l,e.dom.select("#languageSwitcher").events("change").map(e=>e.target.value),r]).thru(withLatestFrom(reducers.setLanguage,e.state)).map(e=>Object.assign({},{type:"setLanguage",sink:"state"},{state:e})),setAvailableLanguages$:g,requestLoadSettings$:n,requestSaveSettings$:e.state.filter(e=>e.languages).map(e=>e.languages).thru(holdUntil(e.store.filter(e=>"languages"===e.key&&"read"===e.type))).map(reducers.requestSaveSettings).map(e=>Object.assign({},{data:e},{sink:"store",key:"languages",type:"write"})).multicast()}};module.exports=actions;
3247
3247
 
3248
3248
  },{"../../most-utils":794,"most":739}],815:[function(require,module,exports){
3249
+ const path=require("path"),{applyParameterDefinitions:applyParameterDefinitions}=require("@jscad/core").parameters,{makeFakeFs:makeFakeFs}=require("@jscad/core").loading,{getDesignEntryPoint:getDesignEntryPoint,getDesignName:getDesignName}=require("@jscad/core").loading.requireDesignUtilsFs,{keep:keep}=require("../../utils/object"),packageMetadata=require("../../../package.json"),{availableExportFormatsFromSolids:availableExportFormatsFromSolids,exportFilePathFromFormatAndDesign:exportFilePathFromFormatAndDesign}=require("../../core/io/exportUtils"),designEqualityFields=["parameterDefinitions","parameterValues","mainPath","filesAndFolders","vtreeMode"],serializableFields=["name","mainPath","origin","parameterValues","vtreeMode","autoReload","instantUpdate","solidsTimeOut"],reducers={initialize:()=>{return{design:{name:"",path:"",mainPath:"",origin:void 0,filesAndFolders:[],instantUpdate:!1,autoReload:!1,parameterDefinitions:[],parameterValues:{},parameterDefaults:{},solidsTimeOut:8e4,solids:[],vtreeMode:!1,lookup:{},lookupCounts:{},debug:{startTime:0,endTime:0,totalTime:0}}}},resetDesign:(e,t)=>{const i=Object.assign({},e.design,keep(["name","path","mainPath","origin","filesAndFolders","parameterDefinitions","parameterValues","parameterDefaults","lookup","lookupCounts","debug","solids"],reducers.initialize().design));return i.origin=t,{design:i}},setDesignContent:(e,t)=>{const{filesAndFolders:i}=t,s=makeFakeFs(i),a=i[0].fullPath,n=getDesignEntryPoint(s,a),r=getDesignName(s,a),o=path.dirname(a);let d=e.design;const g=Object.assign({},e.design.debug,{startTime:new Date});return{design:d=Object.assign({},d,{name:r,path:o,mainPath:n,filesAndFolders:i,debug:g}),appTitle:`jscad v ${packageMetadata.version}: ${e.design.name}`,status:Object.assign({},e.status,{busy:!0,error:void 0})}},setDesignSolids:(e,{solids:t,lookup:i,lookupCounts:s})=>{t=t||[],i=i||{},s=s||{};const a=new Date,n=a-e.design.debug.startTime,r=Object.assign({},e.design.debug,{endTime:a,totalTime:n});console.warn("total time for design regeneration",n,(new Date).getSeconds());const o=Object.assign({},e.design,{solids:t,lookup:i,lookupCounts:s,debug:r}),{exportFormat:d,availableExportFormats:g}=availableExportFormatsFromSolids(t),l={exportFormat:d,exportFilePath:exportFilePathFromFormatAndDesign(o,d).exportFilePath,availableExportFormats:g};return{design:o,status:Object.assign({},e.status,{busy:!1}),io:l}},setDesignParameterDefinitions:(e,t)=>{const i=t.parameterDefaults||e.design.parameterDefaults,s=t.parameterDefinitions||e.design.parameterDefinitions;return{design:Object.assign({},e.design,{parameterDefaults:i,parameterDefinitions:s,parametersOrigin:t.origin})}},setDesignParameterValues:(e,t)=>{let i=t.parameterValues;"instantUpdate"!==t.origin||e.design.instantUpdate||(i=e.design.parameterValues),i=i?applyParameterDefinitions(i,e.design.parameterDefinitions):i,i=Object.assign({},e.design.parameterValues,i);let s=Object.assign({},e.design,{parameterValues:i,parametersOrigin:t.origin});const a=Object.assign({},e.design.debug,{startTime:new Date});return{design:s=Object.assign({},s,{debug:a}),status:Object.assign({},e.status,{busy:!0,error:void 0})}},setSettings:(e,{data:t})=>{const{vtreeMode:i,autoReload:s,instantUpdate:a,solidsTimeOut:n}=t;return void 0===i?{design:e.design}:{design:Object.assign({},e.design,{vtreeMode:i,autoReload:s,instantUpdate:a,solidsTimeOut:n})}},requestGeometryRecompute:({design:e},t)=>keep(["mainPath","parameterValues","filesAndFolders","vtreeMode","lookup","lookupCounts"],e),timeoutGeometryRecompute:({status:e},t)=>e.isBusy?Object.assign({},e,{busy:!1,error:new Error("Failed to generate design within an acceptable time, bailing out")}):{status:e},requestWriteCachedGeometry:({design:e},t)=>{const i={};return Object.keys(t).forEach(e=>{i[e]=t[e]}),{path:".solidsCache",options:{isRawData:!0},origin:e.origin}},requestSaveSettings:({design:e})=>keep(serializableFields,e),isDesignValid:e=>e.design&&e.design.name&&""!==e.design.path,isDesignTheSame:(e,t)=>{if(!e.design)return!1;const i=JSON.stringify(keep(designEqualityFields,t.design));return JSON.stringify(keep(designEqualityFields,e.design))===i},isDesignTheSameForSerialization:(e,t)=>{if(!e.design)return!1;const i=JSON.stringify(keep(serializableFields,t.design));return JSON.stringify(keep(serializableFields,e.design))===i},toggleAutoReload:(e,t)=>{return{design:Object.assign({},e.design,{autoReload:t})}},toggleInstantUpdate:(e,t)=>{return{design:Object.assign({},e.design,{instantUpdate:t})}},toggleVtreeMode:(e,t)=>{return{design:Object.assign({},e.design,{vtreeMode:t})}},setSolidsTimeout:(e,t)=>{return{design:Object.assign({},e.design,{solidsTimeOut:t})}}};module.exports=reducers;
3250
+
3251
+ },{"../../../package.json":782,"../../core/io/exportUtils":783,"../../utils/object":835,"@jscad/core":19,"path":683}],816:[function(require,module,exports){
3249
3252
  const most=require("most"),{head:head}=require("@jscad/array-utils"),{holdUntil:holdUntil,withLatestFrom:withLatestFrom}=require("../../most-utils"),{getKeyCombos:getKeyCombos,isKeyEventScopeValid:isKeyEventScopeValid,simpleKey:simpleKey}=require("../../utils/keys"),{merge:merge}=require("../../utils/utils"),reducers={initialize:e=>e,setShortcuts:(e,t)=>{return{shortcuts:merge([],e.shortcuts,t)}},setShortcut:(e,t)=>{const s=t=>e.shortcuts.filter(e=>e.key===t).length>0;return{shortcuts:e.shortcuts.map(e=>{if(e.command===t.command&&e.args===t.args){if("inProgress"in t){const{inProgress:r,tmpKey:o}=t;if(r){const t=s(o)?"shortcut already exists":void 0;return Object.assign({},e,{inProgress:r,tmpKey:o,error:t})}return Object.assign({},e,{inProgress:r,tmpKey:o})}if(t.done&&!s(t.key)){const{command:s,args:r}=e;return{key:t.key,command:s,args:r}}return e}return e})}},triggerShortcut:(e,{event:t,compositeKey:s})=>{const r=head(e.shortcuts.filter(e=>e.key.toLowerCase()===s));if(r){const{command:e,args:t}=r;return{type:e,data:t}}},requestSaveSettings:e=>e},actions=({sources:e})=>{const t=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>Object.assign({},{type:"initializeShortcuts",sink:"state"},{state:e})),s=most.mergeArray([e.store.filter(e=>"shortcuts"===e.key&&"read"===e.type&&e.data&&e.data.shortcuts).map(e=>e.data.shortcuts)]).thru(withLatestFrom(reducers.setShortcuts,e.state)).map(e=>Object.assign({},{type:"setShortcuts",sink:"state"},{state:e})),r=e.dom.select(".shortcutCommand").events("keyup").multicast(),o=e.dom.select(".shortcutCommand").events("keydown").multicast(),a=getKeyCombos({dropRepeats:!0,endKeys:["enter","escape"]},r,o);r.forEach(e=>(e.preventDefault(),e.stopPropagation(),!1)),o.forEach(e=>(e.preventDefault(),e.stopPropagation(),!1));const i=most.mergeArray([a.map(({event:e,compositeKey:t})=>({event:e,compositeKey:t,inProgress:!0})).merge(e.dom.select(".shortcutCommand").events("focus").map(e=>({event:e,compositeKey:"",inProgress:!0}))).merge(e.dom.select(".shortcutCommand").events("blur").map(e=>({event:e,compositeKey:"",inProgress:!1}))).merge(r.filter(e=>"escape"===simpleKey(e)).map(e=>({event:e,compositeKey:"",inProgress:!1}))).merge(r.filter(e=>"enter"===simpleKey(e)).map(e=>({event:e,done:!0}))).scan((e,t)=>{const{event:s,compositeKey:r,inProgress:o,done:a}=t,i=s.target.dataset.command,n=s.target.dataset.args,m=Object.assign({},e,{command:i,args:n,inProgress:o,done:a});return void 0!==r&&""!==r&&(m.key=r,m.tmpKey=r),"done"in m&&m.done&&(delete m.inProgress,delete m.tmpKey),m},{}).filter(e=>void 0!==e)]).thru(withLatestFrom(reducers.setShortcut,e.state)).map(e=>({type:"setShortcut",state:e,sink:"state"})).multicast(),n=e.dom.element.getAttribute("key"),m=most.fromEvent("keyup",e.dom.element).filter(e=>isKeyEventScopeValid(n,e.target)).multicast(),c=most.fromEvent("keydown",e.dom.element).filter(e=>isKeyEventScopeValid(n,e.target)).multicast(),u=getKeyCombos({dropRepeats:!1},m,c).thru(withLatestFrom(reducers.triggerShortcut,e.state)).filter(e=>void 0!==e),d=t.map(e=>({sink:"store",key:"shortcuts",type:"read"}));return{initialize$:t,setShortcut$:i,setShortcuts$:s,triggerFromShortcut$:u,requestLoadSettings$:d,requestSaveSettings$:e.state.filter(e=>e.shortcuts).map(e=>e.shortcuts).thru(holdUntil(e.store.filter(e=>"shortcuts"===e.key&&"read"===e.type))).map(reducers.requestSaveSettings).map(e=>Object.assign({},{data:e},{sink:"store",key:"shortcuts",type:"write"})).multicast()}};module.exports=actions;
3250
3253
 
3251
- },{"../../most-utils":794,"../../utils/keys":832,"../../utils/utils":836,"@jscad/array-utils":520,"most":739}],816:[function(require,module,exports){
3254
+ },{"../../most-utils":794,"../../utils/keys":833,"../../utils/utils":837,"@jscad/array-utils":520,"most":739}],817:[function(require,module,exports){
3252
3255
  const most=require("most"),{holdUntil:holdUntil,withLatestFrom:withLatestFrom}=require("../../most-utils"),{merge:merge}=require("../../utils/utils"),reducers={initialize:e=>{return{themes:{active:"light",themeSettings:{mainTextColor:"#FFF"}}}},setTheme:(e,t)=>{const s=require("../../../data/themes"),i=s[t]?s[t]:s.light;return{viewer:e.viewer?merge({},e.viewer,i.viewer):i.viewer,themes:Object.assign({},e.themes,{available:s,active:t,themeSettings:i})}},requestSaveSettings:e=>({active:e.active})},actions=({sources:e})=>{const t=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>Object.assign({},{type:"initializeThemes",sink:"state"},{state:e})),s=most.mergeArray([e.dom.select("#themeSwitcher").events("change").map(e=>e.target.value),e.store.filter(e=>"themes"===e.key&&"read"===e.type&&e.data&&e.data.active).map(e=>e.data.active)]).startWith("light").thru(withLatestFrom(reducers.setTheme,e.state)).map(e=>Object.assign({},{type:"setTheme",sink:"state"},{state:e})),i=t.map(e=>({sink:"store",key:"themes",type:"read"}));return{initialize$:t,setTheme$:s,requestLoadSettings$:i,requestSaveSettings$:e.state.filter(e=>e.themes).map(e=>e.themes).thru(holdUntil(e.store.filter(e=>"themes"===e.key&&"read"===e.type))).map(reducers.requestSaveSettings).map(e=>Object.assign({},{data:e},{sink:"store",key:"themes",type:"write"})).multicast()}};module.exports=actions;
3253
3256
 
3254
- },{"../../../data/themes":670,"../../most-utils":794,"../../utils/utils":836,"most":739}],817:[function(require,module,exports){
3257
+ },{"../../../data/themes":670,"../../most-utils":794,"../../utils/utils":837,"most":739}],818:[function(require,module,exports){
3255
3258
  const most=require("most"),{withLatestFrom:withLatestFrom}=require("../../most-utils"),actions=({sources:e})=>{return{setActiveTool$:most.mergeArray([e.dom.select("#toggleOptions").events("click").map(e=>"options"),e.dom.select("#toggleEditor").events("click").map(e=>"editor"),e.dom.select("#toggleHelp").events("click").map(e=>"help"),e.dom.select(".example").events("mouseup").map(e=>void 0)]).thru(withLatestFrom((e,t)=>{return{activeTool:e.activeTool===t?void 0:t}},e.state)).map(e=>Object.assign({},{type:"setActiveTool",sink:"state"},{state:e}))}};module.exports=actions;
3256
3259
 
3257
- },{"../../most-utils":794,"most":739}],818:[function(require,module,exports){
3260
+ },{"../../most-utils":794,"most":739}],819:[function(require,module,exports){
3258
3261
  const most=require("most"),{withLatestFrom:withLatestFrom}=require("../../most-utils"),reducers={initialize:e=>{return{viewer:{rendering:{background:[1,1,1,1],meshColor:[0,.6,1,1],autoRotate:!1,autoZoom:!1},grid:{show:!1,color:[1,1,1,.1]},axes:{show:!0},camera:{position:""}}}},toggleAutoRotate:(e,t)=>{const r=Object.assign({},e.viewer.rendering,{autoRotate:t});return{viewer:Object.assign({},e.viewer,{rendering:r})}},toggleAutoZoom:(e,t)=>{const r=Object.assign({},e.viewer.rendering,{autoZoom:t});return{viewer:Object.assign({},e.viewer,{rendering:r})}},toggleGrid:(e,t)=>{const r=Object.assign({},e.viewer.grid,{show:t});return{viewer:Object.assign({},e.viewer,{grid:r})}},toggleAxes:(e,t)=>{const r=Object.assign({},e.viewer.axes,{show:t});return{viewer:Object.assign({},e.viewer,{axes:r})}},toPresetView:(e,t)=>{const r=Object.assign({},e.viewer.camera,{position:t});return{viewer:Object.assign({},e.viewer,{camera:r})}},setProjectionType:(e,t)=>{return{viewer:Object.assign({},e.viewer,{camera:{projectionType:t}})}}},actions=({sources:e})=>{const t=most.just({}).thru(withLatestFrom(reducers.initialize,e.state)).map(e=>Object.assign({},{type:"initializeViewer",sink:"state"},{state:e})),r=most.mergeArray([e.dom.select("#toggleGrid").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleGrid,e.state)).map(e=>({type:"toggleGrid",state:e,sink:"state"})),s=most.mergeArray([e.dom.select("#toggleAxes").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleAxes,e.state)).map(e=>({type:"toggleAxes",state:e,sink:"state"})),o=most.mergeArray([e.dom.select("#toggleAutoRotate").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleAutoRotate,e.state)).map(e=>({type:"toggleAutoRotate",state:e,sink:"state"})),i=most.mergeArray([e.dom.select("#toggleAutoZoom").events("click").map(e=>e.target.checked)]).thru(withLatestFrom(reducers.toggleAutoZoom,e.state)).map(e=>({type:"toggleAutoZoom",state:e,sink:"state"})),a=["toPresetView"];return{initializeViewer$:t,toggleGrid$:r,toggleAxes$:s,toggleAutoRotate$:o,toggleAutoZoom$:i,otherViewerActions$:e.actions.filter(e=>a.includes(e.type)).thru(withLatestFrom((e,t)=>reducers[t.type](e,t.data),e.state)).map(e=>({type:"otherActions",state:e,sink:"state"}))}};module.exports=actions;
3259
3262
 
3260
- },{"../../most-utils":794,"most":739}],819:[function(require,module,exports){
3263
+ },{"../../most-utils":794,"most":739}],820:[function(require,module,exports){
3261
3264
  const html=require("nanohtml"),{createParamControls:createParamControls}=require("./parameterControls"),designParameters=(e,t,a)=>{const{parameterValues:s,parameterDefinitions:r,parameterDefaults:n}=e.design;try{const{controls:i}=createParamControls(Object.assign({},n,s),r,t.callback);return html`
3262
3265
  <section id='params' style='visibility:${0===e.design.parameterDefinitions.length?"hidden":"visible"};color:${e.themes.themeSettings.secondaryTextColor}'>
3263
3266
  <span id='paramsTable'>
@@ -3274,19 +3277,19 @@ const html=require("nanohtml"),{createParamControls:createParamControls}=require
3274
3277
  </section>
3275
3278
  `}catch(t){t.stack=void 0,e.status.error=t}};module.exports=designParameters;
3276
3279
 
3277
- },{"./parameterControls":826,"nanohtml":775}],820:[function(require,module,exports){
3280
+ },{"./parameterControls":827,"nanohtml":775}],821:[function(require,module,exports){
3278
3281
  const html=require("nanohtml"),CodeMirror=require("codemirror");require("codemirror/mode/javascript/javascript"),require("codemirror/addon/hint/javascript-hint");const editorOptions={mode:"javascript",indentUnit:2,smartIndent:!1,indentWithTabs:!1,lineNumbers:!0,autofocus:!0};let editor,wrapper;const createFileTree=e=>{const r=e.getValue();return r&&r.length>0?[{ext:"js",fullPath:"/changes.js",mimetype:"javascript",name:"changes.js",source:r}]:null},createWrapper=(e,r)=>{if(!wrapper){(wrapper=html`
3279
3282
  <section class='popup-menu' id='editor' key='editor' style='visibility:${"editor"===e.activeTool?"visible":"hidden"}'>
3280
3283
  <textarea></textarea>
3281
3284
  </section>
3282
3285
  `).onkeydown=(e=>e.stopPropagation()),wrapper.onkeyup=(e=>e.stopPropagation()),(editor=CodeMirror.fromTextArea(wrapper.firstChild,editorOptions)).setOption("extraKeys",{Tab:e=>{const r=Array(e.getOption("indentUnit")+1).join(" ");e.replaceSelection(r)}});const r=document.getElementsByTagName("HEAD")[0],t=document.createElement("LINK");t.rel="stylesheet",t.href="./css/codemirror.css",r.appendChild(t)}return wrapper},editorWrapper=(e,r)=>{const t=createWrapper(e);if("editor"===e.activeTool){t.style.visibility="visible",t.focus();let i=e.shortcuts.find(e=>"reevaluate"===e.args);i||(i={args:"Shift-Enter"});let o=i.key.toUpperCase();const s={Tab:e=>{const r=Array(e.getOption("indentUnit")+1).join(" ");e.replaceSelection(r)}};s[o=(o=(o=(o=(o=o.replace(/enter/i,"Enter")).replace(/alt[+-]/i,"Alt-")).replace(/cmd[+-]/i,"Cmd-")).replace(/control[+-]/i,"Ctrl-")).replace(/shift[+-]/i,"Shift-")]=(e=>{const t=createFileTree(e);t&&r.callback({type:"read",id:"loadRemote",data:t})}),editor.setOption("extraKeys",s),editor.focus(),editor.scrollIntoView({line:0,ch:0}),setTimeout(()=>editor.refresh(),0)}else t.style.visibility="hidden";if(e.design&&e.design.filesAndFolders&&1===e.design.filesAndFolders.length){const r=e.design.filesAndFolders[0];let t=r.source?r.source:"";r.mimetype?r.mimetype.indexOf("javascript")<0&&(t="// imported from external format"):t="// imported from project",t!==editor.getValue()&&(editor.focus(),editor.setValue(t),editor.setCursor(0,0),editor.refresh())}return t};module.exports={editorWrapper:editorWrapper};
3283
3286
 
3284
- },{"codemirror":692,"codemirror/addon/hint/javascript-hint":691,"codemirror/mode/javascript/javascript":693,"nanohtml":775}],821:[function(require,module,exports){
3287
+ },{"codemirror":692,"codemirror/addon/hint/javascript-hint":691,"codemirror/mode/javascript/javascript":693,"nanohtml":775}],822:[function(require,module,exports){
3285
3288
  const html=require("nanohtml"),path=require("path"),examplesData=require("../../../examples/examples.json"),examples=(e,a)=>{const l=new URL(window.location.href);let t=("null"===l.origin?"file://":l.origin)+path.dirname(l.pathname);t=t.endsWith("/")?t:t+path.sep;const s=[];for(const e in examplesData){if(!Object.prototype.hasOwnProperty.call(examplesData,e))continue;const a=examplesData[e].map(e=>html`<li>
3286
3289
  <a class="example" title="${e.description}" data-path="${t}${e.filePath}" href="#"> ${e.title} </a>
3287
3290
  </li>`);s.push(html`<li>${e}<ul class="examples-list">${a}</ul></li>`)}return html`<ul class="examples-group">${s}</ul>`};module.exports=examples;
3288
3291
 
3289
- },{"../../../examples/examples.json":671,"nanohtml":775,"path":683}],822:[function(require,module,exports){
3292
+ },{"../../../examples/examples.json":671,"nanohtml":775,"path":683}],823:[function(require,module,exports){
3290
3293
  const html=require("nanohtml"),help=(l,e)=>{const n=require("./examples")(l,e);return html`
3291
3294
  <section id='help' class="popup-menu" style='visibility:${"help"===l.activeTool?"visible":"hidden"};' >
3292
3295
  <div>
@@ -3313,7 +3316,7 @@ const html=require("nanohtml"),help=(l,e)=>{const n=require("./examples")(l,e);r
3313
3316
  </section>
3314
3317
  `};module.exports=help;
3315
3318
 
3316
- },{"./examples":821,"nanohtml":775}],823:[function(require,module,exports){
3319
+ },{"./examples":822,"nanohtml":775}],824:[function(require,module,exports){
3317
3320
  const html=require("nanohtml"),io=(e,o)=>{const t=e.io.availableExportFormats.map(({name:t,displayName:l})=>{l=o.translate(l);const a=e.io.exportFormat?e.io.exportFormat.toLowerCase()===t.toLowerCase():void 0;return html`<option value=${t} selected='${a}'>
3318
3321
  ${l}
3319
3322
  </option>`}),l=e.io.availableExportFormats.length>0;return html`
@@ -3332,7 +3335,7 @@ const html=require("nanohtml"),io=(e,o)=>{const t=e.io.availableExportFormats.ma
3332
3335
  </span>
3333
3336
  `};module.exports=io;
3334
3337
 
3335
- },{"nanohtml":775}],824:[function(require,module,exports){
3338
+ },{"nanohtml":775}],825:[function(require,module,exports){
3336
3339
  const html=require("nanohtml"),dom=(e,r,t,o)=>{const i=e=>e;i.translate=(e=>e),r=r||i;const s=require("./options")(e,r),n=require("./designParameters")(e,t,r),a=require("./status")(e,r),d=require("./help")(e,r),m=require("./io")(e,r),p=require("./editor").editorWrapper(e,o,r),u=require("./toolbar")(e,r),l=require("./viewer")(e,r),h=require("./viewerControls")(e,r);if(e.themes&&e.themes.themeSettings){const{mainTextColor:r,secondaryTextColor:t}=e.themes.themeSettings,o=document.body;o.style.setProperty("--main-text-color",`${r}`),o.style.setProperty("--secondary-text-color",`${t}`)}return html`
3337
3340
  <div id='container'>
3338
3341
  <div id='header'>
@@ -3367,7 +3370,7 @@ const html=require("nanohtml"),dom=(e,r,t,o)=>{const i=e=>e;i.translate=(e=>e),r
3367
3370
  </div>
3368
3371
  `};module.exports=dom;
3369
3372
 
3370
- },{"./designParameters":819,"./editor":820,"./help":822,"./io":823,"./options":825,"./status":828,"./toolbar":829,"./viewer":830,"./viewerControls":831,"nanohtml":775}],825:[function(require,module,exports){
3373
+ },{"./designParameters":820,"./editor":821,"./help":823,"./io":824,"./options":826,"./status":829,"./toolbar":830,"./viewer":831,"./viewerControls":832,"nanohtml":775}],826:[function(require,module,exports){
3371
3374
  const html=require("nanohtml"),options=(e,t)=>{const l=e.languages.available.map(l=>{const i=e.languages.active===l.code;return html`<option value='${l.code}' selected=${i}>${t.translate(l.fullName)}</option>`}),i=Object.entries(e.themes.available).map(t=>{const l=t[0],i=t[1].name,s=e.themes.active===l;return html`<option value='${l}' selected=${s}>${i}</option>`}),s=require("./shortcuts")(e,t);return html`
3372
3375
  <section class="popup-menu" id='options' style='visibility:${"options"===e.activeTool?"visible":"hidden"}; color:${e.themes.themeSettings.secondaryTextColor}'>
3373
3376
 
@@ -3396,7 +3399,7 @@ const html=require("nanohtml"),options=(e,t)=>{const l=e.languages.available.map
3396
3399
 
3397
3400
  </section>`};module.exports=options;
3398
3401
 
3399
- },{"./shortcuts":827,"nanohtml":775}],826:[function(require,module,exports){
3402
+ },{"./shortcuts":828,"nanohtml":775}],827:[function(require,module,exports){
3400
3403
  const html=require("nanohtml");let paramControls,currentGroupName,currentGroupIsExpanded;const createParamControls=(e={},t,r)=>{return paramControls=[],currentGroupName="",currentGroupIsExpanded=!0,{controls:t.map(t=>createParamRowFromDefinition(t,e,r))}},createParamRowFromDefinition=(e,t,r)=>{const n=e.type.toLowerCase();return"group"===n?createGroupRowFromDefinition(e,t):createInputRowFromDefinition(n,e,t,r)},createGroupRowFromDefinition=(e,t)=>{let r=e.name+":",n="";"caption"in e&&(r=e.caption,n="caption"),currentGroupIsExpanded=e.name in t?"closed"!==t[e.name]:"closed"!==e.initial,currentGroupName=e.name;const o=html`<tr class=${"groupTitle "+(currentGroupIsExpanded?"open":"closed")} data-groupname=${currentGroupName} >
3401
3404
  <td class=${n} colspan="2">
3402
3405
  <h1>
@@ -3423,7 +3426,7 @@ const html=require("nanohtml");let paramControls,currentGroupName,currentGroupIs
3423
3426
  checked=${"checked"in e?a:""}
3424
3427
  />`;i.paramName=e.name,i.paramType=e.type;for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.indexOf(t)<0&&i.setAttribute(t,e[t]);return[i]};module.exports={createParamControls:createParamControls};
3425
3428
 
3426
- },{"nanohtml":775}],827:[function(require,module,exports){
3429
+ },{"nanohtml":775}],828:[function(require,module,exports){
3427
3430
  const html=require("nanohtml"),shortcuts=(t,r)=>{const e=t.shortcuts.map((t,e)=>{const{command:a,key:s,args:n,tmpKey:o,error:h}=t,d=o&&o.length>0?o:r.translate("type and hit enter"),l=t.inProgress?"":s,c=n||"";return html`
3428
3431
  <tr>
3429
3432
  <td>${r.translate(a)}: ${r.translate(c)}</td>
@@ -3456,7 +3459,7 @@ const html=require("nanohtml"),shortcuts=(t,r)=>{const e=t.shortcuts.map((t,e)=>
3456
3459
  </table>
3457
3460
  </section>`};module.exports=shortcuts;
3458
3461
 
3459
- },{"nanohtml":775}],828:[function(require,module,exports){
3462
+ },{"nanohtml":775}],829:[function(require,module,exports){
3460
3463
  const html=require("nanohtml"),status=(r,e)=>{const s=r.status;let t="",a="",o="";s.error&&(s.error.fileName&&!s.error.fileName.startsWith("blob")&&(t=`${s.error.fileName}:${s.error.lineNumber}:${s.error.columnNumber}`),a=`${s.error.name}: ${s.error.message}`,s.error.stack&&(o=s.error.stack.trim().split("\n").map(r=>html`<ul>${r}</ul>`)));const i=void 0!==s.error?html`<span>
3461
3464
  <div id='errormessage'>
3462
3465
  <p>
@@ -3476,7 +3479,7 @@ const html=require("nanohtml"),status=(r,e)=>{const s=r.status;let t="",a="",o="
3476
3479
  </span>
3477
3480
  `};module.exports=status;
3478
3481
 
3479
- },{"nanohtml":775}],829:[function(require,module,exports){
3482
+ },{"nanohtml":775}],830:[function(require,module,exports){
3480
3483
  const html=require("nanohtml"),toolbar=(t,e)=>{const o=html`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`,l=html`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit-3"><polygon points="14 2 18 6 7 17 3 17 3 13 14 2"/><line x1="3" y1="22" x2="21" y2="22"/></svg>`,r=html`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-help-circle"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12" y2="17"/></svg>`;return html`<span id='toolbar'>
3481
3484
  <button id='toggleOptions' aria-label='options'>
3482
3485
  ${o}
@@ -3489,10 +3492,10 @@ const html=require("nanohtml"),toolbar=(t,e)=>{const o=html`<svg xmlns="http://w
3489
3492
  </button>
3490
3493
  </span>`};module.exports=toolbar;
3491
3494
 
3492
- },{"nanohtml":775}],830:[function(require,module,exports){
3495
+ },{"nanohtml":775}],831:[function(require,module,exports){
3493
3496
  const html=require("nanohtml"),rendererStuff=require("@jscad/regl-renderer"),{pointerGestures:pointerGestures}=require("../../most-gestures"),{prepareRender:prepareRender,drawCommands:drawCommands,cameras:cameras,entitiesFromSolids:entitiesFromSolids}=rendererStuff,perspectiveCamera=cameras.perspective,orbitControls=rendererStuff.controls.orbit,rotateSpeed=.002,panSpeed=1,zoomSpeed=.08;let render,viewerOptions,camera=perspectiveCamera.defaults,controls=orbitControls.defaults,rotateDelta=[0,0],panDelta=[0,0],zoomDelta=0,zoomToFit=!1,updateView=!0;const grid={visuals:{drawCmd:"drawGrid",show:!0,color:[0,0,0,1],subColor:[0,0,1,.5],fadeOut:!1,transparent:!0},size:[200,200],ticks:[10,1]},axes={visuals:{drawCmd:"drawAxis",show:!0}};let prevSolids,prevEntities=[],prevColor=[];const viewer=(e,r)=>{const t=html`<canvas id='renderTarget'> </canvas>`;if(render){const r=e.design.solids.filter(e=>e&&e instanceof Object);if(prevSolids){const t=e.themes.themeSettings.viewer.rendering.meshColor,o=prevColor===t;compareSolids(r,prevSolids)&&o||(prevEntities=entitiesFromSolids({color:t},r),prevColor=t,zoomToFit=e.viewer.rendering.autoZoom)}if(prevSolids=r,e.themes&&e.themes.themeSettings){const r=e.themes.themeSettings.viewer;grid.visuals.color=r.grid.color,grid.visuals.subColor=r.grid.subColor,viewerOptions.rendering&&(viewerOptions.rendering.background=r.rendering.background,viewerOptions.rendering.meshColor=r.rendering.meshColor,updateView=!0)}if(viewerOptions.entities=[e.viewer.grid.show?grid:void 0,e.viewer.axes.show?axes:void 0,...prevEntities].filter(e=>void 0!==e),""!==e.viewer.camera.position){const r=cameras.camera.toPresetView(e.viewer.camera.position,{camera:camera});camera.position=r.position,perspectiveCamera.update(camera),e.viewer.camera.position=""}e.viewer.rendering&&(controls.autoRotate.enabled=e.viewer.rendering.autoRotate)}else{const e=setup(t);if(e.error)return html`<b style="color:red; background:white; position:fixed; z-index:10; top:50%">${e.error}</b>`;viewerOptions=e.viewerOptions,camera=e.camera,render=prepareRender(viewerOptions);const r=pointerGestures(t);window.addEventListener("resize",e=>{updateView=!0}),r.drags.forEach(e=>{const r=e.originalEvents[0],{x:t,y:o}=e.delta;!0===r.shiftKey||r.touches&&r.touches.length>2?(panDelta[0]+=t,panDelta[1]+=o):(rotateDelta[0]-=t,rotateDelta[1]-=o)}),r.zooms.forEach(e=>{zoomDelta-=e}),r.taps.filter(e=>2===e.nb).forEach(e=>{zoomToFit=!0});const o=()=>{if(rotateDelta[0]||rotateDelta[1]){const e=orbitControls.rotate({controls:controls,camera:camera,speed:.002},rotateDelta);rotateDelta=[0,0],controls={...controls,...e.controls},updateView=!0}if(panDelta[0]||panDelta[1]){const e=orbitControls.pan({controls:controls,camera:camera,speed:1},panDelta);panDelta=[0,0],camera.position=e.camera.position,camera.target=e.camera.target,updateView=!0}if(zoomDelta){const e=orbitControls.zoom({controls:controls,camera:camera,speed:.08},zoomDelta);controls={...controls,...e.controls},zoomDelta=0,updateView=!0}if(zoomToFit){controls.zoomToFit.tightness=1.5;const e=orbitControls.zoomToFit({controls:controls,camera:camera,entities:prevEntities});controls={...controls,...e.controls},zoomToFit=!1,updateView=!0}},a=e=>{if(o(),updateView){const e=orbitControls.update({controls:controls,camera:camera});controls={...controls,...e.controls},updateView=controls.changed,camera.position=e.camera.position,perspectiveCamera.update(camera),resize(t),render(viewerOptions)}window.requestAnimationFrame(a)};window.requestAnimationFrame(a)}return t},createContext=(e,r)=>{const t=r=>{try{const t=e.getContext(r);return t?{gl:t,type:r}:null}catch(e){return null}};return t("webgl2")||t("webgl")||t("experimental-webgl")||t("webgl-experimental")},setup=e=>{const r=Object.assign({},perspectiveCamera.defaults);r.position=[150,-180,233];const{gl:t,type:o}=createContext(e),a={glOptions:{gl:t},camera:r,drawCommands:{drawAxis:drawCommands.drawAxis,drawGrid:drawCommands.drawGrid,drawLines:drawCommands.drawLines,drawMesh:drawCommands.drawMesh},entities:[]};return"webgl"===o&&t.getExtension("OES_element_index_uint")&&(a.glOptions.optionalExtensions=["oes_element_index_uint"]),{viewerOptions:a,camera:r,error:void 0}},resize=e=>{const r=window.devicePixelRatio||1,t=e.getBoundingClientRect(),o=(t.right-t.left)*r,a=(t.bottom-t.top)*r,i=e.width,n=e.height;i===o&&n===a||(e.width=o,e.height=a,perspectiveCamera.setProjection(camera,camera,{width:o,height:a}),perspectiveCamera.update(camera,camera))};let idCounter=Date.now();const compareSolids=(e,r)=>(e=e.map(e=>(e.id||(e.id=++idCounter),e)),!!r&&(e.length===r.length&&e.reduce((t,o,a)=>t&&e[a].id===r[a].id,!0)));module.exports=viewer;
3494
3497
 
3495
- },{"../../most-gestures":786,"@jscad/regl-renderer":614,"nanohtml":775}],831:[function(require,module,exports){
3498
+ },{"../../most-gestures":786,"@jscad/regl-renderer":614,"nanohtml":775}],832:[function(require,module,exports){
3496
3499
  const html=require("nanohtml"),viewerControls=(e,o)=>html`
3497
3500
  <div id='controls'>
3498
3501
  <label for="toggleGrid">${o`grid`}</label>
@@ -3505,19 +3508,19 @@ const html=require("nanohtml"),viewerControls=(e,o)=>html`
3505
3508
  <input type="checkbox" id="toggleAutoZoom" checked=${e.viewer.rendering.autoZoom}/>
3506
3509
  </div>`;module.exports=viewerControls;
3507
3510
 
3508
- },{"nanohtml":775}],832:[function(require,module,exports){
3511
+ },{"nanohtml":775}],833:[function(require,module,exports){
3509
3512
  const compositeKeyFromKeyEvent=e=>{const t=e.ctrlKey?"ctrl+":"",o=e.shiftKey?"shift+":"",s=e.metaKey?"command+":"";let i=e.key.toLowerCase();return t&&"control"===i&&(i=""),o&&"shift"===i&&(i=""),s&&"meta"===i&&(i=""),`${t}${o}${s}${i}`},simpleKey=e=>e.key?e.key.toLowerCase():void 0,getKeyCombos=(e,t,o)=>{const{dropRepeats:s,endKeys:i}=Object.assign({},{dropRepeats:!1,endKeys:[]},e);o=o.multicast().debounce(10),s&&(o=o.skipRepeatsWith((e,t)=>simpleKey(e)===simpleKey(t)));const m=o.throttle(1e3).delay(2e3);return o.merge(t.map(e=>"end")).merge(m.map(e=>"end")).loop((e,t)=>{if("end"===t||i.includes(simpleKey(t))){return{seed:[],value:{event:e.length>0?e[0].event:void 0,compositeKey:e.map(e=>e.compositeKey).join("+")}}}{const o=simpleKey(t);e.push({event:t,compositeKey:o})}return{seed:e}},[]).filter(e=>void 0!==e).filter(e=>void 0!==e.event).multicast()},isKeyEventScopeValid=(e,t)=>!(!t.className||"jscad"!==t.className||t.getAttribute("key")!==e);module.exports={compositeKeyFromKeyEvent:compositeKeyFromKeyEvent,getKeyCombos:getKeyCombos,simpleKey:simpleKey,isKeyEventScopeValid:isKeyEventScopeValid};
3510
3513
 
3511
- },{}],833:[function(require,module,exports){
3514
+ },{}],834:[function(require,module,exports){
3512
3515
  const makeLogger=e=>{const{enabled:o}=Object.assign({},{enabled:!1},e);return{debug:(...e)=>{o&&console.debug(...e)},info:o?console.info.bind(window.console):()=>{},warning:(...e)=>{o&&console.warn(...e)},error:(...e)=>{o&&console.error(...e)}}};module.exports=makeLogger;
3513
3516
 
3514
- },{}],834:[function(require,module,exports){
3517
+ },{}],835:[function(require,module,exports){
3515
3518
  const omit=(e,t)=>Object.keys(t).reduce((c,i)=>(e.includes(i)||(c[i]=t[i]),c),{}),keep=(e,t)=>Object.keys(t).reduce((c,i)=>(e.includes(i)&&(c[i]=t[i]),c),{}),atKey=(e,t)=>e in t?e:{};module.exports={omit:omit,keep:keep,atKey:atKey};
3516
3519
 
3517
- },{}],835:[function(require,module,exports){
3520
+ },{}],836:[function(require,module,exports){
3518
3521
  const url=require("url"),fetchUriParams=(r,a,e)=>{const s=new URL(r);return s.searchParams.get(a)?s.searchParams.get(a):e},getAllUriParams=r=>url.parse(r,!0).query;module.exports={fetchUriParams:fetchUriParams,getAllUriParams:getAllUriParams};
3519
3522
 
3520
- },{"url":689}],836:[function(require,module,exports){
3523
+ },{"url":689}],837:[function(require,module,exports){
3521
3524
  const merge=(e={},s,o)=>(e=s,Object.keys(o).forEach(t=>{const r=o[t],c="object"==typeof r,f="function"==typeof r,n=Array.isArray(r);if(f)e[t]=o[t];else if(n){const r=s[t]||[];e[t]=Object.assign([],r,o[t])}else if(c){const o=s[t]||{};e[t]=merge({},o,r)}else e[t]=o[t]}),e);module.exports={merge:merge};
3522
3525
 
3523
3526
  },{}]},{},[784])(784)