{"id":50999870,"url":"https://github.com/localvoid/aena","last_synced_at":"2026-06-20T13:30:49.394Z","repository":{"id":362244527,"uuid":"1257943656","full_name":"localvoid/aena","owner":"localvoid","description":"Rust macro-free HTML/SVG/MathML renderer","archived":false,"fork":false,"pushed_at":"2026-06-03T08:17:16.000Z","size":26,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T10:12:02.676Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/localvoid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-03T06:22:13.000Z","updated_at":"2026-06-03T08:17:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/localvoid/aena","commit_stats":null,"previous_names":["localvoid/aena"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/localvoid/aena","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localvoid%2Faena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localvoid%2Faena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localvoid%2Faena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localvoid%2Faena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/localvoid","download_url":"https://codeload.github.com/localvoid/aena/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localvoid%2Faena/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34572423,"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-20T02:00:06.407Z","response_time":98,"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":[],"created_at":"2026-06-20T13:30:45.745Z","updated_at":"2026-06-20T13:30:49.380Z","avatar_url":"https://github.com/localvoid.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aena\n\nLightweight HTML/SVG/MathML renderer.\n\n- **Dependencies**: `std`, `bytes`\n- **Composition**: components\n- **Escaping**: context-dependent escaping rules\n- **Macro-Free**: pure functions\n\n```rust\nuse bytes::BytesMut;\nuse aena::{render_html, html as h, CC};\n\nlet mut out = BytesMut::new();\nrender_html(\u0026mut out, |c| {\n    c.add(h::html((), |c: \u0026mut CC| {\n        c.add(h::head((), |c: \u0026mut CC| {\n            c.add(h::title((), \"Hello\"))\n        }))?;\n        c.add(h::body((), |c: \u0026mut CC| {\n            c.add(h::div(\"container\", |c: \u0026mut CC| {\n                c.add(h::h1((), \"Welcome\"))?;\n                c.add(h::p((), \"text\"))\n            }))\n        }))\n    }))?;\n    Ok(())\n})\n```\n\n## API\n\n### Element Factories\n\n`html`, `svg`, `mathml` modules provide element factories:\n\n```rust\nhtml::div((), \"content\")\nhtml::img(|a: \u0026mut AC| a.set(\"href\", \"logo.png\"))\nsvg::circle((), ())\n```\n\n- **HTML elements**: `html::div`, `html::span`, …\n- **HTML void elements**: `html::img`, `html::br`, …\n- **XML elements**: `svg::circle`, `mathml::mrow`, …\n\n### Attributes\n\n```rust\n// None\nhtml::div((), ())\n\n// Class shortcut (first arg)\nhtml::div(\"container\", \"text\")\nhtml::div((\"btn\", \"primary\"), \"text\")\n\n// Conditional classes\nhtml::div((\"btn\", is_active.then_some(\"active\")), ())\n\n// Inline styles\nhtml::div(|a: \u0026mut AC| {\n    a.set(\"style\", style(|s: \u0026mut SC| {\n        s.set(\"color\", \"red\")?;\n        s.set(\"font-size\", \"1rem\")\n    }))\n}, ())\n\n// Closure\nhtml::div(|a: \u0026mut AC| {\n    a.set(\"id\", \"main\")?;\n    a.set(\"data-val\", \"42\")?;\n    a.set(\"disabled\", true)\n}, ())\n```\n\n### Text\n\n```rust\nhtml::div((), \"escaped \u003ctext\u003e\")       // \u0026lt;text\u0026gt;\nhtml::div((), SafeStr(\"\u003craw\u003e\"))       // \u003craw\u003e (unescaped)\nhtml::div((), format_args!(\"{}\", n))  // formatted, escaped\n\n// Also works with children context `CC`\nhtml::div((), |c: \u0026mut CC| {\n    c.add(\"text\")\n})\n```\n\n### Components\n\nImplement `Render` on your types:\n\n```rust\nimpl Render for Button\u003c'_\u003e {\n    fn render(self, c: \u0026mut CC) -\u003e std::fmt::Result {\n        c.add(html::button(\n            |a: \u0026mut AC| {\n                a.set(\"class\", self.variant)?;\n                a.set(\"disabled\", self.disabled)\n            },\n            self.label,\n        ))\n    }\n}\n\nc.add(Button { label: \"Click\", disabled: false, variant: \"primary\" });\n```\n\n### Custom Elements\n\n```rust\nElement::new(\"my-tag\", \"class-name\", \"content\")\nVoidElement::new(\"my-void\", ())\nXmlElement::new(\"circle\", (\"big\",), ())\n```\n\n### Misc\n\n```rust\nhtml::Doctype // \u003c!doctype html\u003e\nComment(\"note\") // \u003c!-- note --\u003e\n```\n\n## Tradeoffs\n\nEverything is coupled to `BytesMut` rather than abstracting over `std::fmt::Write` to keep user code less verbose.\n\n## Features\n\nAll enabled by default:\n\n- `html` — HTML element factories\n- `svg` — SVG element factories\n- `mathml` — MathML element factories\n\n## License\n\nMIT or Apache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocalvoid%2Faena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocalvoid%2Faena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocalvoid%2Faena/lists"}