{"id":51064727,"url":"https://github.com/cosmiciron/layoutmaster","last_synced_at":"2026-06-23T05:32:25.186Z","repository":{"id":354953499,"uuid":"1225220477","full_name":"cosmiciron/layoutmaster","owner":"cosmiciron","description":"Solve text layout before you render. No DOM. No reflow. Real layout engine -- not just a measurer.","archived":false,"fork":false,"pushed_at":"2026-06-15T10:31:47.000Z","size":17722,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T12:23:45.169Z","etag":null,"topics":["ai","browser","browser-animations","canvas","dom","dom-reflow","frontend","generative-ui","infinite-scroll","javascript","layout-engine","layout-thrashing","masonry-layout","pagination","react","text-animation","text-layout","text-measuring","text-wrapping","typography"],"latest_commit_sha":null,"homepage":"https://layoutmaster.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cosmiciron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-30T04:14:21.000Z","updated_at":"2026-06-15T10:31:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cosmiciron/layoutmaster","commit_stats":null,"previous_names":["cosmiciron/layoutmaster"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cosmiciron/layoutmaster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmiciron%2Flayoutmaster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmiciron%2Flayoutmaster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmiciron%2Flayoutmaster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmiciron%2Flayoutmaster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cosmiciron","download_url":"https://codeload.github.com/cosmiciron/layoutmaster/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmiciron%2Flayoutmaster/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34677382,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","browser","browser-animations","canvas","dom","dom-reflow","frontend","generative-ui","infinite-scroll","javascript","layout-engine","layout-thrashing","masonry-layout","pagination","react","text-animation","text-layout","text-measuring","text-wrapping","typography"],"created_at":"2026-06-23T05:32:22.523Z","updated_at":"2026-06-23T05:32:25.172Z","avatar_url":"https://github.com/cosmiciron.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Layoutmaster\n\nEvery time you ask the DOM a layout question, it has to render that layout **before**\nit can answer. It's like *committing a crime while you're still contemplating it*.\n\nAsk too often and too fast (you will), **DR. DOM** will punish you, thrash your layout, \ncrash your browser, and make your life miserable. \n\nVery miserable.\n\n![Dr. DOM — The Tyrant of Terrible Layouts, versus Layoutmaster](https://raw.githubusercontent.com/cosmiciron/layoutmaster/main/demos/assets/dr-dom.png)\n\nWhen that happens, Layoutmaster will be your hero. It will come to your browser's rescue. \nBeating at its heart is a microkernel-driven layout engine that's so fast and so versatile,\nit can power an entire city. And it lets you do layout without paying taxes to DR. DOM ever \nagain.\n\nAnd you can do this as many times as you want, as fast as you want.\n\nHow fast? Picture this:\n \n- 320,000 words. \n- Four novels back to back.\n- A MASSIVE **343,912px**, 50-story high masonry wall.\n\nThis is the stuff that makes your new MacBook Pro M5 secretly weep behind its shiny armor. \nYet the master casually lays it out in just...\n\n**882ms**\n\non a... \n\n**Base Pixel 10 phone!**\n\n*BAM!*\n\n## See the Master in Action\n\n### Dancing Text\n\n\u003ca href=\"https://layoutmaster.dev/demo.mp4\"\u003e\n   \u003cimg src=\"https://raw.githubusercontent.com/cosmiciron/layoutmaster/main/demos/assets/video-cover.png\"\n     alt=\"Layoutmaster dancing text demo: live text layout wrapping around animated video silhouettes in real time\"\n     width=\"480\"\u003e\n\u003c/a\u003e\n\n### Live Interactive Demo\n\n[cosmiciron.github.io/layoutmaster](https://cosmiciron.github.io/layoutmaster/)\n\n## The Hero's Secret Origin\n\nI hear you thinking — how is this possible? \n\n*Is this even legal?*\n\nTwo words: *game engines*.\n\nFor decades, while layout technology stayed pretty much stale, game engine technology\nadvanced enormously. Layoutmaster comes from that lineage. It is —\n\n*The world's first layout engine with game engine DNA.*\n\nThat — is where the insane speed comes from.\n\nPut simply, the master does not see text as sequential streams of characters or layout \nas a pile of complex conditionals. It sees actors, collisions, terrain, constraints, \nviewports, and deterministic updates.\n\nUnder its tiny browser API is a deterministic 2D spatial simulation engine for layout —\ncontent enters a \"world\", collides with constraints, flows through regions, avoids terrain,\nsplits across viewports, and settles into exact coordinates.\n\nThat is where the master gets its superpowers.\n\n## The Four Mantras\n\n`form()`, `fit()`, `flow()`, and `pour()`\n\nThese are the four mantras (APIs if you like, but the master prefers mantras) of the\nLayoutmaster. Do not be deceived by their overwhelming simplicity. These four verbs can\nsolve a world of complex layout challenges and unlock possibilities you could only dream of\nbefore - precisely none of which browsers could do without rebuilding DOMs.\n\n```js\nimport {\n  form,\n  fit,\n  flow,\n  pour,\n  exclusion\n} from \"@layoutmaster/layoutmaster\";\n```\n\nI know, you count five. We will get to that later. Just trust the master.\n\n### `form` - given space, how does this lay out, and how tall does it get?\n\nThe most fundamental question in layout. You have content and a width. You want\nto know what happens. `form()` gives you the pieces and the height.\n\n```js\nconst result = form(\"Layout is data.\", {\n  width: 320,\n  fontFamily: \"Georgia, serif\",\n  fontSize: 18,\n  lineHeight: 1.4,\n  direction: \"auto\",\n  lang: \"en\"\n});\n\nconsole.log(result.height);\nconsole.log(result.pieces);\n```\n\n### `fit` - given bounded space, what fits, and what remains?\n\nBoxes have lids. `fit()` is for when overflow matters: what consumed the space,\nwhat could not, and what needs to go somewhere else.\n\n```js\nconst result = fit(longText, {\n  width: 360,\n  height: 240\n});\n\nconsole.log(result.content.consumed.text);\nconsole.log(result.content.remaining.text);\n```\n\n### `flow` - given content that overflows, where does it continue?\n\nMagazines and newspapers have known for centuries that content does not always\nfit in one box. `flow()` carries text through multiple regions and tells you\nexactly what landed where. Perfect for multi-column layouts, split panels, \nmagazine spreads.\n\n```js\nconst result = flow(longText, [\n  { width: 260, height: 320 },\n  { width: 260, height: 320 }\n]);\n\nconsole.log(result.placements.map((p) =\u003e p.pieces));\n```\n\n### `pour` - given a shape instead of a rectangle, fill it.\n\nNot every layout surface is a box. `pour()` fills text like water inside ANY \nshape - circles, polygons, image silhouettes, arbitrary geometry. \n\n```js\nconst shape = exclusion.circle({ x: 40, y: 40, radius: 140 });\nconst result = pour(longText, shape, {\n  width: 360,\n  height: 360,\n  fontSize: 16\n});\n\nconsole.log(result.pieces);\n```\n\n## Be Water, My Friend\n\nHere is that \"fifth\" element.\n\nRemember, *the highest virtue is like water*. Text in Layoutmaster is like water. \nIt fills, it bends, it flows, and it navigates around any obstacle you place in \nits path. Those obstacles are called exclusions - and they are one of the master's \nfinest tricks.\n\nExclusions are reusable spatial geometry. Build them from primitives or sample\nthem directly from image and video alpha channels. Pass them as obstacles to\n`form()` and `fit()`, or flip them inside out and use them as containers for\n`pour()`. They are serializable and replayable - compile the geometry once, use\nit everywhere, store it as JSON, replay it without the original source.\n\n```js\nexclusion.circle({ x, y, radius, gap });\nexclusion.rect({ x, y, width, height, gap });\nexclusion.ellipse({ x, y, width, height, gap });\nexclusion.polygon({ x, y, points, gap });\nexclusion.assembly({ x, y, parts, gap });\nexclusion.fromAlphaChannel(alpha, width, height, options);\nexclusion.fromJSON(savedData, options);\n```\n\nAssemblies are crude composed fields: circles, rectangles, ellipses, polygons,\nand line/capsule helpers merged into one obstacle. That makes them a good fit\nfor stick figures, mascots, diagrams, dragons, and other programmable shapes\nwhere speed matters more than perfect contours.\n\nThe dancing text demo builds exclusion assemblies from video frames and animates \nthem through `form()` with smooth framerate. The text renegotiates its path on \nevery frame around the actual shape of the figure in motion.\n\nNo CSS tricks. No pre-authored columns. Uses 1% of your CPU. No browser screaming \nat you in distress.\n\n## Performance\n\nBrowser layout is actually very fast. Those who claim their stuff is 600 times faster \nare lying, big time.\n\nBut Layoutmaster is just *as fast*, creating usual layouts just as beautifully and quickly \nas the browser would, so you can use it as a replacement for browser DOM-based layout on \nregular stuff without guilt. \n\nAnd mind you, the browser's layout engine is written in C++ with direct access to font \nmachinery and rendering internals. So the mere fact that the master hangs with it nicely \ntells you it is punching above its weight.\n\nBut *David would not have become a legend* if all he had done was throw one rock.\n\n### The Resize Test\n\nThis test is not about a benchmark table. It is about what happens when the layout has to \nkeep changing while the user is changing the available space. So I recorded it.\n\n\u003e **Watch the resize stress test:**\n\u003e\n\u003e \u003ca href=\"https://youtu.be/qy0HDfbuthw\"\u003e\n\u003e   \u003cimg src=\"https://i.ytimg.com/vi/qy0HDfbuthw/hqdefault.jpg\"\n\u003e     alt=\"Layoutmaster versus DOM masonry resize stress test\" width=\"480\"\u003e\n\u003e \u003c/a\u003e\n\nThe test is a masonry wall made from the same book content. Each chapter becomes a live card.\n\nLayoutmaster uses `fit()` to solve the text pieces, packs the cards,\nand paints the returned geometry. The browser version uses ordinary DOM/CSS flow.\n\nAs shown in the video, Layoutmaster keeps recomputing the whole wall in roughly the same \nbounded range - around 400ms for the 300+ card case - and snaps into the new geometry as the\nwindow changes. \n\nResize it slowly, resize it quickly, resize it violently: the solve remains explicit. Given \na width, the engine returns a wall.\n\nThe browser version does it in 4,000ms, which isn't so bad. Then it falls apart when you grab \nits window and resize. The layout goes into a frenzy and cannot settle until some 20+ seconds \nlater. Try harder, it can take even minutes to recover.\n\nThat's the whole point — when layout becomes highly dynamic and intense, it can overwhelm the\nbrowser. That's why you should leave the job to the specialist — \n\nLet Layoutmaster handle the layout for the browser, and let the browser handle everything else.\n\n## Footprint\n\nAt this point you probably picture the master as a burly man smoking a cigar and holding a \nGatling gun torn from a tank. \n\nNope. \n\nThe package packs to about 243 kB on npm - about 206 KiB gzip at runtime, the embedded\nengine included. \n\n**No other dependencies.**\n\nSo like the master (the other one) says: \n\n*Smaller in number are we, but larger in mind*.\n\n## Install\n\n```bash\nnpm install @layoutmaster/layoutmaster\n```\n\n*Layoutmaster is specifically built for the browser so it requires the Canvas\nAPI to be available. If you need non-browser solutions, head over to the sibling\nproject [VMPrint](https://github.com/cosmiciron/vmprint).*\n\n## Repo Map\n\n- [src](https://github.com/cosmiciron/layoutmaster/tree/main/src): the public package surface\n- [engine](https://github.com/cosmiciron/layoutmaster/tree/main/engine): the embedded engine copy built locally\n- [demos](https://github.com/cosmiciron/layoutmaster/tree/main/demos): browser demos and showcases\n- [demos/helpers](https://github.com/cosmiciron/layoutmaster/tree/main/demos/helpers): copyable helper source used by demos\n- [documents](https://github.com/cosmiciron/layoutmaster/tree/main/documents): API, rendering, helper, and product notes\n- [CONTRIBUTING.md](https://github.com/cosmiciron/layoutmaster/blob/main/CONTRIBUTING.md): local setup and project boundaries\n\nUseful reading:\n\n- [API reference](https://github.com/cosmiciron/layoutmaster/blob/main/documents/API-REFERENCE.md)\n- [Structured content](https://github.com/cosmiciron/layoutmaster/blob/main/documents/STRUCTURED-CONTENT.md)\n- [Painting pieces](https://github.com/cosmiciron/layoutmaster/blob/main/documents/PAINTING-PIECES.md)\n- [Piece contract](https://github.com/cosmiciron/layoutmaster/blob/main/documents/PIECE-CONTRACT.md)\n- [Helpers](https://github.com/cosmiciron/layoutmaster/blob/main/documents/HELPERS.md)\n\n## Run The Demos\n\n```bash\nnpm run serve\n```\n\nThe server starts at `http://127.0.0.1:4173/`. Open\n`http://127.0.0.1:4173/demos/` for the demo index.\n\nThe public demo site runs the published npm package through an ESM CDN, so it\nmatches what package consumers actually install.\n\nTo make demos use your local workspace source instead of the published package,\nappend `?local` to any demo URL.\n\nExamples:\n\n- `http://127.0.0.1:4173/demos/form.html?local`\n- `http://127.0.0.1:4173/demos/pour-image.html?local`\n\nWithout `?local`, demos import `@layoutmaster/layoutmaster` from the CDN.\n\nCurrent demos:\n\n- `form`: width-bounded fragments and returned pieces\n- `fit`: bounded layout with consumed and remaining content\n- `flow`: continuation through multiple targets\n- `bidi`: native browser BIDI rendering beside Layoutmaster's solved pieces\n- `browser-fonts`: browser font-scope probe with DOM text beside Layoutmaster pieces using the same CSS stack and native fallback\n- `pour`: text contained inside a primitive shape\n- `pour-image`: text contained inside image-derived alpha geometry\n- `pieces`: minimal piece and baseline inspection\n- `exclusion`: live primitive exclusion fields\n- `exclusion-assembly`: animated primitive assembly rig with hideable visual layer\n- `exclusion-image`: image alpha as wrap geometry\n- `masonry-book`: chapter cards packed from Layoutmaster `fit()` pieces\n- `dancing-text`: animated exclusion fields from video frames\n\nThe demos use browser import maps, so serve them from the repo root. Opening\nthe files directly from disk won't work well.\n\n## Helpers\n\nThe master keeps its package small. Browser image sampling, video frame\nextraction, and HTML piece painting live as source files under\n[demos/helpers](https://github.com/cosmiciron/layoutmaster/tree/main/demos/helpers).\nThey are official examples, not package exports.\n\nCopy them when they help. Change them when your app needs something different.\nThe deal is simple: helpers may prepare explicit inputs or paint returned\nresults. They do not get to make up layout geometry. That is the master's job.\n\n## The One Rule\n\nEvery layout decision belongs to the engine.\n\n- engine owns layout\n- wrapper owns normalization and result projection\n- helpers own adapter glue\n- demos own inspection and presentation\n- applications own rendering\n\nIf browser code starts inventing line breaks, baselines, page geometry, or\ncontinuation behavior, it has wandered into engine territory. Gently escort it\nback.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcosmiciron%2Flayoutmaster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcosmiciron%2Flayoutmaster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcosmiciron%2Flayoutmaster/lists"}