Browse Source

dioxus-native WIP

Signed-off-by: Nico Burns <nico@nicoburns.com>
Nico Burns 6 tháng trước cách đây
mục cha
commit
fca7d03894

+ 2353 - 164
Cargo.lock

@@ -12,6 +12,111 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "ab_glyph"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0"
+dependencies = [
+ "ab_glyph_rasterizer",
+ "owned_ttf_parser",
+]
+
+[[package]]
+name = "ab_glyph_rasterizer"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
+
+[[package]]
+name = "accesskit"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ac5b518d65f20dc920b3a7bb92bb2b90cdb301416f27c2a55a128cd99f75c0c"
+
+[[package]]
+name = "accesskit_atspi_common"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97d50c9c8c4e3ad243b8a567ddf3595c6eb064304b76baf246bb069700e03a2e"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "atspi-common",
+ "serde",
+ "thiserror 1.0.69",
+ "zvariant 3.15.2",
+]
+
+[[package]]
+name = "accesskit_consumer"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17fa06310c6256253ef3474cb4694346222b4bca85a53aec7f796a73d18e7082"
+dependencies = [
+ "accesskit",
+ "immutable-chunkmap",
+]
+
+[[package]]
+name = "accesskit_macos"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a3c2a5bb8b5e403502faff2bbb85de5c14bb822a0ba7e9561cb5229b42a176"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "once_cell",
+]
+
+[[package]]
+name = "accesskit_unix"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8b8bfe5d626a7a0ae929df970857b3738198c66dfbf27a8d60d199e29bf2836"
+dependencies = [
+ "accesskit",
+ "accesskit_atspi_common",
+ "async-channel 2.3.1",
+ "async-executor",
+ "async-task",
+ "atspi",
+ "futures-lite 1.13.0",
+ "futures-util",
+ "serde",
+ "zbus 3.15.2",
+]
+
+[[package]]
+name = "accesskit_windows"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ab7baf1a8adacddc2c5a4f14d1f936f73a0f0e1c6d4592514992c4d4c57743"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "paste",
+ "static_assertions",
+ "windows 0.54.0",
+]
+
+[[package]]
+name = "accesskit_winit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8201853811d37a43c4753753d89d86802913be12496e5d77c1a418f7f2eaac"
+dependencies = [
+ "accesskit",
+ "accesskit_macos",
+ "accesskit_unix",
+ "accesskit_windows",
+ "raw-window-handle 0.6.2",
+ "winit",
+]
+
 [[package]]
 name = "addr2line"
 version = "0.24.2"
