wadi-mcp 0.1.24 → 0.1.25
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.
- package/README.md +1 -0
- package/dist/server.mjs +201 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ repo; this server replaces them for agents that speak MCP.)
|
|
|
16
16
|
| Tool | What it does |
|
|
17
17
|
| --- | --- |
|
|
18
18
|
| `wadi_check` | Compile + validate a `.wdl`: parse, resolve formulas/grids, schema + wall/roof geometry, and the structural conventions (C1/C2/C3). Returns pass/fail + errors/warnings. **Run after every edit.** |
|
|
19
|
+
| `wadi_scope` | Resolve a `.wdl`'s **variables, points & grid lines** to their actual values (with each variable's formula). See what `main.x2` / `House.W/2` resolves to before placing an object. |
|
|
19
20
|
| `wadi_preview` | Render a `.wdl` to **PNG images** you can look at — floor plans, elevations, roof top view. Confirm layout/sizes/openings/roof visually. |
|
|
20
21
|
| `wadi_examples` | List, or fetch the full source of, a validated example `.wdl` (`minimal` / `two_room` / `two_story` / `coastal` / `complete`). Copy from these. |
|
|
21
22
|
| `wadi_reference` | The authoring docs, embedded: `guide`, `dsl`, `conventions`, `coordinate-system`, `parametric-conventions`, `roof-v2-guide`, `data-model`. |
|
package/dist/server.mjs
CHANGED
|
@@ -14016,7 +14016,7 @@ function resolveGrids(config3, scope, warnings, defaultT) {
|
|
|
14016
14016
|
const out = /* @__PURE__ */ new Map();
|
|
14017
14017
|
const grids = config3.grids;
|
|
14018
14018
|
if (!grids) return out;
|
|
14019
|
-
const
|
|
14019
|
+
const num4 = (v, where) => {
|
|
14020
14020
|
if (typeof v === "number") return v;
|
|
14021
14021
|
if (isFormula(v)) {
|
|
14022
14022
|
const r2 = evalFormula(v, scope);
|
|
@@ -14037,9 +14037,9 @@ function resolveGrids(config3, scope, warnings, defaultT) {
|
|
|
14037
14037
|
const thickMap = axis === "x" ? rg.xt : rg.yt;
|
|
14038
14038
|
for (const ln of lines ?? []) {
|
|
14039
14039
|
if (!ln || typeof ln.name !== "string") continue;
|
|
14040
|
-
const pos =
|
|
14040
|
+
const pos = num4(ln.at, `grids/${id}/${axis}/${ln.name}`);
|
|
14041
14041
|
if (pos !== null) posMap.set(ln.name, pos);
|
|
14042
|
-
const t = ln.thickness === void 0 ? defaultT :
|
|
14042
|
+
const t = ln.thickness === void 0 ? defaultT : num4(ln.thickness, `grids/${id}/${axis}/${ln.name}/thickness`) ?? defaultT;
|
|
14043
14043
|
thickMap.set(ln.name, t);
|
|
14044
14044
|
}
|
|
14045
14045
|
}
|
|
@@ -31568,15 +31568,15 @@ var init_layerDefaults = __esm({
|
|
|
31568
31568
|
// ../editor/src/svg2d/config.ts
|
|
31569
31569
|
function houseSpanUnits(hc) {
|
|
31570
31570
|
const o = hc;
|
|
31571
|
-
const
|
|
31571
|
+
const num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
31572
31572
|
let best = 0;
|
|
31573
31573
|
for (const fl of o?.floors ?? []) {
|
|
31574
31574
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
31575
31575
|
for (const obj of fl.objects ?? []) {
|
|
31576
31576
|
const t = obj.type;
|
|
31577
31577
|
if (t === "floor_slab" || t === "beam" || t === "room") {
|
|
31578
|
-
const x =
|
|
31579
|
-
const w =
|
|
31578
|
+
const x = num4(obj.x), y = num4(obj.y);
|
|
31579
|
+
const w = num4(obj.width), l = num4(obj.length);
|
|
31580
31580
|
if (x !== void 0 && y !== void 0 && w !== void 0 && l !== void 0) {
|
|
31581
31581
|
if (x < minX) minX = x;
|
|
31582
31582
|
if (y < minY) minY = y;
|
|
@@ -31584,8 +31584,8 @@ function houseSpanUnits(hc) {
|
|
|
31584
31584
|
if (y + l > maxY) maxY = y + l;
|
|
31585
31585
|
}
|
|
31586
31586
|
} else if (t === "wall") {
|
|
31587
|
-
const sx =
|
|
31588
|
-
const ex =
|
|
31587
|
+
const sx = num4(obj.start_x), sy = num4(obj.start_y);
|
|
31588
|
+
const ex = num4(obj.end_x), ey = num4(obj.end_y);
|
|
31589
31589
|
if (sx !== void 0 && sy !== void 0 && ex !== void 0 && ey !== void 0) {
|
|
31590
31590
|
minX = Math.min(minX, sx, ex);
|
|
31591
31591
|
maxX = Math.max(maxX, sx, ex);
|
|
@@ -31600,7 +31600,7 @@ function houseSpanUnits(hc) {
|
|
|
31600
31600
|
}
|
|
31601
31601
|
if (best > 0) return best;
|
|
31602
31602
|
const s = o?.site;
|
|
31603
|
-
return Math.max(
|
|
31603
|
+
return Math.max(num4(s?.plot_length) ?? 0, num4(s?.plot_width) ?? 0);
|
|
31604
31604
|
}
|
|
31605
31605
|
function computeTextScale(spanUnits) {
|
|
31606
31606
|
if (!(spanUnits > 0)) return 1;
|
|
@@ -83764,8 +83764,8 @@ var require_three = __commonJS({
|
|
|
83764
83764
|
function onSegment(p, q, r2) {
|
|
83765
83765
|
return q.x <= Math.max(p.x, r2.x) && q.x >= Math.min(p.x, r2.x) && q.y <= Math.max(p.y, r2.y) && q.y >= Math.min(p.y, r2.y);
|
|
83766
83766
|
}
|
|
83767
|
-
function sign(
|
|
83768
|
-
return
|
|
83767
|
+
function sign(num4) {
|
|
83768
|
+
return num4 > 0 ? 1 : num4 < 0 ? -1 : 0;
|
|
83769
83769
|
}
|
|
83770
83770
|
function intersectsPolygon(a, b) {
|
|
83771
83771
|
let p = a;
|
|
@@ -149717,7 +149717,7 @@ var require_ColladaExporter = __commonJS({
|
|
|
149717
149717
|
const IS_END_TAG = /^<\//;
|
|
149718
149718
|
const IS_SELF_CLOSING = /(\?>$)|(\/>$)/;
|
|
149719
149719
|
const HAS_TEXT = /<[^>]+>[^<]*<\/[^<]+>/;
|
|
149720
|
-
const pad = (ch,
|
|
149720
|
+
const pad = (ch, num4) => num4 > 0 ? ch + pad(ch, num4 - 1) : "";
|
|
149721
149721
|
let tagnum = 0;
|
|
149722
149722
|
return (_b = (_a3 = urdf.match(/(<[^>]+>[^<]+<\/[^<]+>)|(<[^>]+>)/g)) == null ? void 0 : _a3.map((tag) => {
|
|
149723
149723
|
if (!HAS_TEXT.test(tag) && !IS_SELF_CLOSING.test(tag) && IS_END_TAG.test(tag)) {
|
|
@@ -160756,10 +160756,10 @@ var require_MMDExporter = __commonJS({
|
|
|
160756
160756
|
console.warn("THREE.MMDExporter: parseVpd() requires SkinnedMesh instance.");
|
|
160757
160757
|
return null;
|
|
160758
160758
|
}
|
|
160759
|
-
function toStringsFromNumber(
|
|
160760
|
-
if (Math.abs(
|
|
160761
|
-
|
|
160762
|
-
let a =
|
|
160759
|
+
function toStringsFromNumber(num4) {
|
|
160760
|
+
if (Math.abs(num4) < 1e-6)
|
|
160761
|
+
num4 = 0;
|
|
160762
|
+
let a = num4.toString();
|
|
160763
160763
|
if (a.indexOf(".") === -1) {
|
|
160764
160764
|
a += ".";
|
|
160765
160765
|
}
|
|
@@ -202252,8 +202252,8 @@ var require_FBXLoader = __commonJS({
|
|
|
202252
202252
|
return result;
|
|
202253
202253
|
}
|
|
202254
202254
|
for (let i2 = 0; i2 < CORRECT.length; ++i2) {
|
|
202255
|
-
const
|
|
202256
|
-
if (
|
|
202255
|
+
const num4 = read(1);
|
|
202256
|
+
if (num4 === CORRECT[i2]) {
|
|
202257
202257
|
return false;
|
|
202258
202258
|
}
|
|
202259
202259
|
}
|
|
@@ -219131,8 +219131,8 @@ var require_KTX2Loader = __commonJS({
|
|
|
219131
219131
|
this.transcoderPath = path;
|
|
219132
219132
|
return this;
|
|
219133
219133
|
}
|
|
219134
|
-
setWorkerLimit(
|
|
219135
|
-
this.workerPool.setWorkerLimit(
|
|
219134
|
+
setWorkerLimit(num4) {
|
|
219135
|
+
this.workerPool.setWorkerLimit(num4);
|
|
219136
219136
|
return this;
|
|
219137
219137
|
}
|
|
219138
219138
|
detectSupport(renderer) {
|
|
@@ -225396,8 +225396,8 @@ var require_lottie = __commonJS({
|
|
|
225396
225396
|
this.renderableComponents.splice(this.renderableComponents.indexOf(component), 1);
|
|
225397
225397
|
}
|
|
225398
225398
|
},
|
|
225399
|
-
prepareRenderableFrame: function(
|
|
225400
|
-
this.checkLayerLimits(
|
|
225399
|
+
prepareRenderableFrame: function(num4) {
|
|
225400
|
+
this.checkLayerLimits(num4);
|
|
225401
225401
|
},
|
|
225402
225402
|
checkTransparency: function() {
|
|
225403
225403
|
if (this.finalTransform.mProp.o.v <= 0) {
|
|
@@ -225418,8 +225418,8 @@ var require_lottie = __commonJS({
|
|
|
225418
225418
|
* current frame number in Layer's time
|
|
225419
225419
|
*
|
|
225420
225420
|
*/
|
|
225421
|
-
checkLayerLimits: function(
|
|
225422
|
-
if (this.data.ip - this.data.st <=
|
|
225421
|
+
checkLayerLimits: function(num4) {
|
|
225422
|
+
if (this.data.ip - this.data.st <= num4 && this.data.op - this.data.st > num4) {
|
|
225423
225423
|
if (this.isInRange !== true) {
|
|
225424
225424
|
this.globalData._mdf = true;
|
|
225425
225425
|
this._mdf = true;
|
|
@@ -226772,7 +226772,7 @@ var require_lottie = __commonJS({
|
|
|
226772
226772
|
* if layers is currently in range
|
|
226773
226773
|
*
|
|
226774
226774
|
*/
|
|
226775
|
-
prepareProperties: function(
|
|
226775
|
+
prepareProperties: function(num4, isVisible) {
|
|
226776
226776
|
var i2;
|
|
226777
226777
|
var len = this.dynamicProperties.length;
|
|
226778
226778
|
for (i2 = 0; i2 < len; i2 += 1) {
|
|
@@ -226885,14 +226885,14 @@ var require_lottie = __commonJS({
|
|
|
226885
226885
|
this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true };
|
|
226886
226886
|
this.lv = PropertyFactory.getProp(this, data.au && data.au.lv ? data.au.lv : { k: [100] }, 1, 0.01, this);
|
|
226887
226887
|
}
|
|
226888
|
-
AudioElement.prototype.prepareFrame = function(
|
|
226889
|
-
this.prepareRenderableFrame(
|
|
226890
|
-
this.prepareProperties(
|
|
226888
|
+
AudioElement.prototype.prepareFrame = function(num4) {
|
|
226889
|
+
this.prepareRenderableFrame(num4, true);
|
|
226890
|
+
this.prepareProperties(num4, true);
|
|
226891
226891
|
if (!this.tm._placeholder) {
|
|
226892
226892
|
var timeRemapped = this.tm.v;
|
|
226893
226893
|
this._currentTime = timeRemapped;
|
|
226894
226894
|
} else {
|
|
226895
|
-
this._currentTime =
|
|
226895
|
+
this._currentTime = num4 / this.data.sr;
|
|
226896
226896
|
}
|
|
226897
226897
|
this._volume = this.lv.v[0];
|
|
226898
226898
|
var totalVolume = this._volume * this._volumeMultiplier;
|
|
@@ -226946,7 +226946,7 @@ var require_lottie = __commonJS({
|
|
|
226946
226946
|
};
|
|
226947
226947
|
function BaseRenderer() {
|
|
226948
226948
|
}
|
|
226949
|
-
BaseRenderer.prototype.checkLayers = function(
|
|
226949
|
+
BaseRenderer.prototype.checkLayers = function(num4) {
|
|
226950
226950
|
var i2;
|
|
226951
226951
|
var len = this.layers.length;
|
|
226952
226952
|
var data;
|
|
@@ -226954,7 +226954,7 @@ var require_lottie = __commonJS({
|
|
|
226954
226954
|
for (i2 = len - 1; i2 >= 0; i2 -= 1) {
|
|
226955
226955
|
if (!this.elements[i2]) {
|
|
226956
226956
|
data = this.layers[i2];
|
|
226957
|
-
if (data.ip - data.st <=
|
|
226957
|
+
if (data.ip - data.st <= num4 - this.layers[i2].st && data.op - data.st > num4 - this.layers[i2].st) {
|
|
226958
226958
|
this.buildItem(i2);
|
|
226959
226959
|
}
|
|
226960
226960
|
}
|
|
@@ -227702,10 +227702,10 @@ var require_lottie = __commonJS({
|
|
|
227702
227702
|
},
|
|
227703
227703
|
renderInnerContent: function() {
|
|
227704
227704
|
},
|
|
227705
|
-
prepareFrame: function(
|
|
227705
|
+
prepareFrame: function(num4) {
|
|
227706
227706
|
this._mdf = false;
|
|
227707
|
-
this.prepareRenderableFrame(
|
|
227708
|
-
this.prepareProperties(
|
|
227707
|
+
this.prepareRenderableFrame(num4);
|
|
227708
|
+
this.prepareProperties(num4, this.isInRange);
|
|
227709
227709
|
this.checkTransparency();
|
|
227710
227710
|
},
|
|
227711
227711
|
destroy: function() {
|
|
@@ -227810,9 +227810,9 @@ var require_lottie = __commonJS({
|
|
|
227810
227810
|
}
|
|
227811
227811
|
elements.push(new ProcessedElement(elem, pos));
|
|
227812
227812
|
},
|
|
227813
|
-
prepareFrame: function(
|
|
227814
|
-
this.prepareRenderableFrame(
|
|
227815
|
-
this.prepareProperties(
|
|
227813
|
+
prepareFrame: function(num4) {
|
|
227814
|
+
this.prepareRenderableFrame(num4);
|
|
227815
|
+
this.prepareProperties(num4, this.isInRange);
|
|
227816
227816
|
}
|
|
227817
227817
|
};
|
|
227818
227818
|
const lineCapEnum = {
|
|
@@ -229978,10 +229978,10 @@ var require_lottie = __commonJS({
|
|
|
229978
229978
|
this.hide();
|
|
229979
229979
|
this.textAnimator.searchProperties(this.dynamicProperties);
|
|
229980
229980
|
};
|
|
229981
|
-
ITextElement.prototype.prepareFrame = function(
|
|
229981
|
+
ITextElement.prototype.prepareFrame = function(num4) {
|
|
229982
229982
|
this._mdf = false;
|
|
229983
|
-
this.prepareRenderableFrame(
|
|
229984
|
-
this.prepareProperties(
|
|
229983
|
+
this.prepareRenderableFrame(num4);
|
|
229984
|
+
this.prepareProperties(num4, this.isInRange);
|
|
229985
229985
|
if (this.textProperty._mdf || this.textProperty._isFirstFrame) {
|
|
229986
229986
|
this.buildNewText();
|
|
229987
229987
|
this.textProperty._isFirstFrame = false;
|
|
@@ -230339,8 +230339,8 @@ var require_lottie = __commonJS({
|
|
|
230339
230339
|
this.initTransform(data, globalData, comp);
|
|
230340
230340
|
this.initHierarchy();
|
|
230341
230341
|
}
|
|
230342
|
-
NullElement.prototype.prepareFrame = function(
|
|
230343
|
-
this.prepareProperties(
|
|
230342
|
+
NullElement.prototype.prepareFrame = function(num4) {
|
|
230343
|
+
this.prepareProperties(num4, true);
|
|
230344
230344
|
};
|
|
230345
230345
|
NullElement.prototype.renderFrame = function() {
|
|
230346
230346
|
};
|
|
@@ -230482,27 +230482,27 @@ var require_lottie = __commonJS({
|
|
|
230482
230482
|
}
|
|
230483
230483
|
}
|
|
230484
230484
|
};
|
|
230485
|
-
SVGRendererBase.prototype.renderFrame = function(
|
|
230486
|
-
if (this.renderedFrame ===
|
|
230485
|
+
SVGRendererBase.prototype.renderFrame = function(num4) {
|
|
230486
|
+
if (this.renderedFrame === num4 || this.destroyed) {
|
|
230487
230487
|
return;
|
|
230488
230488
|
}
|
|
230489
|
-
if (
|
|
230490
|
-
|
|
230489
|
+
if (num4 === null) {
|
|
230490
|
+
num4 = this.renderedFrame;
|
|
230491
230491
|
} else {
|
|
230492
|
-
this.renderedFrame =
|
|
230492
|
+
this.renderedFrame = num4;
|
|
230493
230493
|
}
|
|
230494
|
-
this.globalData.frameNum =
|
|
230494
|
+
this.globalData.frameNum = num4;
|
|
230495
230495
|
this.globalData.frameId += 1;
|
|
230496
|
-
this.globalData.projectInterface.currentFrame =
|
|
230496
|
+
this.globalData.projectInterface.currentFrame = num4;
|
|
230497
230497
|
this.globalData._mdf = false;
|
|
230498
230498
|
var i2;
|
|
230499
230499
|
var len = this.layers.length;
|
|
230500
230500
|
if (!this.completeLayers) {
|
|
230501
|
-
this.checkLayers(
|
|
230501
|
+
this.checkLayers(num4);
|
|
230502
230502
|
}
|
|
230503
230503
|
for (i2 = len - 1; i2 >= 0; i2 -= 1) {
|
|
230504
230504
|
if (this.completeLayers || this.elements[i2]) {
|
|
230505
|
-
this.elements[i2].prepareFrame(
|
|
230505
|
+
this.elements[i2].prepareFrame(num4 - this.layers[i2].st);
|
|
230506
230506
|
}
|
|
230507
230507
|
}
|
|
230508
230508
|
if (this.globalData._mdf) {
|
|
@@ -230555,10 +230555,10 @@ var require_lottie = __commonJS({
|
|
|
230555
230555
|
}
|
|
230556
230556
|
this.hide();
|
|
230557
230557
|
};
|
|
230558
|
-
ICompElement.prototype.prepareFrame = function(
|
|
230558
|
+
ICompElement.prototype.prepareFrame = function(num4) {
|
|
230559
230559
|
this._mdf = false;
|
|
230560
|
-
this.prepareRenderableFrame(
|
|
230561
|
-
this.prepareProperties(
|
|
230560
|
+
this.prepareRenderableFrame(num4);
|
|
230561
|
+
this.prepareProperties(num4, this.isInRange);
|
|
230562
230562
|
if (!this.isInRange && !this.data.xt) {
|
|
230563
230563
|
return;
|
|
230564
230564
|
}
|
|
@@ -230569,7 +230569,7 @@ var require_lottie = __commonJS({
|
|
|
230569
230569
|
}
|
|
230570
230570
|
this.renderedFrame = timeRemapped;
|
|
230571
230571
|
} else {
|
|
230572
|
-
this.renderedFrame =
|
|
230572
|
+
this.renderedFrame = num4 / this.data.sr;
|
|
230573
230573
|
}
|
|
230574
230574
|
var i2;
|
|
230575
230575
|
var len = this.elements.length;
|
|
@@ -231990,23 +231990,23 @@ var require_lottie = __commonJS({
|
|
|
231990
231990
|
this.animationItem.container = null;
|
|
231991
231991
|
this.destroyed = true;
|
|
231992
231992
|
};
|
|
231993
|
-
CanvasRendererBase.prototype.renderFrame = function(
|
|
231994
|
-
if (this.renderedFrame ===
|
|
231993
|
+
CanvasRendererBase.prototype.renderFrame = function(num4, forceRender) {
|
|
231994
|
+
if (this.renderedFrame === num4 && this.renderConfig.clearCanvas === true && !forceRender || this.destroyed || num4 === -1) {
|
|
231995
231995
|
return;
|
|
231996
231996
|
}
|
|
231997
|
-
this.renderedFrame =
|
|
231998
|
-
this.globalData.frameNum =
|
|
231997
|
+
this.renderedFrame = num4;
|
|
231998
|
+
this.globalData.frameNum = num4 - this.animationItem._isFirstFrame;
|
|
231999
231999
|
this.globalData.frameId += 1;
|
|
232000
232000
|
this.globalData._mdf = !this.renderConfig.clearCanvas || forceRender;
|
|
232001
|
-
this.globalData.projectInterface.currentFrame =
|
|
232001
|
+
this.globalData.projectInterface.currentFrame = num4;
|
|
232002
232002
|
var i2;
|
|
232003
232003
|
var len = this.layers.length;
|
|
232004
232004
|
if (!this.completeLayers) {
|
|
232005
|
-
this.checkLayers(
|
|
232005
|
+
this.checkLayers(num4);
|
|
232006
232006
|
}
|
|
232007
232007
|
for (i2 = 0; i2 < len; i2 += 1) {
|
|
232008
232008
|
if (this.completeLayers || this.elements[i2]) {
|
|
232009
|
-
this.elements[i2].prepareFrame(
|
|
232009
|
+
this.elements[i2].prepareFrame(num4 - this.layers[i2].st);
|
|
232010
232010
|
}
|
|
232011
232011
|
}
|
|
232012
232012
|
if (this.globalData._mdf) {
|
|
@@ -232459,13 +232459,13 @@ var require_lottie = __commonJS({
|
|
|
232459
232459
|
var $bm_mul = mul;
|
|
232460
232460
|
var $bm_div = div;
|
|
232461
232461
|
var $bm_mod = mod;
|
|
232462
|
-
function clamp3(
|
|
232462
|
+
function clamp3(num4, min2, max) {
|
|
232463
232463
|
if (min2 > max) {
|
|
232464
232464
|
var mm = max;
|
|
232465
232465
|
max = min2;
|
|
232466
232466
|
min2 = mm;
|
|
232467
232467
|
}
|
|
232468
|
-
return Math2.min(Math2.max(
|
|
232468
|
+
return Math2.min(Math2.max(num4, min2), max);
|
|
232469
232469
|
}
|
|
232470
232470
|
function radiansToDegrees(val) {
|
|
232471
232471
|
return val / degToRads;
|
|
@@ -233334,12 +233334,12 @@ var require_opentype = __commonJS({
|
|
|
233334
233334
|
}
|
|
233335
233335
|
}
|
|
233336
233336
|
var offs = new Uint16Array(16);
|
|
233337
|
-
function tinf_build_tree(t, lengths2, off,
|
|
233337
|
+
function tinf_build_tree(t, lengths2, off, num4) {
|
|
233338
233338
|
var i2, sum;
|
|
233339
233339
|
for (i2 = 0; i2 < 16; ++i2) {
|
|
233340
233340
|
t.table[i2] = 0;
|
|
233341
233341
|
}
|
|
233342
|
-
for (i2 = 0; i2 <
|
|
233342
|
+
for (i2 = 0; i2 < num4; ++i2) {
|
|
233343
233343
|
t.table[lengths2[off + i2]]++;
|
|
233344
233344
|
}
|
|
233345
233345
|
t.table[0] = 0;
|
|
@@ -233347,7 +233347,7 @@ var require_opentype = __commonJS({
|
|
|
233347
233347
|
offs[i2] = sum;
|
|
233348
233348
|
sum += t.table[i2];
|
|
233349
233349
|
}
|
|
233350
|
-
for (i2 = 0; i2 <
|
|
233350
|
+
for (i2 = 0; i2 < num4; ++i2) {
|
|
233351
233351
|
if (lengths2[off + i2]) {
|
|
233352
233352
|
t.trans[offs[lengths2[off + i2]]++] = i2;
|
|
233353
233353
|
}
|
|
@@ -233362,17 +233362,17 @@ var require_opentype = __commonJS({
|
|
|
233362
233362
|
d.tag >>>= 1;
|
|
233363
233363
|
return bit;
|
|
233364
233364
|
}
|
|
233365
|
-
function tinf_read_bits(d,
|
|
233366
|
-
if (!
|
|
233365
|
+
function tinf_read_bits(d, num4, base) {
|
|
233366
|
+
if (!num4) {
|
|
233367
233367
|
return base;
|
|
233368
233368
|
}
|
|
233369
233369
|
while (d.bitcount < 24) {
|
|
233370
233370
|
d.tag |= d.source[d.sourceIndex++] << d.bitcount;
|
|
233371
233371
|
d.bitcount += 8;
|
|
233372
233372
|
}
|
|
233373
|
-
var val = d.tag & 65535 >>> 16 -
|
|
233374
|
-
d.tag >>>=
|
|
233375
|
-
d.bitcount -=
|
|
233373
|
+
var val = d.tag & 65535 >>> 16 - num4;
|
|
233374
|
+
d.tag >>>= num4;
|
|
233375
|
+
d.bitcount -= num4;
|
|
233376
233376
|
return val + base;
|
|
233377
233377
|
}
|
|
233378
233378
|
function tinf_decode_symbol(d, t) {
|
|
@@ -233395,7 +233395,7 @@ var require_opentype = __commonJS({
|
|
|
233395
233395
|
}
|
|
233396
233396
|
function tinf_decode_trees(d, lt, dt) {
|
|
233397
233397
|
var hlit, hdist, hclen;
|
|
233398
|
-
var i2,
|
|
233398
|
+
var i2, num4, length;
|
|
233399
233399
|
hlit = tinf_read_bits(d, 5, 257);
|
|
233400
233400
|
hdist = tinf_read_bits(d, 5, 1);
|
|
233401
233401
|
hclen = tinf_read_bits(d, 4, 4);
|
|
@@ -233407,27 +233407,27 @@ var require_opentype = __commonJS({
|
|
|
233407
233407
|
lengths[clcidx[i2]] = clen;
|
|
233408
233408
|
}
|
|
233409
233409
|
tinf_build_tree(code_tree, lengths, 0, 19);
|
|
233410
|
-
for (
|
|
233410
|
+
for (num4 = 0; num4 < hlit + hdist; ) {
|
|
233411
233411
|
var sym = tinf_decode_symbol(d, code_tree);
|
|
233412
233412
|
switch (sym) {
|
|
233413
233413
|
case 16:
|
|
233414
|
-
var prev = lengths[
|
|
233414
|
+
var prev = lengths[num4 - 1];
|
|
233415
233415
|
for (length = tinf_read_bits(d, 2, 3); length; --length) {
|
|
233416
|
-
lengths[
|
|
233416
|
+
lengths[num4++] = prev;
|
|
233417
233417
|
}
|
|
233418
233418
|
break;
|
|
233419
233419
|
case 17:
|
|
233420
233420
|
for (length = tinf_read_bits(d, 3, 3); length; --length) {
|
|
233421
|
-
lengths[
|
|
233421
|
+
lengths[num4++] = 0;
|
|
233422
233422
|
}
|
|
233423
233423
|
break;
|
|
233424
233424
|
case 18:
|
|
233425
233425
|
for (length = tinf_read_bits(d, 7, 11); length; --length) {
|
|
233426
|
-
lengths[
|
|
233426
|
+
lengths[num4++] = 0;
|
|
233427
233427
|
}
|
|
233428
233428
|
break;
|
|
233429
233429
|
default:
|
|
233430
|
-
lengths[
|
|
233430
|
+
lengths[num4++] = sym;
|
|
233431
233431
|
break;
|
|
233432
233432
|
}
|
|
233433
233433
|
}
|
|
@@ -262207,8 +262207,8 @@ var require_IFFParser = __commonJS({
|
|
|
262207
262207
|
}
|
|
262208
262208
|
}
|
|
262209
262209
|
};
|
|
262210
|
-
function isEven(
|
|
262211
|
-
return
|
|
262210
|
+
function isEven(num4) {
|
|
262211
|
+
return num4 % 2;
|
|
262212
262212
|
}
|
|
262213
262213
|
function stringOffset(string6) {
|
|
262214
262214
|
return string6.length + 1 + (isEven(string6.length + 1) ? 1 : 0);
|
|
@@ -262685,8 +262685,8 @@ var require_LWOLoader = __commonJS({
|
|
|
262685
262685
|
return texture;
|
|
262686
262686
|
}
|
|
262687
262687
|
// 0 = Reset, 1 = Repeat, 2 = Mirror, 3 = Edge
|
|
262688
|
-
getWrappingType(
|
|
262689
|
-
switch (
|
|
262688
|
+
getWrappingType(num4) {
|
|
262689
|
+
switch (num4) {
|
|
262690
262690
|
case 0:
|
|
262691
262691
|
console.warn('LWOLoader: "Reset" texture wrapping type is not supported in three.js');
|
|
262692
262692
|
return THREE.ClampToEdgeWrapping;
|
|
@@ -262837,7 +262837,7 @@ var require_LWOLoader = __commonJS({
|
|
|
262837
262837
|
geometry.setAttribute("uv", new THREE.Float32BufferAttribute(remappedUVs, 2));
|
|
262838
262838
|
}
|
|
262839
262839
|
parseMorphTargets(geometry, layer) {
|
|
262840
|
-
let
|
|
262840
|
+
let num4 = 0;
|
|
262841
262841
|
for (const name in layer.morphTargets) {
|
|
262842
262842
|
const remappedPoints = geometry.attributes.position.array.slice();
|
|
262843
262843
|
if (!geometry.morphAttributes.position)
|
|
@@ -262856,9 +262856,9 @@ var require_LWOLoader = __commonJS({
|
|
|
262856
262856
|
remappedPoints[i2 * 3 + 2] = morphPoints[j * 3 + 2];
|
|
262857
262857
|
}
|
|
262858
262858
|
});
|
|
262859
|
-
geometry.morphAttributes.position[
|
|
262860
|
-
geometry.morphAttributes.position[
|
|
262861
|
-
|
|
262859
|
+
geometry.morphAttributes.position[num4] = new THREE.Float32BufferAttribute(remappedPoints, 3);
|
|
262860
|
+
geometry.morphAttributes.position[num4].name = name;
|
|
262861
|
+
num4++;
|
|
262862
262862
|
}
|
|
262863
262863
|
geometry.morphTargetsRelative = false;
|
|
262864
262864
|
}
|
|
@@ -310866,8 +310866,8 @@ var require_hls = __commonJS({
|
|
|
310866
310866
|
function toHex(x) {
|
|
310867
310867
|
return ("0" + x.toString(16).toUpperCase()).slice(-2);
|
|
310868
310868
|
}
|
|
310869
|
-
function addLeadingZero(
|
|
310870
|
-
return (
|
|
310869
|
+
function addLeadingZero(num4) {
|
|
310870
|
+
return (num4 < 10 ? "0" : "") + num4;
|
|
310871
310871
|
}
|
|
310872
310872
|
function patchEncyptionData(initSegment, decryptdata) {
|
|
310873
310873
|
if (!initSegment || !decryptdata) {
|
|
@@ -311680,13 +311680,13 @@ var require_hls = __commonJS({
|
|
|
311680
311680
|
}
|
|
311681
311681
|
function codecsSetSelectionPreferenceValue(codecSet) {
|
|
311682
311682
|
var limitedHevcSupport = userAgentHevcSupportIsInaccurate();
|
|
311683
|
-
return codecSet.split(",").reduce(function(
|
|
311683
|
+
return codecSet.split(",").reduce(function(num4, fourCC) {
|
|
311684
311684
|
var lowerPriority = limitedHevcSupport && isHEVC(fourCC);
|
|
311685
311685
|
var preferenceValue = lowerPriority ? 9 : sampleEntryCodesISO.video[fourCC];
|
|
311686
311686
|
if (preferenceValue) {
|
|
311687
|
-
return (preferenceValue * 2 +
|
|
311687
|
+
return (preferenceValue * 2 + num4) / (num4 ? 3 : 2);
|
|
311688
311688
|
}
|
|
311689
|
-
return (sampleEntryCodesISO.audio[fourCC] +
|
|
311689
|
+
return (sampleEntryCodesISO.audio[fourCC] + num4) / (num4 ? 2 : 1);
|
|
311690
311690
|
}, 0);
|
|
311691
311691
|
}
|
|
311692
311692
|
var CODEC_COMPATIBLE_NAMES = {};
|
|
@@ -404296,7 +404296,7 @@ var DefaultHydrator = class {
|
|
|
404296
404296
|
hydrateReference(reference, node, name, context) {
|
|
404297
404297
|
return this.linker.buildReference(node, name, context.cstNodes.get(reference.$refNode), reference.$refText);
|
|
404298
404298
|
}
|
|
404299
|
-
hydrateCstNode(cstNode, context,
|
|
404299
|
+
hydrateCstNode(cstNode, context, num4 = 0) {
|
|
404300
404300
|
const cstNodeObj = context.cstNodes.get(cstNode);
|
|
404301
404301
|
if (typeof cstNode.grammarSource === "number") {
|
|
404302
404302
|
cstNodeObj.grammarSource = this.getGrammarElement(cstNode.grammarSource);
|
|
@@ -404304,7 +404304,7 @@ var DefaultHydrator = class {
|
|
|
404304
404304
|
cstNodeObj.astNode = context.astNodes.get(cstNode.astNode);
|
|
404305
404305
|
if (isCompositeCstNode(cstNodeObj)) {
|
|
404306
404306
|
for (const child of cstNode.content) {
|
|
404307
|
-
const hydrated = this.hydrateCstNode(child, context,
|
|
404307
|
+
const hydrated = this.hydrateCstNode(child, context, num4++);
|
|
404308
404308
|
cstNodeObj.content.push(hydrated);
|
|
404309
404309
|
}
|
|
404310
404310
|
}
|
|
@@ -416937,6 +416937,41 @@ function moduleExports3(text) {
|
|
|
416937
416937
|
|
|
416938
416938
|
// src/pipeline.ts
|
|
416939
416939
|
init_resolve();
|
|
416940
|
+
|
|
416941
|
+
// ../editor/src/param/refsView.ts
|
|
416942
|
+
init_resolve();
|
|
416943
|
+
var isFormula2 = (v) => typeof v === "string" && v.trimStart().startsWith("=");
|
|
416944
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
416945
|
+
function buildRefsView(config3) {
|
|
416946
|
+
const scope = scopeForConfig(config3);
|
|
416947
|
+
const c = config3;
|
|
416948
|
+
const variables = Object.entries(c?.variables ?? {}).map(([name, val]) => ({
|
|
416949
|
+
name,
|
|
416950
|
+
value: num(scope[name]),
|
|
416951
|
+
formula: isFormula2(val) ? val : void 0
|
|
416952
|
+
}));
|
|
416953
|
+
const points = Object.keys(c?.points ?? {}).map((name) => ({
|
|
416954
|
+
name,
|
|
416955
|
+
x: num(scope[`${name}.x`]),
|
|
416956
|
+
y: num(scope[`${name}.y`])
|
|
416957
|
+
}));
|
|
416958
|
+
const grids = /* @__PURE__ */ new Map();
|
|
416959
|
+
for (const [key, val] of Object.entries(scope)) {
|
|
416960
|
+
const m = key.match(/^(\w+)\.([xy])(.+)$/);
|
|
416961
|
+
if (!m) continue;
|
|
416962
|
+
const [, id, axis, line] = m;
|
|
416963
|
+
if (!grids.has(id)) grids.set(id, { xLines: [], yLines: [] });
|
|
416964
|
+
const g = grids.get(id);
|
|
416965
|
+
(axis === "x" ? g.xLines : g.yLines).push({ name: line, value: num(val) });
|
|
416966
|
+
}
|
|
416967
|
+
return {
|
|
416968
|
+
variables,
|
|
416969
|
+
points,
|
|
416970
|
+
grids: [...grids].map(([id, g]) => ({ id, ...g }))
|
|
416971
|
+
};
|
|
416972
|
+
}
|
|
416973
|
+
|
|
416974
|
+
// src/pipeline.ts
|
|
416940
416975
|
init_houseConfig();
|
|
416941
416976
|
init_promote();
|
|
416942
416977
|
|
|
@@ -418771,7 +418806,7 @@ function deriveOne(cfg, wallTopZ, framing, wallThickness) {
|
|
|
418771
418806
|
init_config();
|
|
418772
418807
|
|
|
418773
418808
|
// ../editor/src/estimate/wallArea.ts
|
|
418774
|
-
var
|
|
418809
|
+
var num2 = (v, d = 0) => typeof v === "number" && isFinite(v) ? v : d;
|
|
418775
418810
|
function inAnyRoom(rects, px, py, eps = 1) {
|
|
418776
418811
|
for (const r2 of rects) {
|
|
418777
418812
|
if (px > r2.x + eps && px < r2.x + r2.w - eps && py > r2.y + eps && py < r2.y + r2.l - eps) return true;
|
|
@@ -418790,7 +418825,7 @@ function buildRoomRects(config3) {
|
|
|
418790
418825
|
for (let fi = 0; fi < floors.length; fi++) {
|
|
418791
418826
|
for (const o of floors[fi].objects ?? []) {
|
|
418792
418827
|
if (o.type !== "room" || o.enabled === false) continue;
|
|
418793
|
-
out.push({ x:
|
|
418828
|
+
out.push({ x: num2(o.x), y: num2(o.y), w: num2(o.width), l: num2(o.length), floor: fi });
|
|
418794
418829
|
}
|
|
418795
418830
|
}
|
|
418796
418831
|
return out;
|
|
@@ -418814,7 +418849,7 @@ function roomSideOpenToWeather(rects, rx, ry, rw, rl, side2, wallT) {
|
|
|
418814
418849
|
// ../editor/src/lint/structural.ts
|
|
418815
418850
|
init_expand();
|
|
418816
418851
|
var ALL_SIDES = ["north", "south", "east", "west"];
|
|
418817
|
-
function
|
|
418852
|
+
function num3(v) {
|
|
418818
418853
|
return typeof v === "number" ? v : Number(v) || 0;
|
|
418819
418854
|
}
|
|
418820
418855
|
function cap(s) {
|
|
@@ -418822,7 +418857,7 @@ function cap(s) {
|
|
|
418822
418857
|
}
|
|
418823
418858
|
function floorLabel(fl) {
|
|
418824
418859
|
const nm = typeof fl.name === "string" && fl.name ? ` "${fl.name}"` : "";
|
|
418825
|
-
return `floor ${
|
|
418860
|
+
return `floor ${num3(fl.floor_number)}${nm}`;
|
|
418826
418861
|
}
|
|
418827
418862
|
function objLabel(o) {
|
|
418828
418863
|
if (typeof o.name === "string" && o.name) return `"${o.name}"`;
|
|
@@ -418851,10 +418886,10 @@ function collectWallSegments(floors) {
|
|
|
418851
418886
|
if (o.type === "room") {
|
|
418852
418887
|
const declared = declaredSides(o.walls);
|
|
418853
418888
|
const sides = declared === "all" ? ALL_SIDES : [...declared];
|
|
418854
|
-
const x =
|
|
418889
|
+
const x = num3(o.x), y = num3(o.y), w = num3(o.width), l = num3(o.length);
|
|
418855
418890
|
for (const s of sides) segs.push(sideSegment(x, y, w, l, s));
|
|
418856
418891
|
} else if (o.type === "wall") {
|
|
418857
|
-
const sx =
|
|
418892
|
+
const sx = num3(o.start_x), sy = num3(o.start_y), ex = num3(o.end_x), ey = num3(o.end_y);
|
|
418858
418893
|
if (Math.abs(sy - ey) < 1) segs.push({ horiz: true, at: sy, lo: Math.min(sx, ex), hi: Math.max(sx, ex) });
|
|
418859
418894
|
else if (Math.abs(sx - ex) < 1) segs.push({ horiz: false, at: sx, lo: Math.min(sy, ey), hi: Math.max(sy, ey) });
|
|
418860
418895
|
}
|
|
@@ -418881,12 +418916,12 @@ function collectOpeningSegs(objs) {
|
|
|
418881
418916
|
if (o.type === "room") {
|
|
418882
418917
|
const walls = o.walls;
|
|
418883
418918
|
if (!walls || typeof walls !== "object" || Array.isArray(walls)) continue;
|
|
418884
|
-
const rx =
|
|
418919
|
+
const rx = num3(o.x), ry = num3(o.y), rw = num3(o.width), rl = num3(o.length);
|
|
418885
418920
|
for (const side2 of ALL_SIDES) {
|
|
418886
418921
|
const ops = walls[side2]?.openings;
|
|
418887
418922
|
if (!Array.isArray(ops)) continue;
|
|
418888
418923
|
for (const op of ops) {
|
|
418889
|
-
const off =
|
|
418924
|
+
const off = num3(op.offset), w = num3(op.width);
|
|
418890
418925
|
const owner = `room ${objLabel(o)} ${side2}`;
|
|
418891
418926
|
const label = openLabel(op);
|
|
418892
418927
|
if (side2 === "north") out.push({ horiz: true, at: ry, lo: rx + off, hi: rx + off + w, owner, label });
|
|
@@ -418898,12 +418933,12 @@ function collectOpeningSegs(objs) {
|
|
|
418898
418933
|
} else if (o.type === "wall") {
|
|
418899
418934
|
const ops = o.openings;
|
|
418900
418935
|
if (!Array.isArray(ops)) continue;
|
|
418901
|
-
const sx =
|
|
418936
|
+
const sx = num3(o.start_x), sy = num3(o.start_y), ex = num3(o.end_x), ey = num3(o.end_y);
|
|
418902
418937
|
const horiz = Math.abs(sy - ey) < 1, vert = Math.abs(sx - ex) < 1;
|
|
418903
418938
|
if (!horiz && !vert) continue;
|
|
418904
418939
|
const start = horiz ? Math.min(sx, ex) : Math.min(sy, ey);
|
|
418905
418940
|
for (const op of ops) {
|
|
418906
|
-
const off =
|
|
418941
|
+
const off = num3(op.offset), w = num3(op.width);
|
|
418907
418942
|
out.push({ horiz, at: horiz ? sy : sx, lo: start + off, hi: start + off + w, owner: `wall ${objLabel(o)}`, label: openLabel(op) });
|
|
418908
418943
|
}
|
|
418909
418944
|
}
|
|
@@ -418926,24 +418961,24 @@ function itemMetersToUnits(m, units) {
|
|
|
418926
418961
|
function itemBox(it, units) {
|
|
418927
418962
|
const asset2 = it.asset;
|
|
418928
418963
|
if (!asset2?.dimensions) return null;
|
|
418929
|
-
const scale = it.scale != null ?
|
|
418964
|
+
const scale = it.scale != null ? num3(it.scale) : 1;
|
|
418930
418965
|
const fw = itemMetersToUnits(asset2.dimensions[0], units) * scale;
|
|
418931
418966
|
const fd = itemMetersToUnits(asset2.dimensions[2], units) * scale;
|
|
418932
|
-
const th =
|
|
418967
|
+
const th = num3(it.rotation) * Math.PI / 180;
|
|
418933
418968
|
const c = Math.abs(Math.cos(th)), s = Math.abs(Math.sin(th));
|
|
418934
418969
|
const hx = fw / 2 * c + fd / 2 * s;
|
|
418935
418970
|
const hy = fw / 2 * s + fd / 2 * c;
|
|
418936
|
-
const cx =
|
|
418971
|
+
const cx = num3(it.x), cy = num3(it.y);
|
|
418937
418972
|
return { x0: cx - hx, y0: cy - hy, x1: cx + hx, y1: cy + hy };
|
|
418938
418973
|
}
|
|
418939
418974
|
function lintStructure(config3) {
|
|
418940
418975
|
const cfg = config3;
|
|
418941
418976
|
const floors = cfg.floors ?? [];
|
|
418942
418977
|
const defaults = cfg.defaults ?? {};
|
|
418943
|
-
const wallTDefault =
|
|
418944
|
-
const slabDefault = defaults.slab_thickness != null ?
|
|
418945
|
-
const floorHeightDefault = defaults.floor_height != null ?
|
|
418946
|
-
const wallHeightDefault = defaults.wall_height != null ?
|
|
418978
|
+
const wallTDefault = num3(defaults.wall_thickness ?? DEFAULT_GLOBAL_CONFIG.wall_thickness);
|
|
418979
|
+
const slabDefault = defaults.slab_thickness != null ? num3(defaults.slab_thickness) : DEFAULT_GLOBAL_CONFIG.floor_slab_thickness;
|
|
418980
|
+
const floorHeightDefault = defaults.floor_height != null ? num3(defaults.floor_height) : DEFAULT_GLOBAL_CONFIG.floor_height;
|
|
418981
|
+
const wallHeightDefault = defaults.wall_height != null ? num3(defaults.wall_height) : DEFAULT_GLOBAL_CONFIG.wall_height;
|
|
418947
418982
|
const findings = [];
|
|
418948
418983
|
const rects = buildRoomRects(config3);
|
|
418949
418984
|
const wallSegs = collectWallSegments(floors);
|
|
@@ -418958,9 +418993,9 @@ function lintStructure(config3) {
|
|
|
418958
418993
|
for (let fi = 0; fi < floors.length; fi++) {
|
|
418959
418994
|
const fl = floors[fi];
|
|
418960
418995
|
const objs = activeObjects2(fl);
|
|
418961
|
-
const fnum =
|
|
418996
|
+
const fnum = num3(fl.floor_number);
|
|
418962
418997
|
const floorBaseZ = baseZ;
|
|
418963
|
-
baseZ += fl.height != null ?
|
|
418998
|
+
baseZ += fl.height != null ? num3(fl.height) : floorHeightDefault;
|
|
418964
418999
|
const plinths = objs.filter((o) => o.type === "plinth");
|
|
418965
419000
|
if (plinths.length) {
|
|
418966
419001
|
const fh = fl.height;
|
|
@@ -418975,14 +419010,14 @@ function lintStructure(config3) {
|
|
|
418975
419010
|
for (const p of plinths) {
|
|
418976
419011
|
const ph = p.height;
|
|
418977
419012
|
if (ph == null) continue;
|
|
418978
|
-
if (fh != null && Math.abs(
|
|
418979
|
-
const diff =
|
|
419013
|
+
if (fh != null && Math.abs(num3(fh) - num3(ph)) > 1e-3) {
|
|
419014
|
+
const diff = num3(fh) - num3(ph);
|
|
418980
419015
|
findings.push({
|
|
418981
419016
|
rule: "C1",
|
|
418982
419017
|
level: "error",
|
|
418983
419018
|
floor: fnum,
|
|
418984
419019
|
where: objLabel(p),
|
|
418985
|
-
message: `${cap(floorLabel(fl))}: floor \`height\` (${
|
|
419020
|
+
message: `${cap(floorLabel(fl))}: floor \`height\` (${num3(fh)}) \u2260 plinth ${objLabel(p)} height (${num3(ph)}). The floor above ${diff > 0 ? "floats" : "sinks into the plinth by"} ${Math.abs(diff)} units. Make the floor height and the plinth height equal.`
|
|
418986
419021
|
});
|
|
418987
419022
|
}
|
|
418988
419023
|
}
|
|
@@ -418991,7 +419026,7 @@ function lintStructure(config3) {
|
|
|
418991
419026
|
const deckObjs = objs.filter((o) => o.type === "room" || o.type === "wall");
|
|
418992
419027
|
if (!hasSlab && deckObjs.length) {
|
|
418993
419028
|
const explicit = fl.slab_thickness;
|
|
418994
|
-
const eff = explicit != null ?
|
|
419029
|
+
const eff = explicit != null ? num3(explicit) : slabDefault;
|
|
418995
419030
|
if (eff !== 0) {
|
|
418996
419031
|
findings.push({
|
|
418997
419032
|
rule: "C3",
|
|
@@ -419003,9 +419038,9 @@ function lintStructure(config3) {
|
|
|
419003
419038
|
}
|
|
419004
419039
|
const hasFloorAbove = fi < floors.length - 1;
|
|
419005
419040
|
if (deckObjs.length && hasFloorAbove && !plinths.length) {
|
|
419006
|
-
const h = fl.height != null ?
|
|
419007
|
-
const wh = fl.wall_height != null ?
|
|
419008
|
-
const st = fl.slab_thickness != null ?
|
|
419041
|
+
const h = fl.height != null ? num3(fl.height) : floorHeightDefault;
|
|
419042
|
+
const wh = fl.wall_height != null ? num3(fl.wall_height) : wallHeightDefault;
|
|
419043
|
+
const st = fl.slab_thickness != null ? num3(fl.slab_thickness) : slabDefault;
|
|
419009
419044
|
const gap = h - (wh + st);
|
|
419010
419045
|
if (Math.abs(gap) > 1e-3) {
|
|
419011
419046
|
findings.push({
|
|
@@ -419018,13 +419053,13 @@ function lintStructure(config3) {
|
|
|
419018
419053
|
}
|
|
419019
419054
|
for (const o of objs) {
|
|
419020
419055
|
if (o.type !== "staircase") continue;
|
|
419021
|
-
const riser =
|
|
419056
|
+
const riser = num3(o.step_rise);
|
|
419022
419057
|
if (riser <= 0) continue;
|
|
419023
|
-
const belowH = fi > 0 && floors[fi - 1].height != null ?
|
|
419024
|
-
const riseHeight = o.rise_height != null &&
|
|
419058
|
+
const belowH = fi > 0 && floors[fi - 1].height != null ? num3(floors[fi - 1].height) : floorHeightDefault;
|
|
419059
|
+
const riseHeight = o.rise_height != null && num3(o.rise_height) > 0 ? num3(o.rise_height) : belowH;
|
|
419025
419060
|
const totalRise = Math.max(1, Math.round(riseHeight / riser)) * riser;
|
|
419026
|
-
const slabT = fl.slab_thickness != null ?
|
|
419027
|
-
const topZ = o.z_offset != null ?
|
|
419061
|
+
const slabT = fl.slab_thickness != null ? num3(fl.slab_thickness) : slabDefault;
|
|
419062
|
+
const topZ = o.z_offset != null ? num3(o.z_offset) : slabT;
|
|
419028
419063
|
const bottomZ = floorBaseZ + (topZ - totalRise);
|
|
419029
419064
|
if (bottomZ < -1) {
|
|
419030
419065
|
findings.push({
|
|
@@ -419042,8 +419077,8 @@ function lintStructure(config3) {
|
|
|
419042
419077
|
if (declared === "all") continue;
|
|
419043
419078
|
const missing = ALL_SIDES.filter((s) => !declared.has(s));
|
|
419044
419079
|
if (!missing.length) continue;
|
|
419045
|
-
const wallT =
|
|
419046
|
-
const rx =
|
|
419080
|
+
const wallT = num3(o.wall_thickness ?? o.thickness ?? wallTDefault);
|
|
419081
|
+
const rx = num3(o.x), ry = num3(o.y), rw = num3(o.width), rl = num3(o.length);
|
|
419047
419082
|
for (const side2 of missing) {
|
|
419048
419083
|
if (sideHasWall(wallSegs, sideSegment(rx, ry, rw, rl, side2))) continue;
|
|
419049
419084
|
if (roomSideOpenToWeather(rects, rx, ry, rw, rl, side2, wallT)) {
|
|
@@ -422689,7 +422724,7 @@ house TwoRoom {
|
|
|
422689
422724
|
var DOCS = {
|
|
422690
422725
|
"guide": {
|
|
422691
422726
|
"title": "How to author a Wadi house (the workflow)",
|
|
422692
|
-
"body": '# Wadi architect \u2014 author `.wdl` house designs with a live 3D preview\n\nYou are the architect/editor. The user describes a house (in words, or with a\nsketch/photo); you write or update its **`.wdl`** file (the Wadi DSL), and the **Wadi\napp\'s DSL editor renders the model live** from that same file. The user watches and\nsteers with follow-up messages \u2014 and can edit the `.wdl` alongside you.\n\nYou author in the **Wadi DSL** (`.wdl`), not raw JSON. It\'s more direct (formulas,\ngrids, and the configurator are one-liners), the grammar enforces structure, and the\ncompiler reports parse errors with `line:col`. The DSL is **complete** \u2014 every object\ntype has first-class syntax \u2014 so it can express any house the model can hold.\n**`reference/dsl.md` is your syntax reference; read it first.**\n\n**The `.wdl` IS the design \u2014 do not produce a `.wadi`.** The Wadi app\'s DSL previewer\ncompiles + renders the `.wdl` live (in-app), so a single `.wdl` file on disk is the\n**shared source you and the human co-edit**. You never convert it to JSON; you just\nauthor the `.wdl` and verify it with `check.sh`.\n\nThis skill is **agent-neutral** \u2014 it is plain instructions + reference docs + scripts,\nusable by any coding agent (Claude Code, Google Antigravity, \u2026). Agent-specific\nentrypoints live outside this folder (e.g. `.claude/skills/wadi-architect/` for Claude\nCode, `AGENTS.md` at the repo root); they just point here.\n\n## What you need to run this\n\n- **Read/write files** and **run shell + Node** (the only capabilities assumed).\n- The **Wadi repo checked out**, with deps installed once:\n `npm --prefix editor install` and `npm --prefix wadi-dsl install` (the latter also\n regenerates the DSL parser via its `prepare` hook). The `check` and `preview` scripts\n reuse the app\'s own TypeScript, so they flag exactly what the app would.\n- For the *live* render: the **Wadi app\'s DSL editor** open on the `.wdl` you edit \u2014\n desktop **\u2318\u21E7D \u2192 Open**, or the browser playground at `wadi.house/dsl`. It compiles +\n renders the `.wdl` live. Without it you can still author + `check` + render preview\n images yourself.\n\n## The live loop (read this first, every session)\n\nThe **`.wdl` file is the single shared source.** You edit it; the Wadi app\'s DSL editor\n\u2014 open on that same file \u2014 compiles and re-renders it live; the human can edit it too (in\nthe DSL editor, in their own editor, or by asking you). **You never produce or touch a\n`.wadi`** \u2014 the app does the `.wdl` \u2192 render conversion.\n\n**Starting a NEW model:**\n1. Write a starter `house.wdl` (copy the shape from `../../wadi-dsl/examples/` \u2014 start\n from `minimal.wdl`, or `coastal.wdl` for a full cottage) at a path the user wants,\n e.g. `~/Documents/<name>.wdl`.\n2. Tell the user to open it in the **Wadi DSL editor** (**\u2318\u21E7D \u2192 Open** in the desktop\n app) so it renders live and watches the file.\n3. Build the house by editing `house.wdl`. Run `check.sh` after each change to confirm it\n still compiles + validates; the editor re-renders as the file changes.\n\n**Editing an EXISTING model:** edit its `.wdl`. Because it\'s a **co-edited** file, **read\nit first** (the human may have changed it since your last edit) and make a **minimal\npatch** \u2014 change only the lines you need and preserve the rest verbatim, so your edit\nmerges cleanly with theirs.\n\n**Always:**\n- **Tell the user which `.wdl` you are editing**, and edit only that path.\n- **Run `check.sh` after every edit.** It runs the DSL compiler + validator against a\n **throwaway temp** (it does NOT create a `.wadi`) purely for feedback \u2014 fix any\n reported error before telling the user anything changed. A broken `.wdl` just makes the\n editor show a diagnostic and keep the last good render; it never corrupts anything.\n\n## Two ways users work with you\n\n- **Brief \u2192 house.** They describe requirements ("3-bed L-shaped bungalow, ~1500 sq\n ft, hip roof"). You *derive* the base config. Keep a running **design brief** as the\n source of truth so later changes re-derive cleanly \u2014 see `prompts/design-brief.md`.\n This is Wadi\'s "higher-level language": the brief is the intent, the config is the\n derived artifact, you are the compiler.\n- **Drawings \u2192 house (recreate an existing design).** **Do NOT try to read dimensions\n off an architect\'s drawing yourself \u2014 it\'s unreliable and produces the wrong house.**\n Instead run a **guided dialog**: the USER reads their drawing and describes each\n piece in plain terms (names, sizes in feet, where things sit), and YOU do all the\n coordinate / scale / convention work, building **one room at a time** and rendering\n after each so they confirm. Ask **spatially** ("how big? which corner? next to\n what?"), never for coordinates. Never build the whole plan from one answer. Full\n method in `prompts/sketch-to-config.md`.\n- **Iterate.** They react to the live model ("make Bedroom 2 bigger", "add a north\n window"). Apply a **minimal patch** \u2014 see `prompts/update-existing.md`.\n\n## The data model & references (read lazily \u2014 don\'t dump them all up front)\n\n- **`reference/dsl.md`** \u2014 **your primary reference: the complete `.wdl` SYNTAX** \u2014\n the skeleton, the parametric core (var/point/grid/configurator/formulas), the common\n attribute tail (`enabled`/`z_offset`/`layer`/`material`), and the first-class syntax\n for every object type (rooms/walls/openings, slab/beam/plinth/ground/pillar,\n staircase/kitchen/item, roof, components, layers) plus the `raw` escape. Read this\n first, then the semantics references below.\n- **`reference/data-model.md`** \u2014 the underlying **`.wadi` schema** the DSL compiles to:\n every object type, field, type, requiredness, units, semantics. **Generated from the\n Zod schema** (`editor/src/schema/houseConfig.ts`) so it can\'t drift \u2014 regenerate with\n `scripts/gen-schema-doc.mjs` after any schema change. It\'s the field reference for the\n `raw` escape and for understanding exactly what your `.wdl` produces.\n- **`reference/coordinate-system.md`** \u2014 the #1 source of mistakes. X\u2192right, **Y\u2192DOWN**\n (Inkscape frame, not Y-up), Z\u2192up. Units: **10 project units = 1 ft** by default. Read\n before placing anything.\n- **`reference/roof-v2-guide.md`** \u2014 the unified `roof` object (segments, hip vs gable,\n joints, trusses, shed). Its fields are freeform in the schema (validated at\n derivation), so this guide is the field reference for roofs. Read before touching a\n roof.\n- **`reference/conventions.md`** \u2014 the **structural coding conventions** every house\n must follow (plinth-floor height must match the plinth block, rooms must wall every\n exterior side, a floor with no slab must set `slab_thickness 0`, \u2026). These are\n *enforced* by `check.sh` \u2014 errors fail, warnings are advisory \u2014 and shown in the DSL\n editor\'s status. Read it so you author sound houses the first time.\n- **`reference/parametric-conventions.md`** \u2014 how to build a **fully-parametric** model\n (a reusable template that stays valid under any knob change): the **grid-first**\n recipe \u2014 variables (knobs) \u2192 named grid lines (formulas of the house size) \u2192 rooms &\n columns that reference those lines \u2014 plus `coord_convention:center`, proportional grid\n lines with minimums, the `pilInset` flush-column rule, opening placement, and the\n scale-sweep verification. Read before authoring or editing a parametric template.\n- **`../../wadi-dsl/examples/*.wdl`** \u2014 correct, validated `.wdl` houses to copy shapes\n from (every one passes the compile \u2192 resolve \u2192 schema+geometry pipeline in the DSL\'s\n test suite, so **copy from these, not from memory**): `minimal.wdl` (smallest house),\n `two_room.wdl` (no grid), `two_story.wdl` (multi-floor + hip roof), `coastal.wdl`\n (grid + configurator + full cottage), `complete.wdl` (every entity \u2014 beam, wall,\n kitchen, item, component, gable roof, layers). `examples/coastal_konkan.wadi` in this\n folder is a resolved `.wadi` for reference on the compiled output shape.\n\n## Check after every edit (get compiler feedback \u2014 no `.wadi` produced)\n\n`check.sh` runs the DSL end-to-end for **feedback only**: it parses the `.wdl` (reporting\nparse errors with `line:col`), resolves formulas/grids into numbers, and runs the real\nschema + roof/wall geometry validator (catches zero-length roof segments, missing slope,\nbad openings that the schema alone misses), and finally the **structural conventions**\nlinter (`reference/conventions.md`: floating floors, open exterior walls, no-slab floors)\n\u2014 all against a **throwaway temp** that is deleted. It never writes a `.wadi`; the app\'s\nDSL previewer does the real conversion.\n\nConvention **errors** (`\u2716 [C\u2026]`) fail the check \u2014 fix them. Convention **warnings**\n(`\u26A0 [C\u2026]`) are printed but don\'t fail; fix them, or keep them if the open side is a\ndeliberate verandah.\n\n```bash\nwadi-skill/architect/scripts/check.sh "<ABS>.wdl"\n```\n\nExit 0 = compiles + valid. Non-zero prints the exact `parse: \u2026` or `/path: message`\nerror \u2014 fix the `.wdl` and re-run before telling the user anything is ready.\n\n**If you have the `wadi_*` MCP tools** (from the `wadi-mcp` server) instead of a repo\ncheckout, use them \u2014 they\'re the same pipeline, no clone needed: `wadi_check(wdl)` for\nthis step, `wadi_preview(wdl)` for the images below, and `wadi_examples` / `wadi_reference`\nfor the examples and these docs.\n\n## See your work (don\'t author blind)\n\nYou can\'t see the app\'s live render, but you CAN render your `.wdl` to images and **read\nthem** to check your own edit \u2014 layout, sizes, openings, and roof are exactly where\nmistakes happen. `preview.sh` takes the `.wdl` directly (it compiles to a throwaway temp\njust for rendering \u2014 again, no persistent `.wadi`):\n\n```bash\nwadi-skill/architect/scripts/preview.sh "<ABS>.wdl"\n```\n\nIt writes (and prints paths to) `plans.png` (floor plans \u2014 room layout + sizes),\n`elevations.png` (front/back/left/right \u2014 heights + **roof profile**, the 2D view of the\nbuilt 3D model), and `roof.png` (roof top view), plus all SVGs under `.../2d/`. **Read\nthe PNGs** after a non-trivial edit and confirm what you built matches the request (rooms\nin the right place, not overlapping, correct sizes in feet, roof over the plinth). **If\nit doesn\'t match, fix the `.wdl` and re-render \u2014 repeat until it looks right, and only\nthen tell the user it\'s ready.** It reuses the app\'s own generators, so it matches the\napp\'s 2D tabs byte-for-byte. See `prompts/verify-visually.md`.\n\n## Top pitfalls (memorize)\n\n- **Y is DOWN.** A room "to the north" has a *smaller* Y. Never treat Y as up.\n- **Dimensions are project units, not feet.** `width: 120` is 12 ft. Multiply feet by\n 10 (the default; `units.per_unit` can change it).\n- **Set `"coord_convention": "center"`.** Then a room\'s `x,y,width,length` are wall\n **CENTRELINES**, and **two rooms that share a wall just ABUT on the shared line** \u2014 room\n A spans X `[0,150]`, room B `[150,300]`; the wall is centred on `150` and shared. No\n overlap, no `wall_thickness` math (the system grows to the outer face at render). On a\n grid, a room is simply `x:"= main.x1", width:"= main.x2 - main.x1"`. (Legacy files\n without the flag use the OUTER convention where adjacent rooms must overlap by\n `wall_thickness`.) See `coordinate-system.md` \u2192 "the centreline convention".\n- **The roof footprint must cover the plinth footprint.** Roof segment widths and\n positions come from the walls they sit on, not arbitrary numbers.\n- **The roof lives on its OWN top floor** (`floor_number` ABOVE the floors it covers,\n containing only the roof), and you **never set its Z** \u2014 the base height is computed\n from the plinth height + the `height`s of the floors below it. To move the roof\n up/down, change floor heights, not the roof. (See `reference/roof-v2-guide.md`.)\n- **Floors stack; `floor_number` is 0-based** (the plinth floor = 0). Heights are\n independent per floor (`height`, `wall_height`, `slab_thickness` are unrelated\n fields) \u2014 *except* where the **structural conventions** require a match: the\n plinth-floor `height` must equal the plinth block height, and a floor with no slab\n must set `slab_thickness 0`, or the floors above float. See `reference/conventions.md`.\n- **A partial `wall` list makes a room a whitelist.** A bare room (no `wall` lines) is\n enclosed on all four sides; add one `wall` line and every side you don\'t list becomes a\n hole. Wall every **exterior** side (convention C2). List plain sides compactly:\n `wall east west`, then the opening sides separately.\n- **Minimal patches.** Preserve unchanged `.wdl` lines verbatim so the user (and diffs)\n can see exactly what moved.\n- **Formulas are bare expressions in the DSL** \u2014 write `at (main.x1, main.yA)`, not\n `"= main.x1"`; the compiler emits the `= \u2026` form. Quote only `name "\u2026"` strings;\n `room`/`pillar`/`var`/grid-line names are bare identifiers.\n- **Errors are caught by `check.sh`.** A parse error (bad syntax) or a `.strict()` schema\n error (unknown/misspelled key inside a `raw` block) fails `check.sh` with the exact\n location \u2014 and the app\'s DSL editor shows the same squiggle live; nothing reaches the\n model silently.\n'
|
|
422727
|
+
"body": '# Wadi architect \u2014 author `.wdl` house designs with a live 3D preview\n\nYou are the architect/editor. The user describes a house (in words, or with a\nsketch/photo); you write or update its **`.wdl`** file (the Wadi DSL), and the **Wadi\napp\'s DSL editor renders the model live** from that same file. The user watches and\nsteers with follow-up messages \u2014 and can edit the `.wdl` alongside you.\n\nYou author in the **Wadi DSL** (`.wdl`), not raw JSON. It\'s more direct (formulas,\ngrids, and the configurator are one-liners), the grammar enforces structure, and the\ncompiler reports parse errors with `line:col`. The DSL is **complete** \u2014 every object\ntype has first-class syntax \u2014 so it can express any house the model can hold.\n**`reference/dsl.md` is your syntax reference; read it first.**\n\n**The `.wdl` IS the design \u2014 do not produce a `.wadi`.** The Wadi app\'s DSL previewer\ncompiles + renders the `.wdl` live (in-app), so a single `.wdl` file on disk is the\n**shared source you and the human co-edit**. You never convert it to JSON; you just\nauthor the `.wdl` and verify it with `check.sh`.\n\nThis skill is **agent-neutral** \u2014 it is plain instructions + reference docs + scripts,\nusable by any coding agent (Claude Code, Google Antigravity, \u2026). Agent-specific\nentrypoints live outside this folder (e.g. `.claude/skills/wadi-architect/` for Claude\nCode, `AGENTS.md` at the repo root); they just point here.\n\n## What you need to run this\n\n- **Read/write files** and **run shell + Node** (the only capabilities assumed).\n- The **Wadi repo checked out**, with deps installed once:\n `npm --prefix editor install` and `npm --prefix wadi-dsl install` (the latter also\n regenerates the DSL parser via its `prepare` hook). The `check` and `preview` scripts\n reuse the app\'s own TypeScript, so they flag exactly what the app would.\n- For the *live* render: the **Wadi app\'s DSL editor** open on the `.wdl` you edit \u2014\n desktop **\u2318\u21E7D \u2192 Open**, or the browser playground at `wadi.house/dsl`. It compiles +\n renders the `.wdl` live. Without it you can still author + `check` + render preview\n images yourself.\n\n## The live loop (read this first, every session)\n\nThe **`.wdl` file is the single shared source.** You edit it; the Wadi app\'s DSL editor\n\u2014 open on that same file \u2014 compiles and re-renders it live; the human can edit it too (in\nthe DSL editor, in their own editor, or by asking you). **You never produce or touch a\n`.wadi`** \u2014 the app does the `.wdl` \u2192 render conversion.\n\n**Starting a NEW model:**\n1. Write a starter `house.wdl` (copy the shape from `../../wadi-dsl/examples/` \u2014 start\n from `minimal.wdl`, or `coastal.wdl` for a full cottage) at a path the user wants,\n e.g. `~/Documents/<name>.wdl`.\n2. Tell the user to open it in the **Wadi DSL editor** (**\u2318\u21E7D \u2192 Open** in the desktop\n app) so it renders live and watches the file.\n3. Build the house by editing `house.wdl`. Run `check.sh` after each change to confirm it\n still compiles + validates; the editor re-renders as the file changes.\n\n**Editing an EXISTING model:** edit its `.wdl`. Because it\'s a **co-edited** file, **read\nit first** (the human may have changed it since your last edit) and make a **minimal\npatch** \u2014 change only the lines you need and preserve the rest verbatim, so your edit\nmerges cleanly with theirs.\n\n**Always:**\n- **Tell the user which `.wdl` you are editing**, and edit only that path.\n- **Run `check.sh` after every edit.** It runs the DSL compiler + validator against a\n **throwaway temp** (it does NOT create a `.wadi`) purely for feedback \u2014 fix any\n reported error before telling the user anything changed. A broken `.wdl` just makes the\n editor show a diagnostic and keep the last good render; it never corrupts anything.\n\n## Two ways users work with you\n\n- **Brief \u2192 house.** They describe requirements ("3-bed L-shaped bungalow, ~1500 sq\n ft, hip roof"). You *derive* the base config. Keep a running **design brief** as the\n source of truth so later changes re-derive cleanly \u2014 see `prompts/design-brief.md`.\n This is Wadi\'s "higher-level language": the brief is the intent, the config is the\n derived artifact, you are the compiler.\n- **Drawings \u2192 house (recreate an existing design).** **Do NOT try to read dimensions\n off an architect\'s drawing yourself \u2014 it\'s unreliable and produces the wrong house.**\n Instead run a **guided dialog**: the USER reads their drawing and describes each\n piece in plain terms (names, sizes in feet, where things sit), and YOU do all the\n coordinate / scale / convention work, building **one room at a time** and rendering\n after each so they confirm. Ask **spatially** ("how big? which corner? next to\n what?"), never for coordinates. Never build the whole plan from one answer. Full\n method in `prompts/sketch-to-config.md`.\n- **Iterate.** They react to the live model ("make Bedroom 2 bigger", "add a north\n window"). Apply a **minimal patch** \u2014 see `prompts/update-existing.md`.\n\n## The data model & references (read lazily \u2014 don\'t dump them all up front)\n\n- **`reference/dsl.md`** \u2014 **your primary reference: the complete `.wdl` SYNTAX** \u2014\n the skeleton, the parametric core (var/point/grid/configurator/formulas), the common\n attribute tail (`enabled`/`z_offset`/`layer`/`material`), and the first-class syntax\n for every object type (rooms/walls/openings, slab/beam/plinth/ground/pillar,\n staircase/kitchen/item, roof, components, layers) plus the `raw` escape. Read this\n first, then the semantics references below.\n- **`reference/data-model.md`** \u2014 the underlying **`.wadi` schema** the DSL compiles to:\n every object type, field, type, requiredness, units, semantics. **Generated from the\n Zod schema** (`editor/src/schema/houseConfig.ts`) so it can\'t drift \u2014 regenerate with\n `scripts/gen-schema-doc.mjs` after any schema change. It\'s the field reference for the\n `raw` escape and for understanding exactly what your `.wdl` produces.\n- **`reference/coordinate-system.md`** \u2014 the #1 source of mistakes. X\u2192right, **Y\u2192DOWN**\n (Inkscape frame, not Y-up), Z\u2192up. Units: **10 project units = 1 ft** by default. Read\n before placing anything.\n- **`reference/roof-v2-guide.md`** \u2014 the unified `roof` object (segments, hip vs gable,\n joints, trusses, shed). Its fields are freeform in the schema (validated at\n derivation), so this guide is the field reference for roofs. Read before touching a\n roof.\n- **`reference/conventions.md`** \u2014 the **structural coding conventions** every house\n must follow (plinth-floor height must match the plinth block, rooms must wall every\n exterior side, a floor with no slab must set `slab_thickness 0`, \u2026). These are\n *enforced* by `check.sh` \u2014 errors fail, warnings are advisory \u2014 and shown in the DSL\n editor\'s status. Read it so you author sound houses the first time.\n- **`reference/parametric-conventions.md`** \u2014 how to build a **fully-parametric** model\n (a reusable template that stays valid under any knob change): the **grid-first**\n recipe \u2014 variables (knobs) \u2192 named grid lines (formulas of the house size) \u2192 rooms &\n columns that reference those lines \u2014 plus `coord_convention:center`, proportional grid\n lines with minimums, the `pilInset` flush-column rule, opening placement, and the\n scale-sweep verification. Read before authoring or editing a parametric template.\n- **`../../wadi-dsl/examples/*.wdl`** \u2014 correct, validated `.wdl` houses to copy shapes\n from (every one passes the compile \u2192 resolve \u2192 schema+geometry pipeline in the DSL\'s\n test suite, so **copy from these, not from memory**): `minimal.wdl` (smallest house),\n `two_room.wdl` (no grid), `two_story.wdl` (multi-floor + hip roof), `coastal.wdl`\n (grid + configurator + full cottage), `complete.wdl` (every entity \u2014 beam, wall,\n kitchen, item, component, gable roof, layers). `examples/coastal_konkan.wadi` in this\n folder is a resolved `.wadi` for reference on the compiled output shape.\n\n## Check after every edit (get compiler feedback \u2014 no `.wadi` produced)\n\n`check.sh` runs the DSL end-to-end for **feedback only**: it parses the `.wdl` (reporting\nparse errors with `line:col`), resolves formulas/grids into numbers, and runs the real\nschema + roof/wall geometry validator (catches zero-length roof segments, missing slope,\nbad openings that the schema alone misses), and finally the **structural conventions**\nlinter (`reference/conventions.md`: floating floors, open exterior walls, no-slab floors)\n\u2014 all against a **throwaway temp** that is deleted. It never writes a `.wadi`; the app\'s\nDSL previewer does the real conversion.\n\nConvention **errors** (`\u2716 [C\u2026]`) fail the check \u2014 fix them. Convention **warnings**\n(`\u26A0 [C\u2026]`) are printed but don\'t fail; fix them, or keep them if the open side is a\ndeliberate verandah.\n\n```bash\nwadi-skill/architect/scripts/check.sh "<ABS>.wdl"\n```\n\nExit 0 = compiles + valid. Non-zero prints the exact `parse: \u2026` or `/path: message`\nerror \u2014 fix the `.wdl` and re-run before telling the user anything is ready.\n\n**If you have the `wadi_*` MCP tools** (from the `wadi-mcp` server) instead of a repo\ncheckout, use them \u2014 they\'re the same pipeline, no clone needed: `wadi_check(wdl)` for\nthis step, `wadi_preview(wdl)` for the images below, `wadi_scope(wdl)` to see the actual\nresolved value of every variable/point/grid line before you place an object on it, and\n`wadi_examples` / `wadi_reference` for the examples and these docs.\n\n## See your work (don\'t author blind)\n\nYou can\'t see the app\'s live render, but you CAN render your `.wdl` to images and **read\nthem** to check your own edit \u2014 layout, sizes, openings, and roof are exactly where\nmistakes happen. `preview.sh` takes the `.wdl` directly (it compiles to a throwaway temp\njust for rendering \u2014 again, no persistent `.wadi`):\n\n```bash\nwadi-skill/architect/scripts/preview.sh "<ABS>.wdl"\n```\n\nIt writes (and prints paths to) `plans.png` (floor plans \u2014 room layout + sizes),\n`elevations.png` (front/back/left/right \u2014 heights + **roof profile**, the 2D view of the\nbuilt 3D model), and `roof.png` (roof top view), plus all SVGs under `.../2d/`. **Read\nthe PNGs** after a non-trivial edit and confirm what you built matches the request (rooms\nin the right place, not overlapping, correct sizes in feet, roof over the plinth). **If\nit doesn\'t match, fix the `.wdl` and re-render \u2014 repeat until it looks right, and only\nthen tell the user it\'s ready.** It reuses the app\'s own generators, so it matches the\napp\'s 2D tabs byte-for-byte. See `prompts/verify-visually.md`.\n\n## Top pitfalls (memorize)\n\n- **Y is DOWN.** A room "to the north" has a *smaller* Y. Never treat Y as up.\n- **Dimensions are project units, not feet.** `width: 120` is 12 ft. Multiply feet by\n 10 (the default; `units.per_unit` can change it).\n- **Set `"coord_convention": "center"`.** Then a room\'s `x,y,width,length` are wall\n **CENTRELINES**, and **two rooms that share a wall just ABUT on the shared line** \u2014 room\n A spans X `[0,150]`, room B `[150,300]`; the wall is centred on `150` and shared. No\n overlap, no `wall_thickness` math (the system grows to the outer face at render). On a\n grid, a room is simply `x:"= main.x1", width:"= main.x2 - main.x1"`. (Legacy files\n without the flag use the OUTER convention where adjacent rooms must overlap by\n `wall_thickness`.) See `coordinate-system.md` \u2192 "the centreline convention".\n- **The roof footprint must cover the plinth footprint.** Roof segment widths and\n positions come from the walls they sit on, not arbitrary numbers.\n- **The roof lives on its OWN top floor** (`floor_number` ABOVE the floors it covers,\n containing only the roof), and you **never set its Z** \u2014 the base height is computed\n from the plinth height + the `height`s of the floors below it. To move the roof\n up/down, change floor heights, not the roof. (See `reference/roof-v2-guide.md`.)\n- **Floors stack; `floor_number` is 0-based** (the plinth floor = 0). Heights are\n independent per floor (`height`, `wall_height`, `slab_thickness` are unrelated\n fields) \u2014 *except* where the **structural conventions** require a match: the\n plinth-floor `height` must equal the plinth block height, and a floor with no slab\n must set `slab_thickness 0`, or the floors above float. See `reference/conventions.md`.\n- **A partial `wall` list makes a room a whitelist.** A bare room (no `wall` lines) is\n enclosed on all four sides; add one `wall` line and every side you don\'t list becomes a\n hole. Wall every **exterior** side (convention C2). List plain sides compactly:\n `wall east west`, then the opening sides separately.\n- **Minimal patches.** Preserve unchanged `.wdl` lines verbatim so the user (and diffs)\n can see exactly what moved.\n- **Formulas are bare expressions in the DSL** \u2014 write `at (main.x1, main.yA)`, not\n `"= main.x1"`; the compiler emits the `= \u2026` form. Quote only `name "\u2026"` strings;\n `room`/`pillar`/`var`/grid-line names are bare identifiers.\n- **Errors are caught by `check.sh`.** A parse error (bad syntax) or a `.strict()` schema\n error (unknown/misspelled key inside a `raw` block) fails `check.sh` with the exact\n location \u2014 and the app\'s DSL editor shows the same squiggle live; nothing reaches the\n model silently.\n'
|
|
422693
422728
|
},
|
|
422694
422729
|
"dsl": {
|
|
422695
422730
|
"title": "The Wadi DSL (.wdl) \u2014 syntax reference",
|
|
@@ -422738,6 +422773,11 @@ function compileConfig(wdl) {
|
|
|
422738
422773
|
const { config: config3 } = resolveParametric(compiled);
|
|
422739
422774
|
return config3;
|
|
422740
422775
|
}
|
|
422776
|
+
function scopeWdl(wdl) {
|
|
422777
|
+
const compiled = compileDsl(wdl, { resolveModule: stdResolveModule });
|
|
422778
|
+
registerExposedComponents(compiled);
|
|
422779
|
+
return buildRefsView(compiled);
|
|
422780
|
+
}
|
|
422741
422781
|
function checkWdl(wdl) {
|
|
422742
422782
|
let config3;
|
|
422743
422783
|
try {
|
|
@@ -422864,6 +422904,39 @@ server.registerTool(
|
|
|
422864
422904
|
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent: r2 };
|
|
422865
422905
|
}
|
|
422866
422906
|
);
|
|
422907
|
+
server.registerTool(
|
|
422908
|
+
"wadi_scope",
|
|
422909
|
+
{
|
|
422910
|
+
title: "Resolve a Wadi design's variables, points & grid lines",
|
|
422911
|
+
description: "Compile a .wdl and return every symbol you can reference in an `= formula` with its RESOLVED numeric value: variables (with their formula source), point coordinates (x/y, also referenceable as .w/.l), and grid lines (`<grid>.x1`, `<grid>.yA`, \u2026). Use it to see the ACTUAL numbers a formula will produce before you place an object (e.g. what `main.x2` or `House.W/2` resolves to). \u26A0 = unresolved.",
|
|
422912
|
+
inputSchema: { wdl: external_exports.string().describe("The full .wdl source text.") }
|
|
422913
|
+
},
|
|
422914
|
+
async ({ wdl }) => {
|
|
422915
|
+
let view;
|
|
422916
|
+
try {
|
|
422917
|
+
view = scopeWdl(wdl);
|
|
422918
|
+
} catch (e) {
|
|
422919
|
+
return {
|
|
422920
|
+
content: [{ type: "text", text: "\u274C Could not compile: " + e.message + "\nRun wadi_check for details." }],
|
|
422921
|
+
isError: true
|
|
422922
|
+
};
|
|
422923
|
+
}
|
|
422924
|
+
const fmt = (v) => v === null ? "\u26A0" : Number.isInteger(v) ? String(v) : String(Math.round(v * 1e3) / 1e3);
|
|
422925
|
+
const lines = [];
|
|
422926
|
+
lines.push("Variables:");
|
|
422927
|
+
if (!view.variables.length) lines.push(" (none)");
|
|
422928
|
+
for (const v of view.variables) lines.push(` ${v.name} = ${fmt(v.value)}${v.formula ? ` ${v.formula}` : ""}`);
|
|
422929
|
+
lines.push("Points (x/y, also .w/.l):");
|
|
422930
|
+
if (!view.points.length) lines.push(" (none)");
|
|
422931
|
+
for (const p of view.points) lines.push(` ${p.name}: x ${fmt(p.x)} \xB7 y ${fmt(p.y)}`);
|
|
422932
|
+
for (const g of view.grids) {
|
|
422933
|
+
lines.push(`Grid "${g.id}":`);
|
|
422934
|
+
for (const l of g.xLines) lines.push(` ${g.id}.x${l.name} = ${fmt(l.value)}`);
|
|
422935
|
+
for (const l of g.yLines) lines.push(` ${g.id}.y${l.name} = ${fmt(l.value)}`);
|
|
422936
|
+
}
|
|
422937
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent: view };
|
|
422938
|
+
}
|
|
422939
|
+
);
|
|
422867
422940
|
server.registerTool(
|
|
422868
422941
|
"wadi_preview",
|
|
422869
422942
|
{
|