@chanmeng666/archlang 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lexer.ts","../src/parser.ts","../src/geometry.ts","../src/validate.ts","../src/render.ts","../src/index.ts"],"sourcesContent":["/** Hand-written lexer for ArchLang. Zero dependencies; tracks line/col. */\n\nexport type TokenType =\n | \"ident\"\n | \"number\"\n | \"string\"\n | \"dimension\" // e.g. 4000x3000\n | \"lparen\"\n | \"rparen\"\n | \"lcurly\"\n | \"rcurly\"\n | \"comma\"\n | \"equals\"\n | \"colon\"\n | \"arrow\" // ->\n | \"eof\";\n\nexport interface Token {\n type: TokenType;\n value: string;\n /** For \"number\": the parsed value. For \"dimension\": w. */\n num?: number;\n /** For \"dimension\": h. */\n num2?: number;\n line: number;\n col: number;\n}\n\nexport interface LexResult {\n tokens: Token[];\n errors: { message: string; line: number; col: number }[];\n}\n\nconst isDigit = (c: string) => c >= \"0\" && c <= \"9\";\nconst isIdentStart = (c: string) =>\n (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\") || c === \"_\";\nconst isIdentPart = (c: string) => isIdentStart(c) || isDigit(c);\n\nexport function lex(src: string): LexResult {\n const tokens: Token[] = [];\n const errors: { message: string; line: number; col: number }[] = [];\n let i = 0;\n let line = 1;\n let col = 1;\n\n const peek = (o = 0) => src[i + o] ?? \"\";\n const advance = () => {\n const c = src[i++];\n if (c === \"\\n\") {\n line++;\n col = 1;\n } else {\n col++;\n }\n return c;\n };\n const push = (type: TokenType, value: string, startLine: number, startCol: number, extra?: Partial<Token>) =>\n tokens.push({ type, value, line: startLine, col: startCol, ...extra });\n\n while (i < src.length) {\n const c = peek();\n const startLine = line;\n const startCol = col;\n\n // Whitespace\n if (c === \" \" || c === \"\\t\" || c === \"\\r\" || c === \"\\n\") {\n advance();\n continue;\n }\n\n // Comment to end of line\n if (c === \"#\") {\n while (i < src.length && peek() !== \"\\n\") advance();\n continue;\n }\n\n // String literal with \\\" and \\\\ escapes\n if (c === '\"') {\n advance();\n let value = \"\";\n let terminated = false;\n while (i < src.length) {\n const ch = peek();\n if (ch === \"\\\\\") {\n advance();\n const esc = advance();\n value += esc === \"n\" ? \"\\n\" : esc;\n continue;\n }\n if (ch === '\"') {\n advance();\n terminated = true;\n break;\n }\n if (ch === \"\\n\") break; // strings don't span lines\n value += advance();\n }\n if (!terminated) {\n errors.push({ message: \"Unterminated string literal\", line: startLine, col: startCol });\n }\n push(\"string\", value, startLine, startCol);\n continue;\n }\n\n // Punctuation & operators\n if (c === \"(\") { advance(); push(\"lparen\", \"(\", startLine, startCol); continue; }\n if (c === \")\") { advance(); push(\"rparen\", \")\", startLine, startCol); continue; }\n if (c === \"{\") { advance(); push(\"lcurly\", \"{\", startLine, startCol); continue; }\n if (c === \"}\") { advance(); push(\"rcurly\", \"}\", startLine, startCol); continue; }\n if (c === \",\") { advance(); push(\"comma\", \",\", startLine, startCol); continue; }\n if (c === \"=\") { advance(); push(\"equals\", \"=\", startLine, startCol); continue; }\n if (c === \":\") { advance(); push(\"colon\", \":\", startLine, startCol); continue; }\n if (c === \"-\" && peek(1) === \">\") { advance(); advance(); push(\"arrow\", \"->\", startLine, startCol); continue; }\n\n // Number (optionally part of a dimension WxH)\n if (isDigit(c) || (c === \"-\" && isDigit(peek(1))) || (c === \".\" && isDigit(peek(1)))) {\n let raw = \"\";\n if (c === \"-\") raw += advance();\n while (isDigit(peek())) raw += advance();\n if (peek() === \".\") {\n raw += advance();\n while (isDigit(peek())) raw += advance();\n }\n const first = parseFloat(raw);\n // Dimension: <num>x<num>\n if (peek() === \"x\" && (isDigit(peek(1)) || (peek(1) === \"-\" && isDigit(peek(2))) || (peek(1) === \".\" && isDigit(peek(2))))) {\n advance(); // consume 'x'\n let raw2 = \"\";\n if (peek() === \"-\") raw2 += advance();\n while (isDigit(peek())) raw2 += advance();\n if (peek() === \".\") {\n raw2 += advance();\n while (isDigit(peek())) raw2 += advance();\n }\n const second = parseFloat(raw2);\n push(\"dimension\", `${raw}x${raw2}`, startLine, startCol, { num: first, num2: second });\n continue;\n }\n push(\"number\", raw, startLine, startCol, { num: first });\n continue;\n }\n\n // Identifier / keyword\n if (isIdentStart(c)) {\n let value = \"\";\n while (i < src.length && isIdentPart(peek())) value += advance();\n push(\"ident\", value, startLine, startCol);\n continue;\n }\n\n // Unknown character\n errors.push({ message: `Unexpected character ${JSON.stringify(c)}`, line: startLine, col: startCol });\n advance();\n }\n\n push(\"eof\", \"\", line, col);\n return { tokens, errors };\n}\n","/** Recursive-descent parser: tokens -> PlanNode. Zero dependencies. */\n\nimport type { Token } from \"./lexer.js\";\nimport { lex } from \"./lexer.js\";\nimport type {\n DimNode,\n DoorNode,\n FurnitureNode,\n NorthDir,\n PlanNode,\n Point,\n RoomNode,\n TitleNode,\n WallNode,\n WindowNode,\n} from \"./ast.js\";\n\nexport interface ParseOutcome {\n plan?: PlanNode;\n errors: { message: string; line: number; col: number }[];\n}\n\nclass ParseError extends Error {\n constructor(public override message: string, public line: number, public col: number) {\n super(message);\n }\n}\n\nexport function parse(src: string): ParseOutcome {\n const { tokens, errors: lexErrors } = lex(src);\n if (lexErrors.length > 0) {\n // Surface the first lexical error; it usually explains the rest.\n return { errors: [lexErrors[0]] };\n }\n try {\n const p = new Parser(tokens);\n const plan = p.parsePlan();\n return { plan, errors: [] };\n } catch (e) {\n if (e instanceof ParseError) {\n return { errors: [{ message: e.message, line: e.line, col: e.col }] };\n }\n throw e;\n }\n}\n\nclass Parser {\n private pos = 0;\n constructor(private toks: Token[]) {}\n\n private peek(o = 0): Token {\n return this.toks[Math.min(this.pos + o, this.toks.length - 1)];\n }\n private next(): Token {\n return this.toks[Math.min(this.pos++, this.toks.length - 1)];\n }\n private fail(msg: string, t = this.peek()): never {\n throw new ParseError(msg, t.line, t.col);\n }\n\n private isKeyword(kw: string, o = 0): boolean {\n const t = this.peek(o);\n return t.type === \"ident\" && t.value === kw;\n }\n private eatKeyword(kw: string): Token {\n const t = this.peek();\n if (t.type !== \"ident\" || t.value !== kw) this.fail(`Expected \"${kw}\" but found ${describe(t)}`);\n return this.next();\n }\n private eat(type: Token[\"type\"]): Token {\n const t = this.peek();\n if (t.type !== type) this.fail(`Expected ${type} but found ${describe(t)}`);\n return this.next();\n }\n private eatIdent(): Token {\n return this.eat(\"ident\");\n }\n private eatNumber(): number {\n const t = this.eat(\"number\");\n return t.num!;\n }\n private eatString(): string {\n return this.eat(\"string\").value;\n }\n\n parsePlan(): PlanNode {\n this.eatKeyword(\"plan\");\n const name = this.eatString();\n this.eat(\"lcurly\");\n\n const plan: PlanNode = {\n name,\n units: \"mm\",\n grid: 0,\n north: \"up\",\n walls: [],\n rooms: [],\n doors: [],\n windows: [],\n furniture: [],\n dims: [],\n };\n\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\n const t = this.peek();\n if (t.type !== \"ident\") this.fail(`Expected a statement but found ${describe(t)}`);\n switch (t.value) {\n case \"units\": {\n this.next();\n const u = this.eatIdent().value;\n if (u !== \"mm\") this.fail(`Unsupported units \"${u}\" (only \"mm\" is supported)`, t);\n plan.units = \"mm\";\n break;\n }\n case \"grid\":\n this.next();\n plan.grid = this.eatNumber();\n break;\n case \"scale\": {\n this.next();\n const a = this.eatNumber();\n this.eat(\"colon\");\n const b = this.eatNumber();\n plan.scale = `${a}:${b}`;\n break;\n }\n case \"north\":\n this.next();\n plan.north = this.parseNorth();\n break;\n case \"wall\":\n plan.walls.push(this.parseWall());\n break;\n case \"room\":\n plan.rooms.push(this.parseRoom());\n break;\n case \"door\":\n plan.doors.push(this.parseDoor());\n break;\n case \"window\":\n plan.windows.push(this.parseWindow());\n break;\n case \"furniture\":\n plan.furniture.push(this.parseFurniture());\n break;\n case \"dim\":\n plan.dims.push(this.parseDim());\n break;\n case \"title\":\n plan.title = this.parseTitle();\n break;\n default:\n this.fail(`Unknown statement \"${t.value}\"`, t);\n }\n }\n this.eat(\"rcurly\");\n return plan;\n }\n\n private isType(type: Token[\"type\"]): boolean {\n return this.peek().type === type;\n }\n\n /** Optional `id=<ident>` prefix; returns \"\" when absent. */\n private parseIdOpt(): string {\n if (this.isKeyword(\"id\")) {\n this.next();\n this.eat(\"equals\");\n return this.eatIdent().value;\n }\n return \"\";\n }\n\n private parseNorth(): NorthDir {\n const t = this.peek();\n if (t.type === \"number\") {\n this.next();\n return { deg: t.num! };\n }\n if (t.type === \"ident\" && [\"up\", \"down\", \"left\", \"right\"].includes(t.value)) {\n this.next();\n return t.value as NorthDir;\n }\n this.fail(`Expected a north direction (up|down|left|right|<degrees>) but found ${describe(t)}`);\n }\n\n private parsePoint(): Point {\n this.eat(\"lparen\");\n const x = this.eatNumber();\n this.eat(\"comma\");\n const y = this.eatNumber();\n this.eat(\"rparen\");\n return { x, y };\n }\n\n private parseWall(): WallNode {\n const kw = this.eatKeyword(\"wall\");\n const id = this.parseIdOpt();\n const kind = this.eatIdent().value;\n this.eatKeyword(\"thickness\");\n const thickness = this.eatNumber();\n this.eat(\"lcurly\");\n const points: Point[] = [];\n let closed = false;\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\n if (this.isKeyword(\"close\")) {\n this.next();\n closed = true;\n break;\n }\n if (this.isType(\"lparen\")) {\n points.push(this.parsePoint());\n continue;\n }\n this.fail(`Expected a point \"(x,y)\" or \"close\" in wall body but found ${describe(this.peek())}`);\n }\n this.eat(\"rcurly\");\n if (points.length < 2) this.fail(\"A wall needs at least two points\", kw);\n return { id, kind, thickness, points, closed, line: kw.line };\n }\n\n private parseRoom(): RoomNode {\n const kw = this.eatKeyword(\"room\");\n const id = this.parseIdOpt();\n this.eatKeyword(\"at\");\n const at = this.parsePoint();\n this.eatKeyword(\"size\");\n const dim = this.eat(\"dimension\");\n const node: RoomNode = { id, at, size: { w: dim.num!, h: dim.num2! }, line: kw.line };\n if (this.isKeyword(\"label\")) {\n this.next();\n node.label = this.eatString();\n }\n return node;\n }\n\n private parseDoor(): DoorNode {\n const kw = this.eatKeyword(\"door\");\n const id = this.parseIdOpt();\n this.eatKeyword(\"at\");\n const at = this.parsePoint();\n this.eatKeyword(\"width\");\n const width = this.eatNumber();\n const node: DoorNode = { id, at, width, hinge: \"left\", swing: \"in\", line: kw.line };\n if (this.isKeyword(\"wall\")) {\n this.next();\n node.wall = this.eatIdent().value;\n }\n if (this.isKeyword(\"hinge\")) {\n this.next();\n const h = this.eatIdent().value;\n if (h !== \"left\" && h !== \"right\") this.fail(`Expected hinge \"left\" or \"right\" but found \"${h}\"`);\n node.hinge = h;\n }\n if (this.isKeyword(\"swing\")) {\n this.next();\n const s = this.eatIdent().value;\n if (s !== \"in\" && s !== \"out\") this.fail(`Expected swing \"in\" or \"out\" but found \"${s}\"`);\n node.swing = s;\n }\n return node;\n }\n\n private parseWindow(): WindowNode {\n const kw = this.eatKeyword(\"window\");\n const id = this.parseIdOpt();\n this.eatKeyword(\"at\");\n const at = this.parsePoint();\n this.eatKeyword(\"width\");\n const width = this.eatNumber();\n const node: WindowNode = { id, at, width, line: kw.line };\n if (this.isKeyword(\"wall\")) {\n this.next();\n node.wall = this.eatIdent().value;\n }\n return node;\n }\n\n private parseFurniture(): FurnitureNode {\n const kw = this.eatKeyword(\"furniture\");\n const id = this.parseIdOpt();\n const kind = this.eatIdent().value;\n this.eatKeyword(\"at\");\n const at = this.parsePoint();\n this.eatKeyword(\"size\");\n const dim = this.eat(\"dimension\");\n const node: FurnitureNode = { id, kind, at, size: { w: dim.num!, h: dim.num2! }, line: kw.line };\n if (this.isKeyword(\"label\")) {\n this.next();\n node.label = this.eatString();\n }\n return node;\n }\n\n private parseDim(): DimNode {\n const kw = this.eatKeyword(\"dim\");\n const from = this.parsePoint();\n this.eat(\"arrow\");\n const to = this.parsePoint();\n const node: DimNode = { id: \"\", from, to, offset: 300, line: kw.line };\n if (this.isKeyword(\"offset\")) {\n this.next();\n node.offset = this.eatNumber();\n }\n if (this.isKeyword(\"text\")) {\n this.next();\n node.text = this.eatString();\n }\n return node;\n }\n\n private parseTitle(): TitleNode {\n const kw = this.eatKeyword(\"title\");\n this.eat(\"lcurly\");\n const node: TitleNode = { line: kw.line };\n while (!this.isType(\"rcurly\") && !this.isType(\"eof\")) {\n const t = this.peek();\n if (t.type !== \"ident\") this.fail(`Expected a title field but found ${describe(t)}`);\n switch (t.value) {\n case \"project\":\n this.next();\n node.project = this.eatString();\n break;\n case \"drawn_by\":\n this.next();\n node.drawnBy = this.eatString();\n break;\n case \"date\":\n this.next();\n node.date = this.eatString();\n break;\n default:\n this.fail(`Unknown title field \"${t.value}\"`, t);\n }\n }\n this.eat(\"rcurly\");\n return node;\n }\n}\n\nfunction describe(t: Token): string {\n if (t.type === \"eof\") return \"end of input\";\n if (t.type === \"string\") return `string ${JSON.stringify(t.value)}`;\n return `\"${t.value}\"`;\n}\n","/** Pure geometry helpers. All coordinates in millimetres. Deterministic. */\n\nimport type { PlanNode, Point } from \"./ast.js\";\n\nexport interface Vec {\n x: number;\n y: number;\n}\n\nexport const sub = (a: Point, b: Point): Vec => ({ x: a.x - b.x, y: a.y - b.y });\nexport const add = (a: Point, b: Vec): Point => ({ x: a.x + b.x, y: a.y + b.y });\nexport const mul = (v: Vec, s: number): Vec => ({ x: v.x * s, y: v.y * s });\nexport const length = (v: Vec): number => Math.hypot(v.x, v.y);\nexport function unit(v: Vec): Vec {\n const l = length(v);\n return l === 0 ? { x: 0, y: 0 } : { x: v.x / l, y: v.y / l };\n}\n/** Left normal (rotate +90°). */\nexport const normal = (v: Vec): Vec => ({ x: -v.y, y: v.x });\n\nexport interface Bounds {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport const emptyBounds = (): Bounds => ({\n minX: Infinity,\n minY: Infinity,\n maxX: -Infinity,\n maxY: -Infinity,\n});\n\nexport function extendBounds(b: Bounds, x: number, y: number): void {\n if (x < b.minX) b.minX = x;\n if (y < b.minY) b.minY = y;\n if (x > b.maxX) b.maxX = x;\n if (y > b.maxY) b.maxY = y;\n}\n\n/** Distance from point p to segment ab. */\nexport function distPointToSegment(p: Point, a: Point, b: Point): number {\n const abx = b.x - a.x;\n const aby = b.y - a.y;\n const apx = p.x - a.x;\n const apy = p.y - a.y;\n const len2 = abx * abx + aby * aby;\n let t = len2 === 0 ? 0 : (apx * abx + apy * aby) / len2;\n t = Math.max(0, Math.min(1, t));\n const cx = a.x + t * abx;\n const cy = a.y + t * aby;\n return Math.hypot(p.x - cx, p.y - cy);\n}\n\n/** Axis-aligned rectangle corners (clockwise) from origin + size. */\nexport function rectCorners(x: number, y: number, w: number, h: number): Point[] {\n return [\n { x, y },\n { x: x + w, y },\n { x: x + w, y: y + h },\n { x, y: y + h },\n ];\n}\n\n/**\n * Square-capped offset rectangle for a wall segment: the segment is widened by\n * `thickness` and extended by `thickness/2` at each end so orthogonal corners\n * fill cleanly when adjacent segments are drawn.\n */\nexport function segmentRectangle(a: Point, b: Point, thickness: number): Point[] {\n const d = unit(sub(b, a));\n const n = normal(d);\n const half = thickness / 2;\n const a2 = add(a, mul(d, -half));\n const b2 = add(b, mul(d, half));\n return [\n add(a2, mul(n, half)),\n add(b2, mul(n, half)),\n add(b2, mul(n, -half)),\n add(a2, mul(n, -half)),\n ];\n}\n\nexport interface WallSegment {\n a: Point;\n b: Point;\n thickness: number;\n kind: string;\n}\n\n/** Flatten all walls to their individual segments. */\nexport function wallSegments(plan: PlanNode): WallSegment[] {\n const segs: WallSegment[] = [];\n for (const w of plan.walls) {\n for (let k = 0; k < w.points.length - 1; k++) {\n segs.push({ a: w.points[k], b: w.points[k + 1], thickness: w.thickness, kind: w.kind });\n }\n if (w.closed && w.points.length > 2) {\n segs.push({ a: w.points[w.points.length - 1], b: w.points[0], thickness: w.thickness, kind: w.kind });\n }\n }\n return segs;\n}\n\n/** The wall segment hosting an opening point (nearest), filtered by ref if given. */\nexport function hostSegment(plan: PlanNode, at: Point, wallRef?: string): WallSegment | null {\n const walls = wallRef\n ? plan.walls.filter((w) => w.id === wallRef || w.kind === wallRef)\n : plan.walls;\n let best: WallSegment | null = null;\n let bestDist = Infinity;\n for (const w of walls) {\n const segs: [Point, Point][] = [];\n for (let k = 0; k < w.points.length - 1; k++) segs.push([w.points[k], w.points[k + 1]]);\n if (w.closed && w.points.length > 2) segs.push([w.points[w.points.length - 1], w.points[0]]);\n for (const [a, b] of segs) {\n const dist = distPointToSegment(at, a, b);\n if (dist < bestDist) {\n bestDist = dist;\n best = { a, b, thickness: w.thickness, kind: w.kind };\n }\n }\n }\n return best;\n}\n\n/** Drawing bounds over walls (offset by thickness), rooms, furniture, and dims. */\nexport function planBounds(plan: PlanNode): Bounds {\n const b = emptyBounds();\n for (const seg of wallSegments(plan)) {\n for (const c of segmentRectangle(seg.a, seg.b, seg.thickness)) extendBounds(b, c.x, c.y);\n }\n for (const r of plan.rooms) {\n extendBounds(b, r.at.x, r.at.y);\n extendBounds(b, r.at.x + r.size.w, r.at.y + r.size.h);\n }\n for (const f of plan.furniture) {\n extendBounds(b, f.at.x, f.at.y);\n extendBounds(b, f.at.x + f.size.w, f.at.y + f.size.h);\n }\n for (const d of plan.dims) {\n extendBounds(b, d.from.x, d.from.y);\n extendBounds(b, d.to.x, d.to.y);\n }\n if (!isFinite(b.minX)) {\n // Nothing to draw; provide a default frame.\n return { minX: 0, minY: 0, maxX: 1000, maxY: 1000 };\n }\n return b;\n}\n","/** Semantic analysis: grid-snap, auto-id assignment, and sanity checks. */\n\nimport type { PlanNode, Point } from \"./ast.js\";\nimport type { CompileError, CompileWarning } from \"./types.js\";\nimport { distPointToSegment } from \"./geometry.js\";\n\nexport interface ValidateResult {\n errors: CompileError[];\n warnings: CompileWarning[];\n}\n\n/** Mutates `plan` in place: snaps coordinates to the grid and assigns ids. */\nexport function validate(plan: PlanNode): ValidateResult {\n const errors: CompileError[] = [];\n const warnings: CompileWarning[] = [];\n\n // --- Grid snapping -------------------------------------------------------\n const g = plan.grid;\n const snap = (v: number) => (g > 0 ? Math.round(v / g) * g : v);\n const snapPt = (p: Point): Point => ({ x: snap(p.x), y: snap(p.y) });\n\n for (const w of plan.walls) {\n w.points = w.points.map(snapPt);\n w.thickness = snap(w.thickness) || w.thickness;\n }\n for (const r of plan.rooms) {\n r.at = snapPt(r.at);\n r.size = { w: snap(r.size.w), h: snap(r.size.h) };\n }\n for (const f of plan.furniture) {\n f.at = snapPt(f.at);\n f.size = { w: snap(f.size.w), h: snap(f.size.h) };\n }\n for (const d of plan.doors) {\n d.at = snapPt(d.at);\n d.width = snap(d.width) || d.width;\n }\n for (const win of plan.windows) {\n win.at = snapPt(win.at);\n win.width = snap(win.width) || win.width;\n }\n for (const dm of plan.dims) {\n dm.from = snapPt(dm.from);\n dm.to = snapPt(dm.to);\n }\n\n // --- Auto-id assignment + duplicate detection ----------------------------\n const seen = new Set<string>();\n const assign = (provided: string, prefix: string, idx: number, line: number): string => {\n if (provided) {\n if (seen.has(provided)) {\n errors.push({ message: `Duplicate id \"${provided}\"`, line });\n }\n seen.add(provided);\n return provided;\n }\n let auto = `${prefix}_${idx}`;\n while (seen.has(auto)) auto = `${auto}_`;\n seen.add(auto);\n return auto;\n };\n\n plan.walls.forEach((w, i) => (w.id = assign(w.id, w.kind || \"wall\", i + 1, w.line)));\n plan.rooms.forEach((r, i) => (r.id = assign(r.id, \"room\", i + 1, r.line)));\n plan.doors.forEach((d, i) => (d.id = assign(d.id, \"door\", i + 1, d.line)));\n plan.windows.forEach((w, i) => (w.id = assign(w.id, \"window\", i + 1, w.line)));\n plan.furniture.forEach((f, i) => (f.id = assign(f.id, f.kind || \"furniture\", i + 1, f.line)));\n plan.dims.forEach((d, i) => (d.id = assign(d.id, \"dim\", i + 1, d.line)));\n\n // --- Dimension sanity ----------------------------------------------------\n for (const r of plan.rooms) {\n if (r.size.w <= 0 || r.size.h <= 0)\n errors.push({ message: `Room \"${r.id}\" must have a positive size`, line: r.line });\n }\n for (const f of plan.furniture) {\n if (f.size.w <= 0 || f.size.h <= 0)\n errors.push({ message: `Furniture \"${f.id}\" must have a positive size`, line: f.line });\n }\n for (const d of plan.doors) {\n if (d.width <= 0) errors.push({ message: `Door \"${d.id}\" must have a positive width`, line: d.line });\n }\n for (const w of plan.windows) {\n if (w.width <= 0) errors.push({ message: `Window \"${w.id}\" must have a positive width`, line: w.line });\n }\n for (const w of plan.walls) {\n if (w.thickness <= 0)\n errors.push({ message: `Wall \"${w.id}\" must have a positive thickness`, line: w.line });\n }\n\n if (\n plan.walls.length === 0 &&\n plan.rooms.length === 0 &&\n plan.furniture.length === 0\n ) {\n warnings.push({ message: \"Plan has no walls, rooms, or furniture — nothing to draw\" });\n }\n\n // --- Openings should lie on a wall --------------------------------------\n const onSomeWall = (at: Point, wallRef?: string): boolean => {\n const candidates = wallRef\n ? plan.walls.filter((w) => w.id === wallRef || w.kind === wallRef)\n : plan.walls;\n for (const w of candidates) {\n const tol = w.thickness / 2 + Math.max(w.thickness, 1);\n for (let k = 0; k < w.points.length - 1; k++) {\n if (distPointToSegment(at, w.points[k], w.points[k + 1]) <= tol) return true;\n }\n if (w.closed && w.points.length > 2) {\n if (distPointToSegment(at, w.points[w.points.length - 1], w.points[0]) <= tol) return true;\n }\n }\n return false;\n };\n for (const d of plan.doors) {\n if (plan.walls.length > 0 && !onSomeWall(d.at, d.wall))\n warnings.push({ message: `Door \"${d.id}\" does not lie on any wall`, line: d.line });\n }\n for (const w of plan.windows) {\n if (plan.walls.length > 0 && !onSomeWall(w.at, w.wall))\n warnings.push({ message: `Window \"${w.id}\" does not lie on any wall`, line: w.line });\n }\n\n // --- Overlapping rooms (advisory) ---------------------------------------\n for (let a = 0; a < plan.rooms.length; a++) {\n for (let b = a + 1; b < plan.rooms.length; b++) {\n const r1 = plan.rooms[a];\n const r2 = plan.rooms[b];\n const ox = Math.max(0, Math.min(r1.at.x + r1.size.w, r2.at.x + r2.size.w) - Math.max(r1.at.x, r2.at.x));\n const oy = Math.max(0, Math.min(r1.at.y + r1.size.h, r2.at.y + r2.size.h) - Math.max(r1.at.y, r2.at.y));\n if (ox > 1 && oy > 1) {\n warnings.push({ message: `Rooms \"${r1.id}\" and \"${r2.id}\" overlap`, line: r2.line });\n }\n }\n }\n\n return { errors, warnings };\n}\n","/** Renders a validated PlanNode to a professional SVG floor plan. Deterministic. */\n\nimport type { PlanNode, Point } from \"./ast.js\";\nimport type { CompileOptions } from \"./types.js\";\nimport {\n add,\n hostSegment,\n length,\n mul,\n normal,\n planBounds,\n rectCorners,\n segmentRectangle,\n sub,\n unit,\n wallSegments,\n} from \"./geometry.js\";\n\nconst THEME = {\n bg: \"#ffffff\",\n pocheBase: \"#e9e4db\",\n pocheHatch: \"#b9b1a4\",\n wallStroke: \"#1b1b1b\",\n roomFill: \"#fbfaf7\",\n roomLabel: \"#222222\",\n areaLabel: \"#7a7a7a\",\n furnitureStroke: \"#a8a29a\",\n furnitureFill: \"#f4f2ee\",\n furnitureLabel: \"#9a948c\",\n opening: \"#ffffff\",\n doorLeaf: \"#555555\",\n windowPane: \"#3a6ea5\",\n dim: \"#0E5484\",\n annotation: \"#333333\",\n annotationMuted: \"#888888\",\n};\n\n/** Round to 2 decimals and strip trailing zeros — keeps output stable & compact. */\nfunction fmt(v: number): string {\n const r = Math.round(v * 100) / 100;\n return Object.is(r, -0) ? \"0\" : String(r);\n}\nconst pt = (p: Point): string => `${fmt(p.x)},${fmt(p.y)}`;\n\nfunction xml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nconst NICE_LENGTHS = [500, 1000, 2000, 5000, 10000, 20000, 50000, 100000];\nfunction niceBarLength(target: number): number {\n let best = NICE_LENGTHS[0];\n for (const v of NICE_LENGTHS) if (v <= target) best = v;\n return best;\n}\n\nexport function render(plan: PlanNode, opts: CompileOptions = {}): string {\n const b = planBounds(plan);\n const drawW = b.maxX - b.minX;\n const drawH = b.maxY - b.minY;\n const refDim = Math.max(drawW, drawH, 1);\n\n const wallStroke = refDim * 0.0028;\n const thin = refDim * 0.0016;\n const roomFont = refDim * 0.03;\n const areaFont = refDim * 0.022;\n const dimFont = refDim * 0.02;\n const furnFont = refDim * 0.017;\n const margin = refDim * 0.17;\n const hatchGap = refDim * 0.013;\n\n const vbX = b.minX - margin;\n const vbY = b.minY - margin;\n const vbW = drawW + margin * 2;\n const vbH = drawH + margin * 2;\n\n const out: string[] = [];\n const svgAttrs = opts.width\n ? `width=\"${fmt(opts.width)}\" height=\"${fmt((opts.width * vbH) / vbW)}\"`\n : \"\";\n out.push(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" ${svgAttrs} viewBox=\"${fmt(vbX)} ${fmt(vbY)} ${fmt(vbW)} ${fmt(vbH)}\" font-family=\"Helvetica, Arial, sans-serif\">`,\n );\n\n // Defs: poché hatch pattern\n out.push(\n `<defs><pattern id=\"poche\" patternUnits=\"userSpaceOnUse\" width=\"${fmt(hatchGap)}\" height=\"${fmt(hatchGap)}\" patternTransform=\"rotate(45)\">` +\n `<rect width=\"${fmt(hatchGap)}\" height=\"${fmt(hatchGap)}\" fill=\"${THEME.pocheBase}\"/>` +\n `<line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"${fmt(hatchGap)}\" stroke=\"${THEME.pocheHatch}\" stroke-width=\"${fmt(thin * 0.7)}\"/>` +\n `</pattern></defs>`,\n );\n\n // Background\n out.push(`<rect x=\"${fmt(vbX)}\" y=\"${fmt(vbY)}\" width=\"${fmt(vbW)}\" height=\"${fmt(vbH)}\" fill=\"${THEME.bg}\"/>`);\n\n // 1. Room floor fills\n for (const r of plan.rooms) {\n const c = rectCorners(r.at.x, r.at.y, r.size.w, r.size.h);\n out.push(`<polygon points=\"${c.map(pt).join(\" \")}\" fill=\"${THEME.roomFill}\"/>`);\n }\n\n // 2. Furniture\n for (const f of plan.furniture) {\n const c = rectCorners(f.at.x, f.at.y, f.size.w, f.size.h);\n out.push(\n `<polygon points=\"${c.map(pt).join(\" \")}\" fill=\"${THEME.furnitureFill}\" stroke=\"${THEME.furnitureStroke}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n if (f.label) {\n const cx = f.at.x + f.size.w / 2;\n const cy = f.at.y + f.size.h / 2;\n out.push(\n `<text x=\"${fmt(cx)}\" y=\"${fmt(cy)}\" font-size=\"${fmt(furnFont)}\" fill=\"${THEME.furnitureLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\">${xml(f.label)}</text>`,\n );\n }\n }\n\n // 3. Walls — poché fill (extended rect) + crisp faces (non-extended)\n const segs = wallSegments(plan);\n for (const s of segs) {\n const poly = segmentRectangle(s.a, s.b, s.thickness);\n out.push(`<polygon points=\"${poly.map(pt).join(\" \")}\" fill=\"url(#poche)\"/>`);\n }\n for (const s of segs) {\n const d = unit(sub(s.b, s.a));\n const n = normal(d);\n const h = s.thickness / 2;\n const fa1 = add(s.a, mul(n, h));\n const fb1 = add(s.b, mul(n, h));\n const fa2 = add(s.a, mul(n, -h));\n const fb2 = add(s.b, mul(n, -h));\n out.push(\n `<line x1=\"${fmt(fa1.x)}\" y1=\"${fmt(fa1.y)}\" x2=\"${fmt(fb1.x)}\" y2=\"${fmt(fb1.y)}\" stroke=\"${THEME.wallStroke}\" stroke-width=\"${fmt(wallStroke)}\" stroke-linecap=\"square\"/>`,\n );\n out.push(\n `<line x1=\"${fmt(fa2.x)}\" y1=\"${fmt(fa2.y)}\" x2=\"${fmt(fb2.x)}\" y2=\"${fmt(fb2.y)}\" stroke=\"${THEME.wallStroke}\" stroke-width=\"${fmt(wallStroke)}\" stroke-linecap=\"square\"/>`,\n );\n }\n\n // 4. Openings (doors + windows): erase wall, then draw symbol\n for (const dr of plan.doors) {\n const seg = hostSegment(plan, dr.at, dr.wall);\n if (!seg) continue;\n const d = unit(sub(seg.b, seg.a));\n const n = normal(d);\n const h = seg.thickness / 2 + wallStroke;\n const hw = dr.width / 2;\n // erase\n const cover = [\n add(add(dr.at, mul(d, -hw)), mul(n, h)),\n add(add(dr.at, mul(d, hw)), mul(n, h)),\n add(add(dr.at, mul(d, hw)), mul(n, -h)),\n add(add(dr.at, mul(d, -hw)), mul(n, -h)),\n ];\n out.push(`<polygon points=\"${cover.map(pt).join(\" \")}\" fill=\"${THEME.opening}\"/>`);\n // door symbol\n const hinge = dr.hinge === \"left\" ? add(dr.at, mul(d, -hw)) : add(dr.at, mul(d, hw));\n const farJamb = dr.hinge === \"left\" ? add(dr.at, mul(d, hw)) : add(dr.at, mul(d, -hw));\n const leafDir = dr.swing === \"in\" ? n : mul(n, -1);\n const leafEnd = add(hinge, mul(leafDir, dr.width));\n const cross = (leafEnd.x - hinge.x) * (farJamb.y - hinge.y) - (leafEnd.y - hinge.y) * (farJamb.x - hinge.x);\n const sweep = cross < 0 ? 1 : 0;\n out.push(\n `<line x1=\"${fmt(hinge.x)}\" y1=\"${fmt(hinge.y)}\" x2=\"${fmt(leafEnd.x)}\" y2=\"${fmt(leafEnd.y)}\" stroke=\"${THEME.doorLeaf}\" stroke-width=\"${fmt(thin * 1.3)}\"/>`,\n );\n out.push(\n `<path d=\"M ${pt(leafEnd)} A ${fmt(dr.width)} ${fmt(dr.width)} 0 0 ${sweep} ${pt(farJamb)}\" fill=\"none\" stroke=\"${THEME.doorLeaf}\" stroke-width=\"${fmt(thin)}\" stroke-dasharray=\"${fmt(thin * 4)} ${fmt(thin * 3)}\"/>`,\n );\n }\n for (const wn of plan.windows) {\n const seg = hostSegment(plan, wn.at, wn.wall);\n if (!seg) continue;\n const d = unit(sub(seg.b, seg.a));\n const n = normal(d);\n const h = seg.thickness / 2;\n const he = h + wallStroke;\n const hw = wn.width / 2;\n const cover = [\n add(add(wn.at, mul(d, -hw)), mul(n, he)),\n add(add(wn.at, mul(d, hw)), mul(n, he)),\n add(add(wn.at, mul(d, hw)), mul(n, -he)),\n add(add(wn.at, mul(d, -hw)), mul(n, -he)),\n ];\n out.push(`<polygon points=\"${cover.map(pt).join(\" \")}\" fill=\"${THEME.opening}\"/>`);\n const jA = add(wn.at, mul(d, -hw));\n const jB = add(wn.at, mul(d, hw));\n for (const off of [h, -h]) {\n const a = add(jA, mul(n, off));\n const bb = add(jB, mul(n, off));\n out.push(\n `<line x1=\"${fmt(a.x)}\" y1=\"${fmt(a.y)}\" x2=\"${fmt(bb.x)}\" y2=\"${fmt(bb.y)}\" stroke=\"${THEME.wallStroke}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n }\n out.push(\n `<line x1=\"${fmt(jA.x)}\" y1=\"${fmt(jA.y)}\" x2=\"${fmt(jB.x)}\" y2=\"${fmt(jB.y)}\" stroke=\"${THEME.windowPane}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n }\n\n // 5. Room labels + area (on top)\n for (const r of plan.rooms) {\n const cx = r.at.x + r.size.w / 2;\n const cy = r.at.y + r.size.h / 2;\n const areaM2 = ((r.size.w / 1000) * (r.size.h / 1000)).toFixed(1);\n if (r.label) {\n out.push(\n `<text x=\"${fmt(cx)}\" y=\"${fmt(cy - roomFont * 0.2)}\" font-size=\"${fmt(roomFont)}\" fill=\"${THEME.roomLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-weight=\"600\">${xml(r.label)}</text>`,\n );\n }\n out.push(\n `<text x=\"${fmt(cx)}\" y=\"${fmt(cy + (r.label ? roomFont * 0.9 : 0))}\" font-size=\"${fmt(areaFont)}\" fill=\"${THEME.areaLabel}\" text-anchor=\"middle\" dominant-baseline=\"central\">${areaM2} m²</text>`,\n );\n }\n\n // 6. Dimensions\n for (const dm of plan.dims) {\n const dir = unit(sub(dm.to, dm.from));\n const n = normal(dir);\n const off = mul(n, dm.offset);\n const p1 = add(dm.from, off);\n const p2 = add(dm.to, off);\n const tick = refDim * 0.012;\n // extension lines\n out.push(\n `<line x1=\"${fmt(dm.from.x)}\" y1=\"${fmt(dm.from.y)}\" x2=\"${fmt(p1.x)}\" y2=\"${fmt(p1.y)}\" stroke=\"${THEME.dim}\" stroke-width=\"${fmt(thin * 0.7)}\"/>`,\n );\n out.push(\n `<line x1=\"${fmt(dm.to.x)}\" y1=\"${fmt(dm.to.y)}\" x2=\"${fmt(p2.x)}\" y2=\"${fmt(p2.y)}\" stroke=\"${THEME.dim}\" stroke-width=\"${fmt(thin * 0.7)}\"/>`,\n );\n // dimension line\n out.push(\n `<line x1=\"${fmt(p1.x)}\" y1=\"${fmt(p1.y)}\" x2=\"${fmt(p2.x)}\" y2=\"${fmt(p2.y)}\" stroke=\"${THEME.dim}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n // ticks (45°)\n for (const p of [p1, p2]) {\n const t1 = add(p, mul(unit({ x: dir.x + n.x, y: dir.y + n.y }), tick));\n const t2 = add(p, mul(unit({ x: dir.x + n.x, y: dir.y + n.y }), -tick));\n out.push(\n `<line x1=\"${fmt(t1.x)}\" y1=\"${fmt(t1.y)}\" x2=\"${fmt(t2.x)}\" y2=\"${fmt(t2.y)}\" stroke=\"${THEME.dim}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n }\n // text\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n const tp = add(mid, mul(n, dimFont * 0.7));\n let angle = (Math.atan2(dir.y, dir.x) * 180) / Math.PI;\n if (angle > 90) angle -= 180;\n if (angle < -90) angle += 180;\n const label = dm.text ?? String(Math.round(length(sub(dm.to, dm.from))));\n out.push(\n `<text x=\"${fmt(tp.x)}\" y=\"${fmt(tp.y)}\" font-size=\"${fmt(dimFont)}\" fill=\"${THEME.dim}\" text-anchor=\"middle\" dominant-baseline=\"central\" transform=\"rotate(${fmt(angle)} ${fmt(tp.x)} ${fmt(tp.y)})\">${xml(label)}</text>`,\n );\n }\n\n // 7. North arrow (top-right band)\n out.push(northArrow(plan, b, margin, refDim));\n\n // 8. Scale bar (bottom-left band)\n out.push(scaleBar(b, margin, refDim, thin));\n\n // 9. Title block (bottom-right band)\n const tb = titleBlock(plan, b, margin, refDim, thin);\n if (tb) out.push(tb);\n\n out.push(\"</svg>\");\n return out.join(\"\\n\");\n}\n\nfunction northArrow(plan: PlanNode, b: ReturnType<typeof planBounds>, margin: number, refDim: number): string {\n const r = refDim * 0.045;\n const cx = b.maxX - r;\n const cy = b.minY - margin * 0.55;\n let deg: number;\n switch (plan.north) {\n case \"up\": deg = 0; break;\n case \"down\": deg = 180; break;\n case \"left\": deg = 270; break;\n case \"right\": deg = 90; break;\n default: deg = typeof plan.north === \"object\" ? plan.north.deg : 0;\n }\n const fs = refDim * 0.026;\n // Triangle points \"up\" before rotation; only the arrow rotates — the \"N\"\n // label stays upright at the pointing end so it always reads correctly.\n const tri = `${fmt(cx)},${fmt(cy - r)} ${fmt(cx - r * 0.5)},${fmt(cy + r * 0.6)} ${fmt(cx)},${fmt(cy + r * 0.25)} ${fmt(cx + r * 0.5)},${fmt(cy + r * 0.6)}`;\n const rad = (deg * Math.PI) / 180;\n // North screen vector (rotate the \"up\" vector (0,-1) clockwise by deg).\n const nx = Math.sin(rad);\n const ny = -Math.cos(rad);\n const lx = cx + nx * (r + fs * 0.8);\n const ly = cy + ny * (r + fs * 0.8);\n return (\n `<g>` +\n `<polygon points=\"${tri}\" fill=\"${THEME.annotation}\" transform=\"rotate(${fmt(deg)} ${fmt(cx)} ${fmt(cy)})\"/>` +\n `<text x=\"${fmt(lx)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"middle\" dominant-baseline=\"central\">N</text>` +\n `</g>`\n );\n}\n\nfunction scaleBar(b: ReturnType<typeof planBounds>, margin: number, refDim: number, thin: number): string {\n const barLen = niceBarLength(refDim * 0.3);\n const x0 = b.minX;\n const y0 = b.maxY + margin * 0.55;\n const hgt = refDim * 0.014;\n const fs = refDim * 0.02;\n const parts: string[] = [];\n const half = barLen / 2;\n // two-segment alternating bar\n parts.push(`<rect x=\"${fmt(x0)}\" y=\"${fmt(y0)}\" width=\"${fmt(half)}\" height=\"${fmt(hgt)}\" fill=\"${THEME.annotation}\"/>`);\n parts.push(\n `<rect x=\"${fmt(x0 + half)}\" y=\"${fmt(y0)}\" width=\"${fmt(half)}\" height=\"${fmt(hgt)}\" fill=\"none\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n parts.push(\n `<text x=\"${fmt(x0)}\" y=\"${fmt(y0 + hgt + fs)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"start\" dominant-baseline=\"central\">0</text>`,\n );\n parts.push(\n `<text x=\"${fmt(x0 + barLen)}\" y=\"${fmt(y0 + hgt + fs)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"middle\" dominant-baseline=\"central\">${barLen / 1000} m</text>`,\n );\n return `<g>${parts.join(\"\")}</g>`;\n}\n\nfunction titleBlock(\n plan: PlanNode,\n b: ReturnType<typeof planBounds>,\n margin: number,\n refDim: number,\n thin: number,\n): string | null {\n const t = plan.title;\n if (!t && !plan.scale) return null;\n const boxW = refDim * 0.34;\n const boxH = margin * 0.82;\n const x0 = b.maxX - boxW;\n const y0 = b.maxY + margin * 0.15;\n const fs = refDim * 0.019;\n const pad = boxW * 0.05;\n const lines: { k: string; v: string }[] = [];\n if (t?.project) lines.push({ k: \"PROJECT\", v: t.project });\n if (t?.drawnBy) lines.push({ k: \"DRAWN BY\", v: t.drawnBy });\n if (t?.date) lines.push({ k: \"DATE\", v: t.date });\n if (plan.scale) lines.push({ k: \"SCALE\", v: plan.scale });\n\n const parts: string[] = [];\n parts.push(\n `<rect x=\"${fmt(x0)}\" y=\"${fmt(y0)}\" width=\"${fmt(boxW)}\" height=\"${fmt(boxH)}\" fill=\"none\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin)}\"/>`,\n );\n const rowH = boxH / Math.max(lines.length, 1);\n lines.forEach((ln, i) => {\n const ly = y0 + rowH * (i + 0.5);\n parts.push(\n `<text x=\"${fmt(x0 + pad)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs * 0.8)}\" fill=\"${THEME.annotationMuted}\" dominant-baseline=\"central\">${xml(ln.k)}</text>`,\n );\n parts.push(\n `<text x=\"${fmt(x0 + boxW - pad)}\" y=\"${fmt(ly)}\" font-size=\"${fmt(fs)}\" fill=\"${THEME.annotation}\" text-anchor=\"end\" dominant-baseline=\"central\">${xml(ln.v)}</text>`,\n );\n if (i > 0)\n parts.push(\n `<line x1=\"${fmt(x0)}\" y1=\"${fmt(y0 + rowH * i)}\" x2=\"${fmt(x0 + boxW)}\" y2=\"${fmt(y0 + rowH * i)}\" stroke=\"${THEME.annotation}\" stroke-width=\"${fmt(thin * 0.5)}\"/>`,\n );\n });\n return `<g>${parts.join(\"\")}</g>`;\n}\n","/**\n * ArchLang — compile declarative floor-plan source to a professional SVG.\n *\n * @example\n * import { compile } from \"@chanmeng666/archlang\";\n * const { svg, errors } = compile(`plan \"Demo\" { room at (0,0) size 4000x3000 label \"Room\" }`);\n */\n\nimport { parse } from \"./parser.js\";\nimport { validate } from \"./validate.js\";\nimport { render } from \"./render.js\";\nimport type { CompileOptions, CompileResult } from \"./types.js\";\n\nexport type {\n CompileError,\n CompileOptions,\n CompileResult,\n CompileWarning,\n} from \"./types.js\";\nexport type * from \"./ast.js\";\n\n/** Small LRU-ish memo cache keyed by source+options. Bounded to 64 entries. */\nconst cache = new Map<string, CompileResult>();\nconst CACHE_MAX = 64;\n\nexport function compile(source: string, opts: CompileOptions = {}): CompileResult {\n const key = JSON.stringify([source, opts.width ?? null]);\n if (!opts.noCache) {\n const hit = cache.get(key);\n if (hit) return hit;\n }\n\n const result = compileUncached(source, opts);\n\n if (!opts.noCache) {\n if (cache.size >= CACHE_MAX) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(key, result);\n }\n return result;\n}\n\nfunction compileUncached(source: string, opts: CompileOptions): CompileResult {\n const { plan, errors: parseErrors } = parse(source);\n if (!plan || parseErrors.length > 0) {\n return { svg: \"\", errors: parseErrors, warnings: [] };\n }\n\n const { errors, warnings } = validate(plan);\n if (errors.length > 0) {\n return { svg: \"\", errors, warnings, ast: plan };\n }\n\n const svg = render(plan, opts);\n return { svg, errors: [], warnings, ast: plan };\n}\n\n/** Clear the internal compile cache (useful in long-lived processes/tests). */\nexport function clearCache(): void {\n cache.clear();\n}\n"],"mappings":"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","names":[]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ compile
4
+ } from "./chunk-J5DEA2KQ.js";
5
+
6
+ // src/cli.ts
7
+ import { readFileSync, writeFileSync, watchFile } from "fs";
8
+ import { basename, resolve } from "path";
9
+ function printErrors(label, items) {
10
+ for (const e of items) {
11
+ const loc = e.line ? `:${e.line}${e.col ? `:${e.col}` : ""}` : "";
12
+ process.stderr.write(`${label}${loc} ${e.message}
13
+ `);
14
+ }
15
+ }
16
+ function compileFile(input, output, width) {
17
+ let source;
18
+ try {
19
+ source = readFileSync(input, "utf8");
20
+ } catch {
21
+ process.stderr.write(`error: cannot read ${input}
22
+ `);
23
+ return false;
24
+ }
25
+ const { svg, errors, warnings } = compile(source, { width, noCache: true });
26
+ printErrors("warning", warnings);
27
+ if (errors.length > 0) {
28
+ printErrors(`${basename(input)}`, errors);
29
+ process.stderr.write(`\u2717 compilation failed (${errors.length} error${errors.length > 1 ? "s" : ""})
30
+ `);
31
+ return false;
32
+ }
33
+ writeFileSync(output, svg, "utf8");
34
+ process.stdout.write(`\u2713 ${input} \u2192 ${output} (${svg.length} bytes)
35
+ `);
36
+ return true;
37
+ }
38
+ function parseArgs(argv) {
39
+ const res = { _: [] };
40
+ for (let i = 0; i < argv.length; i++) {
41
+ const a = argv[i];
42
+ if (a === "-o" || a === "--out") res.o = argv[++i];
43
+ else if (a === "-w" || a === "--width") res.width = Number(argv[++i]);
44
+ else res._.push(a);
45
+ }
46
+ return res;
47
+ }
48
+ function defaultOut(input) {
49
+ return input.replace(/\.arch$/i, "") + ".svg";
50
+ }
51
+ function main() {
52
+ const [cmd, ...rest] = process.argv.slice(2);
53
+ const args = parseArgs(rest);
54
+ if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
55
+ process.stdout.write(
56
+ `arch \u2014 ArchLang compiler
57
+
58
+ Usage:
59
+ arch compile <in.arch> [-o out.svg] [-w width]
60
+ arch watch <in.arch> [-o out.svg] [-w width]
61
+ `
62
+ );
63
+ process.exit(cmd ? 0 : 1);
64
+ }
65
+ const input = args._[0];
66
+ if (!input) {
67
+ process.stderr.write("error: missing input file\n");
68
+ process.exit(1);
69
+ }
70
+ const output = args.o ? resolve(args.o) : defaultOut(resolve(input));
71
+ if (cmd === "compile") {
72
+ process.exit(compileFile(resolve(input), output, args.width) ? 0 : 1);
73
+ } else if (cmd === "watch") {
74
+ compileFile(resolve(input), output, args.width);
75
+ process.stdout.write(`watching ${input} \u2026 (Ctrl+C to stop)
76
+ `);
77
+ watchFile(resolve(input), { interval: 300 }, () => compileFile(resolve(input), output, args.width));
78
+ } else {
79
+ process.stderr.write(`error: unknown command "${cmd}"
80
+ `);
81
+ process.exit(1);
82
+ }
83
+ }
84
+ main();
85
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/** ArchLang CLI: `arch compile <in.arch> [-o out.svg]`, `arch watch <in.arch>`. */\n\nimport { readFileSync, writeFileSync, watchFile } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { compile } from \"./index.js\";\n\nfunction printErrors(label: string, items: { message: string; line?: number; col?: number }[]): void {\n for (const e of items) {\n const loc = e.line ? `:${e.line}${e.col ? `:${e.col}` : \"\"}` : \"\";\n process.stderr.write(`${label}${loc} ${e.message}\\n`);\n }\n}\n\nfunction compileFile(input: string, output: string, width?: number): boolean {\n let source: string;\n try {\n source = readFileSync(input, \"utf8\");\n } catch {\n process.stderr.write(`error: cannot read ${input}\\n`);\n return false;\n }\n const { svg, errors, warnings } = compile(source, { width, noCache: true });\n printErrors(\"warning\", warnings);\n if (errors.length > 0) {\n printErrors(`${basename(input)}`, errors);\n process.stderr.write(`✗ compilation failed (${errors.length} error${errors.length > 1 ? \"s\" : \"\"})\\n`);\n return false;\n }\n writeFileSync(output, svg, \"utf8\");\n process.stdout.write(`✓ ${input} → ${output} (${svg.length} bytes)\\n`);\n return true;\n}\n\nfunction parseArgs(argv: string[]): { _: string[]; o?: string; width?: number } {\n const res: { _: string[]; o?: string; width?: number } = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"-o\" || a === \"--out\") res.o = argv[++i];\n else if (a === \"-w\" || a === \"--width\") res.width = Number(argv[++i]);\n else res._.push(a);\n }\n return res;\n}\n\nfunction defaultOut(input: string): string {\n return input.replace(/\\.arch$/i, \"\") + \".svg\";\n}\n\nfunction main(): void {\n const [cmd, ...rest] = process.argv.slice(2);\n const args = parseArgs(rest);\n\n if (!cmd || cmd === \"help\" || cmd === \"--help\" || cmd === \"-h\") {\n process.stdout.write(\n `arch — ArchLang compiler\\n\\n` +\n `Usage:\\n` +\n ` arch compile <in.arch> [-o out.svg] [-w width]\\n` +\n ` arch watch <in.arch> [-o out.svg] [-w width]\\n`,\n );\n process.exit(cmd ? 0 : 1);\n }\n\n const input = args._[0];\n if (!input) {\n process.stderr.write(\"error: missing input file\\n\");\n process.exit(1);\n }\n const output = args.o ? resolve(args.o) : defaultOut(resolve(input));\n\n if (cmd === \"compile\") {\n process.exit(compileFile(resolve(input), output, args.width) ? 0 : 1);\n } else if (cmd === \"watch\") {\n compileFile(resolve(input), output, args.width);\n process.stdout.write(`watching ${input} … (Ctrl+C to stop)\\n`);\n watchFile(resolve(input), { interval: 300 }, () => compileFile(resolve(input), output, args.width));\n } else {\n process.stderr.write(`error: unknown command \"${cmd}\"\\n`);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":";;;;;;AAGA,SAAS,cAAc,eAAe,iBAAiB;AACvD,SAAS,UAAU,eAAe;AAGlC,SAAS,YAAY,OAAe,OAAiE;AACnG,aAAW,KAAK,OAAO;AACrB,UAAM,MAAM,EAAE,OAAO,IAAI,EAAE,IAAI,GAAG,EAAE,MAAM,IAAI,EAAE,GAAG,KAAK,EAAE,KAAK;AAC/D,YAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,GAAG,IAAI,EAAE,OAAO;AAAA,CAAI;AAAA,EACtD;AACF;AAEA,SAAS,YAAY,OAAe,QAAgB,OAAyB;AAC3E,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,OAAO,MAAM;AAAA,EACrC,QAAQ;AACN,YAAQ,OAAO,MAAM,sBAAsB,KAAK;AAAA,CAAI;AACpD,WAAO;AAAA,EACT;AACA,QAAM,EAAE,KAAK,QAAQ,SAAS,IAAI,QAAQ,QAAQ,EAAE,OAAO,SAAS,KAAK,CAAC;AAC1E,cAAY,WAAW,QAAQ;AAC/B,MAAI,OAAO,SAAS,GAAG;AACrB,gBAAY,GAAG,SAAS,KAAK,CAAC,IAAI,MAAM;AACxC,YAAQ,OAAO,MAAM,8BAAyB,OAAO,MAAM,SAAS,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,CAAK;AACrG,WAAO;AAAA,EACT;AACA,gBAAc,QAAQ,KAAK,MAAM;AACjC,UAAQ,OAAO,MAAM,UAAK,KAAK,WAAM,MAAM,KAAK,IAAI,MAAM;AAAA,CAAW;AACrE,SAAO;AACT;AAEA,SAAS,UAAU,MAA6D;AAC9E,QAAM,MAAmD,EAAE,GAAG,CAAC,EAAE;AACjE,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,QAAQ,MAAM,QAAS,KAAI,IAAI,KAAK,EAAE,CAAC;AAAA,aACxC,MAAM,QAAQ,MAAM,UAAW,KAAI,QAAQ,OAAO,KAAK,EAAE,CAAC,CAAC;AAAA,QAC/D,KAAI,EAAE,KAAK,CAAC;AAAA,EACnB;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,MAAM,QAAQ,YAAY,EAAE,IAAI;AACzC;AAEA,SAAS,OAAa;AACpB,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC;AAC3C,QAAM,OAAO,UAAU,IAAI;AAE3B,MAAI,CAAC,OAAO,QAAQ,UAAU,QAAQ,YAAY,QAAQ,MAAM;AAC9D,YAAQ,OAAO;AAAA,MACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAIF;AACA,YAAQ,KAAK,MAAM,IAAI,CAAC;AAAA,EAC1B;AAEA,QAAM,QAAQ,KAAK,EAAE,CAAC;AACtB,MAAI,CAAC,OAAO;AACV,YAAQ,OAAO,MAAM,6BAA6B;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAAS,KAAK,IAAI,QAAQ,KAAK,CAAC,IAAI,WAAW,QAAQ,KAAK,CAAC;AAEnE,MAAI,QAAQ,WAAW;AACrB,YAAQ,KAAK,YAAY,QAAQ,KAAK,GAAG,QAAQ,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EACtE,WAAW,QAAQ,SAAS;AAC1B,gBAAY,QAAQ,KAAK,GAAG,QAAQ,KAAK,KAAK;AAC9C,YAAQ,OAAO,MAAM,YAAY,KAAK;AAAA,CAAuB;AAC7D,cAAU,QAAQ,KAAK,GAAG,EAAE,UAAU,IAAI,GAAG,MAAM,YAAY,QAAQ,KAAK,GAAG,QAAQ,KAAK,KAAK,CAAC;AAAA,EACpG,OAAO;AACL,YAAQ,OAAO,MAAM,2BAA2B,GAAG;AAAA,CAAK;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;","names":[]}
@@ -0,0 +1,141 @@
1
+ /** Abstract syntax tree for an ArchLang `plan`. All distances are in millimetres. */
2
+ interface Point {
3
+ x: number;
4
+ y: number;
5
+ }
6
+ /** North orientation: a cardinal keyword or an explicit bearing in degrees. */
7
+ type NorthDir = "up" | "down" | "left" | "right" | {
8
+ deg: number;
9
+ };
10
+ interface WallNode {
11
+ id: string;
12
+ /** Free-form category, e.g. "exterior" or "partition". Drives line weight. */
13
+ kind: string;
14
+ /** Wall thickness in mm. */
15
+ thickness: number;
16
+ /** Polyline vertices in order. */
17
+ points: Point[];
18
+ /** Whether the polyline closes back to its first vertex. */
19
+ closed: boolean;
20
+ line: number;
21
+ }
22
+ interface RoomNode {
23
+ id: string;
24
+ at: Point;
25
+ size: {
26
+ w: number;
27
+ h: number;
28
+ };
29
+ label?: string;
30
+ line: number;
31
+ }
32
+ interface DoorNode {
33
+ id: string;
34
+ at: Point;
35
+ width: number;
36
+ /** Optional wall (id or kind) the door is hosted by. */
37
+ wall?: string;
38
+ hinge: "left" | "right";
39
+ swing: "in" | "out";
40
+ line: number;
41
+ }
42
+ interface WindowNode {
43
+ id: string;
44
+ at: Point;
45
+ width: number;
46
+ wall?: string;
47
+ line: number;
48
+ }
49
+ interface FurnitureNode {
50
+ id: string;
51
+ kind: string;
52
+ at: Point;
53
+ size: {
54
+ w: number;
55
+ h: number;
56
+ };
57
+ label?: string;
58
+ line: number;
59
+ }
60
+ interface DimNode {
61
+ id: string;
62
+ from: Point;
63
+ to: Point;
64
+ /** Perpendicular offset of the dimension line from the measured segment, mm. */
65
+ offset: number;
66
+ /** Override text; defaults to the measured length. */
67
+ text?: string;
68
+ line: number;
69
+ }
70
+ interface TitleNode {
71
+ project?: string;
72
+ drawnBy?: string;
73
+ date?: string;
74
+ line: number;
75
+ }
76
+ interface PlanNode {
77
+ name: string;
78
+ /** Only "mm" is supported in v0.1. */
79
+ units: "mm";
80
+ /** Snap module in mm; 0 disables snapping. */
81
+ grid: number;
82
+ /** e.g. "1:50". */
83
+ scale?: string;
84
+ north: NorthDir;
85
+ walls: WallNode[];
86
+ rooms: RoomNode[];
87
+ doors: DoorNode[];
88
+ windows: WindowNode[];
89
+ furniture: FurnitureNode[];
90
+ dims: DimNode[];
91
+ title?: TitleNode;
92
+ }
93
+
94
+ /**
95
+ * Public types for the ArchLang compiler.
96
+ *
97
+ * The compiler never throws on user-source errors; it returns them in
98
+ * {@link CompileResult.errors}. Exceptions only escape on internal bugs.
99
+ */
100
+ interface CompileError {
101
+ /** Human-readable message. */
102
+ message: string;
103
+ /** 1-based source line, when known. */
104
+ line?: number;
105
+ /** 1-based source column, when known. */
106
+ col?: number;
107
+ }
108
+ type CompileWarning = CompileError;
109
+ interface CompileOptions {
110
+ /**
111
+ * Width attribute (in px) for the produced `<svg>`. Height is derived from
112
+ * the drawing's aspect ratio. Omit to emit a viewBox-only, fluid SVG.
113
+ */
114
+ width?: number;
115
+ /** Bypass the internal memoization cache (mostly for benchmarks/tests). */
116
+ noCache?: boolean;
117
+ }
118
+ interface CompileResult {
119
+ /** The rendered SVG document, or `""` when there were fatal errors. */
120
+ svg: string;
121
+ /** Fatal problems. When non-empty, `svg` is `""`. */
122
+ errors: CompileError[];
123
+ /** Non-fatal advisories (e.g. a door not lying on any wall). */
124
+ warnings: CompileWarning[];
125
+ /** The validated AST, present whenever parsing succeeded. */
126
+ ast?: PlanNode;
127
+ }
128
+
129
+ /**
130
+ * ArchLang — compile declarative floor-plan source to a professional SVG.
131
+ *
132
+ * @example
133
+ * import { compile } from "@chanmeng666/archlang";
134
+ * const { svg, errors } = compile(`plan "Demo" { room at (0,0) size 4000x3000 label "Room" }`);
135
+ */
136
+
137
+ declare function compile(source: string, opts?: CompileOptions): CompileResult;
138
+ /** Clear the internal compile cache (useful in long-lived processes/tests). */
139
+ declare function clearCache(): void;
140
+
141
+ export { type CompileError, type CompileOptions, type CompileResult, type CompileWarning, type DimNode, type DoorNode, type FurnitureNode, type NorthDir, type PlanNode, type Point, type RoomNode, type TitleNode, type WallNode, type WindowNode, clearCache, compile };
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import {
2
+ clearCache,
3
+ compile
4
+ } from "./chunk-J5DEA2KQ.js";
5
+ export {
6
+ clearCache,
7
+ compile
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,37 @@
1
+ # A compact studio apartment — the canonical ArchLang example.
2
+ plan "Studio 1BR" {
3
+ units mm
4
+ grid 50
5
+ scale 1:50
6
+ north up
7
+
8
+ # Exterior shell (closed) + one internal partition.
9
+ wall exterior thickness 200 { (0,0) (7000,0) (7000,6000) (0,6000) close }
10
+ wall partition thickness 100 { (4000,0) (4000,4000) }
11
+ wall partition thickness 100 { (4000,4000) (7000,4000) }
12
+
13
+ room id=r_living at (0,0) size 4000x6000 label "Living / Kitchen"
14
+ room id=r_bed at (4000,0) size 3000x4000 label "Bedroom"
15
+ room id=r_bath at (4000,4000) size 3000x2000 label "Bath"
16
+
17
+ door id=d_main at (1000,6000) width 1000 wall exterior hinge left swing in
18
+ door id=d_bed at (4000,1500) width 900 wall partition hinge left swing in
19
+ door id=d_bath at (5200,4000) width 800 wall partition hinge right swing out
20
+
21
+ window at (2500,0) width 1800 wall exterior
22
+ window at (7000,2000) width 1200 wall exterior
23
+ window at (7000,5000) width 800 wall exterior
24
+
25
+ furniture bed at (4300,300) size 1500x2000 label "Bed"
26
+ furniture sofa at (300,4200) size 2000x900 label "Sofa"
27
+ furniture stove at (300,200) size 600x600 label "Stove"
28
+
29
+ dim (0,6000)->(7000,6000) offset 600 text "7000"
30
+ dim (7000,0)->(7000,6000) offset 600 text "6000"
31
+
32
+ title {
33
+ project "Studio Apartment"
34
+ drawn_by "ArchCanvas"
35
+ date "2026-06-25"
36
+ }
37
+ }
@@ -0,0 +1,73 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="717.08" viewBox="-1324 -1324 9648 8648" font-family="Helvetica, Arial, sans-serif">
2
+ <defs><pattern id="poche" patternUnits="userSpaceOnUse" width="93.6" height="93.6" patternTransform="rotate(45)"><rect width="93.6" height="93.6" fill="#e9e4db"/><line x1="0" y1="0" x2="0" y2="93.6" stroke="#b9b1a4" stroke-width="8.06"/></pattern></defs>
3
+ <rect x="-1324" y="-1324" width="9648" height="8648" fill="#ffffff"/>
4
+ <polygon points="0,0 4000,0 4000,6000 0,6000" fill="#fbfaf7"/>
5
+ <polygon points="4000,0 7000,0 7000,4000 4000,4000" fill="#fbfaf7"/>
6
+ <polygon points="4000,4000 7000,4000 7000,6000 4000,6000" fill="#fbfaf7"/>
7
+ <polygon points="4300,300 5800,300 5800,2300 4300,2300" fill="#f4f2ee" stroke="#a8a29a" stroke-width="11.52"/>
8
+ <text x="5050" y="1300" font-size="122.4" fill="#9a948c" text-anchor="middle" dominant-baseline="central">Bed</text>
9
+ <polygon points="300,4200 2300,4200 2300,5100 300,5100" fill="#f4f2ee" stroke="#a8a29a" stroke-width="11.52"/>
10
+ <text x="1300" y="4650" font-size="122.4" fill="#9a948c" text-anchor="middle" dominant-baseline="central">Sofa</text>
11
+ <polygon points="300,200 900,200 900,800 300,800" fill="#f4f2ee" stroke="#a8a29a" stroke-width="11.52"/>
12
+ <text x="600" y="500" font-size="122.4" fill="#9a948c" text-anchor="middle" dominant-baseline="central">Stove</text>
13
+ <polygon points="-100,100 7100,100 7100,-100 -100,-100" fill="url(#poche)"/>
14
+ <polygon points="6900,-100 6900,6100 7100,6100 7100,-100" fill="url(#poche)"/>
15
+ <polygon points="7100,5900 -100,5900 -100,6100 7100,6100" fill="url(#poche)"/>
16
+ <polygon points="100,6100 100,-100 -100,-100 -100,6100" fill="url(#poche)"/>
17
+ <polygon points="3950,-50 3950,4050 4050,4050 4050,-50" fill="url(#poche)"/>
18
+ <polygon points="3950,4050 7050,4050 7050,3950 3950,3950" fill="url(#poche)"/>
19
+ <line x1="0" y1="100" x2="7000" y2="100" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
20
+ <line x1="0" y1="-100" x2="7000" y2="-100" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
21
+ <line x1="6900" y1="0" x2="6900" y2="6000" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
22
+ <line x1="7100" y1="0" x2="7100" y2="6000" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
23
+ <line x1="7000" y1="5900" x2="0" y2="5900" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
24
+ <line x1="7000" y1="6100" x2="0" y2="6100" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
25
+ <line x1="100" y1="6000" x2="100" y2="0" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
26
+ <line x1="-100" y1="6000" x2="-100" y2="0" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
27
+ <line x1="3950" y1="0" x2="3950" y2="4000" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
28
+ <line x1="4050" y1="0" x2="4050" y2="4000" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
29
+ <line x1="4000" y1="4050" x2="7000" y2="4050" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
30
+ <line x1="4000" y1="3950" x2="7000" y2="3950" stroke="#1b1b1b" stroke-width="20.16" stroke-linecap="square"/>
31
+ <polygon points="1500,5879.84 500,5879.84 500,6120.16 1500,6120.16" fill="#ffffff"/>
32
+ <line x1="1500" y1="6000" x2="1500" y2="5000" stroke="#555555" stroke-width="14.98"/>
33
+ <path d="M 1500,5000 A 1000 1000 0 0 1 500,6000" fill="none" stroke="#555555" stroke-width="11.52" stroke-dasharray="46.08 34.56"/>
34
+ <polygon points="3929.84,1050 3929.84,1950 4070.16,1950 4070.16,1050" fill="#ffffff"/>
35
+ <line x1="4000" y1="1050" x2="3100" y2="1050" stroke="#555555" stroke-width="14.98"/>
36
+ <path d="M 3100,1050 A 900 900 0 0 1 4000,1950" fill="none" stroke="#555555" stroke-width="11.52" stroke-dasharray="46.08 34.56"/>
37
+ <polygon points="4800,4070.16 5600,4070.16 5600,3929.84 4800,3929.84" fill="#ffffff"/>
38
+ <line x1="5600" y1="4000" x2="5600" y2="3200" stroke="#555555" stroke-width="14.98"/>
39
+ <path d="M 5600,3200 A 800 800 0 0 1 4800,4000" fill="none" stroke="#555555" stroke-width="11.52" stroke-dasharray="46.08 34.56"/>
40
+ <polygon points="1600,120.16 3400,120.16 3400,-120.16 1600,-120.16" fill="#ffffff"/>
41
+ <line x1="1600" y1="100" x2="3400" y2="100" stroke="#1b1b1b" stroke-width="11.52"/>
42
+ <line x1="1600" y1="-100" x2="3400" y2="-100" stroke="#1b1b1b" stroke-width="11.52"/>
43
+ <line x1="1600" y1="0" x2="3400" y2="0" stroke="#3a6ea5" stroke-width="11.52"/>
44
+ <polygon points="6879.84,1400 6879.84,2600 7120.16,2600 7120.16,1400" fill="#ffffff"/>
45
+ <line x1="6900" y1="1400" x2="6900" y2="2600" stroke="#1b1b1b" stroke-width="11.52"/>
46
+ <line x1="7100" y1="1400" x2="7100" y2="2600" stroke="#1b1b1b" stroke-width="11.52"/>
47
+ <line x1="7000" y1="1400" x2="7000" y2="2600" stroke="#3a6ea5" stroke-width="11.52"/>
48
+ <polygon points="6879.84,4600 6879.84,5400 7120.16,5400 7120.16,4600" fill="#ffffff"/>
49
+ <line x1="6900" y1="4600" x2="6900" y2="5400" stroke="#1b1b1b" stroke-width="11.52"/>
50
+ <line x1="7100" y1="4600" x2="7100" y2="5400" stroke="#1b1b1b" stroke-width="11.52"/>
51
+ <line x1="7000" y1="4600" x2="7000" y2="5400" stroke="#3a6ea5" stroke-width="11.52"/>
52
+ <text x="2000" y="2956.8" font-size="216" fill="#222222" text-anchor="middle" dominant-baseline="central" font-weight="600">Living / Kitchen</text>
53
+ <text x="2000" y="3194.4" font-size="158.4" fill="#7a7a7a" text-anchor="middle" dominant-baseline="central">24.0 m²</text>
54
+ <text x="5500" y="1956.8" font-size="216" fill="#222222" text-anchor="middle" dominant-baseline="central" font-weight="600">Bedroom</text>
55
+ <text x="5500" y="2194.4" font-size="158.4" fill="#7a7a7a" text-anchor="middle" dominant-baseline="central">12.0 m²</text>
56
+ <text x="5500" y="4956.8" font-size="216" fill="#222222" text-anchor="middle" dominant-baseline="central" font-weight="600">Bath</text>
57
+ <text x="5500" y="5194.4" font-size="158.4" fill="#7a7a7a" text-anchor="middle" dominant-baseline="central">6.0 m²</text>
58
+ <line x1="0" y1="6000" x2="0" y2="6600" stroke="#0E5484" stroke-width="8.06"/>
59
+ <line x1="7000" y1="6000" x2="7000" y2="6600" stroke="#0E5484" stroke-width="8.06"/>
60
+ <line x1="0" y1="6600" x2="7000" y2="6600" stroke="#0E5484" stroke-width="11.52"/>
61
+ <line x1="61.09" y1="6661.09" x2="-61.09" y2="6538.91" stroke="#0E5484" stroke-width="11.52"/>
62
+ <line x1="7061.09" y1="6661.09" x2="6938.91" y2="6538.91" stroke="#0E5484" stroke-width="11.52"/>
63
+ <text x="3500" y="6700.8" font-size="144" fill="#0E5484" text-anchor="middle" dominant-baseline="central" transform="rotate(0 3500 6700.8)">7000</text>
64
+ <line x1="7000" y1="0" x2="6400" y2="0" stroke="#0E5484" stroke-width="8.06"/>
65
+ <line x1="7000" y1="6000" x2="6400" y2="6000" stroke="#0E5484" stroke-width="8.06"/>
66
+ <line x1="6400" y1="0" x2="6400" y2="6000" stroke="#0E5484" stroke-width="11.52"/>
67
+ <line x1="6338.91" y1="61.09" x2="6461.09" y2="-61.09" stroke="#0E5484" stroke-width="11.52"/>
68
+ <line x1="6338.91" y1="6061.09" x2="6461.09" y2="5938.91" stroke="#0E5484" stroke-width="11.52"/>
69
+ <text x="6299.2" y="3000" font-size="144" fill="#0E5484" text-anchor="middle" dominant-baseline="central" transform="rotate(90 6299.2 3000)">6000</text>
70
+ <g><polygon points="6776,-1097.2 6614,-578.8 6776,-692.2 6938,-578.8" fill="#333333" transform="rotate(0 6776 -773.2)"/><text x="6776" y="-1246.96" font-size="187.2" fill="#333333" text-anchor="middle" dominant-baseline="central">N</text></g>
71
+ <g><rect x="-100" y="6773.2" width="1000" height="100.8" fill="#333333"/><rect x="900" y="6773.2" width="1000" height="100.8" fill="none" stroke="#333333" stroke-width="11.52"/><text x="-100" y="7018" font-size="144" fill="#333333" text-anchor="start" dominant-baseline="central">0</text><text x="1900" y="7018" font-size="144" fill="#333333" text-anchor="middle" dominant-baseline="central">2 m</text></g>
72
+ <g><rect x="4652" y="6283.6" width="2448" height="1003.68" fill="none" stroke="#333333" stroke-width="11.52"/><text x="4774.4" y="6409.06" font-size="109.44" fill="#888888" dominant-baseline="central">PROJECT</text><text x="6977.6" y="6409.06" font-size="136.8" fill="#333333" text-anchor="end" dominant-baseline="central">Studio Apartment</text><text x="4774.4" y="6659.98" font-size="109.44" fill="#888888" dominant-baseline="central">DRAWN BY</text><text x="6977.6" y="6659.98" font-size="136.8" fill="#333333" text-anchor="end" dominant-baseline="central">ArchCanvas</text><line x1="4652" y1="6534.52" x2="7100" y2="6534.52" stroke="#333333" stroke-width="5.76"/><text x="4774.4" y="6910.9" font-size="109.44" fill="#888888" dominant-baseline="central">DATE</text><text x="6977.6" y="6910.9" font-size="136.8" fill="#333333" text-anchor="end" dominant-baseline="central">2026-06-25</text><line x1="4652" y1="6785.44" x2="7100" y2="6785.44" stroke="#333333" stroke-width="5.76"/><text x="4774.4" y="7161.82" font-size="109.44" fill="#888888" dominant-baseline="central">SCALE</text><text x="6977.6" y="7161.82" font-size="136.8" fill="#333333" text-anchor="end" dominant-baseline="central">1:50</text><line x1="4652" y1="7036.36" x2="7100" y2="7036.36" stroke="#333333" stroke-width="5.76"/></g>
73
+ </svg>
@@ -0,0 +1,39 @@
1
+ # A two-bedroom apartment with a central corridor.
2
+ plan "Two-Bedroom Flat" {
3
+ units mm
4
+ grid 100
5
+ scale 1:100
6
+ north right
7
+
8
+ wall exterior thickness 250 { (0,0) (10000,0) (10000,8000) (0,8000) close }
9
+ wall partition thickness 100 { (4000,0) (4000,5000) }
10
+ wall partition thickness 100 { (4000,5000) (10000,5000) }
11
+ wall partition thickness 100 { (7000,5000) (7000,8000) }
12
+
13
+ room id=r_kitchen at (0,0) size 4000x5000 label "Kitchen / Living"
14
+ room id=r_bed1 at (4000,0) size 6000x5000 label "Master Bedroom"
15
+ room id=r_bed2 at (0,5000) size 4000x3000 label "Bedroom 2"
16
+ room id=r_bath at (4000,5000) size 3000x3000 label "Bathroom"
17
+ room id=r_hall at (7000,5000) size 3000x3000 label "Hall"
18
+
19
+ door at (4000,2500) width 900 wall partition hinge left swing in
20
+ door at (5500,5000) width 800 wall partition hinge left swing in
21
+ door at (7000,6500) width 900 wall partition hinge right swing in
22
+
23
+ window at (2000,0) width 2000 wall exterior
24
+ window at (8000,0) width 2400 wall exterior
25
+ window at (0,3000) width 1500 wall exterior
26
+ window at (10000,3000) width 1500 wall exterior
27
+
28
+ furniture bed at (5000,300) size 1800x2100 label "Bed"
29
+ furniture bed at (300,5300) size 1400x2000 label "Bed"
30
+
31
+ dim (0,8000)->(10000,8000) offset 700 text "10000"
32
+ dim (0,0)->(0,8000) offset 700 text "8000"
33
+
34
+ title {
35
+ project "Two-Bedroom Flat"
36
+ drawn_by "ArchCanvas"
37
+ date "2026-06-25"
38
+ }
39
+ }