Meta Description" name="description" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>CAD Style Floor Plan - 3 Bed, 3 Bath, Rectangular House</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #e6e9ef; /* subtle grey background for contrast, like drafting paper */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: 'Segoe UI', 'Roboto', 'Consolas', 'Monaco', 'Courier New', monospace;
padding: 24px;
}
.cad-container {
background: white;
box-shadow: 0 12px 28px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.02);
display: inline-block;
border: 1px solid #ccc;
}
canvas {
display: block;
width: auto;
height: auto;
background: white;
cursor: crosshair;
}
/* technical info - optional mini legend, but not intrusive */
.note {
text-align: center;
margin-top: 12px;
font-size: 11px;
font-family: monospace;
color: #4a5568;
letter-spacing: 0.3px;
background: white;
display: inline-block;
width: 100%;
padding: 6px 0;
}
</style>
</head>
<body>
<div style="text-align: center;">
<div class="cad-container">
<canvas id="floorPlanCanvas" width="1100" height="800" style="width:1100px; height:800px;"></canvas>
</div>
<div class="note">
⚙ TECHNICAL DRAWING | WALLS: 0.35mm LINE | DOORS: ARC SWING (90°) | WINDOWS: STANDARD RECESS | NO FURNITURE / NO COLOR
</div>
</div>
<script>
(function() {
const canvas = document.getElementById('floorPlanCanvas');
const ctx = canvas.getContext('2d');
// Dimensions: rectangular house: overall width 1040px, height 720px (clean proportions)
// Margins: external walls start at (40,40) to (1080, 760) but canvas = 1100x800 => border air
// Outer wall envelope: left=60, right=1040, top=50, bottom=770 => width 980, height 720 (rectangular)
const leftWallX = 60;
const rightWallX = 1040; // 1040-60 = 980 width
const topWallY = 50;
const bottomWallY = 770; // 770-50 = 720 height
// Central hallway dimensions (spine that runs vertically, connecting zones)
// Hallway width: 100px, starts at X = 480, ends at X = 580 (centered but adjusted for room distribution)
const hallLeft = 480;
const hallRight = 580;
const hallWidth = hallRight - hallLeft; // 100px
// --- ROOM ZONES (based on rectangular layout, all align to grid) ---
// Upper Zone (North): Bedroom 1 (master) + ensuite + walk-in/window layout
// Bedroom 1 spans from leftWallX to hallLeft, and from topWallY to Y = 290
const masterTop = topWallY;
const masterBottom = 290;
const masterLeft = leftWallX;
const masterRight = hallLeft;
// Master Bathroom (ensuite) attached to Bedroom 1, on the right side of bedroom but within master zone? Actually better: ensuite sits between master and hallway?
// For clean circulation: Master Bedroom has private bathroom (ensuite) located at the top-right corner of bedroom zone, accessed from bedroom.
// To keep hallway clear: Ensuite dimensions: width 100px, height 120px, placed at north-east part of master zone adjacent to hallway.
// Ensuite location: X = hallLeft - 100? That would overlap master. Better: ensuite inside master footprint, near hallway.
// Define ensuite: X = masterRight - 100 = 480-100=380, Y = masterTop+20, width=100, height=120.
const ensLeft = masterRight - 100; // 380
const ensRight = masterRight; // 480
const ensTop = masterTop + 30; // 80
const ensBottom = ensTop + 120; // 200
// Bedroom 2 (Middle left side) - below master, adjacent to hallway left side.
const bed2Top = masterBottom; // 290
const bed2Bottom = 520;
const bed2Left = leftWallX;
const bed2Right = hallLeft; // 480
// Bathroom 2 (shared or Jack-and-Jill style) placed near bedroom 2 and hallway access, located at bottom-left corner of Bedroom2 zone?
// To keep adjacency, create bathroom for bedroom2 and general use: placed at left side bottom part of Bedroom 2 or separate.
// For technical clarity: Bathroom2 located along left wall, dimensions 100x120, within bedroom2 region but separated by door.
const bath2Left = leftWallX;
const bath2Right = leftWallX + 100;
const bath2Top = bed2Bottom - 130; // 390 (520-130=390)
const bath2Bottom = bed2Bottom; // 520
// Bedroom 3 (bottom left zone) - under bedroom2, left of hallway lower portion
const bed3Top = bed2Bottom; // 520
const bed3Bottom = bottomWallY; // 770
const bed3Left = leftWallX;
const bed3Right = hallLeft; // 480
// Bathroom 3 (full bath) placed on the left side of Bedroom3 area, similar style.
const bath3Left = leftWallX;
const bath3Right = leftWallX + 100;
const bath3Top = bed3Bottom - 120; // 650 (770-120=650)
const bath3Bottom = bed3Bottom; // 770
// ---- RIGHT SIDE (west to east) : Living Room, Dining, Kitchen ----
// Living Room: top right corner, from hallRight to rightWallX, from topWallY to Y=340
const livingTop = topWallY;
const livingBottom = 340;
const livingLeft = hallRight; // 580
const livingRight = rightWallX; // 1040
// Dining Area: adjacent below living room, from livingBottom to Y=490, same left/right bounds
const diningTop = livingBottom; // 340
const diningBottom = 490;
const diningLeft = hallRight;
const diningRight = rightWallX;
// Kitchen: below dining area, extends to bottomWallY, but we also need to respect hallway continuation.
const kitchenTop = diningBottom; // 490
const kitchenBottom = bottomWallY; // 770
const kitchenLeft = hallRight;
const kitchenRight = rightWallX;
// Additional hallway extension (central corridor runs from topWallY to bottomWallY, between hallLeft/hallRight)
const hallTop = topWallY;
const hallBottom = bottomWallY;
// ---- Window & Door Definitions (standard architectural symbols) ----
// Walls are black lines 1.8px (CAD heavy line). Doors represented as arcs (quarter circle) + door slab line.
// Windows represented as thin parallel lines within wall thickness representation (simple double lines).
// Helper: draw wall (thick black line)
function drawWall(x1, y1, x2, y2, lineWidth = 1.8) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = "#000000";
ctx.stroke();
}
// Helper: draw door (arc swing) given wall line segment and orientation, door width, opening side.
// For simplicity: we create door symbol as an arc from hinge point to 90deg open.
// parameters: hingeX, hingeY, direction 'right'/'down'/'left'/'up' and doorWidth (standard 30px)
// also optionally radius = doorWidth.
function drawDoorArc(hingeX, hingeY, direction, doorWidth = 32) {
ctx.beginPath();
ctx.lineWidth = 1.2;
ctx.strokeStyle = "#000000";
let startAngle, endAngle, centerX, centerY, radius = doorWidth;
// draw the door panel as a line from hinge to arc endpoint? Standard representation: arc and a short line.
if (direction === 'right') {
// hinge on left, door swings to right (opening inward/outward typical)
centerX = hingeX;
centerY = hingeY;
startAngle = -Math.PI / 2;
endAngle = 0;
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
// draw door line from hinge to arc endpoint
let endX = hingeX + radius;
let endY = hingeY;
drawWall(hingeX, hingeY, endX, endY, 1.2);
} else if (direction === 'down') {
centerX = hingeX;
centerY = hingeY;
startAngle = 0;
endAngle = Math.PI / 2;
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
let endX = hingeX;
let endY = hingeY + radius;
drawWall(hingeX, hingeY, endX, endY, 1.2);
} else if (direction === 'left') {
centerX = hingeX;
centerY = hingeY;
startAngle = Math.PI / 2;
endAngle = Math.PI;
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
let endX = hingeX - radius;
let endY = hingeY;
drawWall(hingeX, hingeY, endX, endY, 1.2);
} else if (direction === 'up') {
centerX = hingeX;
centerY = hingeY;
startAngle = -Math.PI;
endAngle = -Math.PI / 2;
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
let endX = hingeX;
let endY = hingeY - radius;
drawWall(hingeX, hingeY, endX, endY, 1.2);
}
}
// Draw simple door representation (two lines: arc + panel). We'll also use a standard door jamb.
function drawDoorWithJamb(x1, y1, x2, y2, swingDir) {
// For simplicity: determine midpoint or hinge based on door opening side.
let midX = (x1 + x2) / 2;
let midY = (y1 + y2) / 2;
let dx = x2 - x1;
let dy = y2 - y1;
let length = Math.hypot(dx, dy);
// hinge is at start point (x1,y1) typically the side where door attaches.
// swingDir can be 'inward' relative to room.
// but easier: choose hinge at (x1,y1), direction based on wall orientation.
if (Math.abs(dx) > Math.abs(dy)) { // horizontal wall
if (x2 > x1) { // wall from left to right
if (swingDir === 'down') drawDoorArc(x1, y1, 'down', 32);
else drawDoorArc(x1, y1, 'up', 32);
} else { // right to left
if (swingDir === 'down') drawDoorArc(x1, y1, 'down', 32);
else drawDoorArc(x1, y1, 'up', 32);
}
} else { // vertical wall
if (y2 > y1) { // downward vertical
if (swingDir === 'right') drawDoorArc(x1, y1, 'right', 32);
else drawDoorArc(x1, y1, 'left', 32);
} else { // upward vertical
if (swingDir === 'right') drawDoorArc(x1, y1, 'right', 32);
else drawDoorArc(x1, y1, 'left', 32);
}
}
}
// Simplified door on a specific wall segment: we provide precise hinge coordinate and direction.
function drawDoorAt(hingeX, hingeY, orientation, doorWidth = 32) {
drawDoorArc(hingeX, hingeY, orientation, doorWidth);
}
// Window: double lines within wall thickness (3px gap) parallel to wall.
function drawWindow(x1, y1, x2, y2) {
ctx.save();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
let dx = x2 - x1;
let dy = y2 - y1;
let len = Math.hypot(dx, dy);
let angle = Math.atan2(dy, dx);
let perpX = -Math.sin(angle) * 6;
let perpY = Math.cos(angle) * 6;
let midX = (x1 + x2)/2;
let midY = (y1 + y2)/2;
let startOffsetX = -Math.cos(angle) * (len/2 - 20);
let startOffsetY = -Math.sin(angle) * (len/2 - 20);
let windowStartX = midX + startOffsetX;
let windowStartY = midY + startOffsetY;
let windowEndX = midX - startOffsetX;
let windowEndY = midY - startOffsetY;
ctx.beginPath();
ctx.moveTo(windowStartX + perpX, windowStartY + perpY);
ctx.lineTo(windowEndX + perpX, windowEndY + perpY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(windowStartX - perpX, windowStartY - perpY);
ctx.lineTo(windowEndX - perpX, windowEndY - perpY);
ctx.stroke();
// draw small perpendicular ticks at ends (optional)
ctx.beginPath();
ctx.moveTo(windowStartX + perpX, windowStartY + perpY);
ctx.lineTo(windowStartX - perpX, windowStartY - perpY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(windowEndX + perpX, windowEndY + perpY);
ctx.lineTo(windowEndX - perpX, windowEndY - perpY);
ctx.stroke();
ctx.restore();
}
// Helper to label rooms: black text, sans-serif technical style.
function labelRoom(text, x, y, fontSize = 12) {
ctx.font = `500 ${fontSize}px 'Segoe UI', 'Consolas', monospace`;
ctx.fillStyle = "#000000";
ctx.shadowBlur = 0;
ctx.fillText(text, x, y);
}
// draw all external and internal walls.
function drawWalls() {
// outer perimeter
drawWall(leftWallX, topWallY, rightWallX, topWallY, 2.0);
drawWall(rightWallX, topWallY, rightWallX, bottomWallY, 2.0);
drawWall(rightWallX, bottomWallY, leftWallX, bottomWallY, 2.0);
drawWall(leftWallX, bottomWallY, leftWallX, topWallY, 2.0);
// hallway vertical walls (central spine)
drawWall(hallLeft, hallTop, hallLeft, hallBottom, 1.8);
drawWall(hallRight, hallTop, hallRight, hallBottom, 1.8);
// horizontal internal dividers
// master / bedroom 2 separator
drawWall(leftWallX, masterBottom, hallLeft, masterBottom, 1.8);
// living/dining divider
drawWall(hallRight, livingBottom, rightWallX, livingBottom, 1.8);
// dining/kitchen divider
drawWall(hallRight, diningBottom, rightWallX, diningBottom, 1.8);
// bedroom2 / bedroom3 divider
drawWall(leftWallX, bed2Bottom, hallLeft, bed2Bottom, 1.8);
// ensuite internal walls (three sides)
drawWall(ensLeft, ensTop, ensRight, ensTop, 1.6);
drawWall(ensLeft, ensTop, ensLeft, ensBottom, 1.6);
drawWall(ensRight, ensTop, ensRight, ensBottom, 1.6);
// bathroom2 walls
drawWall(bath2Left, bath2Top, bath2Right, bath2Top, 1.6);
drawWall(bath2Left, bath2Top, bath2Left, bath2Bottom, 1.6);
drawWall(bath2Right, bath2Top, bath2Right, bath2Bottom, 1.6);
// bathroom3 walls
drawWall(bath3Left, bath3Top, bath3Right, bath3Top, 1.6);
drawWall(bath3Left, bath3Top, bath3Left, bath3Bottom, 1.6);
drawWall(bath3Right, bath3Top, bath3Right, bath3Bottom, 1.6);
}
// insert doors
function drawDoors() {
// 1. Master Bedroom entry from hallway: vertical wall at hallLeft, Y range 180-220, door centered ~200.
drawDoorAt(hallLeft, 200, 'left', 32); // hinge on hallway side swings into master
// 2. Ensuite door: from master bedroom into ensuite, on wall (ensRight, from Y=ensTop+40)
drawDoorAt(ensRight, ensTop+55, 'right', 32);
// 3. Bedroom 2 door from hallway: hinge at hallLeft, Y = 400
drawDoorAt(hallLeft, 410, 'left', 32);
// 4. Bathroom 2 door from bedroom2 area (on wall bath2Right, Y mid)
drawDoorAt(bath2Right, bath2Top+55, 'right', 32);
// 5. Bedroom 3 door from hallway: hinge at hallLeft, Y = 650
drawDoorAt(hallLeft, 660, 'left', 32);
// 6. Bathroom 3 door from bedroom3 area (on wall bath3Right, Y mid)
drawDoorAt(bath3Right, bath3Top+55, 'right', 32);
// 7. Living room entry from hallway: hinge at hallRight, Y=150 (swings into living)
drawDoorAt(hallRight, 150, 'right', 32);
// 8. Dining area entry from hallway: hinge at hallRight, Y=380
drawDoorAt(hallRight, 380, 'right', 32);
// 9. Kitchen entry from hallway: hinge at hallRight, Y=600
drawDoorAt(hallRight, 600, 'right', 32);
// 10. Optional: master bedroom door to exterior? but no, we have windows. For functionality, ensure back doors? but keep minimal.
// Additional door from kitchen to backyard? Not required but typical. omit.
}
// Windows: placed on external walls for each room (standard)
function drawWindows() {
// Master Bedroom: window on left wall (west) at Y 160-200
drawWindow(leftWallX, 160, leftWallX, 210);
// additional window on top wall? but top wall is for bedroom? yes, master north wall: coordinates topWallY, X 200-280
drawWindow(200, topWallY, 300, topWallY);
// Ensuite window on top wall small
drawWindow(ensLeft+20, topWallY, ensRight-20, topWallY);
// Bedroom2 window left wall: Y range 350-410
drawWindow(leftWallX, 350, leftWallX, 410);
// Bathroom2 window left wall (small)
drawWindow(leftWallX, bath2Top+35, leftWallX, bath2Top+80);
// Bedroom3 window left wall: Y range 590-650
drawWindow(leftWallX, 590, leftWallX, 650);
// Bathroom3 window left wall
drawWindow(leftWallX, bath3Top+35, leftWallX, bath3Top+80);
// Living room: window on right wall (east) and top wall
drawWindow(rightWallX, 120, rightWallX, 190);
drawWindow(880, topWallY, 980, topWallY);
// Dining area window on right wall: Y range 380-440
drawWindow(rightWallX, 380, rightWallX, 440);
// Kitchen window on right wall: Y range 580-650
drawWindow(rightWallX, 590, rightWallX, 660);
// Also kitchen window on bottom wall? optional but clean
drawWindow(800, bottomWallY, 920, bottomWallY);
}
// label all rooms with clear technical font
function drawLabels() {
ctx.font = "bold 13px 'Segoe UI', 'Consolas', monospace";
ctx.fillStyle = "#000000";
// Master Bedroom
labelRoom("MASTER BEDROOM", masterLeft+30, masterTop+60, 13);
labelRoom("EN-SUITE", ensLeft+12, ensTop+45, 11);
// Bedroom 2
labelRoom("BEDROOM 2", bed2Left+30, bed2Top+70, 13);
labelRoom("BATHROOM", bath2Left+12, bath2Top+50, 11);
// Bedroom 3
labelRoom("BEDROOM 3", bed3Left+30, bed3Top+70, 13);
labelRoom("BATHROOM", bath3Left+12, bath3Top+50, 11);
// Living
labelRoom("LIVING ROOM", livingLeft+70, livingTop+70, 13);
// Dining
labelRoom("DINING AREA", diningLeft+70, diningTop+45, 13);
// Kitchen
labelRoom("KITCHEN", kitchenLeft+70, kitchenTop+70, 13);
// Central Hallway
ctx.font = "italic 12px monospace";
labelRoom("HALLWAY", hallLeft+30, hallTop+360, 12);
}
// additional walls: ensure all room boundaries are clear
function drawMinorPartitions() {
// Wall separation between ensuite and master? Already existing but draw inside master to ensuite divider: vertical at ensRight, from ensTop to ensBottom is drawn, but master side needs separation line? already done.
// Ensure bathroom2 walls intersect properly.
drawWall(bath2Left, bath2Top, bath2Right, bath2Top, 1.6);
drawWall(bath2Left, bath2Bottom, bath2Right, bath2Bottom, 1.6);
// no extra clutter.
}
// add cased openings? just hallway boundaries are fine.
function drawAnnotations() {
ctx.save();
ctx.lineWidth = 0.8;
ctx.setLineDash([4, 6]);
// dimension indicators minimal? not necessary but adds technical style? maybe skip but keep clean.
ctx.setLineDash([]);
ctx.restore();
}
// draw all elements in order
function renderFloorPlan() {
// white background fill
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawWalls();
drawMinorPartitions();
drawDoors();
drawWindows();
drawLabels();
drawAnnotations();
// additional interior wall lines: e.g., bathroom2 entrance wall is already defined. ensure hallway open.
// no extra.
// Optional: draw door swing indicators (already arcs)
// add dimension markers to represent technical drawing? Not necessary but clean.
}
renderFloorPlan();
// Edge case: ensure all text is visible and no overlapping major.
// quick fix: adjust label positions for bathroom2 not overlapping door.
// manually override a couple labels after render? No, perfect.
})();
</script>
</body>
</html>1
1
22KB
22KB
113.0ms
132.0ms
113.0ms