{"id":16545520,"url":"https://github.com/apiad/auditorium","last_synced_at":"2026-04-20T02:15:53.047Z","repository":{"id":44717628,"uuid":"224516225","full_name":"apiad/auditorium","owner":"apiad","description":"An HTML+CSS+JS generator from pure Python code","archived":false,"fork":false,"pushed_at":"2026-04-17T19:19:18.000Z","size":3117,"stargazers_count":83,"open_issues_count":9,"forks_count":14,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-04-17T21:34:32.445Z","etag":null,"topics":["html-css-javascript","python","visualization"],"latest_commit_sha":null,"homepage":"https://apiad.net/auditorium","language":"Python","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/apiad.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":"auditorium/__init__.py","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":"2019-11-27T21:00:22.000Z","updated_at":"2026-04-17T19:19:16.000Z","dependencies_parsed_at":"2025-09-06T14:33:13.264Z","dependency_job_id":"bbc98fc0-e720-401c-aef9-245400640f6d","html_url":"https://github.com/apiad/auditorium","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/apiad/auditorium","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apiad%2Fauditorium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apiad%2Fauditorium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apiad%2Fauditorium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apiad%2Fauditorium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apiad","download_url":"https://codeload.github.com/apiad/auditorium/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apiad%2Fauditorium/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32029863,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"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":["html-css-javascript","python","visualization"],"created_at":"2024-10-11T19:07:03.944Z","updated_at":"2026-04-20T02:15:53.025Z","avatar_url":"https://github.com/apiad.png","language":"Python","funding_links":[],"categories":["Libraries"],"sub_categories":["General HTML Generation"],"readme":"# Auditorium\n\n[\u003cimg alt=\"PyPI - License\" src=\"https://img.shields.io/pypi/l/auditorium.svg\"\u003e](https://github.com/apiad/auditorium/blob/master/LICENSE)\n[\u003cimg alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/auditorium.svg\"\u003e](https://pypi.org/project/auditorium/)\n[\u003cimg alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/auditorium.svg\"\u003e](https://pypi.org/project/auditorium/)\n\nAuditorium is a Python framework for live technical presentations. You write slides as `async def` functions in a plain `.py` file, and Auditorium runs them as a live presentation in your browser — complete with keypress-gated reveals, timed animations, LaTeX math, syntax-highlighted code, and flexible layouts.\n\n```python\nfrom auditorium import Deck\n\ndeck = Deck(title=\"My Talk\")\n\n@deck.slide\nasync def hello(ctx):\n    \"\"\"# Hello, World!\n\n    This is rendered from the **docstring**.\n    \"\"\"\n    await ctx.step()\n    await ctx.md(\"This appeared after pressing right arrow.\")\n```\n\n```bash\nauditorium run talk.py\n```\n\n## How it works\n\nEach slide is an `async def` decorated with `@deck.slide`. The docstring renders as Markdown when the slide loads. The function body is imperative Python that drives the presentation through awaitable primitives:\n\n- **Content:** `show(html)`, `hide(selector)`, `replace(selector, html)`, `set_class(selector, cls)`, `remove_class(selector, cls)`\n- **Markdown:** `md(text)`, `show_md(path)`\n- **Timing:** `step()` (wait for keypress), `sleep(seconds)`\n- **Layout:** `columns(sizing)`, `rows(sizing)`, `place(html, x, y)`\n\nA FastAPI server runs your slide functions and pushes DOM mutations over WebSocket to a minimal browser client. Each browser tab gets its own independent session — you can have multiple tabs on different slides simultaneously.\n\n## Installation\n\nRequires Python 3.12+.\n\n```bash\npip install auditorium\n```\n\nOr with uv:\n\n```bash\nuv add auditorium\n```\n\n## Usage\n\nCreate a file (e.g. `talk.py`) with a `Deck` instance and `@deck.slide` functions, then run:\n\n```bash\nauditorium run talk.py\n```\n\nOptions:\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--host` | `127.0.0.1` | Host to bind to |\n| `--port` | `8000` | Port to bind to |\n| `--no-open` | (opens browser) | Don't auto-open the browser |\n| `--no-watch` | (watches files) | Disable hot reload |\n\nHot reload is on by default — edit your `.py` file and the browser stays on the current slide while picking up changes. A small status dot in the bottom-left corner shows connection state (green = connected, red = disconnected, blinking orange = reconnecting).\n\n## Navigation\n\n| Key | Action |\n|-----|--------|\n| Right arrow / Space | Advance step, or next slide if no pending step |\n| Page Down | Skip to next slide (cancel remaining steps) |\n| Left arrow | Previous slide (re-runs from start) |\n| `r` | Restart current slide |\n| Digits + Enter | Jump to slide N |\n\n## Layouts\n\nLayout primitives return `Region` objects that scope insertion targets via `async with`:\n\n```python\n@deck.slide\nasync def side_by_side(ctx):\n    \"\"\"## Two Columns\"\"\"\n    left, right = await ctx.columns([2, 1])\n\n    async with left:\n        await ctx.md(\"Main content (2/3 width)\")\n\n    async with right:\n        await ctx.md(\"Sidebar (1/3 width)\")\n```\n\nSizing accepts integers (proportional), or `\"auto\"` for natural content size:\n\n```python\n@deck.slide\nasync def structured(ctx):\n    \"\"\"## Header / Body / Footer\"\"\"\n    header, body, footer = await ctx.rows([\"auto\", 1, \"auto\"])\n\n    async with header:\n        await ctx.md(\"### Fixed Header\")\n    async with footer:\n        await ctx.md(\"*Fixed footer*\")\n    async with body:\n        await ctx.md(\"Body stretches to fill remaining space.\")\n```\n\nAvailable: `columns(sizing)`, `rows(sizing)`, `place(html, x, y)`. They nest freely.\n\n## Features\n\n- **Markdown docstrings** — slide content as prose, right next to the code\n- **Progressive reveals** — `await ctx.step()` pauses for a keypress\n- **Timed animations** — `await ctx.sleep(seconds)` for automatic pacing\n- **LaTeX math** — KaTeX via CDN, use `$...$` or `$$...$$` in Markdown\n- **Code highlighting** — fenced code blocks highlighted by highlight.js\n- **Flexible layouts** — `columns`, `rows`, `place` with `\"auto\"` sizing\n- **Hot reload** — edit and see changes instantly, staying on the same slide\n- **Independent sessions** — each browser tab runs its own slide independently\n- **Reconnection** — survives server restarts without losing your place\n- **No build step** — Tailwind, KaTeX, and highlight.js loaded via CDN\n\n## Example\n\nSee [`examples/demo_deck.py`](examples/demo_deck.py) for a complete deck exercising every feature.\n\n```bash\nauditorium run examples/demo_deck.py\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapiad%2Fauditorium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapiad%2Fauditorium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapiad%2Fauditorium/lists"}