Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Floorplan Syntax: A Declarative Way to Define Room Layouts #6134

Open
Grovkillen opened this issue Dec 15, 2024 · 1 comment
Open

Add Floorplan Syntax: A Declarative Way to Define Room Layouts #6134

Grovkillen opened this issue Dec 15, 2024 · 1 comment
Labels
Status: Triage Needs to be verified, categorized, etc Type: Enhancement New feature or request

Comments

@Grovkillen
Copy link

Grovkillen commented Dec 15, 2024

Proposal

Mermaid.js should add Floorplan Syntax, a declarative way to define architectural layouts such as room-based floor plans. This syntax would enable users to quickly and visually design rooms, hallways, and multi-level spaces in a structured format.

Floorplan syntax supports:
Room Placement: Define rooms using dimensions, coordinates, and walls.
Sub-Rooms: Allow smaller rooms (e.g., closets, toilets) within a parent room.
Connections: Doors and windows can be placed precisely on walls, using percentage-based placement.
Hierarchies: Support multiple levels with nested sub-rooms and hallways.
Automatic Door Behavior: Doors swing into the largest of two connected rooms unless explicitly stated. Swing to closest wall if nothing is stated.
With this addition, Mermaid.js expands its usefulness into architecture, interior design, and even game development for mapping spaces.

Why Add Floorplan Syntax?
Mermaid.js currently lacks tools for architectural diagrams. Adding floorplan capabilities fills a new niche.
Syntax is simple, intuitive, and follows Mermaid.js' declarative principles.
Many industries (real estate, design, construction) use diagrams like floorplans, and this would open Mermaid.js to a wider audience.

Example

floorplan
    floor 1 {
        room MasterBathroom at (0,0) size (15x8) walls [top: solid, right: solid, bottom: door, left: solid] label "Master Bathroom" composed of [
        	sub-room Toilet1 at (10,0) size (5x3) walls [top: solid, right: door, bottom: solid, left: solid] label "Toilet"
        ]

        room MasterBedroom at (0,8) size (15x11) walls [top: door, right: solid, bottom: door, left: door] label "Master Bedroom"

        room KitchenDining at (0,30) size (18x21) walls [top: door, right: solid, bottom: open, left: solid] label "Kitchen / Dining"

        room Bedroom3 at (48,0) size (12x16) walls [top: window, right: solid, bottom: door, left: solid] label "Bedroom #3"
		
        room Hall2 at (12,38) size (16x5) walls [top: door, right: solid, bottom: door, left: door] composed of [
		sub-room Bathroom3 at (0,4) size (5x12) walls [top: solid, right: solid, bottom: solid, left: door] composed of [
			sub-room Closet1 at (0,0) size (2x6) walls [top: open, right: solid, bottom: solid, left: solid]
			sub-room Toilet2 at (0,6) size (2x6) walls [top: solid, right: solid, bottom: door, left: solid]
		]
        ]

        room WalkInCloset at (15,0) size (7x8) walls [top: door, right: solid, bottom: solid, left: solid] label "Walk-In Closet"
		
        room Hall at (15,8) size (9x11) walls [top: door, right: door, bottom: solid, left: door] composed of [
        	sub-room Bathroom1 at (0,0) size (7x5) walls [top: solid, right: door, bottom: solid, left: solid] label "Bathroom"
        ]

        room LivingRoom at (15,30) size (20x21) walls [top: open, right: door, bottom: door, left: door] label "Living Room"

        room Bedroom2 at (17,38) size (16x16) walls [top: door, right: solid, bottom: solid, left: solid] label "Bedroom #2" composed of [
		sub-room Closet2 at (0,4) size (1.5x12) walls [top: solid, right: solid, bottom: open, left: solid]
	]

        room Laundry at (22,0) size (12x9) walls [top: solid, right: door, bottom: solid, left: door] label "Laundry" composed of [
		sub-room Boiler at (10,0) size (2x4) walls [top: solid, right: open, bottom: solid, left: solid]
	]
        
        room OfficeBedroom at (12,19) size (12x11) walls [left: door, right: solid, bottom: solid, top: solid] label "Office / Bedroom"

        room Porch at (40,30) size (6x21) walls [top: door, right: open, bottom: open, left: open] label "Porch"
    }

    # Doors and connections
	connect MasterBathroom.right to MasterBedroom.left door at 0% opens into MasterBathroom
	connect MasterBathroom.right to Toilet1.right door at 100% opens into Toilet1 swing: right
	connect MasterBathroom.bottom to WalkInCloset.top door opens into WalkInCloset
	connect MasterBedroom.bottom to Hall.top door at 100%
	connect Bedroom3.bottom to Hall2.top door at 0%
	connect Bedroom2.top to Hall2.bottom door at 0%
	connect Hall2 to Bathroom3.left door at 0%
	connect Bathroom3 to Toilet2.bottom door at 0% door opens into Toilet2
	connect Hall.left to Laundry.right door
	connect Hall.bottom to OfficeBedroom door at 100%
	connect Laundry.left to outside door at 0%
	connect MasterBedroom.top to outside double-door at 100%
	connect KitchenDining.top to outside double-door at 90%

