{"id":48364763,"url":"https://github.com/brewkits/hyper_render","last_synced_at":"2026-04-05T14:03:14.526Z","repository":{"id":343013884,"uuid":"1122527701","full_name":"brewkits/hyper_render","owner":"brewkits","description":"A custom layout engine for Flutter that renders HTML, Markdown, and Quill Delta   in a single RenderObject. Supports CSS float, flexbox, grid, CJK Ruby/furigana,   and cross-document text selection.","archived":false,"fork":false,"pushed_at":"2026-04-02T05:18:33.000Z","size":28221,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-02T17:37:22.489Z","etag":null,"topics":["cjk","css","css-grid","dart","document-viewer","flexbox","float-layout","flutter","flutter-plugin","html-parser","html-renderer","layout-engine","markdown-renderer","quill-delta","render-engine","rich-text","ruby-furigana","text-selection","typography","xss-sanitization"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/hyper_render","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brewkits.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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":"2025-12-25T00:02:29.000Z","updated_at":"2026-04-02T05:18:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/brewkits/hyper_render","commit_stats":null,"previous_names":["brewkits/hyper_render"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/brewkits/hyper_render","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brewkits%2Fhyper_render","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brewkits%2Fhyper_render/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brewkits%2Fhyper_render/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brewkits%2Fhyper_render/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brewkits","download_url":"https://codeload.github.com/brewkits/hyper_render/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brewkits%2Fhyper_render/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31437927,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T13:13:19.330Z","status":"ssl_error","status_checked_at":"2026-04-05T13:13:17.778Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cjk","css","css-grid","dart","document-viewer","flexbox","float-layout","flutter","flutter-plugin","html-parser","html-renderer","layout-engine","markdown-renderer","quill-delta","render-engine","rich-text","ruby-furigana","text-selection","typography","xss-sanitization"],"created_at":"2026-04-05T14:03:13.800Z","updated_at":"2026-04-05T14:03:14.513Z","avatar_url":"https://github.com/brewkits.png","language":"Dart","readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/logo.svg\" width=\"96\" alt=\"HyperRender logo\" /\u003e\n\n# HyperRender\n\n### Fast, robust HTML rendering for Flutter.\n\n[![pub.dev](https://img.shields.io/pub/v/hyper_render.svg?label=pub.dev\u0026color=0175C2)](https://pub.dev/packages/hyper_render)\n[![pub points](https://img.shields.io/pub/points/hyper_render?label=pub%20points\u0026color=00b4ab)](https://pub.dev/packages/hyper_render/score)\n[![likes](https://img.shields.io/pub/likes/hyper_render?color=FF6B6B)](https://pub.dev/packages/hyper_render/score)\n[![CI](https://github.com/brewkits/hyper_render/actions/workflows/analyze.yml/badge.svg)](https://github.com/brewkits/hyper_render/actions)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Flutter](https://img.shields.io/badge/Flutter-3.10+-54C5F8.svg?logo=flutter)](https://flutter.dev)\n\n**CSS float · crash-free selection · CJK/Furigana · `@keyframes` · Flexbox/Grid · XSS-safe**\n\n[**Quick Start**](#-quick-start) · [**Why Switch?**](#️-why-switch-the-architecture-argument) · [**API**](#-api-reference) · [**Packages**](#-packages)\n\n\u003c/div\u003e\n\n---\n\n## Demos\n\n| CSS Float Layout | Ruby / Furigana | Crash-Free Selection |\n|:---:|:---:|:---:|\n| ![CSS Float Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/float_demo.gif) | ![Ruby Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/ruby_demo.gif) | ![Selection Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/selection_demo.gif) |\n| Text wraps around floated images — no other Flutter HTML renderer does this | Furigana centered above base glyphs, full Kinsoku line-breaking | Select across headings, paragraphs, tables — tested to 100 000 chars |\n\n| Advanced Tables | Head-to-Head | Virtualized Mode |\n|:---:|:---:|:---:|\n| ![Table Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/table_demo.gif) | ![Comparison Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/comparison_demo.gif) | ![Performance Demo](https://raw.githubusercontent.com/brewkits/hyper_render/main/assets/performance_demo.gif) |\n| `colspan` · `rowspan` · W3C 2-pass column algorithm | Same HTML in HyperRender vs flutter_widget_from_html | Virtualized rendering — 60 FPS on documents of any length |\n\n---\n\n## 🚀 Quick Start\n\n```yaml\ndependencies:\n  hyper_render: ^1.2.2\n```\n\n```dart\nimport 'package:hyper_render/hyper_render.dart';\n\nHyperViewer(\n  html: articleHtml,\n  onLinkTap: (url) =\u003e launchUrl(Uri.parse(url)),\n)\n```\n\nZero configuration. XSS sanitization is **on by default**.\n\n\u003e **Android note:** `hyper_render` depends on `super_clipboard` which transitively pulls in `irondash_engine_context`. That library was compiled against Android SDK 31, but its `androidx.fragment:1.7.1` dependency requires `compileSdk ≥ 34`. Add this one-time workaround to your `android/build.gradle.kts`:\n\u003e\n\u003e ```kotlin\n\u003e // android/build.gradle.kts  (root — not app/build.gradle.kts)\n\u003e subprojects {\n\u003e     afterEvaluate {\n\u003e         extensions.findByType(com.android.build.gradle.LibraryExtension::class.java)?.apply {\n\u003e             compileSdk = 35\n\u003e         }\n\u003e     }\n\u003e }\n\u003e ```\n\u003e\n\u003e This overrides `compileSdk` for all library sub-projects so AGP's `checkAarMetadata` passes. Tracked in [#5](https://github.com/brewkits/hyper_render/issues/5).\n\n---\n\n## 🏗️ Why Switch? The Architecture Argument\n\nMost Flutter HTML libraries map each HTML tag to a Flutter widget. A 3 000-word article becomes **500+ nested widgets** — and some layout primitives simply cannot be expressed that way:\n\n\u003e **CSS `float` is not possible in a widget tree.**\n\u003e Wrapping text around a floated image requires every fragment's coordinates before adjacent text can be composed. That geometry only exists when a single `RenderObject` owns the entire layout.\n\nHyperRender renders the whole document inside **one custom `RenderObject`**. Float, crash-free selection, and sub-millisecond binary-search hit-testing all follow from that single design decision.\n\n### Feature Matrix\n\n| Feature | `flutter_html` | `flutter_widget_from_html` | **HyperRender** |\n|---|:---:|:---:|:---:|\n| `float: left / right` | ❌ | ❌ | ✅ |\n| Text selection — large docs | ❌ Crashes | ❌ Crashes | ✅ Crash-free |\n| Ruby / Furigana | ❌ Raw text | ❌ Raw text | ✅ |\n| `\u003cdetails\u003e` / `\u003csummary\u003e` | ❌ | ❌ | ✅ Interactive |\n| CSS Variables `var()` | ❌ | ❌ | ✅ |\n| CSS `@keyframes` | ❌ | ❌ | ✅ |\n| Flexbox / Grid | ⚠️ Partial | ⚠️ Partial | ✅ Full |\n| Box shadow · `filter` | ❌ | ❌ | ✅ |\n| SVG `\u003cimg src=\"*.svg\"\u003e` | ⚠️ | ⚠️ | ✅ |\n\n### Benchmarks\n\nMeasured on iPhone 13 + Pixel 6 with a 25 000-character article:\n\n| Metric | `flutter_html` | `flutter_widget_from_html` | **HyperRender** |\n|---|:---:|:---:|:---:|\n| Widgets created | ~600 | ~500 | **3–5 chunks** |\n| First parse | 420 ms | 250 ms | **95 ms** |\n| Peak RAM | 28 MB | 15 MB | **8 MB** |\n| Scroll FPS | ~35 | ~45 | **60** |\n\n---\n\n## Features\n\n### CSS Float — Magazine Layouts\n\n```dart\nHyperViewer(html: '''\n  \u003carticle\u003e\n    \u003cimg src=\"photo.jpg\" style=\"float:left; width:180px; margin:0 16px 8px 0; border-radius:8px;\" /\u003e\n    \u003ch2\u003eThe Art of Layout\u003c/h2\u003e\n    \u003cp\u003eText wraps around the image exactly like a browser — because HyperRender\n    uses the same block formatting context algorithm.\u003c/p\u003e\n  \u003c/article\u003e\n''')\n```\n\n### Crash-Free Text Selection\n\n```dart\nHyperViewer(\n  html: longArticleHtml,\n  selectable: true,\n  showSelectionMenu: true,\n  selectionHandleColor: Colors.blue,\n)\n```\n\nOne continuous span tree. Selection crosses headings, paragraphs, and table cells.\nO(log N) binary-search hit-testing stays instant on 1 000-line documents.\n\n### CJK Typography — Ruby / Furigana\n\n```dart\nHyperViewer(html: '''\n  \u003cp style=\"font-size:20px; line-height:2;\"\u003e\n    \u003cruby\u003e東京\u003crt\u003eとうきょう\u003c/rt\u003e\u003c/ruby\u003eで\n    \u003cruby\u003e日本語\u003crt\u003eにほんご\u003c/rt\u003e\u003c/ruby\u003eを学ぶ\n  \u003c/p\u003e\n''')\n```\n\nFurigana centered above base characters. Kinsoku shori applied across the full line.\nRuby copied to clipboard as `東京(とうきょう)`.\n\n### CSS Variables · Flexbox · Grid\n\n```dart\nHyperViewer(html: '''\n  \u003cstyle\u003e\n    :root { --brand: #6750A4; --surface: #F3EFF4; }\n  \u003c/style\u003e\n  \u003cdiv style=\"display:grid; grid-template-columns:1fr 1fr; gap:12px;\"\u003e\n    \u003cdiv style=\"background:var(--brand); color:white; padding:16px; border-radius:12px;\"\u003e\n      Column one — themed with CSS custom properties\n    \u003c/div\u003e\n    \u003cdiv style=\"background:var(--surface); padding:16px; border-radius:12px;\"\u003e\n      Column two — same token system\n    \u003c/div\u003e\n  \u003c/div\u003e\n''')\n```\n\n### CSS `@keyframes` Animation\n\n```html\n\u003cstyle\u003e\n  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n  @keyframes slideUp { from { transform: translateY(24px); opacity: 0; }\n                       to   { transform: translateY(0);    opacity: 1; } }\n  .hero { animation: fadeIn 0.6s ease-out; }\n  .card { animation: slideUp 0.4s ease-out; }\n\u003c/style\u003e\n\u003cdiv class=\"hero\"\u003e\u003ch1\u003eWelcome\u003c/h1\u003e\u003c/div\u003e\n\u003cdiv class=\"card\"\u003e\u003cp\u003eAnimated without any Dart code.\u003c/p\u003e\u003c/div\u003e\n```\n\nParsed from `\u003cstyle\u003e` tags automatically — supports `opacity`, `transform`, vendor-prefixed variants,\nand percentage selectors.\n\n### XSS Sanitization — Safe by Default\n\n```dart\n// Safe — strips \u003cscript\u003e, on* handlers, javascript: URLs\nHyperViewer(html: userGeneratedContent)\n\n// Custom allowlist for stricter sandboxing\nHyperViewer(html: userContent, allowedTags: ['p', 'a', 'img', 'strong', 'em'])\n\n// Disable only for fully trusted, internal HTML\nHyperViewer(html: trustedCmsHtml, sanitize: false)\n```\n\n\u003e **Inline SVG note**: `\u003csvg\u003e` and `\u003cmath\u003e` are stripped by default because inline SVG can embed `\u003cscript\u003e` payloads. External SVG via `\u003cimg src=\"*.svg\"\u003e` is fully supported. Add `'svg'` to `allowedTags` only for content you fully control.\n\n### Multi-Format Input\n\n```dart\nHyperViewer(html: '\u003ch1\u003eHello\u003c/h1\u003e\u003cp\u003eWorld\u003c/p\u003e')\nHyperViewer.delta(delta: '{\"ops\":[{\"insert\":\"Hello\\\\n\"}]}')\nHyperViewer.markdown(markdown: '# Hello\\n\\n**Bold** and _italic_.')\n```\n\n### Screenshot Export\n\n```dart\nfinal captureKey = GlobalKey();\nHyperViewer(html: articleHtml, captureKey: captureKey)\n\n// Export to PNG bytes\nfinal png = await captureKey.toPngBytes();\nfinal hd  = await captureKey.toPngBytes(pixelRatio: 3.0);\n```\n\n### Hybrid WebView Fallback\n\n```dart\nHyperViewer(\n  html: maybeComplexHtml,\n  fallbackBuilder: (context) =\u003e WebViewWidget(controller: _webViewController),\n)\n```\n\n---\n\n## 📖 API Reference\n\n### `HyperViewer`\n\n```dart\nHyperViewer({\n  required String html,\n  String? baseUrl,           // resolves relative \u003cimg src\u003e and \u003ca href\u003e\n  String? customCss,         // injected after the document's own \u003cstyle\u003e tags\n  bool selectable = true,\n  bool sanitize = true,\n  List\u003cString\u003e? allowedTags,\n  HyperRenderMode mode = HyperRenderMode.auto, // sync | virtualized | paged | auto\n  bool enableZoom = false,\n  void Function(String)? onLinkTap,\n  HyperWidgetBuilder? widgetBuilder,           // custom widget injection\n  WidgetBuilder? fallbackBuilder,\n  WidgetBuilder? placeholderBuilder,\n  GlobalKey? captureKey,\n  bool showSelectionMenu = true,\n  String? semanticLabel,\n  HyperViewerController? controller,\n  HyperPageController? pageController,         // paged mode only\n  HyperPluginRegistry? pluginRegistry,         // custom tag plugins\n  void Function(Object, StackTrace)? onError,\n})\n\nHyperViewer.delta(delta: jsonString, ...)\nHyperViewer.markdown(markdown: markdownString, ...)\n```\n\n### `HyperRenderMode`\n\n| Value | Behaviour |\n|---|---|\n| `auto` | Sync for ≤ 10 000 chars, async virtualized otherwise |\n| `sync` | Always render synchronously in a single scroll view |\n| `virtualized` | `ListView.builder` — only visible sections built/painted |\n| `paged` | `PageView.builder` — one section per page (e-book / reader UI) |\n\n### `HyperPageController` (paged mode)\n\n```dart\nfinal ctrl = HyperPageController();\n\nHyperViewer(html: html, mode: HyperRenderMode.paged, pageController: ctrl)\n\nctrl.nextPage(duration: Duration(milliseconds: 300), curve: Curves.easeInOut);\nctrl.animateToPage(2, duration: Duration(milliseconds: 300), curve: Curves.easeInOut);\nctrl.jumpToPage(0);\n\n// Reactive page indicator:\nValueListenableBuilder\u003cint\u003e(\n  valueListenable: ctrl.currentPage,\n  builder: (_, page, __) =\u003e Text('Page ${page + 1} of ${ctrl.pageCount}'),\n)\n```\n\n### Plugin API — Custom HTML Tags\n\nRegister custom tag renderers via `HyperPluginRegistry`. Two tiers:\n\n- **Block** (`isInline == false`): full-width widget with CSS margins\n- **Inline** (`isInline == true`): flows with text; intrinsic size measured automatically\n\n```dart\nclass MyCardPlugin implements HyperNodePlugin {\n  @override String get tagName =\u003e 'my-card';\n  @override bool get isInline =\u003e false;\n\n  @override\n  Widget? build(HyperPluginBuildContext ctx) {\n    return Card(child: Text(ctx.node.textContent));\n    // Return null to fall through to default rendering.\n  }\n}\n\nfinal registry = HyperPluginRegistry()..register(MyCardPlugin());\nHyperViewer(html: '\u003cmy-card\u003eHello\u003c/my-card\u003e', pluginRegistry: registry)\n```\n\n### `HyperViewerController`\n\n```dart\nfinal ctrl = HyperViewerController();\nHyperViewer(html: html, controller: ctrl)\n\nctrl.jumpToAnchor('section-2');   // scroll to \u003ca name=\"section-2\"\u003e\nctrl.scrollToOffset(1200);        // absolute pixel offset\n```\n\n### Custom Widget Injection\n\n```dart\nHyperViewer(\n  html: html,\n  widgetBuilder: (context, node) {\n    if (node is AtomicNode \u0026\u0026 node.tagName == 'iframe') {\n      return YoutubePlayer(url: node.attributes['src'] ?? '');\n    }\n    return null; // fall back to default rendering\n  },\n)\n```\n\n### `HtmlHeuristics` — Introspect Before Rendering\n\n```dart\nif (HtmlHeuristics.isComplex(html)) {\n  // use HyperRenderMode.virtualized for long documents\n}\nHtmlHeuristics.hasComplexTables(html)\nHtmlHeuristics.hasUnsupportedCss(html)\nHtmlHeuristics.hasUnsupportedElements(html)\n```\n\n---\n\n## Architecture\n\n```\nHTML / Markdown / Quill Delta\n          │\n          ▼\n   ADAPTER LAYER         HtmlAdapter · MarkdownAdapter · DeltaAdapter\n          │\n          ▼\n  UNIFIED DOCUMENT TREE  BlockNode · InlineNode · AtomicNode\n                         RubyNode · TableNode · FlexContainerNode · GridNode\n          │\n          ▼\n    CSS RESOLVER          specificity cascade · var() · calc() · inheritance\n          │\n          ▼\n  SINGLE RenderObject     BFC · IFC · Float · Flexbox · Grid · Table\n                          Canvas painting · continuous span tree\n                          Kinsoku · O(log N) binary-search selection\n```\n\n- **Single RenderObject** — float layout and crash-free selection require one shared coordinate system\n- **O(1) CSS rule lookup** — rules indexed by tag / class / ID; constant time regardless of stylesheet size\n- **O(log N) hit-testing** — `_lineStartOffsets[]` precomputed at layout time; each touch is a binary search\n- **RepaintBoundary per chunk** — unmodified chunks are composited, not repainted\n\n---\n\n## When NOT to Use\n\n| Need | Better choice |\n|------|--------------|\n| Execute JavaScript | `webview_flutter` |\n| Interactive web forms / input | `webview_flutter` |\n| Rich text editing | `super_editor`, `fleather` |\n| `position: fixed`, `\u003ccanvas\u003e`, media queries | `webview_flutter` (use `fallbackBuilder`) |\n| Maximum CSS coverage, float/CJK not required | `flutter_widget_from_html` |\n\n---\n\n## ♿ Accessibility (WCAG 2.1 AA)\n\n- **Image alt text** (WCAG 1.1.1): `\u003cimg alt=\"…\"\u003e` elements produce a discrete `SemanticsNode` at the image's layout rect — screen-reader users can navigate to images element-by-element.\n- **`aria-label` on links** (WCAG 4.1.2): `\u003ca aria-label=\"…\"\u003e` uses the attribute value as the accessible label instead of text content.\n\n```html\n\u003cimg src=\"chart.png\" alt=\"Q3 revenue chart — $2.4M, up 18% YoY\"\u003e\n\u003ca href=\"/privacy\" aria-label=\"Privacy policy (opens in new tab)\"\u003ePrivacy\u003c/a\u003e\n```\n\n---\n\n## 📦 Packages\n\n| Package | pub.dev | Description |\n|---------|---------|-------------|\n| [`hyper_render`](https://pub.dev/packages/hyper_render) | [![pub](https://img.shields.io/pub/v/hyper_render.svg)](https://pub.dev/packages/hyper_render) | Convenience wrapper — one dependency, everything included |\n| [`hyper_render_core`](https://pub.dev/packages/hyper_render_core) | [![pub](https://img.shields.io/pub/v/hyper_render_core.svg)](https://pub.dev/packages/hyper_render_core) | Core engine — UDT model, CSS resolver, RenderObject |\n| [`hyper_render_html`](https://pub.dev/packages/hyper_render_html) | [![pub](https://img.shields.io/pub/v/hyper_render_html.svg)](https://pub.dev/packages/hyper_render_html) | HTML + CSS parser |\n| [`hyper_render_markdown`](https://pub.dev/packages/hyper_render_markdown) | [![pub](https://img.shields.io/pub/v/hyper_render_markdown.svg)](https://pub.dev/packages/hyper_render_markdown) | Markdown adapter (GFM) |\n| [`hyper_render_highlight`](https://pub.dev/packages/hyper_render_highlight) | [![pub](https://img.shields.io/pub/v/hyper_render_highlight.svg)](https://pub.dev/packages/hyper_render_highlight) | Syntax highlighting for `\u003ccode\u003e` / `\u003cpre\u003e` blocks |\n| [`hyper_render_clipboard`](https://pub.dev/packages/hyper_render_clipboard) | [![pub](https://img.shields.io/pub/v/hyper_render_clipboard.svg)](https://pub.dev/packages/hyper_render_clipboard) | Image copy / share |\n| [`hyper_render_devtools`](https://pub.dev/packages/hyper_render_devtools) | [![pub](https://img.shields.io/pub/v/hyper_render_devtools.svg)](https://pub.dev/packages/hyper_render_devtools) | Flutter DevTools extension — UDT inspector, computed styles |\n\n---\n\n## Contributing\n\n```bash\ngit clone https://github.com/brewkits/hyper_render.git\ncd hyper_render\nflutter pub get\nflutter test\ndart format --set-exit-if-changed .\nflutter analyze --fatal-infos\n```\n\nSee [Architecture Decision Records](doc/adr/) and [Contributing Guide](doc/CONTRIBUTING.md) before submitting a PR.\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n[![GitHub stars](https://img.shields.io/github/stars/brewkits/hyper_render?style=social)](https://github.com/brewkits/hyper_render)\n\n[pub.dev](https://pub.dev/packages/hyper_render) · [API docs](https://pub.dev/documentation/hyper_render/latest/) · [Changelog](CHANGELOG.md) · [Roadmap](doc/ROADMAP.md)\n\n\u003c/div\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrewkits%2Fhyper_render","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrewkits%2Fhyper_render","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrewkits%2Fhyper_render/lists"}