{"id":34502675,"url":"https://github.com/sylvainhalle/lua-pagemaker","last_synced_at":"2025-12-24T02:11:36.628Z","repository":{"id":328228101,"uuid":"1114719116","full_name":"sylvainhalle/lua-pagemaker","owner":"sylvainhalle","description":"Magazine-Style Page Layouts in Pure LaTeX","archived":false,"fork":false,"pushed_at":"2025-12-16T14:42:18.000Z","size":708,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-20T05:24:24.679Z","etag":null,"topics":["dtp","latex-template","lualatex","publishing"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sylvainhalle.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2025-12-11T19:33:38.000Z","updated_at":"2025-12-17T19:53:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sylvainhalle/lua-pagemaker","commit_stats":null,"previous_names":["sylvainhalle/lua-pagemaker"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sylvainhalle/lua-pagemaker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2Flua-pagemaker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2Flua-pagemaker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2Flua-pagemaker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2Flua-pagemaker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sylvainhalle","download_url":"https://codeload.github.com/sylvainhalle/lua-pagemaker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2Flua-pagemaker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27992997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"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":["dtp","latex-template","lualatex","publishing"],"created_at":"2025-12-24T02:11:35.212Z","updated_at":"2025-12-24T02:11:36.621Z","avatar_url":"https://github.com/sylvainhalle.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"lua-pagemaker: Magazine-Style Page Layouts in Pure LaTeX\n======================================================\n\n[![Screenshot](Example/Preview.jpg?raw=true)](Example/paper.pdf?raw=true)\n\n**Did you know you can reproduce an IEEE *Spectrum*-style page layout in pure LaTeX?**\n\nWhy lua-pagemaker?\n\nLaTeX excels at structure, mathematics, and text composition — but page layout remains rigid.\n\nEven with advanced packages, creating designed, magazine-style layouts (multiple columns of arbitrary widths, figures spanning columns, sidebars, banners) is difficult and often fragile. Most solutions rely on floats and heuristics, which makes precise layout control hard to achieve and hard to reproduce.\n\nlua-pagemaker addresses this gap by separating concerns:\n\n- Lua computes page geometry deterministically.\n- LaTeX flows text into precomputed frames.\n- No floats, no guessing, no page-breaking heuristics.\n\nEach page is described declaratively in a small Lua DSL. At compile time, Lua computes all frame coordinates and emits the corresponding flowfram primitives. LaTeX then behaves like a DTP engine: text flows into fixed regions exactly as specified.\n\nThe goal is predictable, reproducible, magazine-style layout: closer in spirit to Aldus PageMaker or InDesign than to newspaper-style balancing.\n\nThis approach is especially useful for:\n\n- magazine articles\n- research papers with complex layouts\n- documents mixing text, code, screenshots, and diagrams\n- situations where exact geometry matters more than automatic balancing\n\n## Example: an IEEE *Spectrum*-like page\n\nThe repository includes an example very close to a pixel-perfect reproduction of a layout from the [*IEEE Spectrum* magazine](https://spectrum.ieee.org/magazine/2025/december/) (see image above).\n\nYou can generate pages containing:\n\n- a hero image\n- a large pull-quote\n- columns of different widths\n- bottom-aligned figures\n- decorative horizontal and vertical rules\n\n## Quick Start\n\n### 1. Clone the repository\n\n```bash\ngit clone https://github.com/sylvainhalle/lua-pagemaker.git\ncd lua-pagemaker\n```\n\n### 2. Compile the example\n\n```bash\nlualatex example.tex\n```\n\nYou must use **LuaLaTeX**.\n\n### 3. Modify `pages.lua`\n\nAdjust pages, columns, static boxes, and decorative rule positions.\n\n### Example page configuration\n\n```lua\nreturn {\n  width  = 7.88,\n  height = 10.75,\n  left   = 0.5,\n  right  = 0.75,\n  top    = 0.5,\n  bottom = 0.75,\n\n  colsep    = 0.25,\n  figtop    = 0,\n  figbottom = 0.5,\n\n  pages = {\n    {\n      cols = 2,\n      boxes = {\n        { name=\"topbanner\", colfrom=1, colto=2,\n          top=0, h=3.875 }\n      }\n    },\n\n    {\n      cols = 3,\n      boxes = {\n        { name=\"guifig\", colfrom=2, colto=3,\n          top=0,\n          image=\"fig/GUI_pipe.png\",\n          label=\"fig:bbgui\",\n          figbottom=1,\n          caption=\"A pipeline in BeepBeep Studio\" },\n\n        { name=\"code-examples\", colfrom=1, colto=2,\n          bottom=0, h=2.5 }\n      }\n    }\n  }\n}\n```\n\n## Core Ideas\n\n### Declarative page layouts (in Lua)\n\nEach page is described in `pages.lua` as a clean, readable structure:\n\n- global page geometry  \n- a list of pages  \n- each page defines:\n  - its own **columns** (with arbitrary fractional widths)\n  - optional **static boxes**\n  - optional **decorative borders**\n\nThe system encourages thinking like a magazine designer: columns, blocks, banners, sidebars — not TeX primitives.\n\n### Static frames and flow frames\n\n`lua-pagemaker` distinguishes two categories:\n\n**Flow frames**  \nWhere your normal body text goes.  \nEach column is automatically clipped above and below to avoid overlapping static boxes.\n\n**Static frames**  \nReserved space for:\n\n- hero images  \n- banners  \n- sidebars  \n- bottom boxes  \n- pull quotes  \n\nStatic frames can be anchored:\n\n- at the top (`top = ...`)\n- or the bottom (`bottom = ...`)\n- and can span any range of columns (`colfrom`–`colto`)\n\nStatic boxes may also specify:\n\n- `image = \"foo.png\"` → height computed from aspect ratio  \n- `valign = \"t\" | \"c\" | \"b\"` → vertical alignment inside the box  \n\n### Coordinates in screen space\n\nCoordinates are given in an intuitive system:\n\n- origin = top-left of the text block\n- *x* grows to the right\n- *y* grows downward\n\nThis mirrors CSS, SVG, and GUI toolkits.  \n`layout.lua` converts to TeX’s bottom-left–based coordinates automatically.\n\n### Works with any class or page size\n\nYou specify:\n\n```lua\nwidth  = 7.88,\nheight = 10.5,\nleft   = 0.5,\nright  = 0.5,\ntop    = 0.75,\nbottom = 1.0,\ncolsep = 0.25,\n```\n\n`lua-pagemaker` computes the text block and uses it as the reference system for all coordinates.\n\n## Features\n\n- Per-page column definitions  \n- Arbitrary (fractional) column widths  \n- Static boxes spanning multiple columns  \n- Image-based automatic box height  \n- Simple DSL for decorative rules (`hline_left`, `hline_right`, `vline_left`, `vline_right`)  \n- TikZ overlay for line drawing  \n- Coordinates in inches  \n- Lua-based preprocessing for predictable TeX output  \n\n\n## How It Works\n\nThe system uses three components.\n\n### 1. `pages.lua` — Declarative layout description\n\nThis file does **not** contain logic.  \nIt receives a DSL table (`dsl`) and returns a configuration table.\n\nExample (simplified):\n\n```lua\nreturn function(dsl)\n  local hline_right = dsl.hline_right\n  local vline_right = dsl.vline_right\n\n  local config = {\n    width  = 7.88,\n    height = 10.5,\n    top    = 0.75,\n    bottom = 1.0,\n    left   = 0.5,\n    right  = 0.5,\n    colsep = 0.25,\n    pages  = {}\n  }\n\n  local H = config.height\n  local T = config.top\n  local B = config.bottom\n\n  config.pages[1] = {\n    columns = {\n      { width = 1/2 },\n      { width = 1/2 }\n    },\n    boxes = {\n      {\n        name    = \"hero\",\n        colfrom = 1, colto = 2,\n        top     = 0,\n        h       = 5.5\n      }\n    },\n    borders = {\n      hline_right(0.6),\n      vline_right(1.5, 0)\n    }\n  }\n\n  return config\nend\n```\n\n### 2. `layout.lua` — Geometry engine\n\nThis script:\n\n- creates the DSL helpers (`hline_right`, `vline_left`, etc.)\n- loads and evaluates `pages.lua`\n- computes:\n  - the text block dimensions\n  - column coordinates\n  - how static boxes clip columns\n  - positions of decorative borders\n- emits:\n  - `\\newflowframe` for text columns  \n  - `\\newstaticframe` for boxes  \n- installs a TikZ overlay for line drawing\n\nYou load it in the preamble:\n\n```latex\n\\directlua{dofile(\"layout.lua\")}\n```\n\n### 3. Your LaTeX document\n\nYour TeX file defines the content of static boxes:\n\n```latex\n\\begin{staticcontents*}{hero}\n  \\centering\n  \\includegraphics[width=\\textwidth]{fig/hero.png}\n\\end{staticcontents*}\n```\n\nThen you write the body text normally. It automatically flows into whatever frames the Lua layer defined.\n\n## Limitations\n\n- Requires **LuaLaTeX** (not pdfLaTeX or XeLaTeX).\n- May conflict with packages that heavily alter page breaking.\n- No automatic column balancing (by design).\n- With highly variable column widths and deep static boxes, `flowfram` may warn about unequal frame widths.\n\n\n## Roadmap / Ideas\n\n- Anchor-based positioning (`anchor=\"top-right\"`, with `dx`, `dy` offsets).\n- Predefined layout templates (`threecol_topfigure`, `sidebar_right`, etc.).\n- Debug overlay showing all frames.\n- Conversion into a package (`lua-pagemaker.sty`).\n- Visual tooling for debugging layouts.\n\n## License\n\nMIT License.  \nYou are free to use, modify, and distribute.\n\n\n## Acknowledgements\n\n- Hans Hagen and the LuaTeX team  \n- Nicola Talbot for `flowfram`  \n- The Lua community  \n- Everyone who wants LaTeX to behave a little more like a real DTP engine\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsylvainhalle%2Flua-pagemaker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsylvainhalle%2Flua-pagemaker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsylvainhalle%2Flua-pagemaker/lists"}