Screenshots

Simple_example

@Grovkillen Grovkillen added Status: Triage Needs to be verified, categorized, etc Type: Enhancement New feature or request labels Dec 15, 2024
@Grovkillen
Copy link
Author

Grovkillen commented Dec 15, 2024

Floorplan Syntax Proposal for Mermaid.js

Overview

The Floorplan Syntax allows users to create architectural layouts in a declarative and intuitive way. It is designed for use cases like floor plans, interior design, event planning, and game maps. This syntax builds on the following principles:

  • The coordinate system starts from the top-left corner (height offset = 0, width offset = 0), aligning with browser standards.
  • All dimensions and offsets are unitless integers, but decimals are allowed for increased precision when necessary.
  • If walls is not specified for a room, all walls default to solid.
  • Sub-rooms are positioned relative to their parent room's origin point (top-left corner).
  • If a wall contains multiple elements (e.g., doors, windows), they are automatically spaced evenly along the wall unless otherwise specified.
  • Overlapping elements on a wall will render with windows positioned beneath doors as the default graphical layer.
  • Shared walls between multiple rooms will prioritize visible rendering of elements (e.g., sliding doors) to ensure they appear in the final diagram.
  • Outer walls are rendered with a thickness of 125% compared to inner walls.
  • Rooms cannot be named "outside", as this name is reserved to describe everything outside the "house."
  • The use of "top, right, bottom, left" for walls is directly inspired by the HTML standard for defining box models.
  • The syntax is not intended to handle overly complex geometries. Instead, it focuses on systematically describing relatively common layouts, making it particularly suitable for AI-generated floorplans.
  • Generated floorplans are not intended to replace real architectural plans. Instead, they are designed to transfer knowledge about the general characteristics of a layout in text form. This is essential for enabling AI to describe its concepts of floorplans. Since current image generation cannot achieve this, saving the information in standardized text is also desirable for further data refinement.
  • Furniture or interior details are not included in this proposal. These considerations could be addressed in a future iteration if this proposal is implemented.

Syntax Features

Room Definition

room [name] at ([height offset],[width offset]) size ([height]x[width]) walls [properties] label "[Room Name]"

Default Behavior:

  1. If walls is omitted, all walls are set to solid.
  2. Walls not explicitly defined default to solid.

Example:

room MasterBedroom at (0,0) size (11x15) walls [top: solid, right: solid, bottom: door, left: solid] label "Master Bedroom"

Simplified to:

room MasterBedroom at (0,0) size (11x15) walls [bottom: door] label "Master Bedroom"

Walls with Multiple Elements

Walls can include multiple elements (e.g., doors and windows) which are either positioned explicitly or automatically spaced evenly.

