{"id":50791832,"url":"https://github.com/pal-tamas/rask","last_synced_at":"2026-07-13T07:01:17.866Z","repository":{"id":357145388,"uuid":"1235366179","full_name":"pal-tamas/rask","owner":"pal-tamas","description":"Live apps in C# — server-rendered over WebSockets, client-side via WebAssembly, or native iOS/Android, from one codebase. No .razor, no JS.","archived":false,"fork":false,"pushed_at":"2026-07-09T22:03:38.000Z","size":6446,"stargazers_count":25,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-09T22:13:41.971Z","etag":null,"topics":["android","blazor-alternative","components","csharp","dotnet","dotnet10","hybrid-app","ios","mobile","native","scoped-css","server-side-rendering","source-generator","wasm","web-framework","webassembly","websockets"],"latest_commit_sha":null,"homepage":"https://pal-tamas.github.io/rask/","language":"C#","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/pal-tamas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","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-05-11T08:56:07.000Z","updated_at":"2026-07-09T21:54:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pal-tamas/rask","commit_stats":null,"previous_names":["pal-tamas/rask"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/pal-tamas/rask","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pal-tamas%2Frask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pal-tamas%2Frask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pal-tamas%2Frask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pal-tamas%2Frask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pal-tamas","download_url":"https://codeload.github.com/pal-tamas/rask/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pal-tamas%2Frask/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35413542,"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-07-13T02:00:06.543Z","response_time":119,"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":["android","blazor-alternative","components","csharp","dotnet","dotnet10","hybrid-app","ios","mobile","native","scoped-css","server-side-rendering","source-generator","wasm","web-framework","webassembly","websockets"],"created_at":"2026-06-12T12:00:15.513Z","updated_at":"2026-07-13T07:01:17.860Z","avatar_url":"https://github.com/pal-tamas.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"assets/rask-logo-dark.svg\"\u003e\n  \u003cimg alt=\"Rask\" src=\"assets/rask-logo.svg\" width=\"300\"\u003e\n\u003c/picture\u003e\n\n### Live apps in C#. One codebase — server-rendered over WebSockets, client-side in the browser via WebAssembly, or a native iOS/Android app.\n\n[![NuGet Rask.Server](https://img.shields.io/nuget/v/Rask.Server.svg?label=Rask.Server)](https://www.nuget.org/packages/Rask.Server)\n[![NuGet Rask.Wasm](https://img.shields.io/nuget/v/Rask.Wasm.svg?label=Rask.Wasm)](https://www.nuget.org/packages/Rask.Wasm)\n[![NuGet Rask.Native](https://img.shields.io/nuget/v/Rask.Native.svg?label=Rask.Native)](https://www.nuget.org/packages/Rask.Native)\n[![NuGet Rask.Templates](https://img.shields.io/nuget/v/Rask.Templates.svg?label=Rask.Templates)](https://www.nuget.org/packages/Rask.Templates)\n[![NuGet Rask.Bootstrap](https://img.shields.io/nuget/v/Rask.Bootstrap.svg?label=Rask.Bootstrap)](https://www.nuget.org/packages/Rask.Bootstrap)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n![.NET](https://img.shields.io/badge/.NET-10-512BD4)\n\n# ▶ **[Try the live demo ↗](https://pal-tamas.github.io/rask/)** \u0026nbsp;·\u0026nbsp; 📖 **[Read the docs ↗](docs/)** \u0026nbsp;·\u0026nbsp; 🧪 **[Browse the examples ↗](samples/)**\n\n\u003c/div\u003e\n\n---\n\nWrite components as plain C# classes. Return a tree of HTML from `Render()`. **No `.razor`, no JSX, no JavaScript to\nwrite** — and the *same* component code runs server-rendered with live WebSocket updates or fully client-side on\nWebAssembly.\n\n```csharp\n[Route(\"/counter\")]\npublic sealed class Counter : Component\n{\n    private int _count;\n\n    protected override Component? Render() =\u003e\n    [\n        H1()[\"Counter\"],\n        P()[$\"Current count: {_count}\"],\n        Button(OnClick: () =\u003e _count++)[\"Click me\"]\n    ];\n}\n```\n\n\u003csub\u003e☝️ A complete, live, interactive component — routing, state, and event handling in a single C# class.\n**[See it running, and dozens more, in the live demo ↗](https://pal-tamas.github.io/rask/)**\u003c/sub\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n## 📱 Build mobile apps in C# — no Swift, Kotlin, React Native, or MAUI\n\n**The same component above ships as an installable, offline mobile app.** A Rask **WASM** app is a\nProgressive Web App: it **installs to the home screen**, **launches full-screen**, **works offline**,\nsends **push notifications**, badges its **app icon**, keeps the **screen awake**, and reaches the\ndevice — **vibration, share sheet, geolocation, clipboard, orientation** — through typed C#.\n\n```bash\ndotnet new rask-wasm --pwa     # → an installable, offline PWA, ready to deploy\n```\n\n**[📖 Build mobile apps with Rask →](docs/pwa.md)**  ·  **[Try the installable demo ↗](https://pal-tamas.github.io/rask/)**\n\nGoing further than a PWA? **`Rask.Native`** *(preview)* ships the *same* component code as a real\n**native iOS/Android app** for App Store / Play Store distribution — a WebView hybrid where your C#\nruns natively on the device. Scaffold it with `dotnet new rask-native` and run on an emulator with\n`dotnet build -t:Run -f net10.0-android` — or run the full in-repo showcase, the native peers of the\nServer/WASM samples: `samples/Rask.Example.Native` (in-process) and `samples/Rask.Example.Native.Server`.\n\n**[📱 Native mobile with Rask →](docs/native.md)**\n\n\u003c/div\u003e\n\n---\n\n## ✨ Why Rask\n\nI've spent 15+ years building full-stack .NET apps, and the front end always meant a second world — another language,\ntype system, and build chain, with a serialization seam in the middle. Blazor answers part of that, but `.razor` puts\nmarkup and code back in one file with its own templating dialect. So Rask is built around a single conviction: **a\ncomponent is just a C# class that returns a tree.** No `.razor`, no JSX, no template language — `Div(...)[Span(...), \"hi\"]`\nis plain, refactor-safe, IDE-native C#, and the *same* component runs server-rendered over a WebSocket or fully\nclient-side on WebAssembly. One codebase; pick the host per project.\n\nIt also treats the network as the real bottleneck: after first paint, a state change ships a minimal diff — a counter\ntick on a 24 KB page goes out as **~41 bytes**, not 24 KB. In a 26-scenario head-to-head, Rask ships **fewer bytes on\nthe wire than Blazor on every one** (typically 2–5×, up to 66×) and, since the diff path stopped materialising the page\nper update, allocates **~40× less per update** too. The honest tradeoff — Blazor keeps a leaner *retained* tree per\nmounted session — and the full byte-for-byte numbers are in the\n**[Rask vs Blazor baselines ↗](benchmarks/Rask.Benchmarks.VsBlazor/Baselines/vs-blazor.md)** (which calls out where Blazor wins).\n\n*Rask* is the Norwegian/Danish/Swedish word for **fast**. **The [docs ↗](docs/) and the [live demo ↗](https://pal-tamas.github.io/rask/)\nare the real tour — this README is just the front door.**\n\n## 📦 Install\n\n\u003e **Prerequisites:** the **.NET 10 SDK** (`dotnet --version` ≥ `10.0`); the `wasm-tools` workload\n\u003e (`dotnet workload install wasm-tools`) for the WASM templates, or the `ios android` workloads\n\u003e (`dotnet workload install ios android`) for the native template. New to Rask? The\n\u003e **[getting started guide](docs/getting-started.md)** walks the whole path end to end.\n\n### Scaffold a new project (recommended)\n\n```bash\ndotnet new install Rask.Templates\n\ndotnet new rask-server       -n MyApp    # ASP.NET live-server app\ndotnet new rask-wasm         -n MyApp    # standalone browser-WASM SPA\ndotnet new rask-wasm-hosted  -n MyApp    # browser-WASM client + ASP.NET host\ndotnet new rask-native       -n MyApp    # native iOS + Android app (WebView hybrid, preview)\n\ncd MyApp \u0026\u0026 dotnet run                    # that's it (native: dotnet build -t:Run -f net10.0-android)\n```\n\nAdd `--auth` for a cookie/JWT-wired starter, or `--pwa` (WASM) for an installable offline app.\n\n### Add packages to an existing project\n\nPick one host package per project, then add opt-in packages as needed:\n\n| Package                            | Project type                                                        | Entry-point API                                             |\n|------------------------------------|---------------------------------------------------------------------|-------------------------------------------------------------|\n| `Rask.Server`                      | `net10.0` ASP.NET                                                   | `services.AddRask()` + `app.UseRask\u003cTApp\u003e()`                |\n| `Rask.Wasm`                        | `net10.0-browser`                                                   | `WasmHostBuilder.CreateDefault()` + `host.RunAsync\u003cTApp\u003e()` |\n| `Rask.Wasm.Hosting`                | `net10.0` ASP.NET (with a `\u003cProjectReference\u003e` to the WASM project) | `app.UseRask()`                                             |\n| `Rask.Native` *(preview)*          | `net10.0-ios;net10.0-android` app head                             | `NativeAppHost.CreateDefault()` + `host.RunLocalAsync\u003cTApp\u003e(webView)` |\n| `Rask.Validation.DataAnnotations`  | any host that hosts your forms                                      | drop `DataAnnotationsValidator()` inside a `Form\u003cT\u003e`        |\n| `Rask.Validation.FluentValidation` | any host that hosts your forms                                      | drop `FluentValidationValidator(new MyValidator())` inside  |\n| `Rask.Bootstrap`                   | any host with your components                                       | link `BootstrapStyles()` in `Head`, then use `Bs*` factories |\n| `Rask.WebPush`                     | any backend (Server app or a WASM PWA's ASP.NET host)              | `services.AddRaskWebPush(...)` + inject `IWebPushSender`     |\n| `Rask.Cqrs`                        | any .NET app (standalone; Server, WASM, or non-Rask)               | `services.AddRaskCqrs()` + inject `IDispatcher`             |\n| `Rask.Testing`                     | your `*.Tests` project (references your app)                       | `RaskTest.Render(new MyComponent())` → assert on `.Html`    |\n\n`Rask.Server`, `Rask.Wasm`, and `Rask.Native` pull in `Rask.Core` and the source generators transitively. Full setup,\nhost trade-offs, and sub-path hosting are covered in **[getting started](docs/getting-started.md)** and the **[docs ↗](docs/)**.\n\n## 🧪 Examples\n\n**The fastest way to understand Rask is to click through a real app and read its source.**\n\n- **[Live demo ↗](https://pal-tamas.github.io/rask/)** — `Rask.Example.Wasm` is published to GitHub Pages on every push\n  to `main`; click through a full multi-page Rask app in the browser before cloning anything.\n- **[`samples/`](samples/)** — runnable showcase apps that exercise every feature end-to-end: the shared feature pages\n  (`samples/Rask.Example.Shared/Features/`), EF Core + SQLite data access, and one auth sample per cell of the\n  `{Cookie, JWT} × {Server, WASM}` matrix. Run one with, e.g.,\n  `dotnet run --project samples/Rask.Example.Server` and open the printed URL.\n\n## 📚 Documentation\n\nEverything lives in **[`docs/`](docs/)** — start here, then dive into the topic you need:\n\n| Guide | What it covers |\n|-------|----------------|\n| **[Getting started](docs/getting-started.md)** | Scaffold, first component, interactivity, routing — the end-to-end path. |\n| **[Best practices](docs/best-practices.md)** | The patterns and pitfalls that keep an app correct, secure, and fast. |\n| **[Elements \u0026 the DSL](docs/elements.md)** | Primitives, tag factories, universal props, and typed SVG — the render surface. |\n| **[Composition](docs/composition.md)** · **[Lifecycle](docs/lifecycle.md)** | Component tiers (static/stateless/stateful), context, callbacks, children; mount/update/dispose. |\n| **[Routing](docs/routing.md)** · **[Forms \u0026 validation](docs/forms.md)** · **[Building form controls](docs/building-form-controls.md)** | URLs, route params, the form pipeline, custom `IFormControl\u003cT\u003e` inputs. |\n| **[Authentication](docs/authentication.md)** · **[Data access](docs/data-access.md)** · **[HTTP \u0026 files](docs/http-and-files.md)** · **[CQRS](docs/cqrs.md)** | Cookie/JWT on Server \u0026 WASM; EF Core + SQLite; a DI'd `HttpClient` + file upload/download; source-generated CQRS. |\n| **[Bootstrap](docs/bootstrap.md)** | Typed Bootstrap 5.3 components, zero-JS interactivity, typed utility classes. |\n| **[Browser APIs](docs/browser-apis.md)** · **[PWA](docs/pwa.md)** · **[Native mobile](docs/native.md)** · **[AOT](docs/aot.md)** | 43 typed Web-API wrappers; installable offline PWAs; native iOS/Android apps; opt-in full WASM AOT. |\n| **[JS interop](docs/js-interop.md)** · **[Accessibility](docs/accessibility.md)** · **[Testing](docs/testing.md)** | Scoped JS + element refs; a11y; unit + E2E. |\n| **[Migrating from Blazor](docs/migration-from-blazor.md)** | How the day-to-day differs, side by side. |\n| **[Diagnostics](docs/diagnostics.md)** | Every RASK build error/warning and its fix. |\n| **[Live rendering \u0026 the diff codec](docs/architecture/live-rendering.md)** | How the runtime works under the hood. |\n\n## 📋 Status\n\nRask is pre-1.0. APIs may change between minor versions. It targets **.NET 10** (`net10.0` for ASP.NET hosts,\n`net10.0-browser` for WASM, `net10.0-ios;net10.0-android` for native app heads). Unit suites cover the core,\ngenerators, hosts (Server, WASM, Native), and validation packages, plus a Playwright E2E smoke suite;\n`Rask.Example.Wasm` publishes with zero IL trimming warnings. The native host is preview-stage. Production use at your\nown discretion — issues and PRs welcome.\n\n## 📄 License\n\nRask is released under the [MIT License](LICENSE).\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n⚡ **Rask** — *Norwegian/Danish/Swedish for \"fast\".*\n\n**[Live demo ↗](https://pal-tamas.github.io/rask/)** · **[Docs ↗](docs/)** · **[Examples ↗](samples/)** · **[NuGet ↗](https://www.nuget.org/packages/Rask.Server)**\n\nBuilt with .NET 10. Issues and PRs welcome.\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpal-tamas%2Frask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpal-tamas%2Frask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpal-tamas%2Frask/lists"}