@@ -139,6 +244,33 @@ version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
+[[package]]
+name = "android-activity"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046"
+dependencies = [
+ "android-properties",
+ "bitflags 2.6.0",
+ "cc",
+ "cesu8",
+ "jni",
+ "jni-sys",
+ "libc",
+ "log",
+ "ndk",
+ "ndk-context",
+ "ndk-sys 0.6.0+11769913",
+ "num_enum",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "android-properties"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -267,6 +399,16 @@ dependencies = [
  "x509-certificate",
 ]
 
+[[package]]
+name = "app_units"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3a46058e45b48cf55b729e4ae34007fa904ea70cfcf2a0fa21dacf1441e521c"
+dependencies = [
+ "num-traits",
+ "serde",
+]
+
 [[package]]
 name = "apple-bundles"
 version = "0.19.0"
@@ -423,6 +565,24 @@ dependencies = [
  "derive_arbitrary",
 ]
 
+[[package]]
+name = "arboard"
+version = "3.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
+dependencies = [
+ "clipboard-win",
+ "core-graphics 0.23.2",
+ "image",
+ "log",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "parking_lot",
+ "windows-sys 0.48.0",
+ "x11rb",
+]
+
 [[package]]
 name = "arc-swap"
 version = "1.7.1"
@@ -452,12 +612,24 @@ dependencies = [
  "password-hash",
 ]
 
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
 [[package]]
 name = "arrayvec"
 version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
+[[package]]
+name = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
 [[package]]
 name = "as-slice"
 version = "0.2.1"
@@ -476,6 +648,15 @@ dependencies = [
  "libloading 0.7.4",
 ]
 
+[[package]]
+name = "ash"
+version = "0.38.0+1.3.281"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
+dependencies = [
+ "libloading 0.8.6",
+]
+
 [[package]]
 name = "ashpd"
 version = "0.8.1"
@@ -490,7 +671,7 @@ dependencies = [
  "serde_repr",
  "tokio",
  "url",
- "zbus",
+ "zbus 4.4.0",
 ]
 
 [[package]]
@@ -549,6 +730,16 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "async-broadcast"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b"
+dependencies = [
+ "event-listener 2.5.3",
+ "futures-core",
+]
+
 [[package]]
 name = "async-broadcast"
 version = "0.7.1"
@@ -608,11 +799,23 @@ checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
 dependencies = [
  "async-task",
  "concurrent-queue",
- "fastrand",
- "futures-lite",
+ "fastrand 2.2.0",
+ "futures-lite 2.5.0",
  "slab",
 ]
 
+[[package]]
+name = "async-fs"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
+dependencies = [
+ "async-lock 2.8.0",
+ "autocfg",
+ "blocking",
+ "futures-lite 1.13.0",
+]
+
 [[package]]
 name = "async-global-executor"
 version = "2.4.1"
@@ -621,32 +824,61 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
 dependencies = [
  "async-channel 2.3.1",
  "async-executor",
- "async-io",
- "async-lock",
+ "async-io 2.4.0",
+ "async-lock 3.4.0",
  "blocking",
- "futures-lite",
+ "futures-lite 2.5.0",
  "once_cell",
 ]
 
+[[package]]
+name = "async-io"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
+dependencies = [
+ "async-lock 2.8.0",
+ "autocfg",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-lite 1.13.0",
+ "log",
+ "parking",
+ "polling 2.8.0",
+ "rustix 0.37.27",
+ "slab",
+ "socket2 0.4.10",
+ "waker-fn",
+]
+
 [[package]]
 name = "async-io"
 version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
 dependencies = [
- "async-lock",
+ "async-lock 3.4.0",
  "cfg-if",
  "concurrent-queue",
  "futures-io",
- "futures-lite",
+ "futures-lite 2.5.0",
  "parking",
- "polling",
- "rustix",
+ "polling 3.7.4",
+ "rustix 0.38.41",
  "slab",
  "tracing",
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "async-lock"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
+dependencies = [
+ "event-listener 2.5.3",
+]
+
 [[package]]
 name = "async-lock"
 version = "3.4.0"
@@ -658,6 +890,23 @@ dependencies = [
  "pin-project-lite",
 ]
 
+[[package]]
+name = "async-process"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
+dependencies = [
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
+ "async-signal",
+ "blocking",
+ "cfg-if",
+ "event-listener 3.1.0",
+ "futures-lite 1.13.0",
+ "rustix 0.38.41",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "async-process"
 version = "2.3.0"
@@ -665,15 +914,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
 dependencies = [
  "async-channel 2.3.1",
- "async-io",
- "async-lock",
+ "async-io 2.4.0",
+ "async-lock 3.4.0",
  "async-signal",
  "async-task",
  "blocking",
  "cfg-if",
  "event-listener 5.3.1",
- "futures-lite",
- "rustix",
+ "futures-lite 2.5.0",
+ "rustix 0.38.41",
  "tracing",
 ]
 
@@ -694,13 +943,13 @@ version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
 dependencies = [
- "async-io",
- "async-lock",
+ "async-io 2.4.0",
+ "async-lock 3.4.0",
  "atomic-waker",
  "cfg-if",
  "futures-core",
  "futures-io",
- "rustix",
+ "rustix 0.38.41",
  "signal-hook-registry",
  "slab",
  "windows-sys 0.59.0",
@@ -714,13 +963,13 @@ checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615"
 dependencies = [
  "async-channel 1.9.0",
  "async-global-executor",
- "async-io",
- "async-lock",
+ "async-io 2.4.0",
+ "async-lock 3.4.0",
  "crossbeam-utils",
  "futures-channel",
  "futures-core",
  "futures-io",
- "futures-lite",
+ "futures-lite 2.5.0",
  "gloo-timers 0.3.0",
  "kv-log-macro",
  "log",
@@ -818,6 +1067,63 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
+[[package]]
+name = "atomic_refcell"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "atspi"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca"
+dependencies = [
+ "atspi-common",
+ "atspi-connection",
+ "atspi-proxies",
+]
+
+[[package]]
+name = "atspi-common"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5"
+dependencies = [
+ "enumflags2",
+ "serde",
+ "static_assertions",
+ "zbus 3.15.2",
+ "zbus_names 2.6.1",
+ "zvariant 3.15.2",
+]
+
+[[package]]
+name = "atspi-connection"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939"
+dependencies = [
+ "atspi-common",
+ "atspi-proxies",
+ "futures-lite 1.13.0",
+ "zbus 3.15.2",
+]
+
+[[package]]
+name = "atspi-proxies"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52"
+dependencies = [
+ "atspi-common",
+ "serde",
+ "zbus 3.15.2",
+]
+
 [[package]]
 name = "auth-git2"
 version = "0.5.5"
@@ -888,7 +1194,7 @@ dependencies = [
  "aws-smithy-types",
  "aws-types",
  "bytes",
- "fastrand",
+ "fastrand 2.2.0",
  "hex",
  "http 0.2.12",
  "ring",
@@ -954,7 +1260,7 @@ dependencies = [
  "aws-smithy-types",
  "aws-types",
  "bytes",
- "fastrand",
+ "fastrand 2.2.0",
  "http 0.2.12",
  "http-body 0.4.6",
  "once_cell",
@@ -984,7 +1290,7 @@ dependencies = [
  "aws-smithy-xml",
  "aws-types",
  "bytes",
- "fastrand",
+ "fastrand 2.2.0",
  "hex",
  "hmac",
  "http 0.2.12",
@@ -1188,7 +1494,7 @@ dependencies = [
  "aws-smithy-runtime-api",
  "aws-smithy-types",
  "bytes",
- "fastrand",
+ "fastrand 2.2.0",
  "h2 0.3.26",
  "http 0.2.12",
  "http-body 0.4.6",
@@ -1384,7 +1690,7 @@ dependencies = [
  "axum 0.7.9",
  "axum-core 0.4.5",
  "bytes",
- "fastrand",
+ "fastrand 2.2.0",
  "futures-util",
  "headers",
  "http 1.1.0",
@@ -1613,7 +1919,16 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
 dependencies = [
- "bit-vec",
+ "bit-vec 0.6.3",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
+dependencies = [
+ "bit-vec 0.7.0",
 ]
 
 [[package]]
@@ -1622,6 +1937,12 @@ version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
 
+[[package]]
+name = "bit-vec"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
+
 [[package]]
 name = "bit_field"
 version = "0.10.2"
@@ -1699,40 +2020,143 @@ dependencies = [
 ]
 
 [[package]]
-name = "block"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+name = "blitz-dom"
+version = "0.0.0"
+dependencies = [
+ "app_units",
+ "arboard",
+ "atomic_refcell",
+ "blitz-traits",
+ "data-url 0.3.1",
+ "dom",
+ "euclid",
+ "html-escape",
+ "image",
+ "markup5ever 0.14.0",
+ "parley",
+ "peniko",
+ "selectors 0.26.0",
+ "slab",
+ "string_cache",
+ "style",
+ "style_config",
+ "style_traits",
+ "stylo_taffy",
+ "taffy",
+ "tracing",
+ "url",
+ "usvg",
+ "winit",
+ "woff",
+]
 
 [[package]]
-name = "block-buffer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+name = "blitz-html"
+version = "0.1.0"
 dependencies = [
- "generic-array 0.14.7",
+ "blitz-dom",
+ "blitz-net",
+ "blitz-traits",
+ "html5ever 0.29.0",
+ "xml5ever",
 ]
 
 [[package]]
-name = "block-padding"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
+name = "blitz-net"
+version = "0.1.0"
 dependencies = [
- "generic-array 0.14.7",
+ "blitz-traits",
+ "data-url 0.3.1",
+ "reqwest 0.12.9",
+ "thiserror 1.0.69",
+ "tokio",
 ]
 
 [[package]]
-name = "block2"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
+name = "blitz-renderer-vello"
+version = "0.1.0"
 dependencies = [
- "objc2",
+ "blitz-dom",
+ "blitz-traits",
+ "euclid",
+ "futures-intrusive",
+ "image",
+ "parley",
+ "raw-window-handle 0.6.2",
+ "style",
+ "taffy",
+ "tracing",
+ "vello",
+ "vello_svg",
+ "wgpu 22.1.0",
 ]
 
 [[package]]
-name = "blocking"
+name = "blitz-shell"
+version = "0.0.0"
+dependencies = [
+ "accesskit",
+ "accesskit_winit",
+ "android-activity",
+ "blitz-dom",
+ "blitz-html",
+ "blitz-net",
+ "blitz-renderer-vello",
+ "blitz-traits",
+ "futures-util",
+ "muda 0.11.5",
+ "style",
+ "tokio",
+ "tracing",
+ "ureq",
+ "url",
+ "winit",
+]
+
+[[package]]
+name = "blitz-traits"
+version = "0.1.0"
+dependencies = [
+ "bytes",
+ "http 1.1.0",
+ "url",
+]
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array 0.14.7",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
+dependencies = [
+ "generic-array 0.14.7",
+]
+
+[[package]]
+name = "block2"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "blocking"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
@@ -1740,7 +2164,7 @@ dependencies = [
  "async-channel 2.3.1",
  "async-task",
  "futures-io",
- "futures-lite",
+ "futures-lite 2.5.0",
  "piper",
 ]
 
@@ -1892,6 +2316,20 @@ name = "bytemuck"
 version = "1.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
 
 [[package]]
 name = "byteorder"
@@ -1973,6 +2411,32 @@ dependencies = [
  "system-deps",
 ]
 
+[[package]]
+name = "calloop"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
+dependencies = [
+ "bitflags 2.6.0",
+ "log",
+ "polling 3.7.4",
+ "rustix 0.38.41",
+ "slab",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
+dependencies = [
+ "calloop",
+ "rustix 0.38.41",
+ "wayland-backend",
+ "wayland-client",
+]
+
 [[package]]
 name = "camellia"
 version = "0.1.0"
@@ -2305,6 +2769,15 @@ version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
 
+[[package]]
+name = "clipboard-win"
+version = "5.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
+dependencies = [
+ "error-code",
+]
+
 [[package]]
 name = "cmac"
 version = "0.7.2"
@@ -2742,6 +3215,27 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "core-text"
+version = "20.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5"
+dependencies = [
+ "core-foundation 0.9.4",
+ "core-graphics 0.23.2",
+ "foreign-types 0.5.0",
+ "libc",
+]
+
+[[package]]
+name = "core_maths"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3"
+dependencies = [
+ "libm",
+]
+
 [[package]]
 name = "cpio"
 version = "0.4.1"
@@ -2900,7 +3394,7 @@ dependencies = [
  "futures-core",
  "mio 1.0.3",
  "parking_lot",
- "rustix",
+ "rustix 0.38.41",
  "signal-hook",
  "signal-hook-mio",
  "winapi",
@@ -3003,6 +3497,20 @@ dependencies = [
  "smallvec",
 ]
 
+[[package]]
+name = "cssparser"
+version = "0.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3"
+dependencies = [
+ "cssparser-macros",
+ "dtoa-short",
+ "itoa 1.0.14",
+ "phf 0.11.2",
+ "serde",
+ "smallvec",
+]
+
 [[package]]
 name = "cssparser-color"
 version = "0.1.0"
@@ -3051,6 +3559,12 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "cursor-icon"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
+
 [[package]]
 name = "curve25519-dalek"
 version = "4.1.3"
@@ -3158,6 +3672,17 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "d3d12"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017"
+dependencies = [
+ "bitflags 2.6.0",
+ "libloading 0.8.6",
+ "winapi",
+]
+
 [[package]]
 name = "darling"
 version = "0.20.10"
@@ -3221,6 +3746,12 @@ dependencies = [
  "matches",
 ]
 
+[[package]]
+name = "data-url"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
+
 [[package]]
 name = "dbl"
 version = "0.3.2"
@@ -3271,6 +3802,17 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "derive_arbitrary"
 version = "1.4.1"
@@ -3392,6 +3934,7 @@ dependencies = [
  "dioxus-liveview",
  "dioxus-logger",
  "dioxus-mobile",
+ "dioxus-native",
  "dioxus-router",
  "dioxus-signals",
  "dioxus-ssr",
@@ -3791,7 +4334,7 @@ dependencies = [
  "serde_json",
  "tokio",
  "web-time",
- "wgpu",
+ "wgpu 0.19.4",
 ]
 
 [[package]]
@@ -4016,6 +4559,27 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "dioxus-native"
+version = "0.0.0"
+dependencies = [
+ "blitz-dom",
+ "blitz-net",
+ "blitz-renderer-vello",
+ "blitz-shell",
+ "blitz-traits",
+ "dioxus-cli-config",
+ "dioxus-core",
+ "dioxus-devtools",
+ "dioxus-html",
+ "futures-util",
+ "keyboard-types",
+ "rustc-hash 1.1.0",
+ "tokio",
+ "tracing",
+ "winit",
+]
+
 [[package]]
 name = "dioxus-playwright-fullstack-test"
 version = "0.1.0"
@@ -4284,6 +4848,15 @@ version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
 
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading 0.8.6",
+]
+
 [[package]]
 name = "dlopen2"
 version = "0.7.0"
@@ -4313,12 +4886,36 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
+[[package]]
+name = "document-features"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
+dependencies = [
+ "litrs",
+]
+
+[[package]]
+name = "dom"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "bitflags 2.6.0",
+ "malloc_size_of",
+]
+
 [[package]]
 name = "dotenvy"
 version = "0.15.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
+[[package]]
+name = "downcast-rs"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+
 [[package]]
 name = "dpi"
 version = "0.1.1"
@@ -4632,6 +5229,12 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "error-code"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
+
 [[package]]
 name = "escargot"
 version = "0.5.13"
@@ -4671,6 +5274,17 @@ version = "2.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
 
+[[package]]
+name = "event-listener"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "event-listener"
 version = "5.3.1"
@@ -4762,6 +5376,15 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
 
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
 [[package]]
 name = "fastrand"
 version = "2.2.0"
@@ -4809,7 +5432,7 @@ version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
 dependencies = [
- "memoffset",
+ "memoffset 0.9.1",
  "rustc_version 0.4.1",
 ]
 
@@ -4863,6 +5486,12 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "float-cmp"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+
 [[package]]
 name = "fluent-uri"
 version = "0.1.4"
@@ -4895,6 +5524,69 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
 
+[[package]]
+name = "font-types"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "fontconfig-cache-parser"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f8afb20c8069fd676d27b214559a337cc619a605d25a87baa90b49a06f3b18"
+dependencies = [
+ "bytemuck",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "fontconfig-parser"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7"
+dependencies = [
+ "roxmltree 0.20.0",
+]
+
+[[package]]
+name = "fontdb"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3a6f9af55fb97ad673fb7a69533eb2f967648a06fa21f8c9bb2cd6d33975716"
+dependencies = [
+ "fontconfig-parser",
+ "log",
+ "memmap2",
+ "slotmap",
+ "tinyvec",
+ "ttf-parser 0.24.1",
+]
+
+[[package]]
+name = "fontique"
+version = "0.2.0"
+source = "git+https://github.com/linebender/parley?rev=4ef147da7909f44827c78aa31b76f184152ab382#4ef147da7909f44827c78aa31b76f184152ab382"
+dependencies = [
+ "core-foundation 0.9.4",
+ "core-text",
+ "fontconfig-cache-parser",
+ "hashbrown 0.15.2",
+ "icu_locid",
+ "memmap2",
+ "objc2",
+ "objc2-foundation",
+ "peniko",
+ "read-fonts",
+ "roxmltree 0.19.0",
+ "smallvec",
+ "windows 0.58.0",
+ "windows-core 0.58.0",
+]
+
 [[package]]
 name = "foreign-types"
 version = "0.3.2"
@@ -5152,22 +5844,37 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
 
 [[package]]
 name = "futures-lite"
-version = "2.5.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
+checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
 dependencies = [
- "fastrand",
+ "fastrand 1.9.0",
  "futures-core",
  "futures-io",
+ "memchr",
  "parking",
  "pin-project-lite",
+ "waker-fn",
 ]
 
 [[package]]
-name = "futures-macro"
-version = "0.3.31"
+name = "futures-lite"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
+dependencies = [
+ "fastrand 2.2.0",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5342,6 +6049,16 @@ dependencies = [
  "typenum",
 ]
 
+[[package]]
+name = "gethostname"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
+dependencies = [
+ "libc",
+ "windows-targets 0.48.5",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.1.16"
@@ -5531,7 +6248,7 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575"
 dependencies = [
- "fastrand",
+ "fastrand 2.2.0",
  "gix-features",
  "gix-utils",
 ]
@@ -5660,7 +6377,7 @@ version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f"
 dependencies = [
- "fastrand",
+ "fastrand 2.2.0",
  "unicode-normalization",
 ]
 
@@ -5855,6 +6572,15 @@ dependencies = [
  "gl_generator",
 ]
 
+[[package]]
+name = "glutin_wgl_sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c"
+dependencies = [
+ "gl_generator",
+]
+
 [[package]]
 name = "gobject-sys"
 version = "0.18.0"
@@ -5909,6 +6635,19 @@ dependencies = [
  "windows 0.52.0",
 ]
 
+[[package]]
+name = "gpu-allocator"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7"
+dependencies = [
+ "log",
+ "presser",
+ "thiserror 1.0.69",
+ "winapi",
+ "windows 0.52.0",
+]
+
 [[package]]
 name = "gpu-descriptor"
 version = "0.2.4"
@@ -5916,7 +6655,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
 dependencies = [
  "bitflags 2.6.0",
- "gpu-descriptor-types",
+ "gpu-descriptor-types 0.1.2",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "gpu-descriptor"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557"
+dependencies = [
+ "bitflags 2.6.0",
+ "gpu-descriptor-types 0.2.0",
  "hashbrown 0.14.5",
 ]
 
@@ -5929,6 +6679,15 @@ dependencies = [
  "bitflags 2.6.0",
 ]
 
+[[package]]
+name = "gpu-descriptor-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
 [[package]]
 name = "grass"
 version = "0.13.4"
@@ -5954,6 +6713,12 @@ dependencies = [
  "rand 0.8.5",
 ]
 
+[[package]]
+name = "grid"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36119f3a540b086b4e436bb2b588cf98a68863470e0e880f4d0842f112a3183a"
+
 [[package]]
 name = "group"
 version = "0.12.1"
@@ -6028,6 +6793,16 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "guillotiere"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782"
+dependencies = [
+ "euclid",
+ "svg_fmt",
+]
+
 [[package]]
 name = "h2"
 version = "0.3.26"
@@ -6272,6 +7047,15 @@ dependencies = [
  "triomphe",
 ]
 
+[[package]]
+name = "html-escape"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
+dependencies = [
+ "utf8-width",
+]
+
 [[package]]
 name = "html5ever"
 version = "0.26.0"
@@ -6280,12 +7064,26 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
 dependencies = [
  "log",
  "mac",
- "markup5ever",
+ "markup5ever 0.11.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "html5ever"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e15626aaf9c351bc696217cbe29cb9b5e86c43f8a46b5e2f5c6c5cf7cb904ce"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever 0.14.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "html_parser"
 version = "0.7.0"
@@ -6415,7 +7213,7 @@ dependencies = [
  "httpdate",
  "itoa 1.0.14",
  "pin-project-lite",
- "socket2",
+ "socket2 0.5.8",
  "tokio",
  "tower-service",
  "tracing",
@@ -6520,7 +7318,7 @@ dependencies = [
  "http-body 1.0.1",
  "hyper 1.5.1",
  "pin-project-lite",
- "socket2",
+ "socket2 0.5.8",
  "tokio",
  "tower-service",
  "tracing",
@@ -6667,6 +7465,28 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "icu_segmenter"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a717725612346ffc2d7b42c94b820db6908048f39434504cb130e8b46256b0de"
+dependencies = [
+ "core_maths",
+ "displaydoc",
+ "icu_collections",
+ "icu_locid",
+ "icu_provider",
+ "icu_segmenter_data",
+ "utf8_iter",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_segmenter_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f739ee737260d955e330bc83fdeaaf1631f7fb7ed218761d3c04bb13bb7d79df"
+
 [[package]]
 name = "id-arena"
 version = "2.2.1"
@@ -6780,12 +7600,27 @@ dependencies = [
  "thread_local",
 ]
 
+[[package]]
+name = "imagesize"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
+
 [[package]]
 name = "imgref"
 version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
 
+[[package]]
+name = "immutable-chunkmap"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578"
+dependencies = [
+ "arrayvec",
+]
+
 [[package]]
 name = "include_dir"
 version = "0.7.4"
@@ -6950,6 +7785,17 @@ version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
 
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "ipnet"
 version = "2.10.1"
@@ -7337,10 +8183,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
 dependencies = [
  "cssparser 0.27.2",
- "html5ever",
+ "html5ever 0.26.0",
  "indexmap 1.9.3",
  "matches",
- "selectors",
+ "selectors 0.22.0",
+]
+
+[[package]]
+name = "kurbo"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f"
+dependencies = [
+ "arrayvec",
+ "smallvec",
 ]
 
 [[package]]
@@ -7480,7 +8336,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
  "bitflags 2.6.0",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.7",
 ]
 
 [[package]]
@@ -7587,6 +8443,12 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.14"
@@ -7656,6 +8518,12 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
 
+[[package]]
+name = "litrs"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
+
 [[package]]
 name = "lock_api"
 version = "0.4.12"
@@ -7750,6 +8618,34 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "malloc_size_of"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "app_units",
+ "cssparser 0.34.0",
+ "euclid",
+ "selectors 0.26.0",
+ "servo_arc 0.4.0",
+ "smallbitvec",
+ "smallvec",
+ "string_cache",
+ "thin-vec",
+ "void",
+]
+
+[[package]]
+name = "malloc_size_of_derive"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f44db74bde26fdf427af23f1d146c211aed857c59e3be750cf2617f6b0b05c94"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.90",
+ "synstructure 0.13.1",
+]
+
 [[package]]
 name = "manganis"
 version = "0.6.0"
@@ -7796,6 +8692,20 @@ dependencies = [
  "tendril",
 ]
 
+[[package]]
+name = "markup5ever"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82c88c6129bd24319e62a0359cb6b958fa7e8be6e19bb1663bc396b90883aca5"
+dependencies = [
+ "log",
+ "phf 0.11.2",
+ "phf_codegen 0.11.2",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
 [[package]]
 name = "matchers"
 version = "0.1.0"
@@ -7858,6 +8768,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
 [[package]]
 name = "memoffset"
 version = "0.9.1"
@@ -7882,6 +8801,21 @@ dependencies = [
  "paste",
 ]
 
+[[package]]
+name = "metal"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
+dependencies = [
+ "bitflags 2.6.0",
+ "block",
+ "core-graphics-types 0.1.3",
+ "foreign-types 0.5.0",
+ "log",
+ "objc",
+ "paste",
+]
+
 [[package]]
 name = "miette"
 version = "7.4.0"
@@ -8032,6 +8966,7 @@ dependencies = [
  "objc",
  "once_cell",
  "png",
+ "serde",
  "thiserror 1.0.69",
  "windows-sys 0.52.0",
 ]
@@ -8079,7 +9014,7 @@ version = "0.19.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843"
 dependencies = [
- "bit-set",
+ "bit-set 0.5.3",
  "bitflags 2.6.0",
  "codespan-reporting",
  "hexf-parse",
@@ -8093,6 +9028,27 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "naga"
+version = "22.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad"
+dependencies = [
+ "arrayvec",
+ "bit-set 0.6.0",
+ "bitflags 2.6.0",
+ "cfg_aliases 0.1.1",
+ "codespan-reporting",
+ "hexf-parse",
+ "indexmap 2.7.0",
+ "log",
+ "rustc-hash 1.1.0",
+ "spirv",
+ "termcolor",
+ "thiserror 1.0.69",
+ "unicode-xid",
+]
+
 [[package]]
 name = "names"
 version = "0.14.0"
@@ -8182,6 +9138,18 @@ version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
 
+[[package]]
+name = "nix"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+dependencies = [
+ "bitflags 1.3.2",
+ "cfg-if",
+ "libc",
+ "memoffset 0.7.1",
+]
+
 [[package]]
 name = "nix"
 version = "0.28.0"
@@ -8192,7 +9160,7 @@ dependencies = [
  "cfg-if",
  "cfg_aliases 0.1.1",
  "libc",
- "memoffset",
+ "memoffset 0.9.1",
 ]
 
 [[package]]
@@ -8205,7 +9173,7 @@ dependencies = [
  "cfg-if",
  "cfg_aliases 0.2.1",
  "libc",
- "memoffset",
+ "memoffset 0.9.1",
 ]
 
 [[package]]
@@ -8508,6 +9476,30 @@ dependencies = [
  "objc2-quartz-core",
 ]
 
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-contacts"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
 [[package]]
 name = "objc2-core-data"
 version = "0.2.2"
@@ -8532,6 +9524,18 @@ dependencies = [
  "objc2-metal",
 ]
 
+[[package]]
+name = "objc2-core-location"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-contacts",
+ "objc2-foundation",
+]
+
 [[package]]
 name = "objc2-encode"
 version = "4.0.3"
@@ -8546,27 +9550,40 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
 dependencies = [
  "bitflags 2.6.0",
  "block2",
+ "dispatch",
  "libc",
  "objc2",
 ]
 
 [[package]]
-name = "objc2-metal"
+name = "objc2-link-presentation"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
 dependencies = [
- "bitflags 2.6.0",
  "block2",
  "objc2",
+ "objc2-app-kit",
  "objc2-foundation",
 ]
 
 [[package]]
-name = "objc2-quartz-core"
+name = "objc2-metal"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
 dependencies = [
  "bitflags 2.6.0",
  "block2",
@@ -8575,6 +9592,61 @@ dependencies = [
  "objc2-metal",
 ]
 
+[[package]]
+name = "objc2-symbols"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-ui-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-foundation",
+ "objc2-link-presentation",
+ "objc2-quartz-core",
+ "objc2-symbols",
+ "objc2-uniform-type-identifiers",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-uniform-type-identifiers"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-user-notifications"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
 [[package]]
 name = "objc_exception"
 version = "0.1.2"
@@ -8739,6 +9811,15 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
+[[package]]
+name = "orbclient"
+version = "0.3.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43"
+dependencies = [
+ "libredox",
+]
+
 [[package]]
 name = "ordered-stream"
 version = "0.2.0"
@@ -8802,6 +9883,15 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
 
+[[package]]
+name = "owned_ttf_parser"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
+dependencies = [
+ "ttf-parser 0.25.1",
+]
+
 [[package]]
 name = "owo-colors"
 version = "4.1.0"
@@ -8926,7 +10016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb"
 dependencies = [
  "base64-simd 0.7.0",
- "data-url",
+ "data-url 0.1.1",
  "rkyv",
  "serde",
  "serde_json",
@@ -8957,11 +10047,23 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.7",
  "smallvec",
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "parley"
+version = "0.2.0"
+source = "git+https://github.com/linebender/parley?rev=4ef147da7909f44827c78aa31b76f184152ab382#4ef147da7909f44827c78aa31b76f184152ab382"
+dependencies = [
+ "fontique",
+ "hashbrown 0.15.2",
+ "peniko",
+ "skrifa",
+ "swash",
+]
+
 [[package]]
 name = "password-hash"
 version = "0.5.0"
@@ -9057,6 +10159,16 @@ dependencies = [
  "base64ct",
 ]
 
+[[package]]
+name = "peniko"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a648c93f502a0bef0a9cb47fa1335994958a2744667d3f82defe513f276741a"
+dependencies = [
+ "kurbo",
+ "smallvec",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.3.1"
@@ -9305,7 +10417,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
 dependencies = [
- "siphasher",
+ "siphasher 0.3.11",
 ]
 
 [[package]]
@@ -9314,7 +10426,7 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
 dependencies = [
- "siphasher",
+ "siphasher 0.3.11",
 ]
 
 [[package]]
@@ -9323,9 +10435,15 @@ version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
 dependencies = [
- "siphasher",
+ "siphasher 0.3.11",
 ]
 
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+
 [[package]]
 name = "pin-project"
 version = "1.1.7"
@@ -9365,7 +10483,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
 dependencies = [
  "atomic-waker",
- "fastrand",
+ "fastrand 2.2.0",
  "futures-io",
 ]
 
@@ -9420,7 +10538,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
 dependencies = [
  "base64 0.22.1",
  "indexmap 2.7.0",
- "quick-xml",
+ "quick-xml 0.32.0",
  "serde",
  "time",
 ]
@@ -9466,6 +10584,22 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "polling"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
+dependencies = [
+ "autocfg",
+ "bitflags 1.3.2",
+ "cfg-if",
+ "concurrent-queue",
+ "libc",
+ "log",
+ "pin-project-lite",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "polling"
 version = "3.7.4"
@@ -9476,7 +10610,7 @@ dependencies = [
  "concurrent-queue",
  "hermit-abi 0.4.0",
  "pin-project-lite",
- "rustix",
+ "rustix 0.38.41",
  "tracing",
  "windows-sys 0.59.0",
 ]
@@ -9789,6 +10923,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "quick-xml"
+version = "0.36.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "quinn"
 version = "0.11.6"
@@ -9801,7 +10944,7 @@ dependencies = [
  "quinn-udp",
  "rustc-hash 2.1.0",
  "rustls 0.23.19",
- "socket2",
+ "socket2 0.5.8",
  "thiserror 2.0.3",
  "tokio",
  "tracing",
@@ -9836,7 +10979,7 @@ dependencies = [
  "cfg_aliases 0.2.1",
  "libc",
  "once_cell",
- "socket2",
+ "socket2 0.5.8",
  "tracing",
  "windows-sys 0.59.0",
 ]
@@ -10099,6 +11242,25 @@ dependencies = [
  "cipher",
 ]
 
+[[package]]
+name = "read-fonts"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a04b892cb6f91951f144c33321843790c8574c825aafdb16d815fd7183b5229"
+dependencies = [
+ "bytemuck",
+ "font-types",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
 [[package]]
 name = "redox_syscall"
 version = "0.5.7"
@@ -10426,6 +11588,18 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "roxmltree"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
+
+[[package]]
+name = "roxmltree"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+
 [[package]]
 name = "rpm"
 version = "0.15.1"
@@ -10537,6 +11711,20 @@ dependencies = [
  "nom",
 ]
 
+[[package]]
+name = "rustix"
+version = "0.37.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "rustix"
 version = "0.38.41"
@@ -10546,7 +11734,7 @@ dependencies = [
  "bitflags 2.6.0",
  "errno",
  "libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.4.14",
  "windows-sys 0.52.0",
 ]
 
@@ -10684,6 +11872,24 @@ version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
 
+[[package]]
+name = "rustybuzz"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181"
+dependencies = [
+ "bitflags 2.6.0",
+ "bytemuck",
+ "core_maths",
+ "log",
+ "smallvec",
+ "ttf-parser 0.24.1",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-properties",
+ "unicode-script",
+]
+
 [[package]]
 name = "ruzstd"
 version = "0.5.0"
@@ -10792,6 +11998,19 @@ dependencies = [
  "untrusted 0.9.0",
 ]
 
+[[package]]
+name = "sctk-adwaita"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
+dependencies = [
+ "ab_glyph",
+ "log",
+ "memmap2",
+ "smithay-client-toolkit",
+ "tiny-skia",
+]
+
 [[package]]
 name = "seahash"
 version = "4.1.0"
@@ -10877,11 +12096,31 @@ dependencies = [
  "phf 0.8.0",
  "phf_codegen 0.8.0",
  "precomputed-hash",
- "servo_arc",
+ "servo_arc 0.1.1",
  "smallvec",
  "thin-slice",
 ]
 
+[[package]]
+name = "selectors"
+version = "0.26.0"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "bitflags 2.6.0",
+ "cssparser 0.34.0",
+ "derive_more",
+ "fxhash",
+ "log",
+ "new_debug_unreachable",
+ "phf 0.11.2",
+ "phf_codegen 0.11.2",
+ "precomputed-hash",
+ "servo_arc 0.4.0",
+ "smallvec",
+ "to_shmem",
+ "to_shmem_derive",
+]
+
 [[package]]
 name = "semver"
 version = "0.9.0"
@@ -11152,6 +12391,24 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "servo_arc"
+version = "0.4.0"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "servo_atoms"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "string_cache",
+ "string_cache_codegen",
+]
+
 [[package]]
 name = "sha1"
 version = "0.10.6"
@@ -11319,12 +12576,37 @@ dependencies = [
  "time",
 ]
 
+[[package]]
+name = "simplecss"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d"
+dependencies = [
+ "log",
+]
+
 [[package]]
 name = "siphasher"
 version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
 
+[[package]]
+name = "siphasher"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+
+[[package]]
+name = "skrifa"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe"
+dependencies = [
+ "bytemuck",
+ "read-fonts",
+]
+
 [[package]]
 name = "slab"
 version = "0.4.9"
@@ -11373,6 +12655,12 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "smallbitvec"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3fc564a4b53fd1e8589628efafe57602d91bde78be18186b5f61e8faea470"
+
 [[package]]
 name = "smallvec"
 version = "1.13.2"
@@ -11390,6 +12678,40 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "smithay-client-toolkit"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
+dependencies = [
+ "bitflags 2.6.0",
+ "calloop",
+ "calloop-wayland-source",
+ "cursor-icon",
+ "libc",
+ "log",
+ "memmap2",
+ "rustix 0.38.41",
+ "thiserror 1.0.69",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-csd-frame",
+ "wayland-cursor",
+ "wayland-protocols",
+ "wayland-protocols-wlr",
+ "wayland-scanner",
+ "xkeysym",
+]
+
+[[package]]
+name = "smol_str"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "snafu"
 version = "0.7.5"
@@ -11413,6 +12735,16 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "socket2"
 version = "0.5.8"
@@ -11561,7 +12893,7 @@ dependencies = [
  "ahash 0.8.11",
  "atoi",
  "bigdecimal",
- "bit-vec",
+ "bit-vec 0.6.3",
  "byteorder",
  "bytes",
  "chrono",
@@ -11698,7 +13030,7 @@ dependencies = [
  "atoi",
  "base64 0.21.7",
  "bigdecimal",
- "bit-vec",
+ "bit-vec 0.6.3",
  "bitflags 2.6.0",
  "byteorder",
  "chrono",
@@ -11808,6 +13140,20 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
+[[package]]
+name = "static_prefs"
+version = "0.1.0"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+dependencies = [
+ "float-cmp",
+]
+
 [[package]]
 name = "string_cache"
 version = "0.8.7"
@@ -11905,21 +13251,129 @@ dependencies = [
 ]
 
 [[package]]
-name = "subtle"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
-
-[[package]]
-name = "supports-color"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
+name = "style"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
 dependencies = [
- "is-terminal",
- "is_ci",
-]
-
+ "app_units",
+ "arrayvec",
+ "atomic_refcell",
+ "bitflags 2.6.0",
+ "byteorder",
+ "cssparser 0.34.0",
+ "derive_more",
+ "dom",
+ "encoding_rs",
+ "euclid",
+ "fxhash",
+ "icu_segmenter",
+ "indexmap 2.7.0",
+ "itertools 0.10.5",
+ "itoa 1.0.14",
+ "lazy_static",
+ "log",
+ "malloc_size_of",
+ "malloc_size_of_derive",
+ "markup5ever 0.14.0",
+ "matches",
+ "mime",
+ "new_debug_unreachable",
+ "num-derive",
+ "num-integer",
+ "num-traits",
+ "num_cpus",
+ "parking_lot",
+ "precomputed-hash",
+ "rayon",
+ "rayon-core",
+ "selectors 0.26.0",
+ "serde",
+ "servo_arc 0.4.0",
+ "servo_atoms",
+ "smallbitvec",
+ "smallvec",
+ "static_assertions",
+ "static_prefs",
+ "string_cache",
+ "style_config",
+ "style_derive",
+ "style_traits",
+ "thin-vec",
+ "to_shmem",
+ "to_shmem_derive",
+ "uluru",
+ "unicode-bidi",
+ "url",
+ "void",
+ "walkdir",
+]
+
+[[package]]
+name = "style_config"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "style_derive"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure 0.13.1",
+]
+
+[[package]]
+name = "style_traits"
+version = "0.0.1"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "app_units",
+ "bitflags 2.6.0",
+ "cssparser 0.34.0",
+ "euclid",
+ "lazy_static",
+ "malloc_size_of",
+ "malloc_size_of_derive",
+ "selectors 0.26.0",
+ "serde",
+ "servo_arc 0.4.0",
+ "servo_atoms",
+ "thin-vec",
+ "to_shmem",
+ "to_shmem_derive",
+ "url",
+]
+
+[[package]]
+name = "stylo_taffy"
+version = "0.1.0"
+dependencies = [
+ "style",
+ "taffy",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "supports-color"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
+dependencies = [
+ "is-terminal",
+ "is_ci",
+]
+
 [[package]]
 name = "supports-color"
 version = "3.0.2"
@@ -11938,6 +13392,31 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "svg_fmt"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa"
+
+[[package]]
+name = "svgtypes"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "794de53cc48eaabeed0ab6a3404a65f40b3e38c067e4435883a65d2aa4ca000e"
+dependencies = [
+ "kurbo",
+ "siphasher 1.0.1",
+]
+
+[[package]]
+name = "swash"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2"
+dependencies = [
+ "skrifa",
+]
+
 [[package]]
 name = "swc"
 version = "0.283.0"
@@ -12045,7 +13524,7 @@ dependencies = [
  "parking_lot",
  "rustc-hash 1.1.0",
  "serde",
- "siphasher",
+ "siphasher 0.3.11",
  "sourcemap",
  "swc_allocator",
  "swc_atoms",
@@ -13490,6 +14969,19 @@ dependencies = [
  "version-compare",
 ]
 
+[[package]]
+name = "taffy"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "136661daffcdfb128afb0d45a8f7e88078739196d64d7ffa47f8513f4a00a6d7"
+dependencies = [
+ "arrayvec",
+ "grid",
+ "num-traits",
+ "serde",
+ "slotmap",
+]
+
 [[package]]
 name = "tao"
 version = "0.30.0"
@@ -13656,7 +15148,7 @@ dependencies = [
  "ctor",
  "dunce",
  "glob",
- "html5ever",
+ "html5ever 0.26.0",
  "infer 0.16.0",
  "json-patch",
  "kuchikiki",
@@ -13684,8 +15176,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
 dependencies = [
  "cfg-if",
- "fastrand",
- "rustix",
+ "fastrand 2.2.0",
+ "rustix 0.38.41",
  "windows-sys 0.52.0",
 ]
 
@@ -13725,7 +15217,7 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
 dependencies = [
- "rustix",
+ "rustix 0.38.41",
  "windows-sys 0.59.0",
 ]
 
@@ -13864,6 +15356,31 @@ dependencies = [
  "crunchy",
 ]
 
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
 [[package]]
 name = "tinystr"
 version = "0.7.6"
@@ -13899,6 +15416,31 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
+[[package]]
+name = "to_shmem"
+version = "0.1.0"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "cssparser 0.34.0",
+ "servo_arc 0.4.0",
+ "smallbitvec",
+ "smallvec",
+ "string_cache",
+ "thin-vec",
+]
+
+[[package]]
+name = "to_shmem_derive"
+version = "0.1.0"
+source = "git+https://github.com/servo/stylo?rev=274e6531#274e653180be6f64c60834b5b47325ddb7a03b4a"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure 0.13.1",
+]
+
 [[package]]
 name = "tokio"
 version = "1.41.1"
@@ -13912,7 +15454,7 @@ dependencies = [
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2",
+ "socket2 0.5.8",
  "tokio-macros",
  "tracing",
  "windows-sys 0.52.0",
@@ -14348,6 +15890,21 @@ dependencies = [
  "toml",
 ]
 
+[[package]]
+name = "ttf-parser"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a"
+dependencies = [
+ "core_maths",
+]
+
+[[package]]
+name = "ttf-parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+
 [[package]]
 name = "tungstenite"
 version = "0.21.0"
@@ -14471,11 +16028,20 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
 dependencies = [
- "memoffset",
+ "memoffset 0.9.1",
  "tempfile",
  "winapi",
 ]
 
+[[package]]
+name = "uluru"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c8a2469e56e6e5095c82ccd3afb98dad95f7af7929aab6d8ba8d6e0f73657da"
+dependencies = [
+ "arrayvec",
+]
+
 [[package]]
 name = "uname"
 version = "0.1.1"
@@ -14547,12 +16113,24 @@ version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
 
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f"
+
 [[package]]
 name = "unicode-bom"
 version = "2.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217"
 
+[[package]]
+name = "unicode-ccc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42"
+
 [[package]]
 name = "unicode-id"
 version = "0.3.5"
@@ -14592,6 +16170,12 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
 
+[[package]]
+name = "unicode-script"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f"
+
 [[package]]
 name = "unicode-segmentation"
 version = "1.12.0"
@@ -14609,6 +16193,12 @@ dependencies = [
  "unicode-width 0.1.14",
 ]
 
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
 [[package]]
 name = "unicode-width"
 version = "0.1.14"
@@ -14668,6 +16258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
 dependencies = [
  "base64 0.22.1",
+ "flate2",
  "log",
  "once_cell",
  "rustls 0.23.19",
@@ -14707,6 +16298,33 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "usvg"
+version = "0.44.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7447e703d7223b067607655e625e0dbca80822880248937da65966194c4864e6"
+dependencies = [
+ "base64 0.22.1",
+ "data-url 0.3.1",
+ "flate2",
+ "fontdb",
+ "imagesize",
+ "kurbo",
+ "log",
+ "pico-args",
+ "roxmltree 0.20.0",
+ "rustybuzz",
+ "simplecss",
+ "siphasher 1.0.1",
+ "strict-num",
+ "svgtypes",
+ "tiny-skia-path",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
 [[package]]
 name = "utf-8"
 version = "0.7.6"
@@ -14719,6 +16337,12 @@ version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
 
+[[package]]
+name = "utf8-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
+
 [[package]]
 name = "utf8_iter"
 version = "1.0.4"
@@ -14771,6 +16395,63 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 
+[[package]]
+name = "vello"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc44dd4eb9af6a41551b9a82c93d068bd832693d6f78ab118ad19780d8e1202e"
+dependencies = [
+ "bytemuck",
+ "futures-intrusive",
+ "log",
+ "peniko",
+ "png",
+ "raw-window-handle 0.6.2",
+ "skrifa",
+ "static_assertions",
+ "thiserror 1.0.69",
+ "vello_encoding",
+ "vello_shaders",
+ "wgpu 22.1.0",
+]
+
+[[package]]
+name = "vello_encoding"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8110c14702a4e17f9200f6e3c4fe05dda5a22bf031ae4feafed4a61429f66fb2"
+dependencies = [
+ "bytemuck",
+ "guillotiere",
+ "peniko",
+ "skrifa",
+ "smallvec",
+]
+
+[[package]]
+name = "vello_shaders"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07cad02d6f29f2212a6ee382a8fec6f9977d0cceefacf07f8e361607ffe3988d"
+dependencies = [
+ "bytemuck",
+ "naga 22.1.0",
+ "thiserror 1.0.69",
+ "vello_encoding",
+]
+
+[[package]]
+name = "vello_svg"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbf8bc9b79b81a290cb8dfa3506c281c7300cc0fcf23e76ec5e2f0174bac4f03"
+dependencies = [
+ "image",
+ "thiserror 1.0.69",
+ "usvg",
+ "vello",
+]
+
 [[package]]
 name = "version-compare"
 version = "0.2.0"
@@ -14789,12 +16470,24 @@ version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff"
 
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
 [[package]]
 name = "vsimd"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
 
+[[package]]
+name = "waker-fn"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
+
 [[package]]
 name = "walkdir"
 version = "2.5.0"
@@ -15156,35 +16849,144 @@ dependencies = [
 ]
 
 [[package]]
-name = "web-sys"
-version = "0.3.76"
+name = "wayland-backend"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
+checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6"
 dependencies = [
- "js-sys",
- "wasm-bindgen",
+ "cc",
+ "downcast-rs",
+ "rustix 0.38.41",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
 ]
 
 [[package]]
-name = "web-time"
-version = "1.1.0"
+name = "wayland-client"
+version = "0.31.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280"
 dependencies = [
- "js-sys",
- "wasm-bindgen",
+ "bitflags 2.6.0",
+ "rustix 0.38.41",
+ "wayland-backend",
+ "wayland-scanner",
 ]
 
 [[package]]
-name = "webbrowser"
-version = "0.8.15"
+name = "wayland-csd-frame"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b"
+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
 dependencies = [
- "core-foundation 0.9.4",
- "home",
- "jni",
- "log",
+ "bitflags 2.6.0",
+ "cursor-icon",
+ "wayland-backend",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c"
+dependencies = [
+ "rustix 0.38.41",
+ "wayland-client",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.32.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e"
+dependencies = [
+ "bitflags 2.6.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-plasma"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd"
+dependencies = [
+ "bitflags 2.6.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-wlr"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022"
+dependencies = [
+ "bitflags 2.6.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml 0.36.2",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webbrowser"
+version = "0.8.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b"
+dependencies = [
+ "core-foundation 0.9.4",
+ "home",
+ "jni",
+ "log",
  "ndk-context",
  "objc",
  "raw-window-handle 0.5.2",
@@ -15261,8 +17063,8 @@ dependencies = [
  "webview2-com-sys",
  "windows 0.58.0",
  "windows-core 0.58.0",
- "windows-implement",
- "windows-interface",
+ "windows-implement 0.58.0",
+ "windows-interface 0.58.0",
 ]
 
 [[package]]
@@ -15304,7 +17106,32 @@ dependencies = [
  "cfg_aliases 0.1.1",
  "js-sys",
  "log",
- "naga",
+ "naga 0.19.2",
+ "parking_lot",
+ "profiling",
+ "raw-window-handle 0.6.2",
+ "smallvec",
+ "static_assertions",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "wgpu-core 0.19.4",
+ "wgpu-hal 0.19.5",
+ "wgpu-types 0.19.2",
+]
+
+[[package]]
+name = "wgpu"
+version = "22.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433"
+dependencies = [
+ "arrayvec",
+ "cfg_aliases 0.1.1",
+ "document-features",
+ "js-sys",
+ "log",
+ "naga 22.1.0",
  "parking_lot",
  "profiling",
  "raw-window-handle 0.6.2",
@@ -15313,9 +17140,9 @@ dependencies = [
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "web-sys",
- "wgpu-core",
- "wgpu-hal",
- "wgpu-types",
+ "wgpu-core 22.1.0",
+ "wgpu-hal 22.0.0",
+ "wgpu-types 22.0.0",
 ]
 
 [[package]]
@@ -15325,13 +17152,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a"
 dependencies = [
  "arrayvec",
- "bit-vec",
+ "bit-vec 0.6.3",
  "bitflags 2.6.0",
  "cfg_aliases 0.1.1",
  "codespan-reporting",
  "indexmap 2.7.0",
  "log",
- "naga",
+ "naga 0.19.2",
  "once_cell",
  "parking_lot",
  "profiling",
@@ -15340,8 +17167,33 @@ dependencies = [
  "smallvec",
  "thiserror 1.0.69",
  "web-sys",
- "wgpu-hal",
- "wgpu-types",
+ "wgpu-hal 0.19.5",
+ "wgpu-types 0.19.2",
+]
+
+[[package]]
+name = "wgpu-core"
+version = "22.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a"
+dependencies = [
+ "arrayvec",
+ "bit-vec 0.7.0",
+ "bitflags 2.6.0",
+ "cfg_aliases 0.1.1",
+ "document-features",
+ "indexmap 2.7.0",
+ "log",
+ "naga 22.1.0",
+ "once_cell",
+ "parking_lot",
+ "profiling",
+ "raw-window-handle 0.6.2",
+ "rustc-hash 1.1.0",
+ "smallvec",
+ "thiserror 1.0.69",
+ "wgpu-hal 22.0.0",
+ "wgpu-types 22.0.0",
 ]
 
 [[package]]
@@ -15352,26 +17204,26 @@ checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703"
 dependencies = [
  "android_system_properties",
  "arrayvec",
- "ash",
- "bit-set",
+ "ash 0.37.3+1.3.251",
+ "bit-set 0.5.3",
  "bitflags 2.6.0",
  "block",
  "cfg_aliases 0.1.1",
  "core-graphics-types 0.1.3",
- "d3d12",
+ "d3d12 0.19.0",
  "glow",
- "glutin_wgl_sys",
+ "glutin_wgl_sys 0.5.0",
  "gpu-alloc",
- "gpu-allocator",
- "gpu-descriptor",
+ "gpu-allocator 0.25.0",
+ "gpu-descriptor 0.2.4",
  "hassle-rs",
  "js-sys",
  "khronos-egl",
  "libc",
  "libloading 0.8.6",
  "log",
- "metal",
- "naga",
+ "metal 0.27.0",
+ "naga 0.19.2",
  "ndk-sys 0.5.0+25.2.9519653",
  "objc",
  "once_cell",
@@ -15385,7 +17237,52 @@ dependencies = [
  "thiserror 1.0.69",
  "wasm-bindgen",
  "web-sys",
- "wgpu-types",
+ "wgpu-types 0.19.2",
+ "winapi",
+]
+
+[[package]]
+name = "wgpu-hal"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f"
+dependencies = [
+ "android_system_properties",
+ "arrayvec",
+ "ash 0.38.0+1.3.281",
+ "bit-set 0.6.0",
+ "bitflags 2.6.0",
+ "block",
+ "cfg_aliases 0.1.1",
+ "core-graphics-types 0.1.3",
+ "d3d12 22.0.0",
+ "glow",
+ "glutin_wgl_sys 0.6.0",
+ "gpu-alloc",
+ "gpu-allocator 0.26.0",
+ "gpu-descriptor 0.3.0",
+ "hassle-rs",
+ "js-sys",
+ "khronos-egl",
+ "libc",
+ "libloading 0.8.6",
+ "log",
+ "metal 0.29.0",
+ "naga 22.1.0",
+ "ndk-sys 0.5.0+25.2.9519653",
+ "objc",
+ "once_cell",
+ "parking_lot",
+ "profiling",
+ "range-alloc",
+ "raw-window-handle 0.6.2",
+ "renderdoc-sys",
+ "rustc-hash 1.1.0",
+ "smallvec",
+ "thiserror 1.0.69",
+ "wasm-bindgen",
+ "web-sys",
+ "wgpu-types 22.0.0",
  "winapi",
 ]
 
@@ -15400,6 +17297,17 @@ dependencies = [
  "web-sys",
 ]
 
+[[package]]
+name = "wgpu-types"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d"
+dependencies = [
+ "bitflags 2.6.0",
+ "js-sys",
+ "web-sys",
+]
+
 [[package]]
 name = "which"
 version = "4.4.2"
@@ -15409,7 +17317,7 @@ dependencies = [
  "either",
  "home",
  "once_cell",
- "rustix",
+ "rustix 0.38.41",
 ]
 
 [[package]]
@@ -15418,7 +17326,7 @@ version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
 dependencies = [
- "redox_syscall",
+ "redox_syscall 0.5.7",
  "wasite",
 ]
 
@@ -15492,6 +17400,18 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
+dependencies = [
+ "windows-core 0.54.0",
+ "windows-implement 0.53.0",
+ "windows-interface 0.53.0",
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows"
 version = "0.58.0"
@@ -15511,19 +17431,40 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows-core"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
+dependencies = [
+ "windows-result 0.1.2",
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows-core"
 version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
 dependencies = [
- "windows-implement",
- "windows-interface",
- "windows-result",
+ "windows-implement 0.58.0",
+ "windows-interface 0.58.0",
+ "windows-result 0.2.0",
  "windows-strings 0.1.0",
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows-implement"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "windows-implement"
 version = "0.58.0"
@@ -15535,6 +17476,17 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "windows-interface"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "windows-interface"
 version = "0.58.0"
@@ -15552,7 +17504,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
 dependencies = [
- "windows-result",
+ "windows-result 0.2.0",
  "windows-strings 0.1.0",
  "windows-targets 0.52.6",
 ]
@@ -15563,11 +17515,20 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a"
 dependencies = [
- "windows-result",
+ "windows-result 0.2.0",
  "windows-strings 0.2.0",
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows-result"
 version = "0.2.0"
@@ -15583,7 +17544,7 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
 dependencies = [
- "windows-result",
+ "windows-result 0.2.0",
  "windows-targets 0.52.6",
 ]
 
@@ -15819,6 +17780,58 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
+[[package]]
+name = "winit"
+version = "0.30.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67"
+dependencies = [
+ "ahash 0.8.11",
+ "android-activity",
+ "atomic-waker",
+ "bitflags 2.6.0",
+ "block2",
+ "bytemuck",
+ "calloop",
+ "cfg_aliases 0.2.1",
+ "concurrent-queue",
+ "core-foundation 0.9.4",
+ "core-graphics 0.23.2",
+ "cursor-icon",
+ "dpi",
+ "js-sys",
+ "libc",
+ "memmap2",
+ "ndk",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "orbclient",
+ "percent-encoding",
+ "pin-project",
+ "raw-window-handle 0.6.2",
+ "redox_syscall 0.4.1",
+ "rustix 0.38.41",
+ "sctk-adwaita",
+ "smithay-client-toolkit",
+ "smol_str",
+ "tracing",
+ "unicode-segmentation",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-protocols-plasma",
+ "web-sys",
+ "web-time",
+ "windows-sys 0.52.0",
+ "x11-dl",
+ "x11rb",
+ "xkbcommon-dl",
+]
+
 [[package]]
 name = "winnow"
 version = "0.5.40"
@@ -15847,6 +17860,15 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "woff"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f117bea2f590de19e2ca1a065eb6f16969faa5674b13cf0f5bde1edc7684a9f7"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "write16"
 version = "1.0.0"
@@ -15874,7 +17896,7 @@ dependencies = [
  "dunce",
  "gdkx11",
  "gtk",
- "html5ever",
+ "html5ever 0.26.0",
  "http 1.1.0",
  "javascriptcore-rs",
  "jni",
@@ -15929,6 +17951,27 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "x11rb"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
+dependencies = [
+ "as-raw-xcb-connection",
+ "gethostname",
+ "libc",
+ "libloading 0.8.6",
+ "once_cell",
+ "rustix 0.38.41",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
+
 [[package]]
 name = "x25519-dalek"
 version = "2.0.1"
@@ -15977,10 +18020,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
 dependencies = [
  "libc",
- "linux-raw-sys",
- "rustix",
+ "linux-raw-sys 0.4.14",
+ "rustix 0.38.41",
 ]
 
+[[package]]
+name = "xcursor"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61"
+
 [[package]]
 name = "xdg-home"
 version = "1.3.0"
@@ -15991,18 +18040,54 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "xkbcommon-dl"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
+dependencies = [
+ "bitflags 2.6.0",
+ "dlib",
+ "log",
+ "once_cell",
+ "xkeysym",
+]
+
+[[package]]
+name = "xkeysym"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
+
 [[package]]
 name = "xml-rs"
 version = "0.8.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f"
 
+[[package]]
+name = "xml5ever"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2278b4bf33071ba8e30368a59436c65eec8e01c49d5c29b3dfeb0cdc45331383"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever 0.14.0",
+]
+
 [[package]]
 name = "xmlparser"
 version = "0.13.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
 
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
 [[package]]
 name = "xxhash-rust"
 version = "0.8.12"
@@ -16054,14 +18139,55 @@ dependencies = [
  "synstructure 0.13.1",
 ]
 
+[[package]]
+name = "zbus"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
+dependencies = [
+ "async-broadcast 0.5.1",
+ "async-executor",
+ "async-fs",
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
+ "async-process 1.8.1",
+ "async-recursion",
+ "async-task",
+ "async-trait",
+ "blocking",
+ "byteorder",
+ "derivative",
+ "enumflags2",
+ "event-listener 2.5.3",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "hex",
+ "nix 0.26.4",
+ "once_cell",
+ "ordered-stream",
+ "rand 0.8.5",
+ "serde",
+ "serde_repr",
+ "sha1",
+ "static_assertions",
+ "tracing",
+ "uds_windows",
+ "winapi",
+ "xdg-home",
+ "zbus_macros 3.15.2",
+ "zbus_names 2.6.1",
+ "zvariant 3.15.2",
+]
+
 [[package]]
 name = "zbus"
 version = "4.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
 dependencies = [
- "async-broadcast",
- "async-process",
+ "async-broadcast 0.7.1",
+ "async-process 2.3.0",
  "async-recursion",
  "async-trait",
  "enumflags2",
@@ -16082,9 +18208,23 @@ dependencies = [
  "uds_windows",
  "windows-sys 0.52.0",
  "xdg-home",
- "zbus_macros",
- "zbus_names",
- "zvariant",
+ "zbus_macros 4.4.0",
+ "zbus_names 3.0.0",
+ "zvariant 4.2.0",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "syn 1.0.109",
+ "zvariant_utils 1.0.1",
 ]
 
 [[package]]
@@ -16097,7 +18237,18 @@ dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.90",
- "zvariant_utils",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zbus_names"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
+dependencies = [
+ "serde",
+ "static_assertions",
+ "zvariant 3.15.2",
 ]
 
 [[package]]
@@ -16108,7 +18259,7 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
 dependencies = [
  "serde",
  "static_assertions",
- "zvariant",
+ "zvariant 4.2.0",
 ]
 
 [[package]]
@@ -16301,6 +18452,20 @@ dependencies = [
  "zune-core",
 ]
 
+[[package]]
+name = "zvariant"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db"
+dependencies = [
+ "byteorder",
+ "enumflags2",
+ "libc",
+ "serde",
+ "static_assertions",
+ "zvariant_derive 3.15.2",
+]
+
 [[package]]
 name = "zvariant"
 version = "4.2.0"
@@ -16312,7 +18477,20 @@ dependencies = [
  "serde",
  "static_assertions",
  "url",
- "zvariant_derive",
+ "zvariant_derive 4.2.0",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "zvariant_utils 1.0.1",
 ]
 
 [[package]]
@@ -16325,7 +18503,18 @@ dependencies = [
  "proc-macro2",
  "quote",
  "syn 2.0.90",
- "zvariant_utils",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
 ]
 
 [[package]]

+ 3 - 0
Cargo.toml

@@ -34,6 +34,7 @@ members = [
     "packages/devtools-types",
     "packages/devtools",
     "packages/dioxus-lib",
+    "packages/native",
     "packages/dioxus",
     "packages/document",
     "packages/extension",
@@ -123,6 +124,7 @@ dioxus-web = { path = "packages/web", version = "0.6.0", default-features = fals
 dioxus-isrg = { path = "packages/isrg", version = "0.6.0" }
 dioxus-ssr = { path = "packages/ssr", version = "0.6.0", default-features = false }
 dioxus-desktop = { path = "packages/desktop", version = "0.6.0", default-features = false }
+dioxus-native = { path = "packages/native", version = "0.0.0", default-features = false }
 dioxus-mobile = { path = "packages/mobile", version = "0.6.0" }
 dioxus-interpreter-js = { path = "packages/interpreter", version = "0.6.0" }
 dioxus-liveview = { path = "packages/liveview", version = "0.6.0" }
@@ -337,6 +339,7 @@ liveview = ["dioxus/liveview"]
 fullstack = ["dioxus/fullstack"]
 server = ["dioxus/server"]
 mobile = ["dioxus/mobile"]
+native = ["dioxus/native"]
 web = ["dioxus/web"]
 http = ["dep:reqwest", "dep:http-range"]
 gpu = ["dep:ouroboros", "dep:wgpu"]

+ 4 - 2
examples/todomvc.rs

@@ -3,7 +3,7 @@
 use dioxus::prelude::*;
 use std::collections::HashMap;
 
-const STYLE: Asset = asset!("/examples/assets/todomvc.css");
+const STYLE: &str = include_str!("../examples/assets/todomvc.css");
 
 fn main() {
     dioxus::launch(app);
@@ -63,7 +63,9 @@ fn app() -> Element {
     };
 
     rsx! {
-        document::Link { rel: "stylesheet", href: STYLE }
+        style {
+            {STYLE}
+        }
         section { class: "todoapp",
             TodoHeader { todos }
             section { class: "main",

+ 1 - 0
packages/config-macro/Cargo.toml

@@ -20,6 +20,7 @@ quote = { workspace = true }
 default = []
 fullstack = []
 desktop = []
+native = []
 mobile = []
 web = []
 ssr = []

+ 1 - 0
packages/config-macro/src/lib.rs

@@ -31,6 +31,7 @@ define_config_macro!(server_only if any(feature = "ssr", feature = "liveview"));
 define_config_macro!(client if any(feature = "desktop", feature = "web"));
 define_config_macro!(web if feature = "web");
 define_config_macro!(desktop if feature = "desktop");
+define_config_macro!(native if feature = "native");
 define_config_macro!(mobile if feature = "mobile");
 define_config_macro!(fullstack if feature = "fullstack");
 define_config_macro!(ssr if feature = "ssr");

+ 4 - 0
packages/dioxus/Cargo.toml

@@ -23,6 +23,9 @@ dioxus-router = { workspace = true, optional = true }
 dioxus-web = { workspace = true, default-features = false, optional = true }
 dioxus-mobile = { workspace = true, optional = true }
 dioxus-desktop = { workspace = true, default-features = true, optional = true }
+dioxus-native = { workspace = true, default-features = true, optional = true }
+# dioxus-native = { path = "../../../blitz/packages/dioxus-native", default-features = true, optional = true }
+# dioxus-native = { git = "https://github.com/DioxusLabs/blitz/packages/dioxus-native", rev = "16b5991f88", default-features = true, optional = true }
 dioxus-fullstack = { workspace = true, default-features = true, optional = true }
 dioxus-liveview = { workspace = true, optional = true }
 dioxus-ssr = { workspace = true, optional = true }
@@ -55,6 +58,7 @@ router = ["dep:dioxus-router"]
 # Platforms
 fullstack = ["dep:dioxus-fullstack", "dioxus-config-macro/fullstack", "dep:serde"]
 desktop = ["dep:dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"]
+native = ["dep:dioxus-native", "dioxus-config-macro/native"]
 mobile = ["dep:dioxus-mobile", "dioxus-fullstack?/mobile", "dioxus-config-macro/mobile"]
 web = ["dep:dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dioxus-cli-config", "dioxus-cli-config/web"]
 ssr = ["dep:dioxus-ssr", "dioxus-config-macro/ssr"]

+ 10 - 0
packages/dioxus/src/launch.rs

@@ -199,8 +199,15 @@ mod current_platform {
     #[cfg(all(feature = "fullstack", feature = "server"))]
     pub use dioxus_fullstack::server::launch::*;
 
+    #[cfg(all(
+        feature = "native",
+        not(all(feature = "fullstack", feature = "server"))
+    ))]
+    pub use dioxus_native::launch_generic as launch;
+
     #[cfg(all(
         feature = "desktop",
+        not(feature = "native"),
         not(all(feature = "fullstack", feature = "server"))
     ))]
     pub use dioxus_desktop::launch::*;
@@ -208,6 +215,7 @@ mod current_platform {
     #[cfg(all(
         feature = "mobile",
         not(feature = "desktop"),
+        not(feature = "native"),
         not(all(feature = "fullstack", feature = "server"))
     ))]
     pub use dioxus_mobile::launch_bindings::*;
@@ -217,6 +225,7 @@ mod current_platform {
         not(all(feature = "fullstack", feature = "server")),
         not(all(feature = "server")),
         not(feature = "desktop"),
+        not(feature = "native"),
         not(feature = "mobile"),
     ))]
     pub fn launch(
@@ -232,6 +241,7 @@ mod current_platform {
         not(all(feature = "fullstack", feature = "server")),
         not(all(feature = "server")),
         not(feature = "desktop"),
+        not(feature = "native"),
         not(feature = "mobile"),
         not(feature = "web"),
     ))]

+ 42 - 0
packages/native/Cargo.toml

@@ -0,0 +1,42 @@
+[package]
+name = "dioxus-native"
+version = "0.0.0"
+license = "MIT OR Apache-2.0"
+edition = "2021"
+
+[features]
+default = ["accessibility", "hot-reload", "menu", "tracing"]
+accessibility = ["blitz-shell/accessibility"]
+menu = ["blitz-shell/menu"]
+tracing = ["dep:tracing", "blitz-shell/tracing"]
+hot-reload = ["dep:dioxus-cli-config", "dep:dioxus-devtools"]
+
+[dependencies]
+# Blitz dependencies
+blitz-traits = { path = "../../../blitz/packages/blitz-traits" }
+blitz-dom = { path = "../../../blitz/packages/blitz-dom" }
+blitz-shell = { path = "../../../blitz/packages/blitz-shell" }
+blitz-net = { path = "../../../blitz/packages/blitz-net" }
+blitz-renderer-vello = { path = "../../../blitz/packages/blitz-renderer-vello" }
+
+# DioxusLabs dependencies
+dioxus-core = { workspace = true }
+dioxus-html = { workspace = true }
+dioxus-cli-config = { workspace = true, optional = true }
+dioxus-devtools = { workspace = true, optional = true }
+
+# Windowing & Input
+winit = { version = "0.30.2", features = ["rwh_06"] }
+keyboard-types = { version = "0.7", default-features = false }
+
+# IO & Networking
+tokio = { version = "1.25", features = ["full"] }
+
+# Other dependencies
+tracing = { workspace = true, optional = true }
+rustc-hash = { workspace = true }
+futures-util = { workspace = true }
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]

+ 96 - 0
packages/native/src/dioxus_application.rs

@@ -0,0 +1,96 @@
+use blitz_shell::BlitzApplication;
+use winit::application::ApplicationHandler;
+use winit::event::{StartCause, WindowEvent};
+use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
+use winit::window::WindowId;
+
+use crate::{BlitzEvent, DioxusDocument, DioxusNativeEvent, WindowConfig};
+
+pub struct DioxusNativeApplication {
+    inner: BlitzApplication<DioxusDocument>,
+}
+
+impl DioxusNativeApplication {
+    pub fn new(rt: tokio::runtime::Runtime, proxy: EventLoopProxy<BlitzEvent>) -> Self {
+        Self {
+            inner: BlitzApplication::new(rt, proxy.clone()),
+        }
+    }
+
+    pub fn add_window(&mut self, window_config: WindowConfig<DioxusDocument>) {
+        self.inner.add_window(window_config);
+    }
+
+    fn handle_blitz_shell_event(
+        &mut self,
+        event_loop: &ActiveEventLoop,
+        event: &DioxusNativeEvent,
+    ) {
+        match event {
+            #[cfg(all(
+                feature = "hot-reload",
+                debug_assertions,
+                not(target_os = "android"),
+                not(target_os = "ios")
+            ))]
+            DioxusNativeEvent::DevserverEvent(event) => match event {
+                dioxus_devtools::DevserverMsg::HotReload(hotreload_message) => {
+                    for window in self.inner.windows.values_mut() {
+                        dioxus_devtools::apply_changes(&window.doc.vdom, hotreload_message);
+                        window.poll();
+                    }
+                }
+                dioxus_devtools::DevserverMsg::Shutdown => event_loop.exit(),
+                dioxus_devtools::DevserverMsg::FullReloadStart => todo!(),
+                dioxus_devtools::DevserverMsg::FullReloadFailed => todo!(),
+                dioxus_devtools::DevserverMsg::FullReloadCommand => todo!(),
+            },
+
+            // Suppress unused variable warning
+            #[cfg(not(all(
+                feature = "hot-reload",
+                debug_assertions,
+                not(target_os = "android"),
+                not(target_os = "ios")
+            )))]
+            _ => {
+                let _ = event_loop;
+                let _ = event;
+            }
+        }
+    }
+}
+
+impl ApplicationHandler<BlitzEvent> for DioxusNativeApplication {
+    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
+        self.inner.resumed(event_loop);
+    }
+
+    fn suspended(&mut self, event_loop: &ActiveEventLoop) {
+        self.inner.suspended(event_loop);
+    }
+
+    fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
+        self.inner.new_events(event_loop, cause);
+    }
+
+    fn window_event(
+        &mut self,
+        event_loop: &ActiveEventLoop,
+        window_id: WindowId,
+        event: WindowEvent,
+    ) {
+        self.inner.window_event(event_loop, window_id, event);
+    }
+
+    fn user_event(&mut self, event_loop: &ActiveEventLoop, event: BlitzEvent) {
+        match event {
+            BlitzEvent::Embedder(event) => {
+                if let Some(event) = event.downcast_ref::<DioxusNativeEvent>() {
+                    self.handle_blitz_shell_event(event_loop, event);
+                }
+            }
+            event => self.inner.user_event(event_loop, event),
+        }
+    }
+}

+ 454 - 0
packages/native/src/dioxus_document.rs

@@ -0,0 +1,454 @@
+//! Integration between Dioxus and Blitz
+
+use std::{any::Any, collections::HashMap, rc::Rc, sync::Arc};
+
+use blitz_dom::{
+    events::{EventData, RendererEvent},
+    local_name, namespace_url,
+    net::Resource,
+    node::NodeSpecificData,
+    ns, Atom, ColorScheme, Document, DocumentLike, ElementNodeData, Node, NodeData, QualName,
+    Viewport, DEFAULT_CSS,
+};
+
+use blitz_traits::net::NetProvider;
+use dioxus_core::{ElementId, Event, VirtualDom};
+use dioxus_html::{set_event_converter, FormValue, PlatformEventData};
+use futures_util::{pin_mut, FutureExt};
+
+use super::event_handler::{NativeClickData, NativeConverter, NativeFormData};
+use crate::keyboard_event::BlitzKeyboardData;
+use crate::mutation_writer::{DioxusState, MutationWriter};
+use crate::NodeId;
+
+pub(crate) fn qual_name(local_name: &str, namespace: Option<&str>) -> QualName {
+    QualName {
+        prefix: None,
+        ns: namespace.map(Atom::from).unwrap_or(ns!(html)),
+        local: Atom::from(local_name),
+    }
+}
+
+pub struct DioxusDocument {
+    pub(crate) vdom: VirtualDom,
+    vdom_state: DioxusState,
+    inner: Document,
+}
+
+// Implement DocumentLike and required traits for DioxusDocument
+
+pub struct DxNodeIds {
+    node_id: usize,
+    dioxus_id: Option<ElementId>,
+}
+
+impl AsRef<Document> for DioxusDocument {
+    fn as_ref(&self) -> &Document {
+        &self.inner
+    }
+}
+impl AsMut<Document> for DioxusDocument {
+    fn as_mut(&mut self) -> &mut Document {
+        &mut self.inner
+    }
+}
+impl From<DioxusDocument> for Document {
+    fn from(doc: DioxusDocument) -> Document {
+        doc.inner
+    }
+}
+impl DocumentLike for DioxusDocument {
+    fn poll(&mut self, mut cx: std::task::Context) -> bool {
+        {
+            let fut = self.vdom.wait_for_work();
+            pin_mut!(fut);
+
+            match fut.poll_unpin(&mut cx) {
+                std::task::Poll::Ready(_) => {}
+                std::task::Poll::Pending => return false,
+            }
+        }
+
+        let mut writer = MutationWriter::new(&mut self.inner, &mut self.vdom_state);
+        self.vdom.render_immediate(&mut writer);
+
+        true
+    }
+
+    fn handle_event(&mut self, event: blitz_dom::events::RendererEvent) {
+        // Collect the nodes into a chain by traversing upwards
+        // This is important so the "capture" phase can be implemented
+        let mut next_node_id = Some(event.target);
+        let mut chain = Vec::with_capacity(16);
+
+        // if it's a capturing event, we want to fill in the chain with the parent nodes
+        // until we reach the root - that way we can call the listeners in the correct order
+        // otherwise, we just want to call the listeners on the target
+        //
+        // todo: this is harcoded for "click" events - eventually we actually need to handle proper propagation
+        // if event.name == "click" {
+        while let Some(node_id) = next_node_id {
+            let node = &self.inner.tree()[node_id];
+
+            if let Some(element) = node.element_data() {
+                let dioxus_id = DioxusDocument::dioxus_id(element);
+                chain.push(DxNodeIds { node_id, dioxus_id })
+            }
+
+            next_node_id = node.parent;
+        }
+
+        set_event_converter(Box::new(NativeConverter {}));
+
+        let renderer_event = event.clone();
+
+        let mut prevent_default = false;
+        let mut stop_propagation = false;
+
+        match &event.data {
+            EventData::Click { .. } => {
+                // look for the data-dioxus-id attribute on the element
+                // todo: we might need to walk upwards to find the first element with a data-dioxus-id attribute
+
+                let click_event_data = wrap_event_data(NativeClickData);
+
+                for &DxNodeIds { node_id, dioxus_id } in chain.iter() {
+                    let mut trigger_label = false;
+
+                    if let Some(id) = dioxus_id {
+                        // Trigger click event
+                        let click_event = Event::new(click_event_data.clone(), true);
+                        self.vdom
+                            .runtime()
+                            .handle_event("click", click_event.clone(), id);
+                        prevent_default |= !click_event.default_action_enabled();
+                        stop_propagation |= !click_event.propagates();
+
+                        if !prevent_default {
+                            let default_event = RendererEvent {
+                                target: node_id,
+                                data: renderer_event.data.clone(),
+                            };
+                            self.inner.as_mut().handle_event(default_event);
+                            prevent_default = true;
+
+                            let element = self.inner.tree()[node_id].element_data().unwrap();
+                            trigger_label = element.name.local == *"label";
+
+                            //TODO Check for other inputs which trigger input event on click here, eg radio
+                            let triggers_input_event = element.name.local == local_name!("input")
+                                && element.attr(local_name!("type")) == Some("checkbox");
+                            if triggers_input_event {
+                                let form_data =
+                                    wrap_event_data(self.input_event_form_data(&chain, element));
+                                let input_event = Event::new(form_data, true);
+                                self.vdom.runtime().handle_event("input", input_event, id);
+                            }
+                        }
+                    }
+
+                    //Clicking labels triggers click, and possibly input event, of bound input
+                    if trigger_label {
+                        if let Some((dioxus_id, node_id)) = self.label_bound_input_element(node_id)
+                        {
+                            let click_event = Event::new(click_event_data.clone(), true);
+                            self.vdom.runtime().handle_event(
+                                "click",
+                                click_event.clone(),
+                                dioxus_id,
+                            );
+
+                            // Handle default DOM event
+                            if click_event.default_action_enabled() {
+                                let &EventData::Click { mods, .. } = &renderer_event.data else {
+                                    unreachable!();
+                                };
+                                let input_click_data = self
+                                    .inner
+                                    .get_node(node_id)
+                                    .unwrap()
+                                    .synthetic_click_event(mods);
+                                let default_event = RendererEvent {
+                                    target: node_id,
+                                    data: input_click_data,
+                                };
+                                self.inner.as_mut().handle_event(default_event);
+                                prevent_default = true;
+
+                                // TODO: Generated click events should bubble separatedly
+                                // prevent_default |= !click_event.default_action_enabled();
+
+                                //TODO Check for other inputs which trigger input event on click here, eg radio
+                                let element_data = self
+                                    .inner
+                                    .get_node(node_id)
+                                    .unwrap()
+                                    .element_data()
+                                    .unwrap();
+                                let triggers_input_event =
+                                    element_data.attr(local_name!("type")) == Some("checkbox");
+                                let form_data = wrap_event_data(
+                                    self.input_event_form_data(&chain, element_data),
+                                );
+                                if triggers_input_event {
+                                    let input_event = Event::new(form_data, true);
+                                    self.vdom.runtime().handle_event(
+                                        "input",
+                                        input_event,
+                                        dioxus_id,
+                                    );
+                                }
+                            }
+                        }
+                    }
+
+                    if stop_propagation {
+                        break;
+                    }
+                }
+            }
+            EventData::KeyPress {
+                event: wevent,
+                mods,
+            } => {
+                let key_event_data =
+                    wrap_event_data(BlitzKeyboardData::from_winit(wevent, mods.state()));
+
+                for &DxNodeIds { node_id, dioxus_id } in chain.iter() {
+                    println!("{} {:?}", node_id, dioxus_id);
+
+                    if let Some(id) = dioxus_id {
+                        if wevent.state.is_pressed() {
+                            // Handle keydown event
+                            let event = Event::new(key_event_data.clone(), true);
+                            self.vdom
+                                .runtime()
+                                .handle_event("keydown", event.clone(), id);
+                            prevent_default |= !event.default_action_enabled();
+                            stop_propagation |= !event.propagates();
+
+                            if !prevent_default && wevent.text.is_some() {
+                                // Handle keypress event
+                                let event = Event::new(key_event_data.clone(), true);
+                                self.vdom
+                                    .runtime()
+                                    .handle_event("keypress", event.clone(), id);
+                                prevent_default |= !event.default_action_enabled();
+                                stop_propagation |= !event.propagates();
+
+                                if !prevent_default {
+                                    // Handle default DOM event
+                                    let default_event = RendererEvent {
+                                        target: node_id,
+                                        data: renderer_event.data.clone(),
+                                    };
+                                    self.inner.as_mut().handle_event(default_event);
+                                    prevent_default = true;
+
+                                    // Handle input event
+                                    let element =
+                                        self.inner.tree()[node_id].element_data().unwrap();
+                                    let triggers_input_event = &element.name.local == "input"
+                                        && matches!(
+                                            element.attr(local_name!("type")),
+                                            None | Some("text" | "password" | "email" | "search")
+                                        );
+                                    if triggers_input_event {
+                                        let form_data = wrap_event_data(dbg!(
+                                            self.input_event_form_data(&chain, element)
+                                        ));
+                                        let input_event = Event::new(form_data, true);
+                                        self.vdom.runtime().handle_event("input", input_event, id);
+                                    }
+                                }
+                            }
+                        } else {
+                            // Handle keyup event
+                            let event = Event::new(key_event_data.clone(), true);
+                            self.vdom.runtime().handle_event("keyup", event.clone(), id);
+                            prevent_default |= !event.default_action_enabled();
+                            stop_propagation |= !event.propagates();
+                        }
+                    }
+
+                    if stop_propagation {
+                        break;
+                    }
+                }
+            }
+            // TODO: Implement IME and Hover events handling
+            EventData::Ime(_) => {}
+            EventData::Hover => {}
+        }
+
+        if !prevent_default {
+            self.inner.as_mut().handle_event(event);
+        }
+    }
+}
+
+fn wrap_event_data<T: Any>(value: T) -> Rc<dyn Any> {
+    Rc::new(PlatformEventData::new(Box::new(value)))
+}
+
+impl DioxusDocument {
+    /// Generate the FormData from an input event
+    /// Currently only cares about input checkboxes
+    pub fn input_event_form_data(
+        &self,
+        parent_chain: &[DxNodeIds],
+        element_node_data: &ElementNodeData,
+    ) -> NativeFormData {
+        let parent_form = parent_chain.iter().map(|ids| ids.node_id).find_map(|id| {
+            let node = self.inner.get_node(id)?;
+            let element_data = node.element_data()?;
+            if element_data.name.local == local_name!("form") {
+                Some(node)
+            } else {
+                None
+            }
+        });
+        let values = if let Some(parent_form) = parent_form {
+            let mut values = HashMap::<String, FormValue>::new();
+            for form_input in self.input_descendents(parent_form).into_iter() {
+                // Match html behaviour here. To be included in values:
+                // - input must have a name
+                // - if its an input, we only include it if checked
+                // - if value is not specified, it defaults to 'on'
+                if let Some(name) = form_input.attr(local_name!("name")) {
+                    if form_input.attr(local_name!("type")) == Some("checkbox")
+                        && form_input
+                            .element_data()
+                            .and_then(|data| data.checkbox_input_checked())
+                            .unwrap_or(false)
+                    {
+                        let value = form_input
+                            .attr(local_name!("value"))
+                            .unwrap_or("on")
+                            .to_string();
+                        values.insert(name.to_string(), FormValue(vec![value]));
+                    }
+                }
+            }
+            values
+        } else {
+            Default::default()
+        };
+        let value = match &element_node_data.node_specific_data {
+            NodeSpecificData::CheckboxInput(checked) => checked.to_string(),
+            NodeSpecificData::TextInput(input_data) => input_data.editor.text().to_string(),
+            _ => element_node_data
+                .attr(local_name!("value"))
+                .unwrap_or_default()
+                .to_string(),
+        };
+
+        NativeFormData { value, values }
+    }
+
+    /// Collect all the inputs which are descendents of a given node
+    fn input_descendents(&self, node: &Node) -> Vec<&Node> {
+        node.children
+            .iter()
+            .flat_map(|id| {
+                let mut res = Vec::<&Node>::new();
+                let Some(n) = self.inner.get_node(*id) else {
+                    return res;
+                };
+                let Some(element_data) = n.element_data() else {
+                    return res;
+                };
+                if element_data.name.local == local_name!("input") {
+                    res.push(n);
+                }
+                res.extend(self.input_descendents(n).iter());
+                res
+            })
+            .collect()
+    }
+
+    pub fn new(
+        vdom: VirtualDom,
+        net_provider: Option<Arc<dyn NetProvider<Data = Resource>>>,
+    ) -> Self {
+        let viewport = Viewport::new(0, 0, 1.0, ColorScheme::Light);
+        let mut doc = Document::new(viewport);
+
+        // Set net provider
+        if let Some(net_provider) = net_provider {
+            doc.set_net_provider(net_provider);
+        }
+
+        // Create a virtual "html" element to act as the root element, as we won't necessarily
+        // have a single root otherwise, while the rest of blitz requires that we do
+        let html_element_id = doc.create_node(NodeData::Element(ElementNodeData::new(
+            qual_name("html", None),
+            Vec::new(),
+        )));
+        let root_node_id = doc.root_node().id;
+        let html_element = doc.get_node_mut(html_element_id).unwrap();
+        html_element.parent = Some(root_node_id);
+        let root_node = doc.get_node_mut(root_node_id).unwrap();
+        root_node.children.push(html_element_id);
+
+        // Include default and user-specified stylesheets
+        doc.add_user_agent_stylesheet(DEFAULT_CSS);
+
+        let state = DioxusState::create(&mut doc);
+        let mut doc = Self {
+            vdom,
+            vdom_state: state,
+            inner: doc,
+        };
+
+        doc.initial_build();
+
+        doc.inner.print_tree();
+
+        doc
+    }
+
+    pub fn initial_build(&mut self) {
+        let mut writer = MutationWriter::new(&mut self.inner, &mut self.vdom_state);
+        self.vdom.rebuild(&mut writer);
+        // dbg!(self.vdom.rebuild_to_vec());
+        // std::process::exit(0);
+        // dbg!(writer.state);
+    }
+
+    pub fn label_bound_input_element(&self, label_node_id: NodeId) -> Option<(ElementId, NodeId)> {
+        let bound_input_elements = self.inner.label_bound_input_elements(label_node_id);
+
+        // Filter down bound elements to those which have dioxus id
+        bound_input_elements.into_iter().find_map(|n| {
+            let target_element_data = n.element_data()?;
+            let node_id = n.id;
+            let dioxus_id = DioxusDocument::dioxus_id(target_element_data)?;
+            Some((dioxus_id, node_id))
+        })
+    }
+
+    fn dioxus_id(element_node_data: &ElementNodeData) -> Option<ElementId> {
+        Some(ElementId(
+            element_node_data
+                .attrs
+                .iter()
+                .find(|attr| *attr.name.local == *"data-dioxus-id")?
+                .value
+                .parse::<usize>()
+                .ok()?,
+        ))
+    }
+
+    // pub fn apply_mutations(&mut self) {
+    //     // Apply the mutations to the actual dom
+    //     let mut writer = MutationWriter {
+    //         doc: &mut self.inner,
+    //         state: &mut self.vdom_state,
+    //     };
+    //     self.vdom.render_immediate(&mut writer);
+
+    //     println!("APPLY MUTATIONS");
+    //     self.inner.print_tree();
+    // }
+}

+ 11 - 0
packages/native/src/event.rs

@@ -0,0 +1,11 @@
+/// Dioxus-native specific event type
+pub enum DioxusNativeEvent {
+    /// A hotreload event, basically telling us to update our templates.
+    #[cfg(all(
+        feature = "hot-reload",
+        debug_assertions,
+        not(target_os = "android"),
+        not(target_os = "ios")
+    ))]
+    DevserverEvent(dioxus_devtools::DevserverMsg),
+}

+ 156 - 0
packages/native/src/event_handler.rs

@@ -0,0 +1,156 @@
+use std::collections::HashMap;
+
+use dioxus_html::{FormValue, HasFileData, HasFormData, HtmlEventConverter, PlatformEventData};
+
+use super::keyboard_event::BlitzKeyboardData;
+
+#[derive(Clone)]
+pub struct NativeClickData;
+
+impl dioxus_html::point_interaction::InteractionLocation for NativeClickData {
+    fn client_coordinates(&self) -> dioxus_html::geometry::ClientPoint {
+        todo!()
+    }
+
+    fn screen_coordinates(&self) -> dioxus_html::geometry::ScreenPoint {
+        todo!()
+    }
+
+    fn page_coordinates(&self) -> dioxus_html::geometry::PagePoint {
+        todo!()
+    }
+}
+impl dioxus_html::point_interaction::InteractionElementOffset for NativeClickData {
+    fn element_coordinates(&self) -> dioxus_html::geometry::ElementPoint {
+        todo!()
+    }
+}
+impl dioxus_html::point_interaction::ModifiersInteraction for NativeClickData {
+    fn modifiers(&self) -> keyboard_types::Modifiers {
+        todo!()
+    }
+}
+
+impl dioxus_html::point_interaction::PointerInteraction for NativeClickData {
+    fn trigger_button(&self) -> Option<dioxus_html::input_data::MouseButton> {
+        todo!()
+    }
+
+    fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
+        todo!()
+    }
+}
+impl dioxus_html::HasMouseData for NativeClickData {
+    fn as_any(&self) -> &dyn std::any::Any {
+        self as &dyn std::any::Any
+    }
+}
+
+pub struct NativeConverter {}
+
+impl HtmlEventConverter for NativeConverter {
+    fn convert_animation_data(&self, _event: &PlatformEventData) -> dioxus_html::AnimationData {
+        todo!()
+    }
+
+    fn convert_clipboard_data(&self, _event: &PlatformEventData) -> dioxus_html::ClipboardData {
+        todo!()
+    }
+
+    fn convert_composition_data(&self, _event: &PlatformEventData) -> dioxus_html::CompositionData {
+        todo!()
+    }
+
+    fn convert_drag_data(&self, _event: &PlatformEventData) -> dioxus_html::DragData {
+        todo!()
+    }
+
+    fn convert_focus_data(&self, _event: &PlatformEventData) -> dioxus_html::FocusData {
+        todo!()
+    }
+
+    fn convert_form_data(&self, event: &PlatformEventData) -> dioxus_html::FormData {
+        let o = event.downcast::<NativeFormData>().unwrap().clone();
+        dioxus_html::FormData::from(o)
+    }
+
+    fn convert_image_data(&self, _event: &PlatformEventData) -> dioxus_html::ImageData {
+        todo!()
+    }
+
+    fn convert_keyboard_data(&self, event: &PlatformEventData) -> dioxus_html::KeyboardData {
+        let data = event.downcast::<BlitzKeyboardData>().unwrap().clone();
+        dioxus_html::KeyboardData::from(data)
+    }
+
+    fn convert_media_data(&self, _event: &PlatformEventData) -> dioxus_html::MediaData {
+        todo!()
+    }
+
+    fn convert_mounted_data(&self, _event: &PlatformEventData) -> dioxus_html::MountedData {
+        todo!()
+    }
+
+    fn convert_mouse_data(&self, event: &PlatformEventData) -> dioxus_html::MouseData {
+        let o = event.downcast::<NativeClickData>().unwrap().clone();
+        dioxus_html::MouseData::from(o)
+    }
+
+    fn convert_pointer_data(&self, _event: &PlatformEventData) -> dioxus_html::PointerData {
+        todo!()
+    }
+
+    fn convert_scroll_data(&self, _event: &PlatformEventData) -> dioxus_html::ScrollData {
+        todo!()
+    }
+
+    fn convert_selection_data(&self, _event: &PlatformEventData) -> dioxus_html::SelectionData {
+        todo!()
+    }
+
+    fn convert_toggle_data(&self, _event: &PlatformEventData) -> dioxus_html::ToggleData {
+        todo!()
+    }
+
+    fn convert_touch_data(&self, _event: &PlatformEventData) -> dioxus_html::TouchData {
+        todo!()
+    }
+
+    fn convert_transition_data(&self, _event: &PlatformEventData) -> dioxus_html::TransitionData {
+        todo!()
+    }
+
+    fn convert_wheel_data(&self, _event: &PlatformEventData) -> dioxus_html::WheelData {
+        todo!()
+    }
+
+    fn convert_resize_data(&self, _event: &PlatformEventData) -> dioxus_html::ResizeData {
+        todo!()
+    }
+
+    fn convert_visible_data(&self, _event: &PlatformEventData) -> dioxus_html::VisibleData {
+        todo!()
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct NativeFormData {
+    pub value: String,
+    pub values: HashMap<String, FormValue>,
+}
+
+impl HasFormData for NativeFormData {
+    fn as_any(&self) -> &dyn std::any::Any {
+        self as &dyn std::any::Any
+    }
+
+    fn value(&self) -> String {
+        self.value.clone()
+    }
+
+    fn values(&self) -> HashMap<String, FormValue> {
+        self.values.clone()
+    }
+}
+
+impl HasFileData for NativeFormData {}

+ 615 - 0
packages/native/src/keyboard_event.rs

@@ -0,0 +1,615 @@
+use std::any::Any;
+
+use dioxus_html::{point_interaction::ModifiersInteraction, HasKeyboardData};
+use keyboard_types::{Code, Key, Location, Modifiers};
+
+use winit::event::KeyEvent as WinitKeyEvent;
+use winit::keyboard::Key as WinitKey;
+use winit::keyboard::KeyCode as WinitKeyCode;
+use winit::keyboard::KeyLocation as WinitKeyLocation;
+use winit::keyboard::ModifiersState as WinitModifiers;
+use winit::keyboard::NamedKey as WinitNamedKey;
+use winit::keyboard::PhysicalKey as WinitPhysicalKey;
+
+#[derive(Clone, Debug)]
+pub(crate) struct BlitzKeyboardData {
+    key: Key,
+    code: Code,
+    modifiers: Modifiers,
+    location: Location,
+    is_auto_repeating: bool,
+    is_composing: bool,
+}
+
+impl ModifiersInteraction for BlitzKeyboardData {
+    fn modifiers(&self) -> Modifiers {
+        self.modifiers
+    }
+}
+
+impl HasKeyboardData for BlitzKeyboardData {
+    fn key(&self) -> Key {
+        self.key.clone()
+    }
+
+    fn code(&self) -> Code {
+        self.code
+    }
+
+    fn location(&self) -> Location {
+        self.location
+    }
+
+    fn is_auto_repeating(&self) -> bool {
+        self.is_auto_repeating
+    }
+
+    fn is_composing(&self) -> bool {
+        self.is_composing
+    }
+
+    fn as_any(&self) -> &dyn std::any::Any {
+        self as &dyn Any
+    }
+}
+
+impl BlitzKeyboardData {
+    pub(crate) fn from_winit(event: &WinitKeyEvent, mods: WinitModifiers) -> Self {
+        Self {
+            key: winit_key_to_kbt_key(&event.logical_key),
+            code: winit_physical_key_to_kbt_code(&event.physical_key),
+            modifiers: winit_modifiers_to_kbt_modifiers(mods),
+            location: winit_key_location_to_kbt_location(event.location),
+            is_auto_repeating: event.repeat,
+            is_composing: false,
+        }
+    }
+}
+
+fn winit_modifiers_to_kbt_modifiers(winit_modifiers: WinitModifiers) -> Modifiers {
+    let mut modifiers = Modifiers::default();
+    if winit_modifiers.control_key() {
+        modifiers.insert(Modifiers::CONTROL);
+    }
+    if winit_modifiers.alt_key() {
+        modifiers.insert(Modifiers::ALT);
+    }
+    if winit_modifiers.shift_key() {
+        modifiers.insert(Modifiers::SHIFT);
+    }
+    if winit_modifiers.super_key() {
+        modifiers.insert(Modifiers::SUPER);
+    }
+    modifiers
+}
+
+fn winit_key_location_to_kbt_location(location: WinitKeyLocation) -> Location {
+    match location {
+        WinitKeyLocation::Standard => Location::Standard,
+        WinitKeyLocation::Left => Location::Left,
+        WinitKeyLocation::Right => Location::Right,
+        WinitKeyLocation::Numpad => Location::Numpad,
+    }
+}
+
+fn winit_physical_key_to_kbt_code(physical_key: &WinitPhysicalKey) -> Code {
+    match physical_key {
+        WinitPhysicalKey::Unidentified(_) => Code::Unidentified,
+        WinitPhysicalKey::Code(key_code) => match key_code {
+            // Variants that don't match 1:1
+            WinitKeyCode::Meta => Code::Super,
+            WinitKeyCode::SuperLeft => Code::Super,
+            WinitKeyCode::SuperRight => Code::Super,
+
+            WinitKeyCode::Backquote => Code::Backquote,
+            WinitKeyCode::Backslash => Code::Backslash,
+            WinitKeyCode::BracketLeft => Code::BracketLeft,
+            WinitKeyCode::BracketRight => Code::BracketRight,
+            WinitKeyCode::Comma => Code::Comma,
+            WinitKeyCode::Digit0 => Code::Digit0,
+            WinitKeyCode::Digit1 => Code::Digit1,
+            WinitKeyCode::Digit2 => Code::Digit2,
+            WinitKeyCode::Digit3 => Code::Digit3,
+            WinitKeyCode::Digit4 => Code::Digit4,
+            WinitKeyCode::Digit5 => Code::Digit5,
+            WinitKeyCode::Digit6 => Code::Digit6,
+            WinitKeyCode::Digit7 => Code::Digit7,
+            WinitKeyCode::Digit8 => Code::Digit8,
+            WinitKeyCode::Digit9 => Code::Digit9,
+            WinitKeyCode::Equal => Code::Equal,
+            WinitKeyCode::IntlBackslash => Code::IntlBackslash,
+            WinitKeyCode::IntlRo => Code::IntlRo,
+            WinitKeyCode::IntlYen => Code::IntlYen,
+            WinitKeyCode::KeyA => Code::KeyA,
+            WinitKeyCode::KeyB => Code::KeyB,
+            WinitKeyCode::KeyC => Code::KeyC,
+            WinitKeyCode::KeyD => Code::KeyD,
+            WinitKeyCode::KeyE => Code::KeyE,
+            WinitKeyCode::KeyF => Code::KeyF,
+            WinitKeyCode::KeyG => Code::KeyG,
+            WinitKeyCode::KeyH => Code::KeyH,
+            WinitKeyCode::KeyI => Code::KeyI,
+            WinitKeyCode::KeyJ => Code::KeyJ,
+            WinitKeyCode::KeyK => Code::KeyK,
+            WinitKeyCode::KeyL => Code::KeyL,
+            WinitKeyCode::KeyM => Code::KeyM,
+            WinitKeyCode::KeyN => Code::KeyN,
+            WinitKeyCode::KeyO => Code::KeyO,
+            WinitKeyCode::KeyP => Code::KeyP,
+            WinitKeyCode::KeyQ => Code::KeyQ,
+            WinitKeyCode::KeyR => Code::KeyR,
+            WinitKeyCode::KeyS => Code::KeyS,
+            WinitKeyCode::KeyT => Code::KeyT,
+            WinitKeyCode::KeyU => Code::KeyU,
+            WinitKeyCode::KeyV => Code::KeyV,
+            WinitKeyCode::KeyW => Code::KeyW,
+            WinitKeyCode::KeyX => Code::KeyX,
+            WinitKeyCode::KeyY => Code::KeyY,
+            WinitKeyCode::KeyZ => Code::KeyZ,
+            WinitKeyCode::Minus => Code::Minus,
+            WinitKeyCode::Period => Code::Period,
+            WinitKeyCode::Quote => Code::Quote,
+            WinitKeyCode::Semicolon => Code::Semicolon,
+            WinitKeyCode::Slash => Code::Slash,
+            WinitKeyCode::AltLeft => Code::AltLeft,
+            WinitKeyCode::AltRight => Code::AltRight,
+            WinitKeyCode::Backspace => Code::Backspace,
+            WinitKeyCode::CapsLock => Code::CapsLock,
+            WinitKeyCode::ContextMenu => Code::ContextMenu,
+            WinitKeyCode::ControlLeft => Code::ControlLeft,
+            WinitKeyCode::ControlRight => Code::ControlRight,
+            WinitKeyCode::Enter => Code::Enter,
+            WinitKeyCode::ShiftLeft => Code::ShiftLeft,
+            WinitKeyCode::ShiftRight => Code::ShiftRight,
+            WinitKeyCode::Space => Code::Space,
+            WinitKeyCode::Tab => Code::Tab,
+            WinitKeyCode::Convert => Code::Convert,
+            WinitKeyCode::KanaMode => Code::KanaMode,
+            WinitKeyCode::Lang1 => Code::Lang1,
+            WinitKeyCode::Lang2 => Code::Lang2,
+            WinitKeyCode::Lang3 => Code::Lang3,
+            WinitKeyCode::Lang4 => Code::Lang4,
+            WinitKeyCode::Lang5 => Code::Lang5,
+            WinitKeyCode::NonConvert => Code::NonConvert,
+            WinitKeyCode::Delete => Code::Delete,
+            WinitKeyCode::End => Code::End,
+            WinitKeyCode::Help => Code::Help,
+            WinitKeyCode::Home => Code::Home,
+            WinitKeyCode::Insert => Code::Insert,
+            WinitKeyCode::PageDown => Code::PageDown,
+            WinitKeyCode::PageUp => Code::PageUp,
+            WinitKeyCode::ArrowDown => Code::ArrowDown,
+            WinitKeyCode::ArrowLeft => Code::ArrowLeft,
+            WinitKeyCode::ArrowRight => Code::ArrowRight,
+            WinitKeyCode::ArrowUp => Code::ArrowUp,
+            WinitKeyCode::NumLock => Code::NumLock,
+            WinitKeyCode::Numpad0 => Code::Numpad0,
+            WinitKeyCode::Numpad1 => Code::Numpad1,
+            WinitKeyCode::Numpad2 => Code::Numpad2,
+            WinitKeyCode::Numpad3 => Code::Numpad3,
+            WinitKeyCode::Numpad4 => Code::Numpad4,
+            WinitKeyCode::Numpad5 => Code::Numpad5,
+            WinitKeyCode::Numpad6 => Code::Numpad6,
+            WinitKeyCode::Numpad7 => Code::Numpad7,
+            WinitKeyCode::Numpad8 => Code::Numpad8,
+            WinitKeyCode::Numpad9 => Code::Numpad9,
+            WinitKeyCode::NumpadAdd => Code::NumpadAdd,
+            WinitKeyCode::NumpadBackspace => Code::NumpadBackspace,
+            WinitKeyCode::NumpadClear => Code::NumpadClear,
+            WinitKeyCode::NumpadClearEntry => Code::NumpadClearEntry,
+            WinitKeyCode::NumpadComma => Code::NumpadComma,
+            WinitKeyCode::NumpadDecimal => Code::NumpadDecimal,
+            WinitKeyCode::NumpadDivide => Code::NumpadDivide,
+            WinitKeyCode::NumpadEnter => Code::NumpadEnter,
+            WinitKeyCode::NumpadEqual => Code::NumpadEqual,
+            WinitKeyCode::NumpadHash => Code::NumpadHash,
+            WinitKeyCode::NumpadMemoryAdd => Code::NumpadMemoryAdd,
+            WinitKeyCode::NumpadMemoryClear => Code::NumpadMemoryClear,
+            WinitKeyCode::NumpadMemoryRecall => Code::NumpadMemoryRecall,
+            WinitKeyCode::NumpadMemoryStore => Code::NumpadMemoryStore,
+            WinitKeyCode::NumpadMemorySubtract => Code::NumpadMemorySubtract,
+            WinitKeyCode::NumpadMultiply => Code::NumpadMultiply,
+            WinitKeyCode::NumpadParenLeft => Code::NumpadParenLeft,
+            WinitKeyCode::NumpadParenRight => Code::NumpadParenRight,
+            WinitKeyCode::NumpadStar => Code::NumpadStar,
+            WinitKeyCode::NumpadSubtract => Code::NumpadSubtract,
+            WinitKeyCode::Escape => Code::Escape,
+            WinitKeyCode::Fn => Code::Fn,
+            WinitKeyCode::FnLock => Code::FnLock,
+            WinitKeyCode::PrintScreen => Code::PrintScreen,
+            WinitKeyCode::ScrollLock => Code::ScrollLock,
+            WinitKeyCode::Pause => Code::Pause,
+            WinitKeyCode::BrowserBack => Code::BrowserBack,
+            WinitKeyCode::BrowserFavorites => Code::BrowserFavorites,
+            WinitKeyCode::BrowserForward => Code::BrowserForward,
+            WinitKeyCode::BrowserHome => Code::BrowserHome,
+            WinitKeyCode::BrowserRefresh => Code::BrowserRefresh,
+            WinitKeyCode::BrowserSearch => Code::BrowserSearch,
+            WinitKeyCode::BrowserStop => Code::BrowserStop,
+            WinitKeyCode::Eject => Code::Eject,
+            WinitKeyCode::LaunchApp1 => Code::LaunchApp1,
+            WinitKeyCode::LaunchApp2 => Code::LaunchApp2,
+            WinitKeyCode::LaunchMail => Code::LaunchMail,
+            WinitKeyCode::MediaPlayPause => Code::MediaPlayPause,
+            WinitKeyCode::MediaSelect => Code::MediaSelect,
+            WinitKeyCode::MediaStop => Code::MediaStop,
+            WinitKeyCode::MediaTrackNext => Code::MediaTrackNext,
+            WinitKeyCode::MediaTrackPrevious => Code::MediaTrackPrevious,
+            WinitKeyCode::Power => Code::Power,
+            WinitKeyCode::Sleep => Code::Sleep,
+            WinitKeyCode::AudioVolumeDown => Code::AudioVolumeDown,
+            WinitKeyCode::AudioVolumeMute => Code::AudioVolumeMute,
+            WinitKeyCode::AudioVolumeUp => Code::AudioVolumeUp,
+            WinitKeyCode::WakeUp => Code::WakeUp,
+            WinitKeyCode::Hyper => Code::Hyper,
+            WinitKeyCode::Turbo => Code::Turbo,
+            WinitKeyCode::Abort => Code::Abort,
+            WinitKeyCode::Resume => Code::Resume,
+            WinitKeyCode::Suspend => Code::Suspend,
+            WinitKeyCode::Again => Code::Again,
+            WinitKeyCode::Copy => Code::Copy,
+            WinitKeyCode::Cut => Code::Cut,
+            WinitKeyCode::Find => Code::Find,
+            WinitKeyCode::Open => Code::Open,
+            WinitKeyCode::Paste => Code::Paste,
+            WinitKeyCode::Props => Code::Props,
+            WinitKeyCode::Select => Code::Select,
+            WinitKeyCode::Undo => Code::Undo,
+            WinitKeyCode::Hiragana => Code::Hiragana,
+            WinitKeyCode::Katakana => Code::Katakana,
+            WinitKeyCode::F1 => Code::F1,
+            WinitKeyCode::F2 => Code::F2,
+            WinitKeyCode::F3 => Code::F3,
+            WinitKeyCode::F4 => Code::F4,
+            WinitKeyCode::F5 => Code::F5,
+            WinitKeyCode::F6 => Code::F6,
+            WinitKeyCode::F7 => Code::F7,
+            WinitKeyCode::F8 => Code::F8,
+            WinitKeyCode::F9 => Code::F9,
+            WinitKeyCode::F10 => Code::F10,
+            WinitKeyCode::F11 => Code::F11,
+            WinitKeyCode::F12 => Code::F12,
+            WinitKeyCode::F13 => Code::F13,
+            WinitKeyCode::F14 => Code::F14,
+            WinitKeyCode::F15 => Code::F15,
+            WinitKeyCode::F16 => Code::F16,
+            WinitKeyCode::F17 => Code::F17,
+            WinitKeyCode::F18 => Code::F18,
+            WinitKeyCode::F19 => Code::F19,
+            WinitKeyCode::F20 => Code::F20,
+            WinitKeyCode::F21 => Code::F21,
+            WinitKeyCode::F22 => Code::F22,
+            WinitKeyCode::F23 => Code::F23,
+            WinitKeyCode::F24 => Code::F24,
+            WinitKeyCode::F25 => Code::F25,
+            WinitKeyCode::F26 => Code::F26,
+            WinitKeyCode::F27 => Code::F27,
+            WinitKeyCode::F28 => Code::F28,
+            WinitKeyCode::F29 => Code::F29,
+            WinitKeyCode::F30 => Code::F30,
+            WinitKeyCode::F31 => Code::F31,
+            WinitKeyCode::F32 => Code::F32,
+            WinitKeyCode::F33 => Code::F33,
+            WinitKeyCode::F34 => Code::F34,
+            WinitKeyCode::F35 => Code::F35,
+            _ => todo!(),
+        },
+    }
+}
+
+fn winit_key_to_kbt_key(winit_key: &WinitKey) -> Key {
+    match winit_key {
+        WinitKey::Character(c) => Key::Character(c.to_string()),
+        WinitKey::Unidentified(_) => Key::Unidentified,
+        WinitKey::Dead(_) => Key::Dead,
+        WinitKey::Named(named_key) => match named_key {
+            WinitNamedKey::Alt => Key::Alt,
+            WinitNamedKey::AltGraph => Key::AltGraph,
+            WinitNamedKey::CapsLock => Key::CapsLock,
+            WinitNamedKey::Control => Key::Control,
+            WinitNamedKey::Fn => Key::Fn,
+            WinitNamedKey::FnLock => Key::FnLock,
+            WinitNamedKey::NumLock => Key::NumLock,
+            WinitNamedKey::ScrollLock => Key::ScrollLock,
+            WinitNamedKey::Shift => Key::Shift,
+            WinitNamedKey::Symbol => Key::Symbol,
+            WinitNamedKey::SymbolLock => Key::SymbolLock,
+            WinitNamedKey::Meta => Key::Meta,
+            WinitNamedKey::Hyper => Key::Hyper,
+            WinitNamedKey::Super => Key::Super,
+            WinitNamedKey::Enter => Key::Enter,
+            WinitNamedKey::Tab => Key::Tab,
+            WinitNamedKey::Space => Key::Character(" ".to_string()),
+            WinitNamedKey::ArrowDown => Key::ArrowDown,
+            WinitNamedKey::ArrowLeft => Key::ArrowLeft,
+            WinitNamedKey::ArrowRight => Key::ArrowRight,
+            WinitNamedKey::ArrowUp => Key::ArrowUp,
+            WinitNamedKey::End => Key::End,
+            WinitNamedKey::Home => Key::Home,
+            WinitNamedKey::PageDown => Key::PageDown,
+            WinitNamedKey::PageUp => Key::PageUp,
+            WinitNamedKey::Backspace => Key::Backspace,
+            WinitNamedKey::Clear => Key::Clear,
+            WinitNamedKey::Copy => Key::Copy,
+            WinitNamedKey::CrSel => Key::CrSel,
+            WinitNamedKey::Cut => Key::Cut,
+            WinitNamedKey::Delete => Key::Delete,
+            WinitNamedKey::EraseEof => Key::EraseEof,
+            WinitNamedKey::ExSel => Key::ExSel,
+            WinitNamedKey::Insert => Key::Insert,
+            WinitNamedKey::Paste => Key::Paste,
+            WinitNamedKey::Redo => Key::Redo,
+            WinitNamedKey::Undo => Key::Undo,
+            WinitNamedKey::Accept => Key::Accept,
+            WinitNamedKey::Again => Key::Again,
+            WinitNamedKey::Attn => Key::Attn,
+            WinitNamedKey::Cancel => Key::Cancel,
+            WinitNamedKey::ContextMenu => Key::ContextMenu,
+            WinitNamedKey::Escape => Key::Escape,
+            WinitNamedKey::Execute => Key::Execute,
+            WinitNamedKey::Find => Key::Find,
+            WinitNamedKey::Help => Key::Help,
+            WinitNamedKey::Pause => Key::Pause,
+            WinitNamedKey::Play => Key::Play,
+            WinitNamedKey::Props => Key::Props,
+            WinitNamedKey::Select => Key::Select,
+            WinitNamedKey::ZoomIn => Key::ZoomIn,
+            WinitNamedKey::ZoomOut => Key::ZoomOut,
+            WinitNamedKey::BrightnessDown => Key::BrightnessDown,
+            WinitNamedKey::BrightnessUp => Key::BrightnessUp,
+            WinitNamedKey::Eject => Key::Eject,
+            WinitNamedKey::LogOff => Key::LogOff,
+            WinitNamedKey::Power => Key::Power,
+            WinitNamedKey::PowerOff => Key::PowerOff,
+            WinitNamedKey::PrintScreen => Key::PrintScreen,
+            WinitNamedKey::Hibernate => Key::Hibernate,
+            WinitNamedKey::Standby => Key::Standby,
+            WinitNamedKey::WakeUp => Key::WakeUp,
+            WinitNamedKey::AllCandidates => Key::AllCandidates,
+            WinitNamedKey::Alphanumeric => Key::Alphanumeric,
+            WinitNamedKey::CodeInput => Key::CodeInput,
+            WinitNamedKey::Compose => Key::Compose,
+            WinitNamedKey::Convert => Key::Convert,
+            WinitNamedKey::FinalMode => Key::FinalMode,
+            WinitNamedKey::GroupFirst => Key::GroupFirst,
+            WinitNamedKey::GroupLast => Key::GroupLast,
+            WinitNamedKey::GroupNext => Key::GroupNext,
+            WinitNamedKey::GroupPrevious => Key::GroupPrevious,
+            WinitNamedKey::ModeChange => Key::ModeChange,
+            WinitNamedKey::NextCandidate => Key::NextCandidate,
+            WinitNamedKey::NonConvert => Key::NonConvert,
+            WinitNamedKey::PreviousCandidate => Key::PreviousCandidate,
+            WinitNamedKey::Process => Key::Process,
+            WinitNamedKey::SingleCandidate => Key::SingleCandidate,
+            WinitNamedKey::HangulMode => Key::HangulMode,
+            WinitNamedKey::HanjaMode => Key::HanjaMode,
+            WinitNamedKey::JunjaMode => Key::JunjaMode,
+            WinitNamedKey::Eisu => Key::Eisu,
+            WinitNamedKey::Hankaku => Key::Hankaku,
+            WinitNamedKey::Hiragana => Key::Hiragana,
+            WinitNamedKey::HiraganaKatakana => Key::HiraganaKatakana,
+            WinitNamedKey::KanaMode => Key::KanaMode,
+            WinitNamedKey::KanjiMode => Key::KanjiMode,
+            WinitNamedKey::Katakana => Key::Katakana,
+            WinitNamedKey::Romaji => Key::Romaji,
+            WinitNamedKey::Zenkaku => Key::Zenkaku,
+            WinitNamedKey::ZenkakuHankaku => Key::ZenkakuHankaku,
+            WinitNamedKey::Soft1 => Key::Soft1,
+            WinitNamedKey::Soft2 => Key::Soft2,
+            WinitNamedKey::Soft3 => Key::Soft3,
+            WinitNamedKey::Soft4 => Key::Soft4,
+            WinitNamedKey::ChannelDown => Key::ChannelDown,
+            WinitNamedKey::ChannelUp => Key::ChannelUp,
+            WinitNamedKey::Close => Key::Close,
+            WinitNamedKey::MailForward => Key::MailForward,
+            WinitNamedKey::MailReply => Key::MailReply,
+            WinitNamedKey::MailSend => Key::MailSend,
+            WinitNamedKey::MediaClose => Key::MediaClose,
+            WinitNamedKey::MediaFastForward => Key::MediaFastForward,
+            WinitNamedKey::MediaPause => Key::MediaPause,
+            WinitNamedKey::MediaPlay => Key::MediaPlay,
+            WinitNamedKey::MediaPlayPause => Key::MediaPlayPause,
+            WinitNamedKey::MediaRecord => Key::MediaRecord,
+            WinitNamedKey::MediaRewind => Key::MediaRewind,
+            WinitNamedKey::MediaStop => Key::MediaStop,
+            WinitNamedKey::MediaTrackNext => Key::MediaTrackNext,
+            WinitNamedKey::MediaTrackPrevious => Key::MediaTrackPrevious,
+            WinitNamedKey::New => Key::New,
+            WinitNamedKey::Open => Key::Open,
+            WinitNamedKey::Print => Key::Print,
+            WinitNamedKey::Save => Key::Save,
+            WinitNamedKey::SpellCheck => Key::SpellCheck,
+            WinitNamedKey::Key11 => Key::Key11,
+            WinitNamedKey::Key12 => Key::Key12,
+            WinitNamedKey::AudioBalanceLeft => Key::AudioBalanceLeft,
+            WinitNamedKey::AudioBalanceRight => Key::AudioBalanceRight,
+            WinitNamedKey::AudioBassBoostDown => Key::AudioBassBoostDown,
+            WinitNamedKey::AudioBassBoostToggle => Key::AudioBassBoostToggle,
+            WinitNamedKey::AudioBassBoostUp => Key::AudioBassBoostUp,
+            WinitNamedKey::AudioFaderFront => Key::AudioFaderFront,
+            WinitNamedKey::AudioFaderRear => Key::AudioFaderRear,
+            WinitNamedKey::AudioSurroundModeNext => Key::AudioSurroundModeNext,
+            WinitNamedKey::AudioTrebleDown => Key::AudioTrebleDown,
+            WinitNamedKey::AudioTrebleUp => Key::AudioTrebleUp,
+            WinitNamedKey::AudioVolumeDown => Key::AudioVolumeDown,
+            WinitNamedKey::AudioVolumeUp => Key::AudioVolumeUp,
+            WinitNamedKey::AudioVolumeMute => Key::AudioVolumeMute,
+            WinitNamedKey::MicrophoneToggle => Key::MicrophoneToggle,
+            WinitNamedKey::MicrophoneVolumeDown => Key::MicrophoneVolumeDown,
+            WinitNamedKey::MicrophoneVolumeUp => Key::MicrophoneVolumeUp,
+            WinitNamedKey::MicrophoneVolumeMute => Key::MicrophoneVolumeMute,
+            WinitNamedKey::SpeechCorrectionList => Key::SpeechCorrectionList,
+            WinitNamedKey::SpeechInputToggle => Key::SpeechInputToggle,
+            WinitNamedKey::LaunchApplication1 => Key::LaunchApplication1,
+            WinitNamedKey::LaunchApplication2 => Key::LaunchApplication2,
+            WinitNamedKey::LaunchCalendar => Key::LaunchCalendar,
+            WinitNamedKey::LaunchContacts => Key::LaunchContacts,
+            WinitNamedKey::LaunchMail => Key::LaunchMail,
+            WinitNamedKey::LaunchMediaPlayer => Key::LaunchMediaPlayer,
+            WinitNamedKey::LaunchMusicPlayer => Key::LaunchMusicPlayer,
+            WinitNamedKey::LaunchPhone => Key::LaunchPhone,
+            WinitNamedKey::LaunchScreenSaver => Key::LaunchScreenSaver,
+            WinitNamedKey::LaunchSpreadsheet => Key::LaunchSpreadsheet,
+            WinitNamedKey::LaunchWebBrowser => Key::LaunchWebBrowser,
+            WinitNamedKey::LaunchWebCam => Key::LaunchWebCam,
+            WinitNamedKey::LaunchWordProcessor => Key::LaunchWordProcessor,
+            WinitNamedKey::BrowserBack => Key::BrowserBack,
+            WinitNamedKey::BrowserFavorites => Key::BrowserFavorites,
+            WinitNamedKey::BrowserForward => Key::BrowserForward,
+            WinitNamedKey::BrowserHome => Key::BrowserHome,
+            WinitNamedKey::BrowserRefresh => Key::BrowserRefresh,
+            WinitNamedKey::BrowserSearch => Key::BrowserSearch,
+            WinitNamedKey::BrowserStop => Key::BrowserStop,
+            WinitNamedKey::AppSwitch => Key::AppSwitch,
+            WinitNamedKey::Call => Key::Call,
+            WinitNamedKey::Camera => Key::Camera,
+            WinitNamedKey::CameraFocus => Key::CameraFocus,
+            WinitNamedKey::EndCall => Key::EndCall,
+            WinitNamedKey::GoBack => Key::GoBack,
+            WinitNamedKey::GoHome => Key::GoHome,
+            WinitNamedKey::HeadsetHook => Key::HeadsetHook,
+            WinitNamedKey::LastNumberRedial => Key::LastNumberRedial,
+            WinitNamedKey::Notification => Key::Notification,
+            WinitNamedKey::MannerMode => Key::MannerMode,
+            WinitNamedKey::VoiceDial => Key::VoiceDial,
+            WinitNamedKey::TV => Key::TV,
+            WinitNamedKey::TV3DMode => Key::TV3DMode,
+            WinitNamedKey::TVAntennaCable => Key::TVAntennaCable,
+            WinitNamedKey::TVAudioDescription => Key::TVAudioDescription,
+            WinitNamedKey::TVAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
+            WinitNamedKey::TVAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
+            WinitNamedKey::TVContentsMenu => Key::TVContentsMenu,
+            WinitNamedKey::TVDataService => Key::TVDataService,
+            WinitNamedKey::TVInput => Key::TVInput,
+            WinitNamedKey::TVInputComponent1 => Key::TVInputComponent1,
+            WinitNamedKey::TVInputComponent2 => Key::TVInputComponent2,
+            WinitNamedKey::TVInputComposite1 => Key::TVInputComposite1,
+            WinitNamedKey::TVInputComposite2 => Key::TVInputComposite2,
+            WinitNamedKey::TVInputHDMI1 => Key::TVInputHDMI1,
+            WinitNamedKey::TVInputHDMI2 => Key::TVInputHDMI2,
+            WinitNamedKey::TVInputHDMI3 => Key::TVInputHDMI3,
+            WinitNamedKey::TVInputHDMI4 => Key::TVInputHDMI4,
+            WinitNamedKey::TVInputVGA1 => Key::TVInputVGA1,
+            WinitNamedKey::TVMediaContext => Key::TVMediaContext,
+            WinitNamedKey::TVNetwork => Key::TVNetwork,
+            WinitNamedKey::TVNumberEntry => Key::TVNumberEntry,
+            WinitNamedKey::TVPower => Key::TVPower,
+            WinitNamedKey::TVRadioService => Key::TVRadioService,
+            WinitNamedKey::TVSatellite => Key::TVSatellite,
+            WinitNamedKey::TVSatelliteBS => Key::TVSatelliteBS,
+            WinitNamedKey::TVSatelliteCS => Key::TVSatelliteCS,
+            WinitNamedKey::TVSatelliteToggle => Key::TVSatelliteToggle,
+            WinitNamedKey::TVTerrestrialAnalog => Key::TVTerrestrialAnalog,
+            WinitNamedKey::TVTerrestrialDigital => Key::TVTerrestrialDigital,
+            WinitNamedKey::TVTimer => Key::TVTimer,
+            WinitNamedKey::AVRInput => Key::AVRInput,
+            WinitNamedKey::AVRPower => Key::AVRPower,
+            WinitNamedKey::ColorF0Red => Key::ColorF0Red,
+            WinitNamedKey::ColorF1Green => Key::ColorF1Green,
+            WinitNamedKey::ColorF2Yellow => Key::ColorF2Yellow,
+            WinitNamedKey::ColorF3Blue => Key::ColorF3Blue,
+            WinitNamedKey::ColorF4Grey => Key::ColorF4Grey,
+            WinitNamedKey::ColorF5Brown => Key::ColorF5Brown,
+            WinitNamedKey::ClosedCaptionToggle => Key::ClosedCaptionToggle,
+            WinitNamedKey::Dimmer => Key::Dimmer,
+            WinitNamedKey::DisplaySwap => Key::DisplaySwap,
+            WinitNamedKey::DVR => Key::DVR,
+            WinitNamedKey::Exit => Key::Exit,
+            WinitNamedKey::FavoriteClear0 => Key::FavoriteClear0,
+            WinitNamedKey::FavoriteClear1 => Key::FavoriteClear1,
+            WinitNamedKey::FavoriteClear2 => Key::FavoriteClear2,
+            WinitNamedKey::FavoriteClear3 => Key::FavoriteClear3,
+            WinitNamedKey::FavoriteRecall0 => Key::FavoriteRecall0,
+            WinitNamedKey::FavoriteRecall1 => Key::FavoriteRecall1,
+            WinitNamedKey::FavoriteRecall2 => Key::FavoriteRecall2,
+            WinitNamedKey::FavoriteRecall3 => Key::FavoriteRecall3,
+            WinitNamedKey::FavoriteStore0 => Key::FavoriteStore0,
+            WinitNamedKey::FavoriteStore1 => Key::FavoriteStore1,
+            WinitNamedKey::FavoriteStore2 => Key::FavoriteStore2,
+            WinitNamedKey::FavoriteStore3 => Key::FavoriteStore3,
+            WinitNamedKey::Guide => Key::Guide,
+            WinitNamedKey::GuideNextDay => Key::GuideNextDay,
+            WinitNamedKey::GuidePreviousDay => Key::GuidePreviousDay,
+            WinitNamedKey::Info => Key::Info,
+            WinitNamedKey::InstantReplay => Key::InstantReplay,
+            WinitNamedKey::Link => Key::Link,
+            WinitNamedKey::ListProgram => Key::ListProgram,
+            WinitNamedKey::LiveContent => Key::LiveContent,
+            WinitNamedKey::Lock => Key::Lock,
+            WinitNamedKey::MediaApps => Key::MediaApps,
+            WinitNamedKey::MediaAudioTrack => Key::MediaAudioTrack,
+            WinitNamedKey::MediaLast => Key::MediaLast,
+            WinitNamedKey::MediaSkipBackward => Key::MediaSkipBackward,
+            WinitNamedKey::MediaSkipForward => Key::MediaSkipForward,
+            WinitNamedKey::MediaStepBackward => Key::MediaStepBackward,
+            WinitNamedKey::MediaStepForward => Key::MediaStepForward,
+            WinitNamedKey::MediaTopMenu => Key::MediaTopMenu,
+            WinitNamedKey::NavigateIn => Key::NavigateIn,
+            WinitNamedKey::NavigateNext => Key::NavigateNext,
+            WinitNamedKey::NavigateOut => Key::NavigateOut,
+            WinitNamedKey::NavigatePrevious => Key::NavigatePrevious,
+            WinitNamedKey::NextFavoriteChannel => Key::NextFavoriteChannel,
+            WinitNamedKey::NextUserProfile => Key::NextUserProfile,
+            WinitNamedKey::OnDemand => Key::OnDemand,
+            WinitNamedKey::Pairing => Key::Pairing,
+            WinitNamedKey::PinPDown => Key::PinPDown,
+            WinitNamedKey::PinPMove => Key::PinPMove,
+            WinitNamedKey::PinPToggle => Key::PinPToggle,
+            WinitNamedKey::PinPUp => Key::PinPUp,
+            WinitNamedKey::PlaySpeedDown => Key::PlaySpeedDown,
+            WinitNamedKey::PlaySpeedReset => Key::PlaySpeedReset,
+            WinitNamedKey::PlaySpeedUp => Key::PlaySpeedUp,
+            WinitNamedKey::RandomToggle => Key::RandomToggle,
+            WinitNamedKey::RcLowBattery => Key::RcLowBattery,
+            WinitNamedKey::RecordSpeedNext => Key::RecordSpeedNext,
+            WinitNamedKey::RfBypass => Key::RfBypass,
+            WinitNamedKey::ScanChannelsToggle => Key::ScanChannelsToggle,
+            WinitNamedKey::ScreenModeNext => Key::ScreenModeNext,
+            WinitNamedKey::Settings => Key::Settings,
+            WinitNamedKey::SplitScreenToggle => Key::SplitScreenToggle,
+            WinitNamedKey::STBInput => Key::STBInput,
+            WinitNamedKey::STBPower => Key::STBPower,
+            WinitNamedKey::Subtitle => Key::Subtitle,
+            WinitNamedKey::Teletext => Key::Teletext,
+            WinitNamedKey::VideoModeNext => Key::VideoModeNext,
+            WinitNamedKey::Wink => Key::Wink,
+            WinitNamedKey::ZoomToggle => Key::ZoomToggle,
+            WinitNamedKey::F1 => Key::F1,
+            WinitNamedKey::F2 => Key::F2,
+            WinitNamedKey::F3 => Key::F3,
+            WinitNamedKey::F4 => Key::F4,
+            WinitNamedKey::F5 => Key::F5,
+            WinitNamedKey::F6 => Key::F6,
+            WinitNamedKey::F7 => Key::F7,
+            WinitNamedKey::F8 => Key::F8,
+            WinitNamedKey::F9 => Key::F9,
+            WinitNamedKey::F10 => Key::F10,
+            WinitNamedKey::F11 => Key::F11,
+            WinitNamedKey::F12 => Key::F12,
+            WinitNamedKey::F13 => Key::F13,
+            WinitNamedKey::F14 => Key::F14,
+            WinitNamedKey::F15 => Key::F15,
+            WinitNamedKey::F16 => Key::F16,
+            WinitNamedKey::F17 => Key::F17,
+            WinitNamedKey::F18 => Key::F18,
+            WinitNamedKey::F19 => Key::F19,
+            WinitNamedKey::F20 => Key::F20,
+            WinitNamedKey::F21 => Key::F21,
+            WinitNamedKey::F22 => Key::F22,
+            WinitNamedKey::F23 => Key::F23,
+            WinitNamedKey::F24 => Key::F24,
+            WinitNamedKey::F25 => Key::F25,
+            WinitNamedKey::F26 => Key::F26,
+            WinitNamedKey::F27 => Key::F27,
+            WinitNamedKey::F28 => Key::F28,
+            WinitNamedKey::F29 => Key::F29,
+            WinitNamedKey::F30 => Key::F30,
+            WinitNamedKey::F31 => Key::F31,
+            WinitNamedKey::F32 => Key::F32,
+            WinitNamedKey::F33 => Key::F33,
+            WinitNamedKey::F34 => Key::F34,
+            WinitNamedKey::F35 => Key::F35,
+            _ => Key::Unidentified,
+        },
+    }
+}

+ 114 - 0
packages/native/src/lib.rs

@@ -0,0 +1,114 @@
+#![cfg_attr(docsrs, feature(doc_cfg))]
+
+//! A native renderer for Dioxus.
+//!
+//! ## Feature flags
+//!  - `default`: Enables the features listed below.
+//!  - `accessibility`: Enables [`accesskit`] accessibility support.
+//!  - `hot-reload`: Enables hot-reloading of Dioxus RSX.
+//!  - `menu`: Enables the [`muda`] menubar.
+//!  - `tracing`: Enables tracing support.
+
+mod dioxus_application;
+mod dioxus_document;
+mod event;
+mod event_handler;
+mod keyboard_event;
+mod mutation_writer;
+
+pub use dioxus_application::DioxusNativeApplication;
+pub use dioxus_document::DioxusDocument;
+pub use event::DioxusNativeEvent;
+
+use blitz_dom::net::Resource;
+use blitz_net::Provider;
+use blitz_shell::{
+    create_default_event_loop, BlitzEvent, BlitzShellNetCallback, Config, WindowConfig,
+};
+use blitz_traits::net::SharedCallback;
+use dioxus_core::{ComponentFunction, Element, VirtualDom};
+use std::{any::Any, sync::Arc};
+
+type NodeId = usize;
+
+/// Launches the WebView and runs the event loop, with configuration and root props.
+pub fn launch_generic(
+    root: fn() -> Element,
+    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
+    platform_config: Vec<Box<dyn Any>>,
+) {
+    let platform_config = *platform_config
+        .into_iter()
+        .find_map(|cfg| cfg.downcast::<Config>().ok())
+        .unwrap_or_default();
+
+    launch_cfg_with_props(root, (), contexts, platform_config)
+}
+
+/// Launch an interactive HTML/CSS renderer driven by the Dioxus virtualdom
+pub fn launch(root: fn() -> Element) {
+    launch_cfg(root, Config::default())
+}
+
+pub fn launch_cfg(root: fn() -> Element, cfg: Config) {
+    launch_cfg_with_props(root, (), Vec::new(), cfg)
+}
+
+// todo: props shouldn't have the clone bound - should try and match dioxus-desktop behavior
+pub fn launch_cfg_with_props<P: Clone + 'static, M: 'static>(
+    root: impl ComponentFunction<P, M>,
+    props: P,
+    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
+    _cfg: Config,
+) {
+    // Turn on the runtime and enter it
+    let rt = tokio::runtime::Builder::new_multi_thread()
+        .enable_all()
+        .build()
+        .unwrap();
+    let _guard = rt.enter();
+
+    let event_loop = create_default_event_loop::<BlitzEvent>();
+    let proxy = event_loop.create_proxy();
+
+    let net_callback = Arc::new(BlitzShellNetCallback::new(proxy));
+    let net_provider = Arc::new(Provider::new(
+        rt.handle().clone(),
+        Arc::clone(&net_callback) as SharedCallback<Resource>,
+    ));
+
+    // Spin up the virtualdom
+    // We're going to need to hit it with a special waker
+    let mut vdom = VirtualDom::new_with_props(root, props);
+    for context in contexts {
+        vdom.insert_any_root_context(context());
+    }
+
+    let doc = DioxusDocument::new(vdom, Some(net_provider));
+    let window = WindowConfig::new(doc);
+
+    // Setup hot-reloading if enabled.
+    #[cfg(all(
+        feature = "hot-reload",
+        debug_assertions,
+        not(target_os = "android"),
+        not(target_os = "ios")
+    ))]
+    {
+        use crate::event::DioxusNativeEvent;
+        if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() {
+            let proxy = event_loop.create_proxy();
+            dioxus_devtools::connect(endpoint, move |event| {
+                let dxn_event = DioxusNativeEvent::DevserverEvent(event);
+                let _ = proxy.send_event(BlitzEvent::embedder_event(dxn_event));
+            })
+        }
+    }
+
+    // Create application
+    let mut application = DioxusNativeApplication::new(rt, event_loop.create_proxy());
+    application.add_window(window);
+
+    // Run event loop
+    event_loop.run_app(&mut application).unwrap();
+}

+ 492 - 0
packages/native/src/mutation_writer.rs

@@ -0,0 +1,492 @@
+use crate::{dioxus_document::qual_name, NodeId};
+use blitz_dom::{
+    local_name, namespace_url,
+    node::{Attribute, NodeSpecificData},
+    ns, Document, ElementNodeData, NodeData, QualName, RestyleHint,
+};
+use dioxus_core::{
+    AttributeValue, ElementId, Template, TemplateAttribute, TemplateNode, WriteMutations,
+};
+use rustc_hash::FxHashMap;
+use std::collections::HashSet;
+
+/// The state of the Dioxus integration with the RealDom
+#[derive(Debug)]
+pub struct DioxusState {
+    /// Store of templates keyed by unique name
+    templates: FxHashMap<Template, Vec<NodeId>>,
+    /// Stack machine state for applying dioxus mutations
+    stack: Vec<NodeId>,
+    /// Mapping from vdom ElementId -> rdom NodeId
+    node_id_mapping: Vec<Option<NodeId>>,
+}
+
+/// A writer for mutations that can be used with the RealDom.
+pub struct MutationWriter<'a> {
+    /// The realdom associated with this writer
+    pub doc: &'a mut Document,
+
+    /// The state associated with this writer
+    pub state: &'a mut DioxusState,
+
+    pub style_nodes: HashSet<usize>,
+}
+
+impl<'a> MutationWriter<'a> {
+    pub fn new(doc: &'a mut Document, state: &'a mut DioxusState) -> Self {
+        MutationWriter {
+            doc,
+            state,
+            style_nodes: HashSet::new(),
+        }
+    }
+
+    fn is_style_node(&self, node_id: NodeId) -> bool {
+        self.doc
+            .get_node(node_id)
+            .unwrap()
+            .raw_dom_data
+            .is_element_with_tag_name(&local_name!("style"))
+    }
+
+    fn maybe_push_style_node(&mut self, node_id: impl Into<Option<NodeId>>) {
+        if let Some(node_id) = node_id.into() {
+            if self.is_style_node(node_id) {
+                self.style_nodes.insert(node_id);
+            }
+        }
+    }
+
+    #[track_caller]
+    fn maybe_push_parent_style_node(&mut self, node_id: NodeId) {
+        let parent_id = self.doc.get_node(node_id).unwrap().parent;
+        self.maybe_push_style_node(parent_id);
+    }
+}
+
+impl Drop for MutationWriter<'_> {
+    fn drop(&mut self) {
+        // Add/Update inline stylesheets (<style> elements)
+        for &id in &self.style_nodes {
+            self.doc.upsert_stylesheet_for_node(id);
+        }
+    }
+}
+
+impl DioxusState {
+    /// Initialize the DioxusState in the RealDom
+    pub fn create(doc: &mut Document) -> Self {
+        let root = doc.root_element();
+        let root_id = root.id;
+
+        Self {
+            templates: FxHashMap::default(),
+            stack: vec![root_id],
+            node_id_mapping: vec![Some(root_id)],
+        }
+    }
+
+    /// Convert an ElementId to a NodeId
+    pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId {
+        self.try_element_to_node_id(element_id).unwrap()
+    }
+
+    /// Attempt to convert an ElementId to a NodeId. This will return None if the ElementId is not in the RealDom.
+    pub fn try_element_to_node_id(&self, element_id: ElementId) -> Option<NodeId> {
+        self.node_id_mapping.get(element_id.0).copied().flatten()
+    }
+
+    // /// Create a mutation writer for the RealDom
+    // pub fn create_mutation_writer<'a>(&'a mut self, doc: &'a mut Document) -> MutationWriter<'a> {
+    //     MutationWriter { doc, state: self }
+    // }
+}
+
+impl MutationWriter<'_> {
+    /// Update an ElementId -> NodeId mapping
+    fn set_id_mapping(&mut self, node_id: NodeId, element_id: ElementId) {
+        let element_id: usize = element_id.0;
+
+        // Ensure node_id_mapping is large enough to contain element_id
+        if self.state.node_id_mapping.len() <= element_id {
+            self.state.node_id_mapping.resize(element_id + 1, None);
+        }
+
+        // Set the new mapping
+        self.state.node_id_mapping[element_id] = Some(node_id);
+    }
+
+    /// Find a child in the document by child index path
+    fn load_child(&self, path: &[u8]) -> NodeId {
+        let mut current = self
+            .doc
+            .get_node(*self.state.stack.last().unwrap())
+            .unwrap();
+        for i in path {
+            let new_id = current.children[*i as usize];
+            current = self.doc.get_node(new_id).unwrap();
+        }
+        current.id
+    }
+}
+
+impl WriteMutations for MutationWriter<'_> {
+    fn append_children(&mut self, id: ElementId, m: usize) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("append_children id:{} m:{}", id.0, m);
+
+        let children = self.state.stack.split_off(self.state.stack.len() - m);
+        let parent = self.state.element_to_node_id(id);
+        for child in children {
+            self.doc.get_node_mut(parent).unwrap().children.push(child);
+            self.doc.get_node_mut(child).unwrap().parent = Some(parent);
+        }
+
+        self.maybe_push_style_node(parent);
+    }
+
+    fn assign_node_id(&mut self, path: &'static [u8], id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("assign_node_id path:{:?} id:{}", path, id.0);
+
+        // If there is an existing node already mapped to that ID and
+        // it has no parent, then drop it
+        if let Some(node_id) = self.state.try_element_to_node_id(id) {
+            if let Some(node) = self.doc.get_node(node_id) {
+                if node.parent.is_none() {
+                    self.doc.remove_and_drop_node(node_id);
+                }
+            }
+        }
+
+        let node_id = self.load_child(path);
+        self.set_id_mapping(node_id, id);
+    }
+
+    fn create_placeholder(&mut self, id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("create_placeholder id:{}", id.0);
+
+        let node_id = self.doc.create_node(NodeData::Comment);
+        self.set_id_mapping(node_id, id);
+        self.state.stack.push(node_id);
+    }
+
+    fn create_text_node(&mut self, value: &str, id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("create_text_node id:{} text:{}", id.0, value);
+
+        let node_id = self.doc.create_text_node(value);
+        self.set_id_mapping(node_id, id);
+        self.state.stack.push(node_id);
+    }
+
+    fn load_template(&mut self, template: Template, index: usize, id: ElementId) {
+        let template_entry = self.state.templates.entry(template).or_insert_with(|| {
+            let template_root_ids: Vec<NodeId> = template
+                .roots
+                .iter()
+                .map(|root| create_template_node(self.doc, root))
+                .collect();
+
+            template_root_ids
+        });
+
+        let template_node_id = template_entry[index];
+        let clone_id = self.doc.deep_clone_node(template_node_id);
+        self.set_id_mapping(clone_id, id);
+        self.state.stack.push(clone_id);
+    }
+
+    fn replace_node_with(&mut self, id: ElementId, m: usize) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("replace_node_with id:{} m:{}", id.0, m);
+
+        let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
+        let anchor_node_id = self.state.element_to_node_id(id);
+        self.maybe_push_parent_style_node(anchor_node_id);
+        self.doc.insert_before(anchor_node_id, &new_nodes);
+        self.doc.remove_node(anchor_node_id);
+    }
+
+    fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("replace_placeholder_with_nodes path:{:?} m:{}", path, m);
+
+        let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
+        let anchor_node_id = self.load_child(path);
+        self.maybe_push_parent_style_node(anchor_node_id);
+        self.doc.insert_before(anchor_node_id, &new_nodes);
+        self.doc.remove_node(anchor_node_id);
+    }
+
+    fn insert_nodes_after(&mut self, id: ElementId, m: usize) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("insert_nodes_after id:{} m:{}", id.0, m);
+
+        let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
+        let anchor_node_id = self.state.element_to_node_id(id);
+        let next_sibling_id = self
+            .doc
+            .get_node(anchor_node_id)
+            .unwrap()
+            .forward(1)
+            .map(|node| node.id);
+
+        match next_sibling_id {
+            Some(anchor_node_id) => {
+                self.doc.insert_before(anchor_node_id, &new_nodes);
+            }
+            None => self.doc.append(anchor_node_id, &new_nodes),
+        }
+
+        self.maybe_push_parent_style_node(anchor_node_id);
+    }
+
+    fn insert_nodes_before(&mut self, id: ElementId, m: usize) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("insert_nodes_before id:{} m:{}", id.0, m);
+
+        let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
+        let anchor_node_id = self.state.element_to_node_id(id);
+        self.doc.insert_before(anchor_node_id, &new_nodes);
+
+        self.maybe_push_parent_style_node(anchor_node_id);
+    }
+
+    fn set_attribute(
+        &mut self,
+        name: &'static str,
+        ns: Option<&'static str>,
+        value: &AttributeValue,
+        id: ElementId,
+    ) {
+        let node_id = self.state.element_to_node_id(id);
+
+        #[cfg(feature = "tracing")]
+        tracing::info!(
+            "set_attribute node_id:{} ns: {:?} name:{}, value:{:?}",
+            node_id,
+            ns,
+            name,
+            value
+        );
+
+        self.doc.snapshot_node(node_id);
+
+        let node = &mut self.doc.nodes[node_id];
+
+        let stylo_element_data = &mut *node.stylo_element_data.borrow_mut();
+        if let Some(data) = stylo_element_data {
+            data.hint |= RestyleHint::restyle_subtree();
+        }
+
+        if let NodeData::Element(ref mut element) = node.raw_dom_data {
+            if element.name.local == local_name!("input") && name == "checked" {
+                set_input_checked_state(element, value);
+            }
+            // FIXME: support other non-text attributes
+            else if let AttributeValue::Text(val) = value {
+                if name == "value" {
+                    // Update text input value
+                    if let Some(input_data) = element.text_input_data_mut() {
+                        input_data.set_text(&mut self.doc.font_ctx, &mut self.doc.layout_ctx, val);
+                    }
+                }
+
+                // FIXME check namespace
+                let existing_attr = element
+                    .attrs
+                    .iter_mut()
+                    .find(|attr| attr.name.local == *name);
+
+                if let Some(existing_attr) = existing_attr {
+                    existing_attr.value.clear();
+                    existing_attr.value.push_str(val);
+                } else {
+                    // we have overloaded the style namespace to accumulate style attributes without a `style` block
+                    if ns == Some("style") {
+                        // todo: need to accumulate style attributes into a single style
+                        //
+                        // element.
+                    } else {
+                        element.attrs.push(Attribute {
+                            name: qual_name(name, ns),
+                            value: val.to_string(),
+                        });
+                    }
+                }
+            }
+
+            if let AttributeValue::None = value {
+                // Update text input value
+                if name == "value" {
+                    if let Some(input_data) = element.text_input_data_mut() {
+                        input_data.set_text(&mut self.doc.font_ctx, &mut self.doc.layout_ctx, "");
+                    }
+                }
+
+                // FIXME: check namespace
+                element.attrs.retain(|attr| attr.name.local != *name);
+            }
+        }
+    }
+
+    fn set_node_text(&mut self, value: &str, id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("set_node_text id:{} value:{}", id.0, value);
+
+        let node_id = self.state.element_to_node_id(id);
+        let node = self.doc.get_node_mut(node_id).unwrap();
+
+        let text = match node.raw_dom_data {
+            NodeData::Text(ref mut text) => text,
+            // todo: otherwise this is basically element.textContent which is a bit different - need to parse as html
+            _ => return,
+        };
+
+        let changed = text.content != value;
+        if changed {
+            text.content.clear();
+            text.content.push_str(value);
+            let parent = node.parent;
+            self.maybe_push_style_node(parent);
+        }
+    }
+
+    fn create_event_listener(&mut self, _name: &'static str, _id: ElementId) {
+        // we're going to actually set the listener here as a placeholder - in JS this would also be a placeholder
+        // we might actually just want to attach the attribute to the root element (delegation)
+        self.set_attribute(
+            _name,
+            None,
+            &AttributeValue::Text("<rust func>".into()),
+            _id,
+        );
+
+        // also set the data-dioxus-id attribute so we can find the element later
+        self.set_attribute(
+            "data-dioxus-id",
+            None,
+            &AttributeValue::Text(_id.0.to_string()),
+            _id,
+        );
+
+        // let node_id = self.state.element_to_node_id(id);
+        // let mut node = self.rdom.get_mut(node_id).unwrap();
+        // node.add_event_listener(name);
+    }
+
+    fn remove_event_listener(&mut self, _name: &'static str, _id: ElementId) {
+        // let node_id = self.state.element_to_node_id(id);
+        // let mut node = self.rdom.get_mut(node_id).unwrap();
+        // node.remove_event_listener(name);
+    }
+
+    fn remove_node(&mut self, id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("remove_node id:{}", id.0);
+
+        let node_id = self.state.element_to_node_id(id);
+        self.doc.remove_node(node_id);
+    }
+
+    fn push_root(&mut self, id: ElementId) {
+        #[cfg(feature = "tracing")]
+        tracing::info!("push_root id:{}", id.0,);
+
+        let node_id = self.state.element_to_node_id(id);
+        self.state.stack.push(node_id);
+    }
+}
+
+/// Set 'checked' state on an input based on given attributevalue
+fn set_input_checked_state(element: &mut ElementNodeData, value: &AttributeValue) {
+    let checked: bool;
+    match value {
+        AttributeValue::Bool(checked_bool) => {
+            checked = *checked_bool;
+        }
+        AttributeValue::Text(val) => {
+            if let Ok(checked_bool) = val.parse() {
+                checked = checked_bool;
+            } else {
+                return;
+            };
+        }
+        _ => {
+            return;
+        }
+    };
+    match element.node_specific_data {
+        NodeSpecificData::CheckboxInput(ref mut checked_mut) => *checked_mut = checked,
+        // If we have just constructed the element, set the node attribute,
+        // and NodeSpecificData will be created from that later
+        // this simulates the checked attribute being set in html,
+        // and the element's checked property being set from that
+        NodeSpecificData::None => element.attrs.push(Attribute {
+            name: QualName {
+                prefix: None,
+                ns: ns!(html),
+                local: local_name!("checked"),
+            },
+            value: checked.to_string(),
+        }),
+        _ => {}
+    }
+}
+
+fn create_template_node(doc: &mut Document, node: &TemplateNode) -> NodeId {
+    match node {
+        TemplateNode::Element {
+            tag,
+            namespace,
+            attrs,
+            children,
+        } => {
+            let name = qual_name(tag, *namespace);
+            let attrs = attrs
+                .iter()
+                .filter_map(|attr| match attr {
+                    TemplateAttribute::Static {
+                        name,
+                        value,
+                        namespace,
+                    } => Some(Attribute {
+                        name: qual_name(name, *namespace),
+                        value: value.to_string(),
+                    }),
+                    TemplateAttribute::Dynamic { .. } => None,
+                })
+                .collect();
+
+            let mut data = ElementNodeData::new(name, attrs);
+            data.flush_style_attribute(doc.guard());
+
+            let id = doc.create_node(NodeData::Element(data));
+            let node = doc.get_node(id).unwrap();
+
+            // Initialise style data
+            *node.stylo_element_data.borrow_mut() = Some(Default::default());
+
+            // If the node has an "id" attribute, store it in the ID map.
+            // FIXME: implement
+            // if let Some(id_attr) = node.attr(local_name!("id")) {
+            //     doc.nodes_to_id.insert(id_attr.to_string(), id);
+            // }
+
+            let child_ids: Vec<NodeId> = children
+                .iter()
+                .map(|child| create_template_node(doc, child))
+                .collect();
+            for &child_id in &child_ids {
+                doc.get_node_mut(child_id).unwrap().parent = Some(id);
+            }
+            doc.get_node_mut(id).unwrap().children = child_ids;
+
+            id
+        }
+        TemplateNode::Text { text } => doc.create_text_node(text),
+        TemplateNode::Dynamic { .. } => doc.create_node(NodeData::Comment),
+    }
+}