Explicit Positioning

walls [top: door at 25%, window at 50%, door at 75%]
  • A door is placed at 25%, a window at 50%, and another door at 75% along the wall.

Automatic Spacing

walls [top: door, window, door]
  • The elements are evenly spaced along the wall if no positions are specified.

Example:

room LivingRoom at (0,15) size (15x20) walls [bottom: door at 20%, window at 50%, door at 80%] label "Living Room"
  • The bottom wall of the living room has:
    • A door at 20%.
    • A window at 50%.
    • A door at 80%.

Overlapping Elements

If multiple elements overlap (e.g., a door and a window both at 50%), the window will render beneath the door by default.

Placement Preferences

  • Horizontal walls: Placements are measured from left (0%) to right (100%).
  • Vertical walls: Placements are measured from top (0%) to bottom (100%).

Walls with Auto-Placement (auto-door)

When defining walls, the keyword auto-door can be used to indicate that a door should be placed in the only remaining gap along a wall.

Syntax:

walls [top: door, right: solid, bottom: auto-door, left: door]
  • auto-door is used when the exact placement of the door is not specified.
  • The system automatically calculates the only possible location for the door based on other defined segments.

Example:

room Hall2 at (12,38) size (16x5) walls [top: door, right: solid, bottom: auto-door, left: door] composed of [
    sub-room Bathroom3 at (0,4) size (5x12) walls [top: solid, right: solid, bottom: solid, left: door] composed of [
        sub-room Closet1 at (0,0) size (2x6) walls [top: open, right: solid, bottom: solid, left: solid]
        sub-room Toilet2 at (0,6) size (2x6) walls [top: solid, right: solid, bottom: door, left: solid]
    ]
]
  • In this example, the auto-door on the bottom wall of Hall2 is placed in the only available gap.

Algorithm for auto-door Placement in JavaScript

function calculateAutoDoor(totalLength, definedSegments) {
    // Sort segments by start point
    definedSegments.sort((a, b) => a.start - b.start);
    
    // Calculate gaps
    const gaps = [];
    let currentStart = 0;
    for (const segment of definedSegments) {
        if (segment.start > currentStart) {
            gaps.push({ start: currentStart, end: segment.start });
        }
        currentStart = segment.end;
    }
    
    // Check for remaining gap at the end
    if (currentStart < totalLength) {
        gaps.push({ start: currentStart, end: totalLength });
    }
    
    // Return the remaining gap
    if (gaps.length === 1) {
        return gaps[0];
    } else if (gaps.length === 0) {
        throw new Error("No space left for auto-door.");
    } else {
        throw new Error("Multiple spaces available; specify manually.");
    }
}

Handling Multiple Doors to Adjacent Rooms

When defining walls with multiple doors connecting to the same or different adjacent rooms, the following default behaviors apply:

Default Placement Rules:

  1. Even Spacing by Default:

    • Doors will be automatically spaced evenly along the wall if no specific positions are provided.
  2. Multiple Doors to the Same Room:

    • If two or more doors connect to the same room, they will be placed as far apart as possible along the wall.
  3. Overlap Handling:

    • If user-defined positions lead to overlapping doors, an error will be raised, prompting adjustments.
  4. Explicit Placement:

    • Users can override default behavior by specifying exact positions for each door.

Syntax for Multiple Doors:

walls [top: door, door]
connect [current room].[wall] to [adjacent room].[wall] door

Example with Multiple Doors:

room Hall at (10,10) size (10x10) walls [bottom: door, door] label "Hall"

connect Hall.bottom to Bathroom.top door at 30% opens into Bathroom
connect Hall.bottom to LivingRoom.top door at 70% opens into Hall
  • Door at 30% connects Hall to Bathroom.
  • Door at 70% connects Hall to Living Room.

Default Example Without Explicit Placement:

room Hall2 at (12,38) size (16x5) walls [bottom: door, door] label "Hall2"

