@floless/app 0.77.0 → 0.78.0

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.
@@ -53093,7 +53093,7 @@ function appVersion() {
53093
53093
  return resolveVersion({
53094
53094
  isSea: isSea2(),
53095
53095
  sqVersionXml: readSqVersionXml(),
53096
- define: true ? "0.77.0" : void 0,
53096
+ define: true ? "0.78.0" : void 0,
53097
53097
  pkgVersion: readPkgVersion()
53098
53098
  });
53099
53099
  }
@@ -53103,7 +53103,7 @@ function resolveChannel(s) {
53103
53103
  return "dev";
53104
53104
  }
53105
53105
  function appChannel() {
53106
- return resolveChannel({ isSea: isSea2(), define: true ? "0.77.0" : void 0 });
53106
+ return resolveChannel({ isSea: isSea2(), define: true ? "0.78.0" : void 0 });
53107
53107
  }
53108
53108
 
53109
53109
  // workflow-update.ts
@@ -53990,6 +53990,16 @@ var BASE_PLATE_PARAMS = {
53990
53990
  edgeDist: [0, 5e3],
53991
53991
  weldLeg: [0, 200]
53992
53992
  };
53993
+ var SHEAR_PLATE_PARAMS = {
53994
+ plateThickness: [1, 100],
53995
+ plateHeight: [1, 5e3],
53996
+ plateWidth: [1, 2e3],
53997
+ boltDia: [1, 100],
53998
+ boltCols: [1, 10],
53999
+ boltRows: [1, 30],
54000
+ boltPitch: [1, 1e3],
54001
+ edgeDist: [0, 2e3]
54002
+ };
53993
54003
  function sanitizeRecipe(raw) {
53994
54004
  if (!raw || typeof raw !== "object") return void 0;
53995
54005
  const r = raw;
@@ -54008,6 +54018,16 @@ function sanitizeRecipe(raw) {
54008
54018
  }
54009
54019
  return Object.keys(params).length ? { kind: r.kind, params } : void 0;
54010
54020
  }
54021
+ if (r.kind === "shear-plate") {
54022
+ const params = {};
54023
+ for (const [k, [lo, hi]] of Object.entries(SHEAR_PLATE_PARAMS)) {
54024
+ if (k in num3) {
54025
+ if (!(num3[k] >= lo && num3[k] <= hi)) return void 0;
54026
+ params[k] = num3[k];
54027
+ }
54028
+ }
54029
+ return Object.keys(params).length ? { kind: r.kind, params } : void 0;
54030
+ }
54011
54031
  return Object.keys(num3).length ? { kind: r.kind, params: num3 } : void 0;
54012
54032
  }
54013
54033
  async function extractConnection(companionId, ifcPath, id) {
@@ -3054,6 +3054,23 @@ const view3dApi={
3054
3054
  toast((had?'Base plate on '+col.id+' replaced with imported “'+(conn.name||'connection')+'”':'Base plate “'+(conn.name||'imported')+'” applied to '+col.id)+' — edit its parameters on the member');
3055
3055
  return;
3056
3056
  }
3057
+ // Slice E: a RECOGNIZED shear/fin plate dropped onto a BEAM → bake an EDITABLE shear-plate recipe joint on
3058
+ // the nearest end; expandShearPlate re-derives it there from the fitted params. Needs a beam at the pick.
3059
+ const beam=(rc&&rc.kind==='shear-plate'&&pick.anchorId)?P.members.find(m=>m&&m.id===pick.anchorId&&m.role==='beam'):null;
3060
+ if(beam){
3061
+ const id='cx'+Date.now().toString(36)+Math.floor(Math.random()*1e4).toString(36);
3062
+ // Nearest end via the resolved 3D geometry: end0 = beam.from (wp[0]), end1 = beam.to (wp[1]).
3063
+ const g=partsById[beam.id],d3=(a,b)=>a&&b?Math.hypot(a[0]-b[0],a[1]-b[1],a[2]-b[2]):Infinity;
3064
+ const endIdx=(g&&g.from&&g.to&&d3(pick.point,g.to)<d3(pick.point,g.from))?1:0;
3065
+ const joint={id,kind:'shear-plate',main:beam.id,at:'end'+endIdx,params:Object.assign({},rc.params),source:'user'};
3066
+ pendingConnSel=id; // its parts only exist after the 3D rebuild → select the whole connection there
3067
+ // One shear plate per beam END: replace any existing joint on this end (else two overlap and "edit on
3068
+ // member" would target the older joint, not this import).
3069
+ const had=(C.joints||[]).some(x=>x&&x.kind==='shear-plate'&&x.main===beam.id&&x.at==='end'+endIdx);
3070
+ edit(()=>{C.joints=(Array.isArray(C.joints)?C.joints:[]).filter(x=>!(x&&x.kind==='shear-plate'&&x.main===beam.id&&x.at==='end'+endIdx));C.joints.push(joint);selIds=new Set();});
3071
+ toast((had?'Shear plate on '+beam.id+' '+(endIdx?'end':'start')+' replaced with imported “'+(conn.name||'connection')+'”':'Shear plate “'+(conn.name||'imported')+'” applied to '+beam.id+' '+(endIdx?'end':'start'))+' — edit its parameters on the member');
3072
+ return;
3073
+ }
3057
3074
  // Slice B: opaque custom mesh — bake at the picked point (joint.place); expandCustom re-expands it into
3058
3075
  // the scene as one selectable unit. Unrecognized imports, and a recognized base plate NOT dropped on a
3059
3076
  // column, land here (still faithful geometry) with a hint toward the editable path.
@@ -3062,7 +3079,7 @@ const view3dApi={
3062
3079
  const joint={id,kind:'custom',name:conn.name||'Imported connection',place:pick.point,geometry:conn.geometry,source:'user'};
3063
3080
  if(pick.anchorId)joint.main=pick.anchorId; // snapped to a member face → record it for the inspector's "on member" line
3064
3081
  edit(()=>{if(!Array.isArray(C.joints))C.joints=[];C.joints.push(joint);selIds=new Set(conn.geometry.map((g,i)=>id+':'+(g.id||'m'+i)));});
3065
- toast(rc?('Imported “'+(conn.name||'connection')+'” as geometry — drop it on a column to apply it as an editable base plate')
3082
+ toast(rc?('Imported “'+(conn.name||'connection')+'” as geometry — drop it on a '+(rc.kind==='shear-plate'?'beam end to apply it as an editable shear plate':'column to apply it as an editable base plate'))
3066
3083
  :('Connection “'+(conn.name||'imported')+'” placed'+(pick.anchorId?' on '+pick.anchorId:'')+' — select it to move or replace'));
3067
3084
  return;
3068
3085
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.77.0",
3
+ "version": "0.78.0",
4
4
  "type": "module",
5
5
  "description": "Thin localhost host for floless.app — serves web/ and shells the aware CLI. No engine, no LLM.",
6
6
  "bin": {