{"id":13502871,"url":"https://github.com/marc2332/freya","last_synced_at":"2026-06-01T14:00:41.472Z","repository":{"id":59212212,"uuid":"518513704","full_name":"marc2332/freya","owner":"marc2332","description":"Cross-platform and non-web GUI library for 🦀 Rust  powered by 🎨 Skia.","archived":false,"fork":false,"pushed_at":"2026-05-31T13:25:24.000Z","size":34622,"stargazers_count":2761,"open_issues_count":26,"forks_count":121,"subscribers_count":18,"default_branch":"main","last_synced_at":"2026-05-31T15:14:27.380Z","etag":null,"topics":["cross-platform","dioxus","gui","hacktoberfest","rust","skia"],"latest_commit_sha":null,"homepage":"https://freyaui.dev","language":"Rust","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/marc2332.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","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},"funding":{"github":["marc2332"],"custom":["https://www.paypal.com/paypalme/mkenzo8"]}},"created_at":"2022-07-27T15:28:11.000Z","updated_at":"2026-05-31T13:25:21.000Z","dependencies_parsed_at":"2025-12-18T11:05:43.362Z","dependency_job_id":"bd8e48ed-1f8c-4297-b36f-3163498e1093","html_url":"https://github.com/marc2332/freya","commit_stats":{"total_commits":434,"total_committers":5,"mean_commits":86.8,"dds":"0.027649769585253448","last_synced_commit":"45242c08fb94c4d406268ab976080c991bd113bf"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/marc2332/freya","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc2332%2Ffreya","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc2332%2Ffreya/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc2332%2Ffreya/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc2332%2Ffreya/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marc2332","download_url":"https://codeload.github.com/marc2332/freya/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc2332%2Ffreya/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33777971,"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-01T02:00:06.963Z","response_time":115,"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":["cross-platform","dioxus","gui","hacktoberfest","rust","skia"],"created_at":"2024-07-31T22:02:27.846Z","updated_at":"2026-06-01T14:00:41.465Z","avatar_url":"https://github.com/marc2332.png","language":"Rust","funding_links":["https://github.com/sponsors/marc2332","https://www.paypal.com/paypalme/mkenzo8","https://github.com/sponsors/marc2332/"],"categories":["Rust","GUI","rust","\u003ca name=\"Rust\"\u003e\u003c/a\u003eRust"],"sub_categories":[],"readme":"# Freya 🦀\n\n\u003ca href=\"https://freyaui.dev/\"\u003e\u003cimg align=\"right\" src=\"logo.svg\" alt=\"Freya logo\" width=\"150\"/\u003e\u003c/a\u003e\n\n[![Discord Server](https://img.shields.io/discord/1015005816094478347.svg?logo=discord\u0026style=flat-square)](https://discord.gg/sYejxCdewG)\n[![Github Sponsors](https://img.shields.io/github/sponsors/marc2332?style=social)](https://github.com/sponsors/marc2332)\n[![codecov](https://codecov.io/github/marc2332/freya/branch/main/graph/badge.svg?token=APSGEC84B8)](https://codecov.io/github/marc2332/freya)\n\n[Website](https://freyaui.dev) | [Stable Documentation](https://docs.rs/freya/) | [Discord](https://discord.gg/sYejxCdewG) | [Contact](#contact)\n\n**Freya** is a **cross-platform, native, declarative** GUI library for Rust 🦀.\n\n\u003e :warning: I recently rewrote a huge percentage of Freya in https://github.com/marc2332/freya/pull/1351, so the `main` branch differs a lot from the latest stable release.\n\n### Components \u0026 State \n\nFreya’s component model lets you create reusable UI elements that automatically re-render when the state they depend on changes. Components can hold their own internal state or subscribe to shared state, and they produce UI as their output. Any type that implements the `Component` trait can be a component, while the root (`app`) component can simply be a function. Built-in examples include components like `Button` and `Switch`.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd style=\"border:hidden;\"\u003e\n\n```rust\nfn app() -\u003e impl IntoElement {\n    let mut count = use_state(|| 4);\n\n    let counter = rect()\n        .width(Size::fill())\n        .height(Size::percent(50.))\n        .center()\n        .color((255, 255, 255))\n        .background((15, 163, 242))\n        .font_weight(FontWeight::BOLD)\n        .font_size(75.)\n        .shadow((0., 4., 20., 4., (0, 0, 0, 80)))\n        .child(count.read().to_string());\n\n    let actions = rect()\n        .horizontal()\n        .width(Size::fill())\n        .height(Size::percent(50.))\n        .center()\n        .spacing(8.0)\n        .child(\n            Button::new()\n                .on_press(move |_| {\n                    *count.write() += 1;\n                })\n                .child(\"Increase\"),\n        )\n        .child(\n            Button::new()\n                .on_press(move |_| {\n                    *count.write() -= 1;\n                })\n                .child(\"Decrease\"),\n        );\n\n    rect().child(counter).child(actions)\n}\n```\n\u003c/td\u003e\n\u003ctd style=\"border:hidden;\"\u003e\n\n\u003cimg src=\"https://github.com/user-attachments/assets/6f13c144-9557-4518-9b2e-93706568f355\"\u003e\n\n\u003c/td\u003e\n\u003c/table\u003e\n\n\n### Out of the box components\n\nFreya comes with a set of components out of the box, from simple like `Button`, `Switch`, `Slider` to more complex like `VirtualScrollView`, `Calendar`, `ColorPicker`, etc.\n\nYou can check all the examples that start with `component_` in the [examples folder](https://github.com/marc2332/freya/blob/main/examples/).\n\nExample of [`component_input.rs`](https://github.com/marc2332/freya/blob/main/examples/component_input.rs):\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/3dd1b7bf-0c9e-4257-a308-f2e3ca057ff1\"\u003e\n\u003c/div\u003e\n\n### Smooth Animations\n\nCreate transitions for colors, sizes, positions, and other visual properties. The animation API gives you full control over timing, easing functions, and animation sequences.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\n\nfn app() -\u003e impl IntoElement {\n    let mut animation = use_animation(|_| AnimColor::new((246, 240, 240), (205, 86, 86)).time(400));\n\n    rect()\n        .background(\u0026*animation.read())\n        .expanded()\n        .center()\n        .spacing(8.0)\n        .child(\n            Button::new()\n                .on_press(move |_| {\n                    animation.start();\n                })\n                .child(\"Start\"),\n        )\n        .child(\n            Button::new()\n                .on_press(move |_| {\n                    animation.reverse();\n                })\n                .child(\"Reverse\"),\n        )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/ab0c4637-7c04-4dd3-8c6f-c841d4e163d7\"\u003e\n\u003c/div\u003e\n\n[Portal example](https://github.com/marc2332/freya/blob/main/examples/animation_portal.rs)\n\n[Component Portal](https://github.com/user-attachments/assets/720dd8ec-2a76-4f80-8787-25b3ebb06611)\n\n### Rich Text Editing\n\nFreya provides text editing capabilities that go beyond simple input fields. You can create rich text editors with cursor management, text selection, keyboard shortcuts, custom formatting, virtulization and more.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\n\nfn app() -\u003e impl IntoElement {\n    let holder = use_state(ParagraphHolder::default);\n    let mut editable = use_editable(|| \"Hello, World!\".to_string(), EditableConfig::new);\n    let focus = use_focus();\n\n    paragraph()\n        .a11y_id(focus.a11y_id())\n        .cursor_index(editable.editor().read().cursor_pos())\n        .highlights(\n            editable\n                .editor()\n                .read()\n                .get_selection()\n                .map(|selection| vec![selection])\n                .unwrap_or_default(),\n        )\n        .on_mouse_down(move |e: Event\u003cMouseEventData\u003e| {\n            focus.request_focus();\n            editable.process_event(EditableEvent::Down {\n                location: e.element_location,\n                editor_line: EditorLine::SingleParagraph,\n                holder: \u0026holder.read(),\n            });\n        })\n        .on_mouse_move(move |e: Event\u003cMouseEventData\u003e| {\n            editable.process_event(EditableEvent::Move {\n                location: e.element_location,\n                editor_line: EditorLine::SingleParagraph,\n                holder: \u0026holder.read(),\n            });\n        })\n        .on_global_pointer_up(move |_| editable.process_event(EditableEvent::Release))\n        .on_key_down(move |e: Event\u003cKeyboardEventData\u003e| {\n            editable.process_event(EditableEvent::KeyDown {\n                key: \u0026e.key,\n                modifiers: e.modifiers,\n            });\n        })\n        .on_key_up(move |e: Event\u003cKeyboardEventData\u003e| {\n            editable.process_event(EditableEvent::KeyUp { key: \u0026e.key });\n        })\n        .span(editable.editor().read().to_string())\n        .holder(holder.read().clone())\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/27fbbcab-3ab4-4dc7-b984-47cec280123c\"\u003e\n\u003c/div\u003e\n\n\n\n### Code Editor\n\nCreate and control text Code Editors. It is state agnostic so as long as it can be turned into a `Writable` it will work. Uses Rope for text editing and tree-sitter for syntax highlighting. \nEnable with the `code-editor` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nfn app() -\u003e impl IntoElement {\n    use_init_theme(dark_theme);\n    let focus = use_focus();\n    let editor = use_state(|| {\n        let path = PathBuf::from(\"./crates/freya-code-editor/src/editor_ui.rs\");\n        let rope = Rope::from_str(\u0026std::fs::read_to_string(\u0026path).unwrap());\n        let mut editor = CodeEditorData::new(rope, LanguageId::Rust);\n        editor.parse();\n        editor.measure(14., \"Jetbrains Mono\");\n        editor\n    });\n\n    CodeEditor::new(editor, focus.a11y_id())\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/4d6c4571-ae74-4c24-a05f-9c715b6b3438\"\u003e\n\u003c/div\u003e\n\n\n### Routing \u0026 Navigation\n\nDefine routes, manage navigation state, and transition between different views.\nEnable with the `router` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::router::prelude::*;\n\n#[derive(Routable, Clone, PartialEq)]\n#[rustfmt::skip]\npub enum Route {\n    #[layout(AppBottomBar)]\n        #[route(\"/\")]\n        Home,\n        #[route(\"/settings\")]\n        Settings,\n}\n\nfn app() -\u003e impl IntoElement {\n    router::\u003cRoute\u003e(|| RouterConfig::default().with_initial_path(Route::Settings))\n}\n\n\n#[derive(PartialEq)]\nstruct AppBottomBar;\nimpl Component for AppBottomBar {\n    fn render(\u0026self) -\u003e impl IntoElement {\n        NativeRouter::new().child(\n            rect()\n                .content(Content::flex())\n                .child(\n                    rect()\n                        .width(Size::fill())\n                        .height(Size::flex(1.))\n                        .center()\n                        .child(outlet::\u003cRoute\u003e()),\n                )\n                .child(\n                    rect()\n                        .horizontal()\n                        .width(Size::fill())\n                        .main_align(Alignment::center())\n                        .padding(8.)\n                        .spacing(8.)\n                        .child(\n                            Link::new(Route::Home)\n                                .child(FloatingTab::new().child(\"Home\"))\n                                .activable_route(Route::Home)\n                                .exact(true),\n                        )\n                        .child(\n                            Link::new(Route::Settings)\n                                .child(FloatingTab::new().child(\"Settings\"))\n                                .activable_route(Route::Settings)\n                                .exact(true),\n                        ),\n                ),\n        )\n    }\n}\n\n#[derive(PartialEq)]\nstruct Home {}\nimpl Component for Home {\n    fn render(\u0026self) -\u003e impl IntoElement {\n        Button::new()\n            .on_press(|_| {\n                RouterContext::get().replace(Route::Settings);\n            })\n            .child(\"Go Settings\")\n    }\n}\n\n#[derive(PartialEq)]\nstruct Settings {}\nimpl Component for Settings {\n    fn render(\u0026self) -\u003e impl IntoElement {\n        Button::new()\n            .on_press(|_| {\n                 let _ = RouterContext::get().replace(Route::Home);\n            })\n            .child(\"Go Home\")\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/1b3ed156-7e29-43f7-a11c-455ba0520223\"\u003e\n\u003c/div\u003e\n\n\n### Global State Management\n\nFreya's `freya-radio` state management system provides efficient global state management through a channels system. Components subscribe to specific \"channels\" and only receive updates when data is mutated and notified through their channel.\nEnable with the `radio` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::radio::*;\n\n#[derive(Default)]\nstruct Data {\n    pub lists: Vec\u003cVec\u003cString\u003e\u003e,\n}\n\n#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]\npub enum DataChannel {\n    ListCreation,\n    SpecificListItemUpdate(usize),\n}\n\nimpl RadioChannel\u003cData\u003e for DataChannel {}\n\nfn app() -\u003e impl IntoElement {\n    use_init_radio_station::\u003cData, DataChannel\u003e(Data::default);\n    let mut radio = use_radio::\u003cData, DataChannel\u003e(DataChannel::ListCreation);\n\n    let on_press = move |_| {\n        radio.write().lists.push(Vec::default());\n    };\n\n    rect()\n        .horizontal()\n        .child(Button::new().on_press(on_press).child(\"Add new list\"))\n        .children(\n            radio\n                .read()\n                .lists\n                .iter()\n                .enumerate()\n                .map(|(list_n, _)| ListComp(list_n).into()),\n        )\n}\n\n\n#[derive(PartialEq)]\nstruct ListComp(usize);\nimpl Component for ListComp {\n    fn render(\u0026self) -\u003e impl IntoElement {\n        let list_n = self.0;\n        let mut radio = use_radio::\u003cData, DataChannel\u003e(DataChannel::SpecificListItemUpdate(list_n));\n\n        println!(\"Running DataChannel::SpecificListItemUpdate({list_n})\");\n\n        rect()\n            .child(\n                Button::new()\n                    .on_press(move |_| radio.write().lists[list_n].push(\"Hello, World\".to_string()))\n                    .child(\"New Item\"),\n            )\n            .children(\n                radio.read().lists[list_n]\n                    .iter()\n                    .enumerate()\n                    .map(move |(i, item)| label().key(i).text(item.clone()).into()),\n            )\n    }\n}\n\n```\n\n\u003c/details\u003e\n\n\n### Icon Library\n\nEasily integrate icons into your applications, only supports Lucide at the moment.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::icons;\n\nfn app() -\u003e impl IntoElement {\n    svg(icons::lucide::antenna())\n        .color((120, 50, 255))\n        .expanded()\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/ee561203-d4d2-4283-8dd2-9df61f04f86f\"\u003e\n\u003c/div\u003e\n\n\n### Headless Testing\n\nUsing `freya-testing` you can test your Freya components in a no-window (headless) environment. You can decide to render the app at any moment to a file though. `freya-testing` is actually used by Freya itself to test all the out of the box components and other APIs.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya_testing::prelude::*;\n\nfn app() -\u003e impl IntoElement {\n    let mut state = use_consume::\u003cState\u003ci32\u003e\u003e();\n    rect()\n        .expanded()\n        .center()\n        .background((240, 240, 240))\n        .on_mouse_up(move |_| *state.write() += 1)\n        .child(format!(\"Clicked: {}\", state.read()))\n}\n\nfn main() {\n    // Create headless testing runner\n    let (mut test, state) = TestingRunner::new(\n        app,\n        (300., 300.).into(),\n        |runner| runner.provide_root_context(|| State::create(0)),\n        1.,\n    );\n\n    test.sync_and_update();\n    assert_eq!(*state.peek(), 0);\n\n    // Simulate user interactions\n    test.click_cursor((15., 15.));\n    assert_eq!(*state.peek(), 1);\n\n    // Render the current ui state to a file\n    test.render_to_file(\"./demo-1.png\");\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/1340796c-f85b-4522-91d2-95d4bc80e7fc\"\u003e\n\u003c/div\u003e\n\n### Advanced Plotting \u0026 Charts\n\nUsing the Plotters library, you can create charts, graphs, and data visualizations directly within your application.\nEnable with the `ploters` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::plot::*;\nuse freya::plot::plotters::*;\n\nfn on_render(ctx: \u0026mut RenderContext, (cursor_x, cursor_y): (f64, f64)) {\n    let backend = PlotSkiaBackend::new(\n        ctx.canvas,\n        ctx.font_collection,\n        ctx.layout_node.area.size.to_i32().to_tuple(),\n    ).into_drawing_area();\n\n    backend.fill(\u0026WHITE).unwrap();\n\n    let pitch = std::f64::consts::PI * (0.5 - cursor_y / ctx.layout_node.area.height() as f64);\n    let yaw = std::f64::consts::PI * 2.0 * (cursor_x / ctx.layout_node.area.width() as f64 - 0.5);\n    let scale = 0.4 + 0.6 * (1.0 - cursor_y / ctx.layout_node.area.height() as f64);\n\n    let x_axis = (-3.0..3.0).step(0.1);\n    let z_axis = (-3.0..3.0).step(0.1);\n\n    let mut chart = ChartBuilder::on(\u0026backend)\n        .caption(\"3D Surface Plot\", (\"sans\", 20))\n        .build_cartesian_3d(x_axis.clone(), -3.0..3.0, z_axis.clone())\n        .unwrap();\n\n    chart.with_projection(|mut pb| {\n        pb.pitch = pitch;\n        pb.yaw = yaw;\n        pb.scale = scale;\n        pb.into_matrix()\n    });\n\n    chart\n        .draw_series(\n            SurfaceSeries::xoz(\n                (-30..30).map(|f| f as f64 / 10.0),\n                (-30..30).map(|f| f as f64 / 10.0),\n                |x, z| (x * x + z * z).cos(),\n            )\n            .style(BLUE.mix(0.2).filled()),\n        )\n        .unwrap()\n        .label(\"Interactive Surface\")\n        .legend(|(x, y)| Rectangle::new([(x + 5, y - 5), (x + 15, y + 5)], BLUE.mix(0.5).filled()));\n}\n\nfn app() -\u003e impl IntoElement {\n    let mut cursor_position = use_state(CursorPoint::default);\n\n    let on_global_pointer_move = move |e: Event\u003cPointerEventData\u003e| {\n        // Dont move when the cursor goes outside the window\n        if e.global_location().to_tuple() != (-1., -1.) {\n            cursor_position.set(e.global_location());\n            let platform = Platform::get();\n            platform.send(UserEvent::RequestRedraw);\n        }\n    };\n\n    canvas(RenderCallback::new(move |context| {\n        on_render(context, cursor_position().to_tuple());\n    }))\n    .expanded()\n    .on_global_pointer_move(on_global_pointer_move)\n}\n```\n\n\u003c/details\u003e\n\n[Plots](https://github.com/user-attachments/assets/236285ea-a2c2-4739-a59d-029a7c3ef601)\n\n### Internationalization (i18n)\n\nFreya supports internationalization with built-in support for the [Fluent](https://github.com/projectfluent/fluent-rs) localization system. Easily manage translations, pluralization, and locale-specific formatting.\nEnable with the `i18n` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::i18n::*;\n\nfn app() -\u003e impl IntoElement {\n    let mut i18n = use_init_i18n(|| {\n        I18nConfig::new(langid!(\"en-US\"))\n            .with_locale((langid!(\"en-US\"), include_str!(\"./i18n/en-US.ftl\")))\n            .with_locale((langid!(\"es-ES\"), PathBuf::from(\"./examples/i18n/es-ES.ftl\")))\n    });\n\n    let change_to_english = move |_| i18n.set_language(langid!(\"en-US\"));\n    let change_to_spanish = move |_| i18n.set_language(langid!(\"es-ES\"));\n\n    rect()\n        .expanded()\n        .center()\n        .child(\n            rect()\n                .horizontal()\n                .child(Button::new().on_press(change_to_english).child(\"English\"))\n                .child(Button::new().on_press(change_to_spanish).child(\"Spanish\")),\n        )\n        .child(t!(\"hello_world\"))\n        .child(t!(\"hello\", name: \"Freya!\"))\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/95dc2547-9137-4291-87d4-3f5161493c65\"\u003e\n\u003c/div\u003e\n\n### Material Design Components\n\nFreya provides Material Design-inspired style modifiers.\nEnable with the `material-design` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::material_design::*;\n\nfn app() -\u003e impl IntoElement {\n    rect().center().expanded().child(\n        Button::new()\n            .on_press(|_| println!(\"Material button pressed\"))\n            .ripple()  // Adds Material Design ripple effect\n            .child(\"Material Button\"),\n    )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/fdc8e4e9-321a-4ad2-8190-ad6772fc9dc0\"\u003e\n\u003c/div\u003e\n\n### WebView Integration\n\nIntegrate web content into your native applications with Freya's WebView support. Embed web applications, or simply display web-based content alongside your native UI components.\nEnable with the `webview` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::webview::*;\n\nfn app() -\u003e impl IntoElement {\n    // Multi-tab webview implementation\n    let mut tabs = use_state(|| vec![Tab {\n        id: WebViewId::new(),\n        title: \"Tab 1\".to_string(),\n        url: \"https://duckduckgo.com\".to_string(),\n    }]);\n    let mut active_tab = use_state(|| tabs.read()[0].id);\n\n    rect()\n        .expanded()\n        .height(Size::fill())\n        .background((35, 35, 35))\n        .child(\n            rect()\n                .width(Size::fill())\n                .height(Size::px(45.))\n                .padding(4.)\n                .background((50, 50, 50))\n                .horizontal()\n                .cross_align(Alignment::Center)\n                .spacing(4.)\n                .children(tabs.read().iter().map(|tab| {\n                    // Tab implementation...\n                }))\n        )\n        .child(WebView::new(\"https://duckduckgo.com\").expanded())\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/60d6db71-fa22-4bbb-a4ad-1ff00a056614\"\u003e\n\u003c/div\u003e\n\n\n### Terminal Emulation\n\nFreya includes terminal emulation capabilities with full PTY (pseudo-terminal) support. Create integrated terminal applications, SSH clients, or development tools.\nEnable with the `terminal` feature.\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse freya::prelude::*;\nuse freya::terminal::*;\n\nfn app() -\u003e impl IntoElement {\n    let mut handle = use_state(|| {\n        let mut cmd = CommandBuilder::new(\"bash\");\n        cmd.env(\"TERM\", \"xterm-256color\");\n        cmd.env(\"COLORTERM\", \"truecolor\");\n        TerminalHandle::new(TerminalId::new(), cmd, None).ok()\n    });\n\n    rect()\n        .expanded()\n        .center()\n        .background((30, 30, 30))\n        .color((245, 245, 245))\n        .padding(6.)\n        .child(if let Some(handle) = handle.read().clone() {\n            Terminal::new(handle.clone())\n                .a11y_id(focus.a11y_id())\n                .on_key_down(move |e: Event\u003cKeyboardEventData\u003e| {\n                    let _ = handle.write_key(\u0026e.key, e.modifiers);\n                })\n        } else {\n            \"Terminal exited\".into_element()\n        })\n}\n```\n\n\u003c/details\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/12322dad-cb89-450b-bd8f-c9d5fbe2d45a\"\u003e\n\u003c/div\u003e\n\n### Developer Tools\n\nExamine the component tree in real-time.\n\nEnable the `devtools` feature in `freya` and then run the devtools app.\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/906fdbec-7b3c-4dc4-a420-95fdf852b1e4\"\u003e\n\u003c/div\u003e\n\n### Trying it out\n\nMake sure to have [Development Setup](https://docs.rs/freya/0.3/freya/_docs/development_setup/index.html) ready.\n\n\u003e ⚠️ If you happen to be on Windows using `windows-gnu` and get compile errors, maybe go check this [issue](https://github.com/marc2332/freya/issues/794).\n\nClone this repo (this project uses git submodules, so make sure to clone with `--recurse-submodules`):\n\n```shell\ngit clone --recurse-submodules https://github.com/marc2332/freya.git\ncd freya\n```\n\n\u003e **Already cloned without submodules?** Run `git submodule update --init --recursive` to fetch them.\n\nThen run an example:\n\n```shell\ncargo run --example counter\n```\n\n### Usage 📜\n`main` branch:\n\n```toml\nfreya = { git = \"https://github.com/marc2332/freya\", branch = \"main\" }\n```\n\nRelease candidates:\n\n```toml\nfreya = \"0.4.0-rc.22\"\n```\n\n### Contributing 🧙‍♂️\nIf you are interested in contributing please make sure to have read the [Contributing](CONTRIBUTING.md) guide first!\n\n### Contact \nYou may contact me for questions, collaboration or anything that comes to your mind at [marc@mespin.me](mailto:marc@mespin.me).\n\n### Support 🤗\n\nIf you are interested in supporting the development of this project feel free to donate to my [Github Sponsor](https://github.com/sponsors/marc2332/) page.\n\nThanks to my sponsors for supporting this project! 😄 \n\n\u003c!-- sponsors --\u003e\u003ca href=\"https://github.com/piny4man\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;piny4man.png\" width=\"60px\" alt=\"User avatar: \" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/gqf2008\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;gqf2008.png\" width=\"60px\" alt=\"User avatar: 高庆丰\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/lino-levan\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;lino-levan.png\" width=\"60px\" alt=\"User avatar: Lino Le Van\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/d3rpp\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;d3rpp.png\" width=\"60px\" alt=\"User avatar: Huddy Buddy\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/DrigsterI\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;DrigsterI.png\" width=\"60px\" alt=\"User avatar: Gabriel Jõe\" /\u003e\u003c/a\u003e\u003ca href=\"https://github.com/markalexander\"\u003e\u003cimg src=\"https:\u0026#x2F;\u0026#x2F;github.com\u0026#x2F;markalexander.png\" width=\"60px\" alt=\"User avatar: Mark\" /\u003e\u003c/a\u003e\u003c!-- sponsors --\u003e\n\n### Special thanks 💪\n\n- [Jonathan Kelley](https://github.com/jkelleyrtp) and [Evan Almloff](https://github.com/ealmloff) for making [Dioxus](https://dioxuslabs.com/) and all their help, specially when I was still creating Freya.\n- [Armin](https://github.com/pragmatrix) for making [rust-skia](https://github.com/rust-skia/rust-skia/) and all his help and making the favor of hosting prebuilt binaries of skia for the combo of features use by Freya.\n- [geom3trik](https://github.com/geom3trik) for helping me figure out how to add incremental rendering.\n- [Tropical](https://github.com/Tropix126) for this contributions to improving accessibility and rendering.\n- [Aiving](https://github.com/Aiving) for having made heavy contributions to [rust-skia](https://github.com/rust-skia/rust-skia/) for better SVG support, and helped optimizing images rendering in Freya.\n- [RobertasJ](https://github.com/RobertasJ) for having added nested parenthesis to the `calc()` function and also pushed for improvements in the animation APIs.\n- And to the rest of contributors and anybody who gave me any kind of feedback!\n- [SparkyTD](https://github.com/SparkyTD) for contributing support for Android.\n\n### History with Dioxus\nFreya 0.1, 0.2 and 0.3 were based on the core crates of Dioxus. Starting 0.4 Freya does no longer use Dioxus, instead it uses its own reactive core, partially inspired by Dioxus but yet with lots of differences.\n\n### Claude Code Skill\n\nA Claude Code skill with Freya best practices and patterns is available. Install it with:\n\n```\n/plugin marketplace add marc2332/freya\n/plugin install freya@freya-marketplace\n```\n\nFor other AI coding agents, you can use the skill document directly as context: [plugins/freya/skills/freya/SKILL.md](plugins/freya/skills/freya/SKILL.md)\n\n### License\n\n[MIT License](./LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarc2332%2Ffreya","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarc2332%2Ffreya","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarc2332%2Ffreya/lists"}