connect Hall2.bottom to Bathroom.top door
connect Hall2.bottom to Bathroom.top door
  • Two doors connecting Hall2 to Bathroom will be spaced as far apart as possible along the bottom wall.

Algorithm for Default Placement in JavaScript:

function calculateDoorPositions(wallLength, doorCount) {
    if (doorCount < 1) throw new Error("No doors to place.");
    
    const positions = [];
    const step = wallLength / (doorCount + 1);

    for (let i = 1; i <= doorCount; i++) {
        positions.push(i * step);
    }

    return positions;
}

Example Usage:

const positions = calculateDoorPositions(100, 2); // [33.33, 66.66]
console.log(positions); // Two doors placed evenly

Element Width

To specify the width of doors, windows, and openings, the width parameter can be added to each element in percentage terms.

Default Behavior:

  1. If width is not specified, standard values are used:
    • 1 unit for doors.
    • 1.5 units for windows.
  2. The width parameter must range from 1% to 100% of the wall length.
  3. Overlapping elements will raise an error.

Syntax:

door at [position%] width [width%]
window at [position%] width [width%]
opening at [position%] width [width%]

Example:

walls [top: door at 25% width 10%, window at 50% width 20%, door at 75% width 15%]

Example without width specification:

walls [top: door at 25%, window at 50%]
  • The door at 25% uses the default width of 1 unit.
  • The window at 50% uses the default width of 1.5 units.

Part Walls

A part wall represents a segment of a wall that extends partway into the room. This is useful for creating alcoves, dividing spaces, or architectural features.

Syntax:

part wall ([start%], [end%])
  • start%: The starting point of the wall segment from the left or top of the parent wall.
  • end%: The ending point of the wall segment from the right or bottom of the parent wall.

Example:

walls [left: part wall (0%, 50%), right: part wall (100%, 50%)]
  • A wall segment starts at 0% and ends at 50% on the left wall.
  • A wall segment starts at 100% and extends back to 50% on the right wall.

Use Case Example:

room LivingRoom at (10,10) size (20x30) walls [top: solid, left: part wall (0%, 25%), bottom: part wall (75%, 100%)] label "Living Room"
  • A partial wall on the left wall spans from 0% to 25%.
  • A partial wall on the bottom wall spans from 75% to 100%.

Algorithm for Element Width Handling in JavaScript

function validateAndPlaceElementsWithWidth(wallLength, elements) {
    elements.sort((a, b) => a.position - b.position);

    for (let i = 0; i < elements.length - 1; i++) {
        const currentEnd = elements[i].position + elements[i].width;
        if (currentEnd > elements[i + 1].position) {
            throw new Error(`Elements overlap at position ${elements[i].position}`);
        }
    }

    return elements.map(element => ({
        position: element.position,
        width: element.width || 10, // Default width for doors
    }));
}

// Example usage
const wallLength = 100;
const elements = [
    { position: 25, width: 10 },
    { position: 50, width: 20 },
    { position: 75, width: 15 },
];

console.log(validateAndPlaceElementsWithWidth(wallLength, elements));

Floor Management

When multiple floors are described, they are divided using floor [n] where [n] can be:

  • Negative integers (e.g., basement levels).
  • Zero (ground level).
  • Positive integers (upper floors).

Example:

floor -1 { ... }  # Basement level
floor 0 { ... }   # Ground level
floor 1 { ... }   # First floor

Single-Floor Plans:

If only one floor is described, the floor keyword can be omitted.


Staircase Definition

Staircases connect different floors and specify their size, position, and direction.

Syntax:

staircase at ([height offset], [width offset]) size ([height]x[width]) connects floor [origin_floor] to floor [destination_floor] direction [up|down] [optional width]

Parameters:

  1. Position and Size:
    • at: Specifies the starting point of the staircase on the origin floor.
    • size: Dimensions (height x width) of the staircase.
  2. Floor Connection:
    • connects floor [origin_floor] to floor [destination_floor]: Specifies the floors the staircase connects.
  3. Direction:
    • direction: Specifies whether the staircase goes up or down.

