@adatechnology/game-floorplan-structure 2.0.2 → 2.1.1

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/dist/index.d.ts CHANGED
@@ -1,18 +1,8 @@
1
- import { FloorplanEngine, ViewerLayer, RoomDef, DoorDef, WindowDef, FloorDef, PlanAxis } from '@adatechnology/game-floorplan';
1
+ import { PlanAxis, ResultItem, FindsQuery, FindStack, Plan, FurnitureDef, FloorplanResult, FloorplanEngine, ViewerLayer, RoomDef, DoorDef, WindowDef, FloorDef } from '@adatechnology/game-floorplan';
2
2
  export { LotPath } from '@adatechnology/game-floorplan';
3
3
  import { MaterialId, JointKind, StructureRole, SoilProfile, PileSpec, DestructibleSpec, WindExposure } from '@adatechnology/game-contracts';
4
4
  import { SoilDef, FrameOptions, WindOptions, SizeStructureOptions } from '@adatechnology/game-destruction';
5
5
 
6
- interface StructurePackOptions {
7
- /** Litres of the tank by template id or style id. */
8
- tankCapacities?: Record<string, number>;
9
- }
10
- /**
11
- * Registers the structure into the engine: `result.construction`, `result.structureExtras`, `result.waterTank`, `result.structure` and `result.roof` of every plan,
12
- * and the structure layer of the 2D viewer. Register the content packs first.
13
- */
14
- declare function register(engine: FloorplanEngine, options?: StructurePackOptions): void;
15
-
16
6
  /** Axis-aligned rectangle `[u0, v0, u1, v1]` in the plan (metres). */
17
7
  type Rect = [number, number, number, number];
18
8
  type ConstructionSystem = 'masonry' | 'wood_frame' | 'log' | 'improvised' | 'canvas';
@@ -38,8 +28,10 @@ interface StructurePart {
38
28
  unit?: true;
39
29
  /** Distance between repeated members (joists, ceiling joists). */
40
30
  spacing?: number;
41
- /** `plate` (timber top plate) or `bond_beam` (masonry bond beam). */
42
- beamKind?: 'plate' | 'bond_beam';
31
+ /** `plate` (timber top plate), `bond_beam` (masonry bond beam) or `ground_beam` (the masonry ground beam, viga baldrame, buried under a ground-floor wall). */
32
+ beamKind?: 'plate' | 'bond_beam' | 'ground_beam';
33
+ /** An exterior wall (it carries the bond beam and the pillars of confined masonry). */
34
+ exterior?: true;
43
35
  steps?: number;
44
36
  door?: string;
45
37
  /** Slab that is the roof (flat roof). */
@@ -111,6 +103,8 @@ interface Structure {
111
103
  /** A reinforced concrete frame carries the building (apartments, commercial buildings, three storeys or more); the walls are infill. */
112
104
  framed: boolean;
113
105
  }
106
+ /** The structure as a `generate` result carries it: the roof goes out apart, in `result.roof`. */
107
+ type PlanStructure = Omit<Structure, 'roof'>;
114
108
  interface WallMaterials {
115
109
  material: MaterialId;
116
110
  interior?: MaterialId;
@@ -329,6 +323,17 @@ interface StructureOptions {
329
323
  wallDetail?: WallDetail;
330
324
  /** `false`: no roof (a free-standing wall, a garden wall). Default `true`. */
331
325
  roof?: boolean;
326
+ /**
327
+ * Concrete pillars along the exterior masonry walls besides the corner ones (at the free ends and door jambs, beside the windows, where walls meet and at
328
+ * most every `spacing` metres, default `WALL_PILLAR_SPACING`). `false`: only the corner pillars. Default `true`.
329
+ */
330
+ wallPillars?: boolean | {
331
+ spacing?: number;
332
+ };
333
+ /** A reinforced concrete ground beam (viga baldrame) under each ground-floor wall of a masonry house on strip footings (`GROUND_BEAM_DEPTH` deep). Default `true`. */
334
+ groundBeams?: boolean;
335
+ /** The sections the Visor de casas 3D drew below the NBR 6118 minimum (16 cm balcony pillars), for the team's golden only. Default `false`. */
336
+ visorSections?: boolean;
332
337
  }
333
338
  /** What a construction builder and the tank get to see: the generated plan, its seed and the template. */
334
339
  interface PlanContext {
@@ -342,12 +347,362 @@ interface PlanContext {
342
347
  };
343
348
  }
344
349
 
350
+ /** What a wall system is made of and how its parts are tied. Timber systems sit on joists, carry the roof on timber plates and have wooden porch posts. */
351
+ interface ConstructionSystemDef {
352
+ /** Wall assembly of `game-destruction` (`registerAssembly`) the detailed wall is built from. Empty: no walls (a tent). */
353
+ walls: string;
354
+ joints: Record<'wall' | 'slab' | 'beam' | 'column' | 'truss', JointKind>;
355
+ /** Thickness of the structural floor under each storey (m). */
356
+ slabThickness: number;
357
+ /** Height of the top plate or bond beam (m). */
358
+ plateThickness: number;
359
+ timber: boolean;
360
+ /** `rules`: bearing when external, under another wall or beside a porch; `bearing`: every wall (logs); `partition`: none (posts carry the roof). */
361
+ wallRole: 'rules' | 'bearing' | 'partition';
362
+ /** Solid fraction of a bearing wall in the structure weight (studs and air). */
363
+ wallFill: number;
364
+ studs?: {
365
+ spacing: number;
366
+ section: string;
367
+ };
368
+ }
369
+ declare const CONSTRUCTION_SYSTEMS: Map<string, ConstructionSystemDef>;
370
+ /** Adds or replaces a construction system (`id` is a `ConstructionSystem` or any name a construction refers to). */
371
+ declare function registerConstructionSystem(id: ConstructionSystem | string, def: ConstructionSystemDef): void;
372
+ interface RoofCoveringDef {
373
+ material: string;
374
+ /** How the covering is fixed to the trusses. */
375
+ joint: JointKind;
376
+ }
377
+ declare const ROOF_COVERINGS: Map<string, RoofCoveringDef>;
378
+ declare function registerRoofCovering(id: string, def: RoofCoveringDef): void;
379
+ interface ConstructionBuild {
380
+ construction: Construction;
381
+ extras?: StructureExtras;
382
+ }
383
+ type ConstructionBuilder = (context: PlanContext) => ConstructionBuild;
384
+ declare const CONSTRUCTIONS: Map<string, ConstructionBuilder>;
385
+ /** Registers how a template's building is made: `TemplateDef.construction` names it. A template without one gets the masonry default. */
386
+ declare function registerConstruction(id: string, builder: ConstructionBuilder): void;
387
+
388
+ type Rng$1 = () => number;
389
+
390
+ /** A point in the world: `[u, v, y]` (y is the absolute height). */
391
+ type Point3 = [number, number, number];
392
+ /** Something fixed to the inner face of a wall of a room: a socket, a switch, the panel. */
393
+ interface WallFixture {
394
+ id: string;
395
+ room: string;
396
+ floor: number;
397
+ u: number;
398
+ v: number;
399
+ /** Height above the storey floor. */
400
+ y: number;
401
+ /** Position along the wall. */
402
+ c: number;
403
+ axis: PlanAxis;
404
+ pos: number;
405
+ frontU: number;
406
+ frontV: number;
407
+ }
408
+ interface Outlet extends WallFixture {
409
+ type: string;
410
+ voltage: number;
411
+ }
412
+ interface LightSwitch extends WallFixture {
413
+ door: string;
414
+ /** On the latch side of the door. */
415
+ latchSide: boolean;
416
+ /** Lamp ids it turns on. */
417
+ controls: string[];
418
+ }
419
+ interface ElectricalPanel extends WallFixture {
420
+ w: number;
421
+ h: number;
422
+ breakers: number;
423
+ }
424
+ interface ElectricMeter {
425
+ id: string;
426
+ place: string;
427
+ u: number;
428
+ v: number;
429
+ y: number;
430
+ side: string;
431
+ w: number;
432
+ d: number;
433
+ h: number;
434
+ }
435
+ /** Pole, drop, meter, descent and the run to the panel; a tap has no meter and a bare connection instead. */
436
+ interface ServiceEntrance {
437
+ pole: {
438
+ u: number;
439
+ v: number;
440
+ h: number;
441
+ };
442
+ drop: Point3[];
443
+ meter: ElectricMeter | null;
444
+ descent: Point3[];
445
+ internalRun: Point3[] | null;
446
+ tap?: boolean;
447
+ connection?: {
448
+ u: number;
449
+ v: number;
450
+ y: number;
451
+ };
452
+ }
453
+ interface Circuit {
454
+ id: string;
455
+ room: string;
456
+ floor: number;
457
+ outlets: string[];
458
+ switches: string[];
459
+ lamps: string[];
460
+ exposed: boolean;
461
+ gauge_mm2: number;
462
+ }
463
+ interface Conduit {
464
+ id: string;
465
+ circuit: string;
466
+ from: string;
467
+ to: string;
468
+ exposed: boolean;
469
+ diameter: number;
470
+ points: Point3[];
471
+ }
472
+ interface OutdoorLamp {
473
+ id: string;
474
+ u: number;
475
+ v: number;
476
+ y: number;
477
+ door: string;
478
+ switch: string | null;
479
+ }
480
+ interface PlumbingPoint {
481
+ id: string;
482
+ kind: string;
483
+ item: string;
484
+ room: string | null;
485
+ floor: number;
486
+ u: number;
487
+ v: number;
488
+ y: number;
489
+ flowLpm: number | undefined;
490
+ run: string | null;
491
+ }
492
+ interface PlumbingRun {
493
+ id: string;
494
+ from: string;
495
+ /** A point, a room, or `ceiling`. */
496
+ to: string | null;
497
+ points: Point3[];
498
+ diameter: number;
499
+ exposed: string;
500
+ }
501
+ interface Plumbing {
502
+ tank: 'water_tank' | null;
503
+ capacityL: number;
504
+ points: PlumbingPoint[];
505
+ visibleRuns: PlumbingRun[];
506
+ }
507
+ interface SolarPanel {
508
+ id: string;
509
+ u: number;
510
+ v: number;
511
+ w: number;
512
+ d: number;
513
+ length: number;
514
+ }
515
+ interface Inverter {
516
+ id: string;
517
+ u: number;
518
+ v: number;
519
+ y: number;
520
+ side: string;
521
+ w: number;
522
+ d: number;
523
+ h: number;
524
+ outdoor: boolean;
525
+ link: string;
526
+ }
527
+ interface Solar {
528
+ type: 'slab_rack' | 'roof';
529
+ orientation: string;
530
+ north: 'front' | 'back';
531
+ slopeSide: 'front' | 'back' | null;
532
+ tilt: number;
533
+ area: number[];
534
+ areaM2: number;
535
+ count: number;
536
+ floor: number;
537
+ y: number;
538
+ panels: SolarPanel[];
539
+ inverter: Inverter | null;
540
+ }
541
+ /** A door or a window in the wall of an outbuilding. */
542
+ interface OutbuildingOpening {
543
+ id: string;
544
+ axis: PlanAxis;
545
+ pos: number;
546
+ at: number;
547
+ u: number;
548
+ v: number;
549
+ width: number;
550
+ side: string;
551
+ height?: number;
552
+ exterior?: boolean;
553
+ y0?: number;
554
+ y1?: number;
555
+ /** Swing area of a door. */
556
+ zone?: Rect;
557
+ }
558
+ interface OutbuildingWall {
559
+ axis: PlanAxis;
560
+ u0: number;
561
+ v0: number;
562
+ u1: number;
563
+ v1: number;
564
+ thickness: number;
565
+ h: number;
566
+ side: string;
567
+ }
568
+ interface OutbuildingItem {
569
+ type: string;
570
+ category: string;
571
+ u: number;
572
+ v: number;
573
+ w: number;
574
+ d: number;
575
+ h: number;
576
+ ry: number;
577
+ frontU: number;
578
+ frontV: number;
579
+ aabb: Rect;
580
+ }
581
+ interface Outbuilding {
582
+ id: string;
583
+ type: 'outbuilding';
584
+ use: string;
585
+ floor: number;
586
+ aabb: Rect;
587
+ interior: Rect[];
588
+ ceiling: number;
589
+ thickness: number;
590
+ front: [number, number];
591
+ walls: OutbuildingWall[];
592
+ doors: OutbuildingOpening[];
593
+ windows: OutbuildingOpening[];
594
+ items: OutbuildingItem[];
595
+ }
596
+
597
+ type EnergyMode = 'grid' | 'tap' | 'offgrid';
598
+ /** What a template says about its energy (a shack taps the grid without a meter, a cabin may run off-grid on solar). */
599
+ interface EnergyConfig {
600
+ mode: EnergyMode;
601
+ solar?: boolean;
602
+ }
603
+ interface Electrical {
604
+ mode: EnergyMode;
605
+ serviceEntrance: ServiceEntrance | null;
606
+ panel: ElectricalPanel | null;
607
+ outlets: Outlet[];
608
+ switches: LightSwitch[];
609
+ circuits: Circuit[];
610
+ conduits: Conduit[];
611
+ exposed: boolean;
612
+ outdoorLamps: OutdoorLamp[];
613
+ source?: 'solar' | 'lamp';
614
+ }
615
+
616
+ interface GasMeter {
617
+ id: 'gas.meter';
618
+ u: number;
619
+ v: number;
620
+ y: number;
621
+ side: string;
622
+ w: number;
623
+ d: number;
624
+ h: number;
625
+ }
626
+ interface Gas {
627
+ type: 'piped' | 'cylinder';
628
+ meter: GasMeter | null;
629
+ }
630
+
631
+ interface Utilities {
632
+ gas: Gas | null;
633
+ electrical: Electrical;
634
+ solar: Solar | null;
635
+ plumbing: Plumbing;
636
+ }
637
+ interface UtilitiesContext {
638
+ plan: Plan;
639
+ items: ResultItem[];
640
+ stateItems: ResultItem[];
641
+ tank: WaterTank | null;
642
+ energy?: EnergyConfig;
643
+ /** Seeded stream by name: `gas`, `electrical`, `solar`. */
644
+ rngFor(key: string): Rng$1;
645
+ }
646
+ /** Gas, electricity, solar panels and plumbing of a house, in the order that lets the later ones see the cylinders the first adds to `items`. */
647
+ declare function planUtilities(context: UtilitiesContext): Utilities;
648
+ interface ContentsContext {
649
+ items: ResultItem[];
650
+ state: string;
651
+ place: string;
652
+ /** Outbreak days and region of the world, passed to the finds provider. */
653
+ day?: number;
654
+ region?: string;
655
+ rngFor(key: string): Rng$1;
656
+ findsFor(query: FindsQuery): readonly FindStack[];
657
+ }
658
+ /** What every container holds, asked of the registered finds provider: by item id, and `<id>#overhead` for the wall cabinet over a sink. */
659
+ declare function planContents(context: ContentsContext): Record<string, readonly FindStack[]>;
660
+
661
+ interface OutbuildingContext {
662
+ plan: Plan;
663
+ items: ResultItem[];
664
+ catalog: Record<string, FurnitureDef>;
665
+ rngFor(key: string): Rng$1;
666
+ }
667
+ /**
668
+ * The outbuilding at the back of the yard is a small building of its own: walls with a gap for the door, a door of 0.85 m facing the yard, two windows and the
669
+ * furniture of a drawn use (guest room, office, storage, gourmet space).
670
+ */
671
+ declare function planOutbuildings(context: OutbuildingContext): Outbuilding[];
672
+
673
+ /**
674
+ * A `generate` result once the structure pack is registered: the plan of `game-floorplan` with what the pack's extensions add (the construction and its extras,
675
+ * the water tank, the structure and its roof, the contents of the furniture, the outbuildings and the utilities).
676
+ */
677
+ type StructuredResult = FloorplanResult & {
678
+ construction: ConstructionBuild['construction'];
679
+ structureExtras: NonNullable<ConstructionBuild['extras']>;
680
+ waterTank: WaterTank | null;
681
+ structure: PlanStructure;
682
+ roof: Roof | null;
683
+ contents: ReturnType<typeof planContents>;
684
+ outbuildings: ReturnType<typeof planOutbuildings>;
685
+ utilities: ReturnType<typeof planUtilities>;
686
+ };
687
+ interface StructurePackOptions {
688
+ /** Litres of the tank by template id or style id. */
689
+ tankCapacities?: Record<string, number>;
690
+ }
691
+ /**
692
+ * Registers the structure into the engine: `result.construction`, `result.structureExtras`, `result.waterTank`, `result.structure` and `result.roof` of every plan,
693
+ * and the structure layer of the 2D viewer. Register the content packs first.
694
+ */
695
+ declare function register(engine: FloorplanEngine, options?: StructurePackOptions): void;
696
+
345
697
  /**
346
698
  * The structure of a generated plan: every part that carries load (foundation, floors, walls, plates and bond beams, pillars, porch posts, trusses,
347
699
  * roof, stairs, tank) with what each rests on. The plan itself is not modified.
348
700
  */
349
701
  declare function buildStructure(source: StructureSource, options?: StructureOptions): Structure;
350
702
 
703
+ /** Depth of the sill beam under a window of a masonry wall, metres (a contraverga is usually 10 cm). */
704
+ declare const SILL_BEAM_DEPTH = 0.1;
705
+
351
706
  interface PartsAndSupports {
352
707
  parts: StructurePart[];
353
708
  supports: Support[];
@@ -413,18 +768,18 @@ declare const beamDepthFor: (span: number, options: SlabPanelOptions, minimum?:
413
768
  * The slabs of concrete cut into panels with beams (`SlabPanelOptions`): see `T10-estrutura-real.md` §12. `input` is the structure as
414
769
  * `toDestructibleSpec` has it (walls with their roles), and the result has the panels, the beams, the pillars they need and the supports re-pointed.
415
770
  */
416
- declare function applySlabPanels(input: PartsAndSupports, structure: Structure, options: SlabPanelOptions): PartsAndSupports;
771
+ declare function applySlabPanels(input: PartsAndSupports, structure: PlanStructure, options: SlabPanelOptions): PartsAndSupports;
417
772
  /**
418
773
  * The panels `toDestructibleSpec` makes of the slabs of a structure (named as it names them), for a renderer that draws the floor of each room apart:
419
774
  * `panels` (each with `slab`, the id of the slab it was cut from), `replaced` (those slabs, which the spec no longer has) and the `supports` that touch the panels.
420
775
  */
421
- declare function slabPanelView(structure: Structure, options: SlabPanelOptions): {
776
+ declare function slabPanelView(structure: PlanStructure, options: SlabPanelOptions): {
422
777
  panels: StructurePart[];
423
778
  replaced: string[];
424
779
  supports: Support[];
425
780
  };
426
781
  /** The panels of `slabPanelView`, alone. */
427
- declare const slabPanelsOf: (structure: Structure, options: SlabPanelOptions) => StructurePart[];
782
+ declare const slabPanelsOf: (structure: PlanStructure, options: SlabPanelOptions) => StructurePart[];
428
783
 
429
784
  interface DestructibleSpecOptions {
430
785
  /** Fraction of its capacity a pillar or bearing wall uses at rest (default 0.65). */
@@ -490,31 +845,43 @@ declare const MEMBER_CAGE: {
490
845
  diameter: number;
491
846
  unit: number;
492
847
  };
848
+ /**
849
+ * What the bare cage of a concrete pillar still carries once its concrete is blown off, as the share of the pillar's `capacity` (kg) the destruction
850
+ * world keeps for it (`reinforcement.residualCapacity`): its perimeter bars (at most `spacing` apart, at least two a face) by the steel's crushing
851
+ * strength, halved for buckling between the stirrups. A pillar under a light bond beam keeps standing on its cage; a loaded one still gives way.
852
+ */
853
+ declare function cageResidualCapacity(size: readonly number[], reinforcement: {
854
+ material: string;
855
+ spacing: number;
856
+ diameter: number;
857
+ }, capacity: number | undefined): number;
493
858
  /**
494
859
  * The structure as a `DestructibleSpec` in the space of the house (x = u, y = height, z = v; the ground is y = 0), one box per part and a terrain slab
495
860
  * that anchors it. Capacities are sized from the loads at rest, as a designer would: a house stands whole, holds the loss of one pillar or bearing wall
496
861
  * and falls with two.
497
862
  */
498
- declare function toDestructibleSpec(structure: Structure, options?: DestructibleSpecOptions): DestructibleSpec;
863
+ declare function toDestructibleSpec(structure: PlanStructure, options?: DestructibleSpecOptions): DestructibleSpec;
499
864
 
500
- interface WallSpecimenOptions {
501
- /** Wall assembly of `game-destruction` (`brick_wall_plastered`, `concrete_block_wall`, `reinforced_concrete`, `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`...). */
502
- assembly: string;
503
- /** Width and height in metres (the test area uses 2.4 x 2.1). */
504
- w: number;
505
- h: number;
506
- opening?: 'door' | 'window' | null;
507
- /** Default `panels`: piers, lintel with its 0.2 m bearing, sill, plaster and rebar; `units` also lays the bricks, blocks or concrete panels one by one. */
508
- detail?: WallDetail;
509
- }
510
865
  /**
511
- * A test wall as its assembly builds it, standing on a plinth: in `panels` the piers beside the opening, the lintel over it (reinforced concrete bearing 0.2 m on
512
- * the piers; a header in timber walls), the sill under a window and the wall above; with the plaster coat and the rebar of the assembly. The mass is the
513
- * assembly's for the whole w x h, whatever the detail.
866
+ * Most a masonry wall runs between two of its concrete pillars, metres. Confined masonry (alvenaria confinada / de vedação with a concrete frame) puts a pillar
867
+ * every 3 to 5 m, at the corners, where walls meet and beside the openings; 4 m is the middle of that range.
514
868
  */
515
- declare function buildWallSpecimen(options: WallSpecimenOptions): DestructibleSpec;
869
+ declare const WALL_PILLAR_SPACING = 4;
870
+ /** Side of a wall pillar, metres: 0.2 x 0.2 m, as the corner pillars (NBR 6118 asks at least 19 cm for a pillar). */
871
+ declare const WALL_PILLAR_SIDE = 0.2;
872
+ /**
873
+ * Centres of the pillars of a stretch: at each end (inside the stretch, flush with it), at the walls that meet it, and in between so that no span passes
874
+ * `spacing`. A short pier still gets one at each end (a door jamb beside a corner keeps its own pillar; `addWallPillars` drops the one a pillar already
875
+ * stands near); one too short for two gets one in its middle, and one too short for a pillar none.
876
+ */
877
+ declare function pillarStations(from: number, to: number, junctions: readonly number[], spacing: number): number[];
878
+
879
+ /** Depth of the ground beam (viga baldrame) under a ground-floor masonry wall, metres: the usual 15 x 30 cm, as wide as the wall. */
880
+ declare const GROUND_BEAM_DEPTH = 0.3;
516
881
 
517
882
  type Rng = () => number;
883
+ /** Side of the concrete pillars of a raised tank slab, metres: NBR 6118 asks at least 19 cm. */
884
+ declare const TANK_PILLAR_SIDE = 0.2;
518
885
  interface TankPlanOptions {
519
886
  /** Litres by template id or style id (default: budget 500, mid 1000, mansion 3000, any other 2000). */
520
887
  capacities?: Record<string, number>;
@@ -522,6 +889,8 @@ interface TankPlanOptions {
522
889
  location?: (source: StructureSource, rng: Rng) => WaterTank['place'];
523
890
  /** A template with its own tank (a trestle for the rural water) answers here instead. */
524
891
  custom?: (source: StructureSource, rng: Rng) => WaterTank | null;
892
+ /** Side of the platform's concrete pillars (default `TANK_PILLAR_SIDE`; the Visor de casas 3D drew 0.12 m). */
893
+ pillarSide?: number;
525
894
  }
526
895
  /**
527
896
  * The water tank of a house: on the roof slab, in the attic, or on a platform that rises out of the roof, never in the yard. Null for a plan without
@@ -529,43 +898,93 @@ interface TankPlanOptions {
529
898
  */
530
899
  declare function planWaterTank(source: StructureSource, rng: Rng, options?: TankPlanOptions): WaterTank | null;
531
900
 
532
- /** What a wall system is made of and how its parts are tied. Timber systems sit on joists, carry the roof on timber plates and have wooden porch posts. */
533
- interface ConstructionSystemDef {
534
- /** Wall assembly of `game-destruction` (`registerAssembly`) the detailed wall is built from. Empty: no walls (a tent). */
535
- walls: string;
536
- joints: Record<'wall' | 'slab' | 'beam' | 'column' | 'truss', JointKind>;
537
- /** Thickness of the structural floor under each storey (m). */
538
- slabThickness: number;
539
- /** Height of the top plate or bond beam (m). */
540
- plateThickness: number;
541
- timber: boolean;
542
- /** `rules`: bearing when external, under another wall or beside a porch; `bearing`: every wall (logs); `partition`: none (posts carry the roof). */
543
- wallRole: 'rules' | 'bearing' | 'partition';
544
- /** Solid fraction of a bearing wall in the structure weight (studs and air). */
545
- wallFill: number;
546
- studs?: {
547
- spacing: number;
548
- section: string;
549
- };
550
- }
551
- declare const CONSTRUCTION_SYSTEMS: Map<string, ConstructionSystemDef>;
552
- /** Adds or replaces a construction system (`id` is a `ConstructionSystem` or any name a construction refers to). */
553
- declare function registerConstructionSystem(id: ConstructionSystem | string, def: ConstructionSystemDef): void;
554
- interface RoofCoveringDef {
555
- material: string;
556
- /** How the covering is fixed to the trusses. */
557
- joint: JointKind;
558
- }
559
- declare const ROOF_COVERINGS: Map<string, RoofCoveringDef>;
560
- declare function registerRoofCovering(id: string, def: RoofCoveringDef): void;
561
- interface ConstructionBuild {
562
- construction: Construction;
563
- extras?: StructureExtras;
901
+ /** Stable codes of what `validateStructure` and `validateSpec` find wrong in a construction. */
902
+ declare const STRUCTURAL_VIOLATION: {
903
+ /** A pillar with no load path to the ground, or that starts above what it rests on. */
904
+ readonly PILLAR_NOT_GROUNDED: "PILLAR_NOT_GROUNDED";
905
+ /** A pillar of a masonry wall that stops short of the bond beam, or that the bond beam does not rest on. */
906
+ readonly PILLAR_DOES_NOT_REACH_BOND_BEAM: "PILLAR_DOES_NOT_REACH_BOND_BEAM";
907
+ /** A masonry wall that runs more than `MAX_PILLAR_SPACING` between two of its pillars. */
908
+ readonly WALL_SPAN_WITHOUT_PILLAR: "WALL_SPAN_WITHOUT_PILLAR";
909
+ /** A free end of a masonry wall (a door jamb, the end of a garden wall) with no pillar. */
910
+ readonly WALL_END_WITHOUT_PILLAR: "WALL_END_WITHOUT_PILLAR";
911
+ /** Two masonry walls meet at a corner with no pillar there. */
912
+ readonly CORNER_WITHOUT_PILLAR: "CORNER_WITHOUT_PILLAR";
913
+ /** Another wall meets a masonry wall inside its length (a T) with no pillar there. */
914
+ readonly WALL_JUNCTION_WITHOUT_PILLAR: "WALL_JUNCTION_WITHOUT_PILLAR";
915
+ /** A window or door in a masonry wall with no lintel (verga) over it. */
916
+ readonly OPENING_WITHOUT_LINTEL: "OPENING_WITHOUT_LINTEL";
917
+ /** A window in a masonry wall with no sill beam (contraverga) under it. */
918
+ readonly OPENING_WITHOUT_SILL: "OPENING_WITHOUT_SILL";
919
+ /** An exterior masonry wall with no bond beam (cinta de amarração) on top. */
920
+ readonly MISSING_BOND_BEAM: "MISSING_BOND_BEAM";
921
+ /** A ground-floor masonry wall standing on the soil with no ground beam (viga baldrame) or foundation under it. */
922
+ readonly MISSING_GROUND_BEAM: "MISSING_GROUND_BEAM";
923
+ /** A part with no load path down to the ground. */
924
+ readonly FLOATING_PART: "FLOATING_PART";
925
+ /** A concrete beam longer than a lintel that rests on masonry alone (no pillar, beam or slab carries it). */
926
+ readonly BEAM_ON_WEAK_MASONRY: "BEAM_ON_WEAK_MASONRY";
927
+ /** A concrete pillar or beam below the NBR 6118 minimum section, or a beam between point supports shallower than a tenth of its span. */
928
+ readonly CONCRETE_BELOW_MIN_SECTION: "CONCRETE_BELOW_MIN_SECTION";
929
+ /** A concrete pillar or beam with no steel (the construction has no rebar). */
930
+ readonly UNREINFORCED_CONCRETE: "UNREINFORCED_CONCRETE";
931
+ /** A brick or block wall laid in stack bond: the vertical joints line up and the wall splits along them. */
932
+ readonly UNBONDED_MASONRY: "UNBONDED_MASONRY";
933
+ /** A plastered brick wall without plaster on both faces. */
934
+ readonly MISSING_PLASTER: "MISSING_PLASTER";
935
+ };
936
+ type StructuralViolationCode = (typeof STRUCTURAL_VIOLATION)[keyof typeof STRUCTURAL_VIOLATION];
937
+ /** One thing a construction gets wrong: the code, the part (or opening) it is about and the rule it breaks, in words. */
938
+ interface StructuralViolation {
939
+ readonly code: StructuralViolationCode;
940
+ readonly part: string;
941
+ readonly message: string;
942
+ }
943
+ /** Most metres a masonry wall runs between two pillars (confined masonry: 3 to 4 m; `WALL_PILLAR_SPACING` is 4). */
944
+ declare const MAX_PILLAR_SPACING = 4;
945
+ /** NBR 6118 13.2.3: no side of a pillar under 19 cm, and at least 360 cm² of section. */
946
+ declare const MIN_PILLAR_SIDE = 0.19;
947
+ declare const MIN_PILLAR_AREA = 0.036;
948
+ /** NBR 6118 13.2.2: a beam at least 12 cm wide. */
949
+ declare const MIN_BEAM_WIDTH = 0.12;
950
+ /** A beam between point supports is at least a tenth of its span deep (pre-sizing of reinforced concrete beams, h = L/10). */
951
+ declare const BEAM_DEPTH_RATIO = 10;
952
+ /** A concrete beam that only masonry carries may be a lintel up to this span; a longer one needs pillars. */
953
+ declare const MAX_LINTEL_ON_MASONRY = 3;
954
+
955
+ interface ValidateStructureOptions {
956
+ /** Detail the walls are built in for play (default `panels`, as the houses are): the lintels and sill beams of the windows come from it. */
957
+ wallDetail?: WallDetail;
958
+ /** The doors of the plan (`plan.doors`): each door gap in a masonry wall needs a lintel. Without them only the windows are checked. */
959
+ doors?: readonly SourceDoor[];
564
960
  }
565
- type ConstructionBuilder = (context: PlanContext) => ConstructionBuild;
566
- declare const CONSTRUCTIONS: Map<string, ConstructionBuilder>;
567
- /** Registers how a template's building is made: `TemplateDef.construction` names it. A template without one gets the masonry default. */
568
- declare function registerConstruction(id: string, builder: ConstructionBuilder): void;
961
+ /**
962
+ * What a structure gets wrong as a real building: load paths (every part down to the ground, every pillar on what carries it), reinforced concrete (NBR
963
+ * 6118 sections, steel, beam depth) and, in masonry, confined masonry (ground beam, pillars at ends, corners, junctions and every 4 m up to the bond beam,
964
+ * lintels and sill beams, bonded and plastered bricks). An empty list is a structure that a structural engineer would sign.
965
+ */
966
+ declare function validateStructure(structure: PlanStructure, options?: ValidateStructureOptions): StructuralViolation[];
967
+ /** What a destructible spec built straight as one (towers, skyscrapers) gets wrong: load paths and concrete sections. */
968
+ declare function validateSpec(spec: DestructibleSpec): StructuralViolation[];
969
+ /** The violations counted by code (for reports and tests). */
970
+ declare function countViolations(violations: readonly StructuralViolation[]): Partial<Record<keyof typeof STRUCTURAL_VIOLATION, number>>;
971
+
972
+ interface WallSpecimenOptions {
973
+ /** Wall assembly of `game-destruction` (`brick_wall_plastered`, `concrete_block_wall`, `reinforced_concrete`, `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`...). */
974
+ assembly: string;
975
+ /** Width and height in metres (the test area uses 2.4 x 2.1). */
976
+ w: number;
977
+ h: number;
978
+ opening?: 'door' | 'window' | null;
979
+ /** Default `panels`: piers, lintel with its 0.2 m bearing, sill, plaster and rebar; `units` also lays the bricks, blocks or concrete panels one by one. */
980
+ detail?: WallDetail;
981
+ }
982
+ /**
983
+ * A test wall as its assembly builds it, standing on a plinth: in `panels` the piers beside the opening, the lintel over it (reinforced concrete bearing 0.2 m on
984
+ * the piers; a header in timber walls), the sill under a window and the wall above; with the plaster coat and the rebar of the assembly. The mass is the
985
+ * assembly's for the whole w x h, whatever the detail.
986
+ */
987
+ declare function buildWallSpecimen(options: WallSpecimenOptions): DestructibleSpec;
569
988
 
570
989
  /** Masonry house of the engine's own templates: brick with plaster, concrete frame, tiles by facade; a unit in a building gets a flat slab roof. */
571
990
  declare function masonryConstruction(source: StructureSource): Construction;
@@ -1160,254 +1579,6 @@ declare const towerLocales: {
1160
1579
  };
1161
1580
  };
1162
1581
 
1163
- /** A point in the world: `[u, v, y]` (y is the absolute height). */
1164
- type Point3 = [number, number, number];
1165
- /** Something fixed to the inner face of a wall of a room: a socket, a switch, the panel. */
1166
- interface WallFixture {
1167
- id: string;
1168
- room: string;
1169
- floor: number;
1170
- u: number;
1171
- v: number;
1172
- /** Height above the storey floor. */
1173
- y: number;
1174
- /** Position along the wall. */
1175
- c: number;
1176
- axis: PlanAxis;
1177
- pos: number;
1178
- frontU: number;
1179
- frontV: number;
1180
- }
1181
- interface Outlet extends WallFixture {
1182
- type: string;
1183
- voltage: number;
1184
- }
1185
- interface LightSwitch extends WallFixture {
1186
- door: string;
1187
- /** On the latch side of the door. */
1188
- latchSide: boolean;
1189
- /** Lamp ids it turns on. */
1190
- controls: string[];
1191
- }
1192
- interface ElectricalPanel extends WallFixture {
1193
- w: number;
1194
- h: number;
1195
- breakers: number;
1196
- }
1197
- interface ElectricMeter {
1198
- id: string;
1199
- place: string;
1200
- u: number;
1201
- v: number;
1202
- y: number;
1203
- side: string;
1204
- w: number;
1205
- d: number;
1206
- h: number;
1207
- }
1208
- /** Pole, drop, meter, descent and the run to the panel; a tap has no meter and a bare connection instead. */
1209
- interface ServiceEntrance {
1210
- pole: {
1211
- u: number;
1212
- v: number;
1213
- h: number;
1214
- };
1215
- drop: Point3[];
1216
- meter: ElectricMeter | null;
1217
- descent: Point3[];
1218
- internalRun: Point3[] | null;
1219
- tap?: boolean;
1220
- connection?: {
1221
- u: number;
1222
- v: number;
1223
- y: number;
1224
- };
1225
- }
1226
- interface Circuit {
1227
- id: string;
1228
- room: string;
1229
- floor: number;
1230
- outlets: string[];
1231
- switches: string[];
1232
- lamps: string[];
1233
- exposed: boolean;
1234
- gauge_mm2: number;
1235
- }
1236
- interface Conduit {
1237
- id: string;
1238
- circuit: string;
1239
- from: string;
1240
- to: string;
1241
- exposed: boolean;
1242
- diameter: number;
1243
- points: Point3[];
1244
- }
1245
- interface OutdoorLamp {
1246
- id: string;
1247
- u: number;
1248
- v: number;
1249
- y: number;
1250
- door: string;
1251
- switch: string | null;
1252
- }
1253
- interface PlumbingPoint {
1254
- id: string;
1255
- kind: string;
1256
- item: string;
1257
- room: string | null;
1258
- floor: number;
1259
- u: number;
1260
- v: number;
1261
- y: number;
1262
- flowLpm: number | undefined;
1263
- run: string | null;
1264
- }
1265
- interface PlumbingRun {
1266
- id: string;
1267
- from: string;
1268
- /** A point, a room, or `ceiling`. */
1269
- to: string | null;
1270
- points: Point3[];
1271
- diameter: number;
1272
- exposed: string;
1273
- }
1274
- interface Plumbing {
1275
- tank: 'water_tank' | null;
1276
- capacityL: number;
1277
- points: PlumbingPoint[];
1278
- visibleRuns: PlumbingRun[];
1279
- }
1280
- interface SolarPanel {
1281
- id: string;
1282
- u: number;
1283
- v: number;
1284
- w: number;
1285
- d: number;
1286
- length: number;
1287
- }
1288
- interface Inverter {
1289
- id: string;
1290
- u: number;
1291
- v: number;
1292
- y: number;
1293
- side: string;
1294
- w: number;
1295
- d: number;
1296
- h: number;
1297
- outdoor: boolean;
1298
- link: string;
1299
- }
1300
- interface Solar {
1301
- type: 'slab_rack' | 'roof';
1302
- orientation: string;
1303
- north: 'front' | 'back';
1304
- slopeSide: 'front' | 'back' | null;
1305
- tilt: number;
1306
- area: number[];
1307
- areaM2: number;
1308
- count: number;
1309
- floor: number;
1310
- y: number;
1311
- panels: SolarPanel[];
1312
- inverter: Inverter | null;
1313
- }
1314
- /** A door or a window in the wall of an outbuilding. */
1315
- interface OutbuildingOpening {
1316
- id: string;
1317
- axis: PlanAxis;
1318
- pos: number;
1319
- at: number;
1320
- u: number;
1321
- v: number;
1322
- width: number;
1323
- side: string;
1324
- height?: number;
1325
- exterior?: boolean;
1326
- y0?: number;
1327
- y1?: number;
1328
- /** Swing area of a door. */
1329
- zone?: Rect;
1330
- }
1331
- interface OutbuildingWall {
1332
- axis: PlanAxis;
1333
- u0: number;
1334
- v0: number;
1335
- u1: number;
1336
- v1: number;
1337
- thickness: number;
1338
- h: number;
1339
- side: string;
1340
- }
1341
- interface OutbuildingItem {
1342
- type: string;
1343
- category: string;
1344
- u: number;
1345
- v: number;
1346
- w: number;
1347
- d: number;
1348
- h: number;
1349
- ry: number;
1350
- frontU: number;
1351
- frontV: number;
1352
- aabb: Rect;
1353
- }
1354
- interface Outbuilding {
1355
- id: string;
1356
- type: 'outbuilding';
1357
- use: string;
1358
- floor: number;
1359
- aabb: Rect;
1360
- interior: Rect[];
1361
- ceiling: number;
1362
- thickness: number;
1363
- front: [number, number];
1364
- walls: OutbuildingWall[];
1365
- doors: OutbuildingOpening[];
1366
- windows: OutbuildingOpening[];
1367
- items: OutbuildingItem[];
1368
- }
1369
-
1370
- type EnergyMode = 'grid' | 'tap' | 'offgrid';
1371
- /** What a template says about its energy (a shack taps the grid without a meter, a cabin may run off-grid on solar). */
1372
- interface EnergyConfig {
1373
- mode: EnergyMode;
1374
- solar?: boolean;
1375
- }
1376
- interface Electrical {
1377
- mode: EnergyMode;
1378
- serviceEntrance: ServiceEntrance | null;
1379
- panel: ElectricalPanel | null;
1380
- outlets: Outlet[];
1381
- switches: LightSwitch[];
1382
- circuits: Circuit[];
1383
- conduits: Conduit[];
1384
- exposed: boolean;
1385
- outdoorLamps: OutdoorLamp[];
1386
- source?: 'solar' | 'lamp';
1387
- }
1388
-
1389
- interface GasMeter {
1390
- id: 'gas.meter';
1391
- u: number;
1392
- v: number;
1393
- y: number;
1394
- side: string;
1395
- w: number;
1396
- d: number;
1397
- h: number;
1398
- }
1399
- interface Gas {
1400
- type: 'piped' | 'cylinder';
1401
- meter: GasMeter | null;
1402
- }
1403
-
1404
- interface Utilities {
1405
- gas: Gas | null;
1406
- electrical: Electrical;
1407
- solar: Solar | null;
1408
- plumbing: Plumbing;
1409
- }
1410
-
1411
1582
  declare const version = "0.1.0";
1412
1583
 
1413
- export { CONSTRUCTIONS, CONSTRUCTION_SYSTEMS, CORE_DEFAULTS, CURTAIN_DEFAULTS, type ChaletOptions, type Chimney, type Circuit, type Conduit, type Construction, type ConstructionBuild, type ConstructionBuilder, type ConstructionSystem, type ConstructionSystemDef, type CoreOptions, type CurtainWallOptions, DAMPER_DEFAULTS, DENSITY, type DamperOptions, type DestructibleSpecOptions, type ElectricMeter, type Electrical, type ElectricalPanel, type EnergyConfig, type EnergyMode, FLAT_ROOF_DEFAULTS, type FlatRoofOptions, type FoundationType, GROUND, type Gas, type GasMeter, type Inverter, type LightSwitch, MECHANICAL_DEFAULTS, MEMBER_CAGE, type MechanicalFloorOptions, type Opening, type Outbuilding, type OutbuildingItem, type OutbuildingOpening, type OutbuildingWall, type OutdoorLamp, type Outlet, PILE_AREA, PILE_DEFAULTS, PLATE_DEFAULTS, PUNCHED_DEFAULTS, type PartRole, type PileDesign, type PlanContext, type PlateOptions, type PlateRect, type PlateStrip, type Plumbing, type PlumbingPoint, type PlumbingRun, type Point3, type PunchedFacadeOptions, RAFT_THICKNESS, REBAR_RATIOS, ROOF_COVERINGS, type Rect, type Roof, type RoofCoveringDef, type RoofPane, type RoofShape, SKYSCRAPER_DEFAULTS, SKYSCRAPER_MAX_STOREYS, SLAB_PANEL_DEFAULTS, type ServiceEntrance, type ShackOptions, type SkyscraperLayout, type SkyscraperOptions, type SkyscraperPreset, type SlabPanelOptions, type Solar, type SolarPanel, type SourceDoor, type SourceWall, type SourceWindow, type StoreyContext, type StoreyKind, type StripFill, type StripFiller, type StripId, type Structure, type StructureExtras, type StructureOptions, type StructurePackOptions, type StructurePart, type StructureSource, type Support, TOWER_DEFAULTS, type TankPlanOptions, type TankPlatform, type Tent, type TowerGeometry, type TowerMechanicalOptions, type TowerOptions, type TowerPlanOptions, type TowerPlate, type Utilities, type WallDetail, type WallFixture, type WallMaterials, type WallSpecimenOptions, type WaterTank, type WoodFrameOptions, addCore, addCurtainWall, addFlatRoof, addMechanicalFloor, addPunchedFacade, addTunedMassDamper, applySlabPanels, beamDepthFor, beamSpan, buildSkyscraper, buildStructure, buildTower, buildWallSpecimen, campConstruction, chaletConstruction, constructionOfSystem, coreSize, damperMass, exteriorWindows, logCabinConstruction, masonryConstruction, mechanicalStoreys, pilesFor, planToSpace, planWaterTank, register, registerConstruction, registerConstructionSystem, registerRoofCovering, resolveSlabPanels, shackConstruction, skyscraperLayout, slabPanelView, slabPanelsOf, splitStrip, storeyKinds, stripDoor, structureLayer, toDestructibleSpec, towerFloors, towerLocales, towerPlate, towerWater, version, windExposureOf, woodFrameConstruction };
1584
+ export { BEAM_DEPTH_RATIO, CONSTRUCTIONS, CONSTRUCTION_SYSTEMS, CORE_DEFAULTS, CURTAIN_DEFAULTS, type ChaletOptions, type Chimney, type Circuit, type Conduit, type Construction, type ConstructionBuild, type ConstructionBuilder, type ConstructionSystem, type ConstructionSystemDef, type CoreOptions, type CurtainWallOptions, DAMPER_DEFAULTS, DENSITY, type DamperOptions, type DestructibleSpecOptions, type ElectricMeter, type Electrical, type ElectricalPanel, type EnergyConfig, type EnergyMode, FLAT_ROOF_DEFAULTS, type FlatRoofOptions, type FoundationType, GROUND, GROUND_BEAM_DEPTH, type Gas, type GasMeter, type Inverter, type LightSwitch, MAX_LINTEL_ON_MASONRY, MAX_PILLAR_SPACING, MECHANICAL_DEFAULTS, MEMBER_CAGE, MIN_BEAM_WIDTH, MIN_PILLAR_AREA, MIN_PILLAR_SIDE, type MechanicalFloorOptions, type Opening, type Outbuilding, type OutbuildingItem, type OutbuildingOpening, type OutbuildingWall, type OutdoorLamp, type Outlet, PILE_AREA, PILE_DEFAULTS, PLATE_DEFAULTS, PUNCHED_DEFAULTS, type PartRole, type PileDesign, type PlanContext, type PlanStructure, type PlateOptions, type PlateRect, type PlateStrip, type Plumbing, type PlumbingPoint, type PlumbingRun, type Point3, type PunchedFacadeOptions, RAFT_THICKNESS, REBAR_RATIOS, ROOF_COVERINGS, type Rect, type Roof, type RoofCoveringDef, type RoofPane, type RoofShape, SILL_BEAM_DEPTH, SKYSCRAPER_DEFAULTS, SKYSCRAPER_MAX_STOREYS, SLAB_PANEL_DEFAULTS, STRUCTURAL_VIOLATION, type ServiceEntrance, type ShackOptions, type SkyscraperLayout, type SkyscraperOptions, type SkyscraperPreset, type SlabPanelOptions, type Solar, type SolarPanel, type SourceDoor, type SourceWall, type SourceWindow, type StoreyContext, type StoreyKind, type StripFill, type StripFiller, type StripId, type StructuralViolation, type StructuralViolationCode, type Structure, type StructureExtras, type StructureOptions, type StructurePackOptions, type StructurePart, type StructureSource, type StructuredResult, type Support, TANK_PILLAR_SIDE, TOWER_DEFAULTS, type TankPlanOptions, type TankPlatform, type Tent, type TowerGeometry, type TowerMechanicalOptions, type TowerOptions, type TowerPlanOptions, type TowerPlate, type Utilities, type ValidateStructureOptions, WALL_PILLAR_SIDE, WALL_PILLAR_SPACING, type WallDetail, type WallFixture, type WallMaterials, type WallSpecimenOptions, type WaterTank, type WoodFrameOptions, addCore, addCurtainWall, addFlatRoof, addMechanicalFloor, addPunchedFacade, addTunedMassDamper, applySlabPanels, beamDepthFor, beamSpan, buildSkyscraper, buildStructure, buildTower, buildWallSpecimen, cageResidualCapacity, campConstruction, chaletConstruction, constructionOfSystem, coreSize, countViolations, damperMass, exteriorWindows, logCabinConstruction, masonryConstruction, mechanicalStoreys, pilesFor, pillarStations, planToSpace, planWaterTank, register, registerConstruction, registerConstructionSystem, registerRoofCovering, resolveSlabPanels, shackConstruction, skyscraperLayout, slabPanelView, slabPanelsOf, splitStrip, storeyKinds, stripDoor, structureLayer, toDestructibleSpec, towerFloors, towerLocales, towerPlate, towerWater, validateSpec, validateStructure, version, windExposureOf, woodFrameConstruction };