Examples:

Example 1: Straight Staircase Between Two Floors

staircase at (5,10) size (4x10) connects floor 1 to floor 2 direction up

Example 2: Staircase Between Ground Floor and Basement

staircase at (8,20) size (3x8) connects floor 0 to floor -1 direction down

Example 3: Staircase with Specified Width

staircase at (10,15) size (5x12) connects floor 1 to floor 2 direction up width 6

Default Behavior:

If width is not explicitly specified, a standard width is used (e.g., 125% of the door's size).


Proposed Default Widths for Elements

To maintain consistency and proportionality in the floorplan syntax, the following default widths are proposed for elements:

Doors: Default width = 1 unit.

Windows: Default width = 150% of a door's width (i.e., 1.5 units).

Staircases: Default width = 125% of a door's width (i.e., 1.25 units).

Rationale:

These proportions ensure visual and functional consistency across floorplans.
Doors serve as the baseline measurement for all other elements.
Windows are slightly wider than doors to reflect their typical architectural design.
Staircases are narrower than windows but slightly wider than doors for practical usability.


Complex Staircase Examples

The floorplan syntax supports the definition of L-shaped, U-shaped, and C-shaped (spiral) staircases. These shapes can be described using the size and radius parameters to define multiple segments or circular paths.


L-Shaped Staircase

staircase LShape at (10,10) size (5x5, 5x10) connects floor 1 to floor 2 direction up
  • Description:
    • The staircase begins with a straight section of 5x5 units.
    • Turns 90 degrees into another section of 5x10 units.
    • Connects floor 1 to floor 2.

U-Shaped Staircase

staircase UShape at (15,15) size (5x10, 5x10) connects floor 0 to floor 1 direction up
  • Description:
    • The staircase has two parallel straight sections of 5x10 units each.
    • Includes a 180-degree turn between the sections.
    • Connects floor 0 to floor 1.

C-Shaped (Spiral) Staircase

staircase Spiral at (20,20) radius 5 connects floor -1 to floor 0 direction up
  • Description:
    • The staircase is circular with a radius of 5 units.
    • Represents a spiral staircase connecting floor -1 to floor 0.

Parameters for Complex Staircases

  1. size:

    • Can take multiple segments (e.g., size (5x5, 5x10)) to define complex shapes.
  2. radius:

    • Used exclusively for circular or spiral staircases, defining the radius of the staircase.
  3. Default Width:

    • Each segment defaults to 125% of a door's width unless explicitly specified.

Key Features Summary:

  1. Top-Left Origin: The coordinate system starts at the top-left corner, following browser conventions.
  2. Flexible Dimensions: Unitless integers for offsets and sizes, with optional decimals.
  3. Part Walls: Allows custom wall segments for more precise layouts.
  4. Door Behavior: Automatic placement and swing logic for simplicity.
  5. Wall Elements: Multiple doors or windows can be explicitly positioned or automatically spaced.
  6. auto-door: Automatically calculates the only valid gap for a door if no manual position is specified.
  7. Shared Walls: Visible elements on shared walls are prioritized in rendering.
  8. Outer Walls: Outer walls are 125% thicker than inner walls.
  9. Room Naming: Rooms cannot be named "outside," as this name is reserved to describe everything outside the "house."
  10. Text-Based Transfer: Designed to transfer knowledge about general floorplan characteristics in text form, essential for AI and further data refinement.
  11. HTML Standard: The use of "top, right, bottom, left" is directly inspired by the HTML box model.
  12. Scope: The syntax is designed to handle relatively common layouts systematically, making it suitable for AI-generated floorplans.
  13. Future Considerations: Furniture and interior details are not included but could be addressed in future iterations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Triage Needs to be verified, categorized, etc Type: Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant