lazer pointer wao

feat: it works tada

ptr.pet aad23617 5ba89399

verified
+10
.cargo/config.toml
··· 1 + [alias] 2 + run-wasm = ["run", "--release", "--package", "run-wasm", "--"] 3 + 4 + [target.x86_64-pc-windows-msvc] 5 + linker = "rust-lld.exe" 6 + rustdocflags = ["-Clinker=rust-lld.exe"] 7 + rustflags = ["-Ctarget-cpu=haswell"] 8 + 9 + # [target.wasm32-unknown-unknown] 10 + # rustflags = ["-Ctarget-feature=+atomics,+bulk-memory,+mutable-globals"]
+2
.gitignore
··· 1 1 /target 2 + /server-build 3 + /client-build
+899 -571
Cargo.lock
··· 24 24 source = "registry+https://github.com/rust-lang/crates.io-index" 25 25 checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 26 26 dependencies = [ 27 - "gimli", 27 + "gimli 0.31.1", 28 28 ] 29 29 30 30 [[package]] ··· 40 40 checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" 41 41 dependencies = [ 42 42 "cfg-if", 43 - "getrandom", 43 + "const-random", 44 + "getrandom 0.3.3", 44 45 "once_cell", 45 46 "version_check", 46 47 "zerocopy", 47 48 ] 48 49 49 50 [[package]] 50 - name = "allocator-api2" 51 - version = "0.2.21" 52 - source = "registry+https://github.com/rust-lang/crates.io-index" 53 - checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 54 - 55 - [[package]] 56 51 name = "android-activity" 57 52 version = "0.6.0" 58 53 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 68 63 "log", 69 64 "ndk", 70 65 "ndk-context", 71 - "ndk-sys 0.6.0+11769913", 66 + "ndk-sys", 72 67 "num_enum", 73 - "thiserror", 68 + "thiserror 1.0.69", 74 69 ] 75 70 76 71 [[package]] ··· 80 75 checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" 81 76 82 77 [[package]] 83 - name = "android_system_properties" 84 - version = "0.1.5" 85 - source = "registry+https://github.com/rust-lang/crates.io-index" 86 - checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 87 - dependencies = [ 88 - "libc", 89 - ] 90 - 91 - [[package]] 92 78 name = "annoyance" 93 79 version = "0.1.0" 94 80 dependencies = [ 95 81 "ahash", 96 - "pixels", 82 + "anyhow", 83 + "bincode", 84 + "console_error_panic_hook", 85 + "fastrand", 86 + "futures-util", 97 87 "quanta", 88 + "softbuffer", 98 89 "tiny-skia", 99 90 "tokio", 100 - "winapi", 91 + "tokio-tungstenite-wasm", 92 + "tokio-websockets", 93 + "wasm-bindgen-futures", 101 94 "winit", 102 95 ] 103 96 104 97 [[package]] 98 + name = "anyhow" 99 + version = "1.0.99" 100 + source = "registry+https://github.com/rust-lang/crates.io-index" 101 + checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" 102 + 103 + [[package]] 105 104 name = "arrayref" 106 105 version = "0.3.9" 107 106 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 120 119 checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" 121 120 122 121 [[package]] 123 - name = "ash" 124 - version = "0.37.3+1.3.251" 125 - source = "registry+https://github.com/rust-lang/crates.io-index" 126 - checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" 127 - dependencies = [ 128 - "libloading 0.7.4", 129 - ] 130 - 131 - [[package]] 132 122 name = "atomic-waker" 133 123 version = "1.1.2" 134 124 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 156 146 ] 157 147 158 148 [[package]] 159 - name = "bit-set" 160 - version = "0.5.3" 149 + name = "base64" 150 + version = "0.22.1" 151 + source = "registry+https://github.com/rust-lang/crates.io-index" 152 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 153 + 154 + [[package]] 155 + name = "bincode" 156 + version = "2.0.1" 161 157 source = "registry+https://github.com/rust-lang/crates.io-index" 162 - checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 158 + checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" 163 159 dependencies = [ 164 - "bit-vec", 160 + "bincode_derive", 161 + "serde", 162 + "unty", 165 163 ] 166 164 167 165 [[package]] 168 - name = "bit-vec" 169 - version = "0.6.3" 166 + name = "bincode_derive" 167 + version = "2.0.1" 170 168 source = "registry+https://github.com/rust-lang/crates.io-index" 171 - checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 169 + checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" 170 + dependencies = [ 171 + "virtue", 172 + ] 172 173 173 174 [[package]] 174 175 name = "bitflags" ··· 183 184 checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" 184 185 185 186 [[package]] 186 - name = "block" 187 - version = "0.1.6" 187 + name = "block-buffer" 188 + version = "0.10.4" 188 189 source = "registry+https://github.com/rust-lang/crates.io-index" 189 - checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 190 + checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 191 + dependencies = [ 192 + "generic-array", 193 + ] 190 194 191 195 [[package]] 192 196 name = "block2" ··· 208 212 version = "1.23.2" 209 213 source = "registry+https://github.com/rust-lang/crates.io-index" 210 214 checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" 215 + dependencies = [ 216 + "bytemuck_derive", 217 + ] 218 + 219 + [[package]] 220 + name = "bytemuck_derive" 221 + version = "1.10.1" 222 + source = "registry+https://github.com/rust-lang/crates.io-index" 223 + checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" 224 + dependencies = [ 225 + "proc-macro2", 226 + "quote", 227 + "syn", 228 + ] 211 229 212 230 [[package]] 213 231 name = "bytes" ··· 226 244 "polling", 227 245 "rustix 0.38.44", 228 246 "slab", 229 - "thiserror", 247 + "thiserror 1.0.69", 230 248 ] 231 249 232 250 [[package]] ··· 242 260 ] 243 261 244 262 [[package]] 263 + name = "cargo-run-wasm" 264 + version = "0.4.0" 265 + source = "registry+https://github.com/rust-lang/crates.io-index" 266 + checksum = "fa9c33bbfab116bda01ec67729b988895b34167a1e9cf034343099092421ed43" 267 + dependencies = [ 268 + "devserver_lib", 269 + "pico-args", 270 + "serde_json", 271 + "wasm-bindgen-cli-support", 272 + ] 273 + 274 + [[package]] 245 275 name = "cc" 246 276 version = "1.2.34" 247 277 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 266 296 267 297 [[package]] 268 298 name = "cfg_aliases" 269 - version = "0.1.1" 270 - source = "registry+https://github.com/rust-lang/crates.io-index" 271 - checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" 272 - 273 - [[package]] 274 - name = "cfg_aliases" 275 299 version = "0.2.1" 276 300 source = "registry+https://github.com/rust-lang/crates.io-index" 277 301 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 278 302 279 303 [[package]] 280 - name = "codespan-reporting" 281 - version = "0.11.1" 304 + name = "combine" 305 + version = "4.6.7" 282 306 source = "registry+https://github.com/rust-lang/crates.io-index" 283 - checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 307 + checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" 284 308 dependencies = [ 285 - "termcolor", 286 - "unicode-width", 309 + "bytes", 310 + "memchr", 287 311 ] 288 312 289 313 [[package]] 290 - name = "com" 291 - version = "0.6.0" 314 + name = "concurrent-queue" 315 + version = "2.5.0" 292 316 source = "registry+https://github.com/rust-lang/crates.io-index" 293 - checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" 317 + checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 294 318 dependencies = [ 295 - "com_macros", 319 + "crossbeam-utils", 296 320 ] 297 321 298 322 [[package]] 299 - name = "com_macros" 300 - version = "0.6.0" 323 + name = "console_error_panic_hook" 324 + version = "0.1.7" 301 325 source = "registry+https://github.com/rust-lang/crates.io-index" 302 - checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" 326 + checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 303 327 dependencies = [ 304 - "com_macros_support", 305 - "proc-macro2", 306 - "syn 1.0.109", 328 + "cfg-if", 329 + "wasm-bindgen", 307 330 ] 308 331 309 332 [[package]] 310 - name = "com_macros_support" 311 - version = "0.6.0" 333 + name = "const-random" 334 + version = "0.1.18" 312 335 source = "registry+https://github.com/rust-lang/crates.io-index" 313 - checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" 336 + checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" 314 337 dependencies = [ 315 - "proc-macro2", 316 - "quote", 317 - "syn 1.0.109", 338 + "const-random-macro", 318 339 ] 319 340 320 341 [[package]] 321 - name = "combine" 322 - version = "4.6.7" 342 + name = "const-random-macro" 343 + version = "0.1.16" 323 344 source = "registry+https://github.com/rust-lang/crates.io-index" 324 - checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" 345 + checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" 325 346 dependencies = [ 326 - "bytes", 327 - "memchr", 347 + "getrandom 0.2.16", 348 + "once_cell", 349 + "tiny-keccak", 328 350 ] 329 351 330 352 [[package]] 331 - name = "concurrent-queue" 332 - version = "2.5.0" 353 + name = "core-foundation" 354 + version = "0.9.4" 333 355 source = "registry+https://github.com/rust-lang/crates.io-index" 334 - checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 356 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 335 357 dependencies = [ 336 - "crossbeam-utils", 358 + "core-foundation-sys", 359 + "libc", 337 360 ] 338 361 339 362 [[package]] 340 363 name = "core-foundation" 341 - version = "0.9.4" 364 + version = "0.10.1" 342 365 source = "registry+https://github.com/rust-lang/crates.io-index" 343 - checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 366 + checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" 344 367 dependencies = [ 345 368 "core-foundation-sys", 346 369 "libc", ··· 359 382 checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" 360 383 dependencies = [ 361 384 "bitflags 1.3.2", 362 - "core-foundation", 363 - "core-graphics-types", 385 + "core-foundation 0.9.4", 386 + "core-graphics-types 0.1.3", 387 + "foreign-types", 388 + "libc", 389 + ] 390 + 391 + [[package]] 392 + name = "core-graphics" 393 + version = "0.24.0" 394 + source = "registry+https://github.com/rust-lang/crates.io-index" 395 + checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" 396 + dependencies = [ 397 + "bitflags 2.9.3", 398 + "core-foundation 0.10.1", 399 + "core-graphics-types 0.2.0", 364 400 "foreign-types", 365 401 "libc", 366 402 ] ··· 372 408 checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" 373 409 dependencies = [ 374 410 "bitflags 1.3.2", 375 - "core-foundation", 411 + "core-foundation 0.9.4", 376 412 "libc", 377 413 ] 378 414 379 415 [[package]] 416 + name = "core-graphics-types" 417 + version = "0.2.0" 418 + source = "registry+https://github.com/rust-lang/crates.io-index" 419 + checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" 420 + dependencies = [ 421 + "bitflags 2.9.3", 422 + "core-foundation 0.10.1", 423 + "libc", 424 + ] 425 + 426 + [[package]] 427 + name = "cpufeatures" 428 + version = "0.2.17" 429 + source = "registry+https://github.com/rust-lang/crates.io-index" 430 + checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 431 + dependencies = [ 432 + "libc", 433 + ] 434 + 435 + [[package]] 436 + name = "crossbeam-deque" 437 + version = "0.8.6" 438 + source = "registry+https://github.com/rust-lang/crates.io-index" 439 + checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 440 + dependencies = [ 441 + "crossbeam-epoch", 442 + "crossbeam-utils", 443 + ] 444 + 445 + [[package]] 446 + name = "crossbeam-epoch" 447 + version = "0.9.18" 448 + source = "registry+https://github.com/rust-lang/crates.io-index" 449 + checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 450 + dependencies = [ 451 + "crossbeam-utils", 452 + ] 453 + 454 + [[package]] 380 455 name = "crossbeam-utils" 381 456 version = "0.8.21" 382 457 source = "registry+https://github.com/rust-lang/crates.io-index" 383 458 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 384 459 385 460 [[package]] 461 + name = "crunchy" 462 + version = "0.2.4" 463 + source = "registry+https://github.com/rust-lang/crates.io-index" 464 + checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" 465 + 466 + [[package]] 467 + name = "crypto-common" 468 + version = "0.1.6" 469 + source = "registry+https://github.com/rust-lang/crates.io-index" 470 + checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 471 + dependencies = [ 472 + "generic-array", 473 + "typenum", 474 + ] 475 + 476 + [[package]] 477 + name = "ctor-lite" 478 + version = "0.1.0" 479 + source = "registry+https://github.com/rust-lang/crates.io-index" 480 + checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b" 481 + 482 + [[package]] 386 483 name = "cursor-icon" 387 484 version = "1.2.0" 388 485 source = "registry+https://github.com/rust-lang/crates.io-index" 389 486 checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" 390 487 391 488 [[package]] 392 - name = "d3d12" 393 - version = "0.19.0" 489 + name = "data-encoding" 490 + version = "2.9.0" 491 + source = "registry+https://github.com/rust-lang/crates.io-index" 492 + checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 493 + 494 + [[package]] 495 + name = "devserver_lib" 496 + version = "0.4.2" 394 497 source = "registry+https://github.com/rust-lang/crates.io-index" 395 - checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" 498 + checksum = "edf215dbb8cb1409cca7645aaed35f9e39fb0a21855bba1ac48bc0334903bf66" 499 + 500 + [[package]] 501 + name = "digest" 502 + version = "0.10.7" 503 + source = "registry+https://github.com/rust-lang/crates.io-index" 504 + checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 396 505 dependencies = [ 397 - "bitflags 2.9.3", 398 - "libloading 0.8.8", 399 - "winapi", 506 + "block-buffer", 507 + "crypto-common", 400 508 ] 401 509 402 510 [[package]] ··· 411 519 source = "registry+https://github.com/rust-lang/crates.io-index" 412 520 checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" 413 521 dependencies = [ 414 - "libloading 0.8.8", 522 + "libloading", 415 523 ] 416 524 417 525 [[package]] ··· 427 535 checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" 428 536 429 537 [[package]] 538 + name = "drm" 539 + version = "0.12.0" 540 + source = "registry+https://github.com/rust-lang/crates.io-index" 541 + checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" 542 + dependencies = [ 543 + "bitflags 2.9.3", 544 + "bytemuck", 545 + "drm-ffi", 546 + "drm-fourcc", 547 + "rustix 0.38.44", 548 + ] 549 + 550 + [[package]] 551 + name = "drm-ffi" 552 + version = "0.8.0" 553 + source = "registry+https://github.com/rust-lang/crates.io-index" 554 + checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" 555 + dependencies = [ 556 + "drm-sys", 557 + "rustix 0.38.44", 558 + ] 559 + 560 + [[package]] 561 + name = "drm-fourcc" 562 + version = "2.2.0" 563 + source = "registry+https://github.com/rust-lang/crates.io-index" 564 + checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" 565 + 566 + [[package]] 567 + name = "drm-sys" 568 + version = "0.7.0" 569 + source = "registry+https://github.com/rust-lang/crates.io-index" 570 + checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" 571 + dependencies = [ 572 + "libc", 573 + "linux-raw-sys 0.6.5", 574 + ] 575 + 576 + [[package]] 577 + name = "either" 578 + version = "1.15.0" 579 + source = "registry+https://github.com/rust-lang/crates.io-index" 580 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 581 + 582 + [[package]] 430 583 name = "equivalent" 431 584 version = "1.0.2" 432 585 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 443 596 ] 444 597 445 598 [[package]] 599 + name = "fallible-iterator" 600 + version = "0.2.0" 601 + source = "registry+https://github.com/rust-lang/crates.io-index" 602 + checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 603 + 604 + [[package]] 605 + name = "fastrand" 606 + version = "2.3.0" 607 + source = "registry+https://github.com/rust-lang/crates.io-index" 608 + checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 609 + dependencies = [ 610 + "getrandom 0.2.16", 611 + ] 612 + 613 + [[package]] 614 + name = "fnv" 615 + version = "1.0.7" 616 + source = "registry+https://github.com/rust-lang/crates.io-index" 617 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 618 + 619 + [[package]] 446 620 name = "foreign-types" 447 621 version = "0.5.0" 448 622 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 460 634 dependencies = [ 461 635 "proc-macro2", 462 636 "quote", 463 - "syn 2.0.106", 637 + "syn", 464 638 ] 465 639 466 640 [[package]] ··· 470 644 checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" 471 645 472 646 [[package]] 473 - name = "gethostname" 474 - version = "0.4.3" 647 + name = "futures-channel" 648 + version = "0.3.31" 475 649 source = "registry+https://github.com/rust-lang/crates.io-index" 476 - checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" 650 + checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 477 651 dependencies = [ 478 - "libc", 479 - "windows-targets 0.48.5", 652 + "futures-core", 480 653 ] 481 654 482 655 [[package]] 483 - name = "getrandom" 484 - version = "0.3.3" 656 + name = "futures-core" 657 + version = "0.3.31" 658 + source = "registry+https://github.com/rust-lang/crates.io-index" 659 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 660 + 661 + [[package]] 662 + name = "futures-sink" 663 + version = "0.3.31" 485 664 source = "registry+https://github.com/rust-lang/crates.io-index" 486 - checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 487 - dependencies = [ 488 - "cfg-if", 489 - "libc", 490 - "r-efi", 491 - "wasi 0.14.2+wasi-0.2.4", 492 - ] 665 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 493 666 494 667 [[package]] 495 - name = "gimli" 496 - version = "0.31.1" 668 + name = "futures-task" 669 + version = "0.3.31" 497 670 source = "registry+https://github.com/rust-lang/crates.io-index" 498 - checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 671 + checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 499 672 500 673 [[package]] 501 - name = "gl_generator" 502 - version = "0.14.0" 674 + name = "futures-util" 675 + version = "0.3.31" 503 676 source = "registry+https://github.com/rust-lang/crates.io-index" 504 - checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" 677 + checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 505 678 dependencies = [ 506 - "khronos_api", 507 - "log", 508 - "xml-rs", 679 + "futures-core", 680 + "futures-sink", 681 + "futures-task", 682 + "pin-project-lite", 683 + "pin-utils", 684 + "slab", 509 685 ] 510 686 511 687 [[package]] 512 - name = "glow" 513 - version = "0.13.1" 688 + name = "generic-array" 689 + version = "0.14.7" 514 690 source = "registry+https://github.com/rust-lang/crates.io-index" 515 - checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" 691 + checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 516 692 dependencies = [ 517 - "js-sys", 518 - "slotmap", 519 - "wasm-bindgen", 520 - "web-sys", 693 + "typenum", 694 + "version_check", 521 695 ] 522 696 523 697 [[package]] 524 - name = "glutin_wgl_sys" 525 - version = "0.5.0" 698 + name = "gethostname" 699 + version = "0.4.3" 526 700 source = "registry+https://github.com/rust-lang/crates.io-index" 527 - checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" 701 + checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" 528 702 dependencies = [ 529 - "gl_generator", 703 + "libc", 704 + "windows-targets 0.48.5", 530 705 ] 531 706 532 707 [[package]] 533 - name = "gpu-alloc" 534 - version = "0.6.0" 708 + name = "getrandom" 709 + version = "0.2.16" 535 710 source = "registry+https://github.com/rust-lang/crates.io-index" 536 - checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" 711 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 537 712 dependencies = [ 538 - "bitflags 2.9.3", 539 - "gpu-alloc-types", 713 + "cfg-if", 714 + "js-sys", 715 + "libc", 716 + "wasi 0.11.1+wasi-snapshot-preview1", 717 + "wasm-bindgen", 540 718 ] 541 719 542 720 [[package]] 543 - name = "gpu-alloc-types" 544 - version = "0.3.0" 721 + name = "getrandom" 722 + version = "0.3.3" 545 723 source = "registry+https://github.com/rust-lang/crates.io-index" 546 - checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" 724 + checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 547 725 dependencies = [ 548 - "bitflags 2.9.3", 726 + "cfg-if", 727 + "libc", 728 + "r-efi", 729 + "wasi 0.14.2+wasi-0.2.4", 549 730 ] 550 731 551 732 [[package]] 552 - name = "gpu-allocator" 553 - version = "0.25.0" 733 + name = "gimli" 734 + version = "0.26.2" 554 735 source = "registry+https://github.com/rust-lang/crates.io-index" 555 - checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" 736 + checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" 556 737 dependencies = [ 557 - "log", 558 - "presser", 559 - "thiserror", 560 - "winapi", 561 - "windows", 738 + "fallible-iterator", 739 + "indexmap 1.9.3", 740 + "stable_deref_trait", 562 741 ] 563 742 564 743 [[package]] 565 - name = "gpu-descriptor" 566 - version = "0.2.4" 744 + name = "gimli" 745 + version = "0.31.1" 567 746 source = "registry+https://github.com/rust-lang/crates.io-index" 568 - checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" 569 - dependencies = [ 570 - "bitflags 2.9.3", 571 - "gpu-descriptor-types", 572 - "hashbrown 0.14.5", 573 - ] 747 + checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 574 748 575 749 [[package]] 576 - name = "gpu-descriptor-types" 577 - version = "0.1.2" 750 + name = "hashbrown" 751 + version = "0.12.3" 578 752 source = "registry+https://github.com/rust-lang/crates.io-index" 579 - checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" 580 - dependencies = [ 581 - "bitflags 2.9.3", 582 - ] 753 + checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 583 754 584 755 [[package]] 585 756 name = "hashbrown" ··· 588 759 checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 589 760 dependencies = [ 590 761 "ahash", 591 - "allocator-api2", 762 + "serde", 592 763 ] 593 764 594 765 [[package]] ··· 598 769 checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 599 770 600 771 [[package]] 601 - name = "hassle-rs" 602 - version = "0.11.0" 772 + name = "heck" 773 + version = "0.5.0" 603 774 source = "registry+https://github.com/rust-lang/crates.io-index" 604 - checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" 605 - dependencies = [ 606 - "bitflags 2.9.3", 607 - "com", 608 - "libc", 609 - "libloading 0.8.8", 610 - "thiserror", 611 - "widestring", 612 - "winapi", 613 - ] 775 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 614 776 615 777 [[package]] 616 778 name = "hermit-abi" ··· 619 781 checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 620 782 621 783 [[package]] 622 - name = "hexf-parse" 623 - version = "0.2.1" 784 + name = "http" 785 + version = "1.3.1" 624 786 source = "registry+https://github.com/rust-lang/crates.io-index" 625 - checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" 787 + checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 788 + dependencies = [ 789 + "bytes", 790 + "fnv", 791 + "itoa", 792 + ] 793 + 794 + [[package]] 795 + name = "httparse" 796 + version = "1.10.1" 797 + source = "registry+https://github.com/rust-lang/crates.io-index" 798 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 799 + 800 + [[package]] 801 + name = "id-arena" 802 + version = "2.2.1" 803 + source = "registry+https://github.com/rust-lang/crates.io-index" 804 + checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" 805 + dependencies = [ 806 + "rayon", 807 + ] 808 + 809 + [[package]] 810 + name = "indexmap" 811 + version = "1.9.3" 812 + source = "registry+https://github.com/rust-lang/crates.io-index" 813 + checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 814 + dependencies = [ 815 + "autocfg", 816 + "hashbrown 0.12.3", 817 + ] 626 818 627 819 [[package]] 628 820 name = "indexmap" ··· 632 824 dependencies = [ 633 825 "equivalent", 634 826 "hashbrown 0.15.5", 827 + "serde", 635 828 ] 636 829 637 830 [[package]] ··· 644 837 "cfg-if", 645 838 "libc", 646 839 ] 840 + 841 + [[package]] 842 + name = "itoa" 843 + version = "1.0.15" 844 + source = "registry+https://github.com/rust-lang/crates.io-index" 845 + checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 647 846 648 847 [[package]] 649 848 name = "jni" ··· 656 855 "combine", 657 856 "jni-sys", 658 857 "log", 659 - "thiserror", 858 + "thiserror 1.0.69", 660 859 "walkdir", 661 860 "windows-sys 0.45.0", 662 861 ] ··· 673 872 source = "registry+https://github.com/rust-lang/crates.io-index" 674 873 checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" 675 874 dependencies = [ 676 - "getrandom", 875 + "getrandom 0.3.3", 677 876 "libc", 678 877 ] 679 878 ··· 688 887 ] 689 888 690 889 [[package]] 691 - name = "khronos-egl" 692 - version = "6.0.0" 890 + name = "leb128" 891 + version = "0.2.5" 693 892 source = "registry+https://github.com/rust-lang/crates.io-index" 694 - checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" 695 - dependencies = [ 696 - "libc", 697 - "libloading 0.8.8", 698 - "pkg-config", 699 - ] 700 - 701 - [[package]] 702 - name = "khronos_api" 703 - version = "3.1.0" 704 - source = "registry+https://github.com/rust-lang/crates.io-index" 705 - checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" 893 + checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" 706 894 707 895 [[package]] 708 896 name = "libc" 709 897 version = "0.2.175" 710 898 source = "registry+https://github.com/rust-lang/crates.io-index" 711 899 checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 712 - 713 - [[package]] 714 - name = "libloading" 715 - version = "0.7.4" 716 - source = "registry+https://github.com/rust-lang/crates.io-index" 717 - checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 718 - dependencies = [ 719 - "cfg-if", 720 - "winapi", 721 - ] 722 900 723 901 [[package]] 724 902 name = "libloading" ··· 749 927 750 928 [[package]] 751 929 name = "linux-raw-sys" 752 - version = "0.9.4" 930 + version = "0.6.5" 753 931 source = "registry+https://github.com/rust-lang/crates.io-index" 754 - checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 932 + checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" 755 933 756 934 [[package]] 757 - name = "lock_api" 758 - version = "0.4.13" 935 + name = "linux-raw-sys" 936 + version = "0.9.4" 759 937 source = "registry+https://github.com/rust-lang/crates.io-index" 760 - checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 761 - dependencies = [ 762 - "autocfg", 763 - "scopeguard", 764 - ] 938 + checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 765 939 766 940 [[package]] 767 941 name = "log" ··· 770 944 checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 771 945 772 946 [[package]] 773 - name = "malloc_buf" 774 - version = "0.0.6" 775 - source = "registry+https://github.com/rust-lang/crates.io-index" 776 - checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 777 - dependencies = [ 778 - "libc", 779 - ] 780 - 781 - [[package]] 782 947 name = "memchr" 783 948 version = "2.7.5" 784 949 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 794 959 ] 795 960 796 961 [[package]] 797 - name = "metal" 798 - version = "0.27.0" 799 - source = "registry+https://github.com/rust-lang/crates.io-index" 800 - checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" 801 - dependencies = [ 802 - "bitflags 2.9.3", 803 - "block", 804 - "core-graphics-types", 805 - "foreign-types", 806 - "log", 807 - "objc", 808 - "paste", 809 - ] 810 - 811 - [[package]] 812 962 name = "miniz_oxide" 813 963 version = "0.8.9" 814 964 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 829 979 ] 830 980 831 981 [[package]] 832 - name = "naga" 833 - version = "0.19.2" 834 - source = "registry+https://github.com/rust-lang/crates.io-index" 835 - checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" 836 - dependencies = [ 837 - "bit-set", 838 - "bitflags 2.9.3", 839 - "codespan-reporting", 840 - "hexf-parse", 841 - "indexmap", 842 - "log", 843 - "num-traits", 844 - "rustc-hash", 845 - "spirv", 846 - "termcolor", 847 - "thiserror", 848 - "unicode-xid", 849 - ] 850 - 851 - [[package]] 852 982 name = "ndk" 853 983 version = "0.9.0" 854 984 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 857 987 "bitflags 2.9.3", 858 988 "jni-sys", 859 989 "log", 860 - "ndk-sys 0.6.0+11769913", 990 + "ndk-sys", 861 991 "num_enum", 862 992 "raw-window-handle", 863 - "thiserror", 993 + "thiserror 1.0.69", 864 994 ] 865 995 866 996 [[package]] ··· 871 1001 872 1002 [[package]] 873 1003 name = "ndk-sys" 874 - version = "0.5.0+25.2.9519653" 875 - source = "registry+https://github.com/rust-lang/crates.io-index" 876 - checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" 877 - dependencies = [ 878 - "jni-sys", 879 - ] 880 - 881 - [[package]] 882 - name = "ndk-sys" 883 1004 version = "0.6.0+11769913" 884 1005 source = "registry+https://github.com/rust-lang/crates.io-index" 885 1006 checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" ··· 888 1009 ] 889 1010 890 1011 [[package]] 891 - name = "num-traits" 892 - version = "0.2.19" 893 - source = "registry+https://github.com/rust-lang/crates.io-index" 894 - checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 895 - dependencies = [ 896 - "autocfg", 897 - ] 898 - 899 - [[package]] 900 1012 name = "num_enum" 901 1013 version = "0.7.4" 902 1014 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 915 1027 "proc-macro-crate", 916 1028 "proc-macro2", 917 1029 "quote", 918 - "syn 2.0.106", 919 - ] 920 - 921 - [[package]] 922 - name = "objc" 923 - version = "0.2.7" 924 - source = "registry+https://github.com/rust-lang/crates.io-index" 925 - checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 926 - dependencies = [ 927 - "malloc_buf", 928 - "objc_exception", 1030 + "syn", 929 1031 ] 930 1032 931 1033 [[package]] ··· 1132 1234 ] 1133 1235 1134 1236 [[package]] 1135 - name = "objc_exception" 1136 - version = "0.1.2" 1137 - source = "registry+https://github.com/rust-lang/crates.io-index" 1138 - checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" 1139 - dependencies = [ 1140 - "cc", 1141 - ] 1142 - 1143 - [[package]] 1144 1237 name = "object" 1145 1238 version = "0.36.7" 1146 1239 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1174 1267 ] 1175 1268 1176 1269 [[package]] 1177 - name = "parking_lot" 1178 - version = "0.12.4" 1270 + name = "percent-encoding" 1271 + version = "2.3.2" 1179 1272 source = "registry+https://github.com/rust-lang/crates.io-index" 1180 - checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 1181 - dependencies = [ 1182 - "lock_api", 1183 - "parking_lot_core", 1184 - ] 1273 + checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1185 1274 1186 1275 [[package]] 1187 - name = "parking_lot_core" 1188 - version = "0.9.11" 1276 + name = "pico-args" 1277 + version = "0.5.0" 1189 1278 source = "registry+https://github.com/rust-lang/crates.io-index" 1190 - checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 1191 - dependencies = [ 1192 - "cfg-if", 1193 - "libc", 1194 - "redox_syscall 0.5.17", 1195 - "smallvec", 1196 - "windows-targets 0.52.6", 1197 - ] 1198 - 1199 - [[package]] 1200 - name = "paste" 1201 - version = "1.0.15" 1202 - source = "registry+https://github.com/rust-lang/crates.io-index" 1203 - checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1204 - 1205 - [[package]] 1206 - name = "percent-encoding" 1207 - version = "2.3.2" 1208 - source = "registry+https://github.com/rust-lang/crates.io-index" 1209 - checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1279 + checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" 1210 1280 1211 1281 [[package]] 1212 1282 name = "pin-project" ··· 1225 1295 dependencies = [ 1226 1296 "proc-macro2", 1227 1297 "quote", 1228 - "syn 2.0.106", 1298 + "syn", 1229 1299 ] 1230 1300 1231 1301 [[package]] ··· 1235 1305 checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1236 1306 1237 1307 [[package]] 1238 - name = "pixels" 1239 - version = "0.15.0" 1308 + name = "pin-utils" 1309 + version = "0.1.0" 1240 1310 source = "registry+https://github.com/rust-lang/crates.io-index" 1241 - checksum = "518d43cd70c5381d4c7bd4bf47ee344beee99b58b0587adcb198cc713ff0dfb5" 1242 - dependencies = [ 1243 - "bytemuck", 1244 - "pollster", 1245 - "raw-window-handle", 1246 - "thiserror", 1247 - "ultraviolet", 1248 - "wgpu", 1249 - ] 1311 + checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1250 1312 1251 1313 [[package]] 1252 1314 name = "pkg-config" ··· 1269 1331 ] 1270 1332 1271 1333 [[package]] 1272 - name = "pollster" 1273 - version = "0.3.0" 1334 + name = "ppv-lite86" 1335 + version = "0.2.21" 1274 1336 source = "registry+https://github.com/rust-lang/crates.io-index" 1275 - checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" 1276 - 1277 - [[package]] 1278 - name = "presser" 1279 - version = "0.3.1" 1280 - source = "registry+https://github.com/rust-lang/crates.io-index" 1281 - checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" 1337 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1338 + dependencies = [ 1339 + "zerocopy", 1340 + ] 1282 1341 1283 1342 [[package]] 1284 1343 name = "proc-macro-crate" ··· 1297 1356 dependencies = [ 1298 1357 "unicode-ident", 1299 1358 ] 1300 - 1301 - [[package]] 1302 - name = "profiling" 1303 - version = "1.0.17" 1304 - source = "registry+https://github.com/rust-lang/crates.io-index" 1305 - checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" 1306 1359 1307 1360 [[package]] 1308 1361 name = "quanta" ··· 1344 1397 checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1345 1398 1346 1399 [[package]] 1347 - name = "range-alloc" 1348 - version = "0.1.4" 1400 + name = "rand" 1401 + version = "0.9.2" 1349 1402 source = "registry+https://github.com/rust-lang/crates.io-index" 1350 - checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" 1403 + checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 1404 + dependencies = [ 1405 + "rand_chacha", 1406 + "rand_core", 1407 + ] 1408 + 1409 + [[package]] 1410 + name = "rand_chacha" 1411 + version = "0.9.0" 1412 + source = "registry+https://github.com/rust-lang/crates.io-index" 1413 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1414 + dependencies = [ 1415 + "ppv-lite86", 1416 + "rand_core", 1417 + ] 1418 + 1419 + [[package]] 1420 + name = "rand_core" 1421 + version = "0.9.3" 1422 + source = "registry+https://github.com/rust-lang/crates.io-index" 1423 + checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1424 + dependencies = [ 1425 + "getrandom 0.3.3", 1426 + ] 1351 1427 1352 1428 [[package]] 1353 1429 name = "raw-cpuid" ··· 1365 1441 checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" 1366 1442 1367 1443 [[package]] 1444 + name = "rayon" 1445 + version = "1.11.0" 1446 + source = "registry+https://github.com/rust-lang/crates.io-index" 1447 + checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" 1448 + dependencies = [ 1449 + "either", 1450 + "rayon-core", 1451 + ] 1452 + 1453 + [[package]] 1454 + name = "rayon-core" 1455 + version = "1.13.0" 1456 + source = "registry+https://github.com/rust-lang/crates.io-index" 1457 + checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" 1458 + dependencies = [ 1459 + "crossbeam-deque", 1460 + "crossbeam-utils", 1461 + ] 1462 + 1463 + [[package]] 1368 1464 name = "redox_syscall" 1369 1465 version = "0.4.1" 1370 1466 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1383 1479 ] 1384 1480 1385 1481 [[package]] 1386 - name = "renderdoc-sys" 1387 - version = "1.1.0" 1482 + name = "ring" 1483 + version = "0.17.14" 1388 1484 source = "registry+https://github.com/rust-lang/crates.io-index" 1389 - checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" 1485 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1486 + dependencies = [ 1487 + "cc", 1488 + "cfg-if", 1489 + "getrandom 0.2.16", 1490 + "libc", 1491 + "untrusted", 1492 + "windows-sys 0.52.0", 1493 + ] 1494 + 1495 + [[package]] 1496 + name = "run-wasm" 1497 + version = "0.1.0" 1498 + dependencies = [ 1499 + "cargo-run-wasm", 1500 + ] 1390 1501 1391 1502 [[package]] 1392 1503 name = "rustc-demangle" 1393 1504 version = "0.1.26" 1394 1505 source = "registry+https://github.com/rust-lang/crates.io-index" 1395 1506 checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 1396 - 1397 - [[package]] 1398 - name = "rustc-hash" 1399 - version = "1.1.0" 1400 - source = "registry+https://github.com/rust-lang/crates.io-index" 1401 - checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1402 1507 1403 1508 [[package]] 1404 1509 name = "rustix" ··· 1427 1532 ] 1428 1533 1429 1534 [[package]] 1535 + name = "rustls" 1536 + version = "0.23.31" 1537 + source = "registry+https://github.com/rust-lang/crates.io-index" 1538 + checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" 1539 + dependencies = [ 1540 + "once_cell", 1541 + "rustls-pki-types", 1542 + "rustls-webpki", 1543 + "subtle", 1544 + "zeroize", 1545 + ] 1546 + 1547 + [[package]] 1548 + name = "rustls-pki-types" 1549 + version = "1.12.0" 1550 + source = "registry+https://github.com/rust-lang/crates.io-index" 1551 + checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 1552 + dependencies = [ 1553 + "zeroize", 1554 + ] 1555 + 1556 + [[package]] 1557 + name = "rustls-webpki" 1558 + version = "0.103.4" 1559 + source = "registry+https://github.com/rust-lang/crates.io-index" 1560 + checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" 1561 + dependencies = [ 1562 + "ring", 1563 + "rustls-pki-types", 1564 + "untrusted", 1565 + ] 1566 + 1567 + [[package]] 1430 1568 name = "rustversion" 1431 1569 version = "1.0.22" 1432 1570 source = "registry+https://github.com/rust-lang/crates.io-index" 1433 1571 checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1434 1572 1435 1573 [[package]] 1436 - name = "safe_arch" 1437 - version = "0.7.4" 1574 + name = "ryu" 1575 + version = "1.0.20" 1438 1576 source = "registry+https://github.com/rust-lang/crates.io-index" 1439 - checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" 1440 - dependencies = [ 1441 - "bytemuck", 1442 - ] 1577 + checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1443 1578 1444 1579 [[package]] 1445 1580 name = "same-file" ··· 1457 1592 checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1458 1593 1459 1594 [[package]] 1460 - name = "scopeguard" 1461 - version = "1.2.0" 1462 - source = "registry+https://github.com/rust-lang/crates.io-index" 1463 - checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1464 - 1465 - [[package]] 1466 1595 name = "sctk-adwaita" 1467 1596 version = "0.10.1" 1468 1597 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1476 1605 ] 1477 1606 1478 1607 [[package]] 1608 + name = "semver" 1609 + version = "1.0.26" 1610 + source = "registry+https://github.com/rust-lang/crates.io-index" 1611 + checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 1612 + 1613 + [[package]] 1479 1614 name = "serde" 1480 1615 version = "1.0.219" 1481 1616 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1492 1627 dependencies = [ 1493 1628 "proc-macro2", 1494 1629 "quote", 1495 - "syn 2.0.106", 1630 + "syn", 1631 + ] 1632 + 1633 + [[package]] 1634 + name = "serde_json" 1635 + version = "1.0.143" 1636 + source = "registry+https://github.com/rust-lang/crates.io-index" 1637 + checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" 1638 + dependencies = [ 1639 + "itoa", 1640 + "memchr", 1641 + "ryu", 1642 + "serde", 1496 1643 ] 1497 1644 1498 1645 [[package]] 1646 + name = "sha1" 1647 + version = "0.10.6" 1648 + source = "registry+https://github.com/rust-lang/crates.io-index" 1649 + checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1650 + dependencies = [ 1651 + "cfg-if", 1652 + "cpufeatures", 1653 + "digest", 1654 + ] 1655 + 1656 + [[package]] 1657 + name = "sha1_smol" 1658 + version = "1.0.1" 1659 + source = "registry+https://github.com/rust-lang/crates.io-index" 1660 + checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" 1661 + 1662 + [[package]] 1499 1663 name = "shlex" 1500 1664 version = "1.3.0" 1501 1665 source = "registry+https://github.com/rust-lang/crates.io-index" 1502 1666 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1503 1667 1504 1668 [[package]] 1505 - name = "signal-hook-registry" 1506 - version = "1.4.6" 1669 + name = "simdutf8" 1670 + version = "0.1.5" 1507 1671 source = "registry+https://github.com/rust-lang/crates.io-index" 1508 - checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" 1509 - dependencies = [ 1510 - "libc", 1511 - ] 1672 + checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" 1512 1673 1513 1674 [[package]] 1514 1675 name = "slab" ··· 1517 1678 checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1518 1679 1519 1680 [[package]] 1520 - name = "slotmap" 1521 - version = "1.0.7" 1522 - source = "registry+https://github.com/rust-lang/crates.io-index" 1523 - checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" 1524 - dependencies = [ 1525 - "version_check", 1526 - ] 1527 - 1528 - [[package]] 1529 1681 name = "smallvec" 1530 1682 version = "1.15.1" 1531 1683 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1545 1697 "log", 1546 1698 "memmap2", 1547 1699 "rustix 0.38.44", 1548 - "thiserror", 1700 + "thiserror 1.0.69", 1549 1701 "wayland-backend", 1550 1702 "wayland-client", 1551 1703 "wayland-csd-frame", ··· 1576 1728 ] 1577 1729 1578 1730 [[package]] 1579 - name = "spirv" 1580 - version = "0.3.0+sdk-1.3.268.0" 1731 + name = "softbuffer" 1732 + version = "0.4.6" 1581 1733 source = "registry+https://github.com/rust-lang/crates.io-index" 1582 - checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" 1734 + checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" 1583 1735 dependencies = [ 1584 - "bitflags 2.9.3", 1736 + "as-raw-xcb-connection", 1737 + "bytemuck", 1738 + "cfg_aliases", 1739 + "core-graphics 0.24.0", 1740 + "drm", 1741 + "fastrand", 1742 + "foreign-types", 1743 + "js-sys", 1744 + "log", 1745 + "memmap2", 1746 + "objc2", 1747 + "objc2-foundation", 1748 + "objc2-quartz-core", 1749 + "raw-window-handle", 1750 + "redox_syscall 0.5.17", 1751 + "rustix 0.38.44", 1752 + "tiny-xlib", 1753 + "wasm-bindgen", 1754 + "wayland-backend", 1755 + "wayland-client", 1756 + "wayland-sys", 1757 + "web-sys", 1758 + "windows-sys 0.59.0", 1759 + "x11rb", 1585 1760 ] 1586 1761 1587 1762 [[package]] 1588 - name = "static_assertions" 1589 - version = "1.1.0" 1763 + name = "stable_deref_trait" 1764 + version = "1.2.0" 1590 1765 source = "registry+https://github.com/rust-lang/crates.io-index" 1591 - checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1766 + checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1592 1767 1593 1768 [[package]] 1594 1769 name = "strict-num" ··· 1597 1772 checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" 1598 1773 1599 1774 [[package]] 1600 - name = "syn" 1601 - version = "1.0.109" 1775 + name = "subtle" 1776 + version = "2.6.1" 1602 1777 source = "registry+https://github.com/rust-lang/crates.io-index" 1603 - checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1604 - dependencies = [ 1605 - "proc-macro2", 1606 - "quote", 1607 - "unicode-ident", 1608 - ] 1778 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1609 1779 1610 1780 [[package]] 1611 1781 name = "syn" ··· 1619 1789 ] 1620 1790 1621 1791 [[package]] 1622 - name = "termcolor" 1623 - version = "1.4.1" 1792 + name = "tempfile" 1793 + version = "3.21.0" 1624 1794 source = "registry+https://github.com/rust-lang/crates.io-index" 1625 - checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1795 + checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" 1626 1796 dependencies = [ 1627 - "winapi-util", 1797 + "fastrand", 1798 + "getrandom 0.3.3", 1799 + "once_cell", 1800 + "rustix 1.0.8", 1801 + "windows-sys 0.60.2", 1628 1802 ] 1629 1803 1630 1804 [[package]] ··· 1633 1807 source = "registry+https://github.com/rust-lang/crates.io-index" 1634 1808 checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1635 1809 dependencies = [ 1636 - "thiserror-impl", 1810 + "thiserror-impl 1.0.69", 1811 + ] 1812 + 1813 + [[package]] 1814 + name = "thiserror" 1815 + version = "2.0.16" 1816 + source = "registry+https://github.com/rust-lang/crates.io-index" 1817 + checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" 1818 + dependencies = [ 1819 + "thiserror-impl 2.0.16", 1637 1820 ] 1638 1821 1639 1822 [[package]] ··· 1644 1827 dependencies = [ 1645 1828 "proc-macro2", 1646 1829 "quote", 1647 - "syn 2.0.106", 1830 + "syn", 1831 + ] 1832 + 1833 + [[package]] 1834 + name = "thiserror-impl" 1835 + version = "2.0.16" 1836 + source = "registry+https://github.com/rust-lang/crates.io-index" 1837 + checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" 1838 + dependencies = [ 1839 + "proc-macro2", 1840 + "quote", 1841 + "syn", 1842 + ] 1843 + 1844 + [[package]] 1845 + name = "tiny-keccak" 1846 + version = "2.0.2" 1847 + source = "registry+https://github.com/rust-lang/crates.io-index" 1848 + checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 1849 + dependencies = [ 1850 + "crunchy", 1648 1851 ] 1649 1852 1650 1853 [[package]] ··· 1673 1876 ] 1674 1877 1675 1878 [[package]] 1879 + name = "tiny-xlib" 1880 + version = "0.2.4" 1881 + source = "registry+https://github.com/rust-lang/crates.io-index" 1882 + checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e" 1883 + dependencies = [ 1884 + "as-raw-xcb-connection", 1885 + "ctor-lite", 1886 + "libloading", 1887 + "pkg-config", 1888 + "tracing", 1889 + ] 1890 + 1891 + [[package]] 1676 1892 name = "tokio" 1677 1893 version = "1.47.1" 1678 1894 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1683 1899 "io-uring", 1684 1900 "libc", 1685 1901 "mio", 1686 - "parking_lot", 1687 1902 "pin-project-lite", 1688 - "signal-hook-registry", 1689 1903 "slab", 1690 1904 "socket2", 1691 1905 "tokio-macros", ··· 1700 1914 dependencies = [ 1701 1915 "proc-macro2", 1702 1916 "quote", 1703 - "syn 2.0.106", 1917 + "syn", 1918 + ] 1919 + 1920 + [[package]] 1921 + name = "tokio-rustls" 1922 + version = "0.26.2" 1923 + source = "registry+https://github.com/rust-lang/crates.io-index" 1924 + checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 1925 + dependencies = [ 1926 + "rustls", 1927 + "tokio", 1928 + ] 1929 + 1930 + [[package]] 1931 + name = "tokio-tungstenite" 1932 + version = "0.26.2" 1933 + source = "registry+https://github.com/rust-lang/crates.io-index" 1934 + checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" 1935 + dependencies = [ 1936 + "futures-util", 1937 + "log", 1938 + "rustls", 1939 + "rustls-pki-types", 1940 + "tokio", 1941 + "tokio-rustls", 1942 + "tungstenite", 1943 + "webpki-roots 0.26.11", 1944 + ] 1945 + 1946 + [[package]] 1947 + name = "tokio-tungstenite-wasm" 1948 + version = "0.6.0" 1949 + source = "registry+https://github.com/rust-lang/crates.io-index" 1950 + checksum = "02567f5f341725fb3e452c1f55dd4e5b0f2a685355c3b10babf0fe8e137d176e" 1951 + dependencies = [ 1952 + "bytes", 1953 + "futures-channel", 1954 + "futures-util", 1955 + "http", 1956 + "httparse", 1957 + "js-sys", 1958 + "rustls", 1959 + "thiserror 2.0.16", 1960 + "tokio", 1961 + "tokio-tungstenite", 1962 + "wasm-bindgen", 1963 + "web-sys", 1964 + ] 1965 + 1966 + [[package]] 1967 + name = "tokio-util" 1968 + version = "0.7.16" 1969 + source = "registry+https://github.com/rust-lang/crates.io-index" 1970 + checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" 1971 + dependencies = [ 1972 + "bytes", 1973 + "futures-core", 1974 + "futures-sink", 1975 + "pin-project-lite", 1976 + "tokio", 1977 + ] 1978 + 1979 + [[package]] 1980 + name = "tokio-websockets" 1981 + version = "0.12.1" 1982 + source = "registry+https://github.com/rust-lang/crates.io-index" 1983 + checksum = "5190767f03b86528ab9f4f6a9158072a6d0ef240d9a9591772eb411f315920f4" 1984 + dependencies = [ 1985 + "base64", 1986 + "bytes", 1987 + "futures-core", 1988 + "futures-sink", 1989 + "http", 1990 + "httparse", 1991 + "sha1_smol", 1992 + "simdutf8", 1993 + "tokio", 1994 + "tokio-util", 1704 1995 ] 1705 1996 1706 1997 [[package]] ··· 1715 2006 source = "registry+https://github.com/rust-lang/crates.io-index" 1716 2007 checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 1717 2008 dependencies = [ 1718 - "indexmap", 2009 + "indexmap 2.11.0", 1719 2010 "toml_datetime", 1720 2011 "winnow", 1721 2012 ] ··· 1743 2034 checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" 1744 2035 1745 2036 [[package]] 1746 - name = "ultraviolet" 1747 - version = "0.9.2" 2037 + name = "tungstenite" 2038 + version = "0.26.2" 1748 2039 source = "registry+https://github.com/rust-lang/crates.io-index" 1749 - checksum = "6a28554d13eb5daba527cc1b91b6c341372a0ae45ed277ffb2c6fbc04f319d7e" 2040 + checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" 1750 2041 dependencies = [ 1751 - "wide", 2042 + "bytes", 2043 + "data-encoding", 2044 + "http", 2045 + "httparse", 2046 + "log", 2047 + "rand", 2048 + "rustls", 2049 + "rustls-pki-types", 2050 + "sha1", 2051 + "thiserror 2.0.16", 2052 + "utf-8", 1752 2053 ] 1753 2054 1754 2055 [[package]] 2056 + name = "typenum" 2057 + version = "1.18.0" 2058 + source = "registry+https://github.com/rust-lang/crates.io-index" 2059 + checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 2060 + 2061 + [[package]] 1755 2062 name = "unicode-ident" 1756 2063 version = "1.0.18" 1757 2064 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1764 2071 checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1765 2072 1766 2073 [[package]] 1767 - name = "unicode-width" 1768 - version = "0.1.14" 2074 + name = "untrusted" 2075 + version = "0.9.0" 1769 2076 source = "registry+https://github.com/rust-lang/crates.io-index" 1770 - checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2077 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1771 2078 1772 2079 [[package]] 1773 - name = "unicode-xid" 1774 - version = "0.2.6" 2080 + name = "unty" 2081 + version = "0.0.4" 1775 2082 source = "registry+https://github.com/rust-lang/crates.io-index" 1776 - checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 2083 + checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" 2084 + 2085 + [[package]] 2086 + name = "utf-8" 2087 + version = "0.7.6" 2088 + source = "registry+https://github.com/rust-lang/crates.io-index" 2089 + checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1777 2090 1778 2091 [[package]] 1779 2092 name = "version_check" ··· 1782 2095 checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1783 2096 1784 2097 [[package]] 2098 + name = "virtue" 2099 + version = "0.0.18" 2100 + source = "registry+https://github.com/rust-lang/crates.io-index" 2101 + checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" 2102 + 2103 + [[package]] 1785 2104 name = "walkdir" 1786 2105 version = "2.5.0" 1787 2106 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1792 2111 ] 1793 2112 1794 2113 [[package]] 2114 + name = "walrus" 2115 + version = "0.23.3" 2116 + source = "registry+https://github.com/rust-lang/crates.io-index" 2117 + checksum = "6481311b98508f4bc2d0abbfa5d42172e7a54b4b24d8f15e28b0dc650be0c59f" 2118 + dependencies = [ 2119 + "anyhow", 2120 + "gimli 0.26.2", 2121 + "id-arena", 2122 + "leb128", 2123 + "log", 2124 + "rayon", 2125 + "walrus-macro", 2126 + "wasm-encoder", 2127 + "wasmparser", 2128 + ] 2129 + 2130 + [[package]] 2131 + name = "walrus-macro" 2132 + version = "0.22.0" 2133 + source = "registry+https://github.com/rust-lang/crates.io-index" 2134 + checksum = "439ad39ff894c43c9649fa724cdde9a6fc50b855d517ef071a93e5df82fe51d3" 2135 + dependencies = [ 2136 + "heck", 2137 + "proc-macro2", 2138 + "quote", 2139 + "syn", 2140 + ] 2141 + 2142 + [[package]] 1795 2143 name = "wasi" 1796 2144 version = "0.11.1+wasi-snapshot-preview1" 1797 2145 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1828 2176 "log", 1829 2177 "proc-macro2", 1830 2178 "quote", 1831 - "syn 2.0.106", 2179 + "syn", 1832 2180 "wasm-bindgen-shared", 1833 2181 ] 1834 2182 1835 2183 [[package]] 2184 + name = "wasm-bindgen-cli-support" 2185 + version = "0.2.100" 2186 + source = "registry+https://github.com/rust-lang/crates.io-index" 2187 + checksum = "21e1a4a49abe9cd6f762fc65fac2ef5732afeeb66be369d2f71a85b165a533cf" 2188 + dependencies = [ 2189 + "anyhow", 2190 + "base64", 2191 + "log", 2192 + "rustc-demangle", 2193 + "serde", 2194 + "serde_json", 2195 + "tempfile", 2196 + "walrus", 2197 + "wasm-bindgen-externref-xform", 2198 + "wasm-bindgen-multi-value-xform", 2199 + "wasm-bindgen-shared", 2200 + "wasm-bindgen-threads-xform", 2201 + "wasm-bindgen-wasm-conventions", 2202 + "wasm-bindgen-wasm-interpreter", 2203 + ] 2204 + 2205 + [[package]] 2206 + name = "wasm-bindgen-externref-xform" 2207 + version = "0.2.100" 2208 + source = "registry+https://github.com/rust-lang/crates.io-index" 2209 + checksum = "940542c5cdbe96c35f98b5da5c65fb9d18df55a0cb1d81fc5ca4acc4fda4d61c" 2210 + dependencies = [ 2211 + "anyhow", 2212 + "walrus", 2213 + "wasm-bindgen-wasm-conventions", 2214 + ] 2215 + 2216 + [[package]] 1836 2217 name = "wasm-bindgen-futures" 1837 - version = "0.4.45" 2218 + version = "0.4.50" 1838 2219 source = "registry+https://github.com/rust-lang/crates.io-index" 1839 - checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" 2220 + checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 1840 2221 dependencies = [ 1841 2222 "cfg-if", 1842 2223 "js-sys", 2224 + "once_cell", 1843 2225 "wasm-bindgen", 1844 2226 "web-sys", 1845 2227 ] ··· 1862 2244 dependencies = [ 1863 2245 "proc-macro2", 1864 2246 "quote", 1865 - "syn 2.0.106", 2247 + "syn", 1866 2248 "wasm-bindgen-backend", 1867 2249 "wasm-bindgen-shared", 1868 2250 ] 1869 2251 1870 2252 [[package]] 2253 + name = "wasm-bindgen-multi-value-xform" 2254 + version = "0.2.100" 2255 + source = "registry+https://github.com/rust-lang/crates.io-index" 2256 + checksum = "64b5ad2e97adde0c3e4369c38e0dbaee329ad8f6cc2ee8e01d1d0b13bd8b14cf" 2257 + dependencies = [ 2258 + "anyhow", 2259 + "walrus", 2260 + "wasm-bindgen-wasm-conventions", 2261 + ] 2262 + 2263 + [[package]] 1871 2264 name = "wasm-bindgen-shared" 1872 2265 version = "0.2.100" 1873 2266 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1877 2270 ] 1878 2271 1879 2272 [[package]] 2273 + name = "wasm-bindgen-threads-xform" 2274 + version = "0.2.100" 2275 + source = "registry+https://github.com/rust-lang/crates.io-index" 2276 + checksum = "1cbdf2d55a50f7edc9dd9aecae7a3a40e9736fda851bd8816f98a86167c8c277" 2277 + dependencies = [ 2278 + "anyhow", 2279 + "walrus", 2280 + "wasm-bindgen-wasm-conventions", 2281 + ] 2282 + 2283 + [[package]] 2284 + name = "wasm-bindgen-wasm-conventions" 2285 + version = "0.2.100" 2286 + source = "registry+https://github.com/rust-lang/crates.io-index" 2287 + checksum = "b1c24fcaa34d2d84407122cfb1d3f37c3586756cf462be18e049b49245a16c08" 2288 + dependencies = [ 2289 + "anyhow", 2290 + "leb128", 2291 + "log", 2292 + "walrus", 2293 + "wasmparser", 2294 + ] 2295 + 2296 + [[package]] 2297 + name = "wasm-bindgen-wasm-interpreter" 2298 + version = "0.2.100" 2299 + source = "registry+https://github.com/rust-lang/crates.io-index" 2300 + checksum = "33f24921401faadd6944206f9d6837d07bbb5ff766ed51ad34528089f66550e0" 2301 + dependencies = [ 2302 + "anyhow", 2303 + "log", 2304 + "walrus", 2305 + "wasm-bindgen-wasm-conventions", 2306 + ] 2307 + 2308 + [[package]] 2309 + name = "wasm-encoder" 2310 + version = "0.214.0" 2311 + source = "registry+https://github.com/rust-lang/crates.io-index" 2312 + checksum = "ff694f02a8d7a50b6922b197ae03883fbf18cdb2ae9fbee7b6148456f5f44041" 2313 + dependencies = [ 2314 + "leb128", 2315 + ] 2316 + 2317 + [[package]] 2318 + name = "wasmparser" 2319 + version = "0.214.0" 2320 + source = "registry+https://github.com/rust-lang/crates.io-index" 2321 + checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" 2322 + dependencies = [ 2323 + "ahash", 2324 + "bitflags 2.9.3", 2325 + "hashbrown 0.14.5", 2326 + "indexmap 2.11.0", 2327 + "semver", 2328 + "serde", 2329 + ] 2330 + 2331 + [[package]] 1880 2332 name = "wayland-backend" 1881 2333 version = "0.3.11" 1882 2334 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1987 2439 1988 2440 [[package]] 1989 2441 name = "web-sys" 1990 - version = "0.3.72" 2442 + version = "0.3.77" 1991 2443 source = "registry+https://github.com/rust-lang/crates.io-index" 1992 - checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" 2444 + checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 1993 2445 dependencies = [ 1994 2446 "js-sys", 1995 2447 "wasm-bindgen", ··· 2006 2458 ] 2007 2459 2008 2460 [[package]] 2009 - name = "wgpu" 2010 - version = "0.19.4" 2461 + name = "webpki-roots" 2462 + version = "0.26.11" 2011 2463 source = "registry+https://github.com/rust-lang/crates.io-index" 2012 - checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01" 2464 + checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" 2013 2465 dependencies = [ 2014 - "arrayvec", 2015 - "cfg-if", 2016 - "cfg_aliases 0.1.1", 2017 - "js-sys", 2018 - "log", 2019 - "naga", 2020 - "parking_lot", 2021 - "profiling", 2022 - "raw-window-handle", 2023 - "smallvec", 2024 - "static_assertions", 2025 - "wasm-bindgen", 2026 - "wasm-bindgen-futures", 2027 - "web-sys", 2028 - "wgpu-core", 2029 - "wgpu-hal", 2030 - "wgpu-types", 2466 + "webpki-roots 1.0.2", 2031 2467 ] 2032 2468 2033 2469 [[package]] 2034 - name = "wgpu-core" 2035 - version = "0.19.4" 2470 + name = "webpki-roots" 2471 + version = "1.0.2" 2036 2472 source = "registry+https://github.com/rust-lang/crates.io-index" 2037 - checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a" 2473 + checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" 2038 2474 dependencies = [ 2039 - "arrayvec", 2040 - "bit-vec", 2041 - "bitflags 2.9.3", 2042 - "cfg_aliases 0.1.1", 2043 - "codespan-reporting", 2044 - "indexmap", 2045 - "log", 2046 - "naga", 2047 - "once_cell", 2048 - "parking_lot", 2049 - "profiling", 2050 - "raw-window-handle", 2051 - "rustc-hash", 2052 - "smallvec", 2053 - "thiserror", 2054 - "web-sys", 2055 - "wgpu-hal", 2056 - "wgpu-types", 2475 + "rustls-pki-types", 2057 2476 ] 2058 2477 2059 2478 [[package]] 2060 - name = "wgpu-hal" 2061 - version = "0.19.5" 2062 - source = "registry+https://github.com/rust-lang/crates.io-index" 2063 - checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703" 2064 - dependencies = [ 2065 - "android_system_properties", 2066 - "arrayvec", 2067 - "ash", 2068 - "bit-set", 2069 - "bitflags 2.9.3", 2070 - "block", 2071 - "cfg_aliases 0.1.1", 2072 - "core-graphics-types", 2073 - "d3d12", 2074 - "glow", 2075 - "glutin_wgl_sys", 2076 - "gpu-alloc", 2077 - "gpu-allocator", 2078 - "gpu-descriptor", 2079 - "hassle-rs", 2080 - "js-sys", 2081 - "khronos-egl", 2082 - "libc", 2083 - "libloading 0.8.8", 2084 - "log", 2085 - "metal", 2086 - "naga", 2087 - "ndk-sys 0.5.0+25.2.9519653", 2088 - "objc", 2089 - "once_cell", 2090 - "parking_lot", 2091 - "profiling", 2092 - "range-alloc", 2093 - "raw-window-handle", 2094 - "renderdoc-sys", 2095 - "rustc-hash", 2096 - "smallvec", 2097 - "thiserror", 2098 - "wasm-bindgen", 2099 - "web-sys", 2100 - "wgpu-types", 2101 - "winapi", 2102 - ] 2103 - 2104 - [[package]] 2105 - name = "wgpu-types" 2106 - version = "0.19.2" 2107 - source = "registry+https://github.com/rust-lang/crates.io-index" 2108 - checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" 2109 - dependencies = [ 2110 - "bitflags 2.9.3", 2111 - "js-sys", 2112 - "web-sys", 2113 - ] 2114 - 2115 - [[package]] 2116 - name = "wide" 2117 - version = "0.7.33" 2118 - source = "registry+https://github.com/rust-lang/crates.io-index" 2119 - checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" 2120 - dependencies = [ 2121 - "bytemuck", 2122 - "safe_arch", 2123 - ] 2124 - 2125 - [[package]] 2126 - name = "widestring" 2127 - version = "1.2.0" 2128 - source = "registry+https://github.com/rust-lang/crates.io-index" 2129 - checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" 2130 - 2131 - [[package]] 2132 2479 name = "winapi" 2133 2480 version = "0.3.9" 2134 2481 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2158 2505 version = "0.4.0" 2159 2506 source = "registry+https://github.com/rust-lang/crates.io-index" 2160 2507 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2161 - 2162 - [[package]] 2163 - name = "windows" 2164 - version = "0.52.0" 2165 - source = "registry+https://github.com/rust-lang/crates.io-index" 2166 - checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" 2167 - dependencies = [ 2168 - "windows-core", 2169 - "windows-targets 0.52.6", 2170 - ] 2171 - 2172 - [[package]] 2173 - name = "windows-core" 2174 - version = "0.52.0" 2175 - source = "registry+https://github.com/rust-lang/crates.io-index" 2176 - checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2177 - dependencies = [ 2178 - "windows-targets 0.52.6", 2179 - ] 2180 2508 2181 2509 [[package]] 2182 2510 name = "windows-link" ··· 2476 2804 "block2", 2477 2805 "bytemuck", 2478 2806 "calloop", 2479 - "cfg_aliases 0.2.1", 2807 + "cfg_aliases", 2480 2808 "concurrent-queue", 2481 - "core-foundation", 2482 - "core-graphics", 2809 + "core-foundation 0.9.4", 2810 + "core-graphics 0.23.2", 2483 2811 "cursor-icon", 2484 2812 "dpi", 2485 2813 "js-sys", ··· 2553 2881 "as-raw-xcb-connection", 2554 2882 "gethostname", 2555 2883 "libc", 2556 - "libloading 0.8.8", 2884 + "libloading", 2557 2885 "once_cell", 2558 2886 "rustix 0.38.44", 2559 2887 "x11rb-protocol", ··· 2591 2919 checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" 2592 2920 2593 2921 [[package]] 2594 - name = "xml-rs" 2595 - version = "0.8.27" 2596 - source = "registry+https://github.com/rust-lang/crates.io-index" 2597 - checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" 2598 - 2599 - [[package]] 2600 2922 name = "zerocopy" 2601 2923 version = "0.8.26" 2602 2924 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2613 2935 dependencies = [ 2614 2936 "proc-macro2", 2615 2937 "quote", 2616 - "syn 2.0.106", 2938 + "syn", 2617 2939 ] 2940 + 2941 + [[package]] 2942 + name = "zeroize" 2943 + version = "1.8.1" 2944 + source = "registry+https://github.com/rust-lang/crates.io-index" 2945 + checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+35 -6
Cargo.toml
··· 3 3 version = "0.1.0" 4 4 edition = "2024" 5 5 6 + [workspace] 7 + members = ["run-wasm"] 8 + 9 + [features] 10 + default = [] 11 + server = [ 12 + "tokio/net", 13 + "futures-util/std", 14 + "dep:tokio-websockets", 15 + ] 16 + client = [ 17 + "dep:tokio-tungstenite-wasm", 18 + ] 19 + 6 20 [dependencies] 21 + anyhow = "1" 7 22 winit = "0.30" 8 - pixels = "0.15" 9 - tokio = { version = "1", features = ["full"] } 10 - ahash = "0.8.12" 23 + softbuffer = "0.4" 24 + ahash = { version = "0.8", default-features = false, features = ["compile-time-rng"] } 11 25 tiny-skia = { version = "0.11", default-features = false, features = ["simd", "std"] } 12 - quanta = "0.12.6" 26 + quanta = "0.12" 27 + bincode = "2.0.1" 28 + fastrand = "2" 29 + futures-util = { version = "0.3.31", default-features = false, features = ["sink"] } 30 + tokio = { version = "1", default-features = false, features = ["rt", "sync", "macros"] } 31 + tokio-websockets = { optional = true, version = "0.12", default-features = false, features = ["nightly", "server", "sha1_smol"] } 32 + tokio-tungstenite-wasm = { optional = true, version = "0.6", default-features = false, features = ["rustls-tls-webpki-roots"] } 13 33 14 - [target.'cfg(windows)'.dependencies] 15 - winapi = "0.3" 34 + [target.'cfg(target_arch = "wasm32")'.dependencies] 35 + fastrand = { version = "2", features = ["js"] } 36 + console_error_panic_hook = "0.1" 37 + wasm-bindgen-futures = "0.4" 38 + 39 + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 40 + tokio = { version = "1", default-features = false, features = ["rt", "rt-multi-thread", "sync"] } 41 + ahash = { version = "0.8", default-features = false, features = ["runtime-rng"] } 42 + 43 + [profile.release] 44 + debug = true
+7
build.nu
··· 1 + def main [feat: string, --run (-r)] { 2 + let dir = pwd | path join $"($feat)-build" 3 + cargo b --release --features $feat --artifact-dir $dir -Z unstable-options 4 + if $run { 5 + exec ($dir | path join "annoyance.exe") 6 + } 7 + }
+11
run-wasm/Cargo.toml
··· 1 + [package] 2 + name = "run-wasm" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [[bin]] 7 + name = "run-wasm" 8 + path = "main.rs" 9 + 10 + [dependencies] 11 + cargo-run-wasm = "0.4.0"
+14
run-wasm/main.rs
··· 1 + fn main() { 2 + cargo_run_wasm::run_wasm_cli_with_css( 3 + "* { 4 + margin:0; 5 + padding:0; 6 + overflow:hidden; 7 + } 8 + 9 + canvas { 10 + width:100vw!important; 11 + height:100vh!important; 12 + }", 13 + ); 14 + }
+3 -2
rust-toolchain.toml
··· 1 1 [toolchain] 2 - channel = "stable" 3 - components = ["rust-src", "rust-analyzer"] 2 + channel = "nightly-2025-08-27" 3 + targets = ["x86_64-pc-windows-msvc", "wasm32-unknown-unknown"] 4 + components = ["rust-src", "rust-analyzer", "llvm-tools"]
+315 -184
src/main.rs
··· 1 - use pixels::Pixels; 1 + #![feature(if_let_guard)] 2 + 2 3 use quanta::{Clock, Instant}; 3 4 use std::collections::HashMap; 5 + use std::ops::DerefMut; 4 6 use std::sync::Arc; 5 7 use std::time::Duration; 6 8 use tiny_skia::{Color, *}; 7 - use tokio::sync::mpsc; 8 - use winit::dpi::PhysicalSize; 9 - use winit::platform::windows::WindowAttributesExtWindows; 9 + use tokio::sync::{OnceCell, mpsc}; 10 10 use winit::{ 11 11 application::ApplicationHandler, 12 12 event::{ElementState, MouseButton, WindowEvent}, 13 13 event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, 14 - window::{Window, WindowAttributes, WindowId, WindowLevel}, 14 + window::{Window, WindowAttributes, WindowId}, 15 15 }; 16 16 17 - const BASE_MAX_AGE: Duration = Duration::from_millis(500); // Base lifetime for newest points 18 - const MIN_AGE: Duration = Duration::from_millis(50); // Minimum lifetime for oldest points 19 - const MAX_POINTS_PER_LINE: usize = 1000; // Maximum points to keep per line 20 - const FAST_DECAY_THRESHOLD: usize = 50; // Points beyond this count start decaying faster 17 + use crate::renderer::{Renderer, skia_rgba_to_bgra_u32}; 18 + use crate::ws::LaserMessage; 21 19 22 - #[derive(Debug, Clone)] 23 - pub struct LaserMessage { 24 - pub x: f32, 25 - pub y: f32, 26 - pub color: [u8; 3], 27 - pub id: u32, 28 - } 20 + mod renderer; 21 + mod utils; 22 + mod ws; 23 + 24 + type BoxedError = Box<dyn std::error::Error + 'static>; 25 + type AppResult<T> = Result<T, BoxedError>; 26 + 27 + const BASE_MAX_AGE: Duration = Duration::from_millis(200); 28 + const MIN_AGE: Duration = Duration::from_millis(50); 29 + const FAST_DECAY_THRESHOLD: usize = 30; 30 + #[cfg(target_arch = "wasm32")] 31 + const TARGET_FPS: u32 = 120; 32 + #[cfg(not(target_arch = "wasm32"))] 33 + const TARGET_FPS: u32 = 60; 34 + const FRAME_TIME_MS: u64 = 1000 / TARGET_FPS as u64; // ~16.67ms 29 35 30 36 #[derive(Clone)] 31 37 struct LaserPoint { 32 38 x: f32, 33 39 y: f32, 34 - color: [u8; 3], // RGB 40 + color: [u8; 3], 35 41 created_at: Instant, 36 42 } 37 43 38 44 impl LaserPoint { 39 45 fn new(msg: LaserMessage, now: Instant) -> Self { 40 46 Self { 41 - x: msg.x, 42 - y: msg.y, 43 - color: msg.color, 47 + x: msg.x as f32, 48 + y: msg.y as f32, 49 + color: utils::id_to_color(msg.id), 44 50 created_at: now, 45 51 } 46 52 } 47 53 } 48 54 55 + pub type WindowHandle = Arc<OnceCell<Arc<Window>>>; 56 + 57 + pub struct Graphics { 58 + window: Arc<Window>, 59 + renderer: Renderer, 60 + pixmap: Pixmap, 61 + } 62 + 63 + impl Graphics { 64 + fn resize(&mut self, width: u32, height: u32) -> AppResult<()> { 65 + self.renderer.resize(width, height)?; 66 + self.pixmap = Pixmap::new(width, height).unwrap(); 67 + Ok(()) 68 + } 69 + } 70 + 49 71 pub struct LaserOverlay { 50 - window: Option<Arc<Window>>, 51 - pixels: Option<Pixels<'static>>, 52 - laser_points: HashMap<u32, Vec<LaserPoint>, ahash::RandomState>, 53 - rx: mpsc::Receiver<LaserMessage>, 54 - tx: mpsc::Sender<LaserMessage>, 55 - width: u32, 56 - height: u32, 72 + gfx: Option<Graphics>, 73 + window: WindowHandle, 74 + laser_points: HashMap<(u64, u8), Vec<LaserPoint>, ahash::RandomState>, 75 + in_chan: (mpsc::Sender<LaserMessage>, mpsc::Receiver<LaserMessage>), 76 + out_tx: mpsc::Sender<LaserMessage>, 57 77 last_render: Instant, 78 + last_cleanup: Instant, 58 79 clock: Clock, 59 - // Mouse state 80 + client_id: u64, 60 81 mouse_pressed: bool, 61 82 mouse_pos: (f32, f32), 62 - current_line_id: u32, 63 - next_line_id: u32, 83 + current_line_id: u8, 84 + next_line_id: u8, 85 + needs_redraw: bool, 86 + has_any_points: bool, 64 87 } 65 88 66 89 impl LaserOverlay { 67 - pub fn new() -> (Self, mpsc::Sender<LaserMessage>) { 68 - let (tx, rx) = mpsc::channel(512); 90 + pub fn new() -> ( 91 + mpsc::Sender<LaserMessage>, 92 + mpsc::Receiver<LaserMessage>, 93 + Self, 94 + ) { 95 + let in_chan = mpsc::channel(1024); 96 + let (out_tx, out_rx) = mpsc::channel(512); 97 + 69 98 let clock = Clock::new(); 99 + let now = clock.now(); 100 + 70 101 let this = Self { 71 - window: None, 72 - pixels: None, 102 + gfx: None, 103 + window: WindowHandle::default(), 73 104 laser_points: Default::default(), 74 - rx, 75 - tx: tx.clone(), 76 - width: 1920, 77 - height: 1080, 78 - last_render: clock.now(), 105 + in_chan, 106 + out_tx, 107 + last_render: now, 108 + last_cleanup: now, 79 109 clock, 110 + client_id: fastrand::u64(..), 80 111 mouse_pressed: false, 81 112 mouse_pos: (0.0, 0.0), 82 113 current_line_id: 0, 83 114 next_line_id: 1, 115 + needs_redraw: false, 116 + has_any_points: false, 84 117 }; 85 - (this, tx) 118 + (this.in_chan.0.clone(), out_rx, this) 86 119 } 87 120 88 - pub fn init_graphics(&mut self, window: Arc<Window>) { 89 - let window_size = window.inner_size(); 90 - self.width = window_size.width; 91 - self.height = window_size.height; 121 + pub fn window_handle(&self) -> WindowHandle { 122 + self.window.clone() 123 + } 92 124 93 - let surface = pixels::SurfaceTexture::new(self.width, self.height, window.clone()); 94 - let pixels = pixels::PixelsBuilder::new(self.width, self.height, surface) 95 - .build() 96 - .unwrap(); 125 + pub fn init_graphics(&mut self, window: Arc<Window>) -> AppResult<()> { 126 + #[cfg(target_arch = "wasm32")] 127 + let size = { 128 + use winit::platform::web::WindowExtWebSys; 129 + let canvas = window.canvas().unwrap(); 130 + let (w, h) = (canvas.client_width(), canvas.client_height()); 131 + canvas.set_width(w.try_into().unwrap()); 132 + canvas.set_height(h.try_into().unwrap()); 133 + winit::dpi::PhysicalSize::new(w as u32, h as u32) 134 + }; 135 + #[cfg(not(target_arch = "wasm32"))] 136 + let size = window.inner_size(); 97 137 98 - self.pixels = Some(pixels); 99 - self.window = Some(window); 138 + let _ = self.window.set(window.clone()); 139 + self.gfx = Some(Graphics { 140 + renderer: Renderer::new(window.clone(), size.width, size.height)?, 141 + pixmap: Pixmap::new(size.width, size.height).unwrap(), 142 + window, 143 + }); 144 + 145 + self.needs_redraw = true; 146 + 147 + Ok(()) 100 148 } 101 149 102 150 fn handle_mouse_press(&mut self, position: (f32, f32)) { 103 151 self.mouse_pressed = true; 104 152 self.mouse_pos = position; 105 153 self.current_line_id = self.next_line_id; 106 - self.next_line_id += 1; 154 + self.next_line_id = self.next_line_id.wrapping_add(1); 155 + self.needs_redraw = true; 107 156 108 - // Send initial point 109 - let _ = self.tx.try_send(LaserMessage { 110 - x: position.0, 111 - y: position.1, 112 - color: [255, 0, 0], // Red laser 113 - id: self.current_line_id, 114 - }); 157 + let msg = LaserMessage { 158 + x: position.0 as u32, 159 + y: position.1 as u32, 160 + id: self.client_id, 161 + line_id: self.current_line_id, 162 + }; 163 + let _ = self.in_chan.0.try_send(msg); 164 + let _ = self.out_tx.try_send(msg); 115 165 } 116 166 117 167 fn handle_mouse_move(&mut self, position: (f32, f32)) { 118 168 if self.mouse_pressed { 119 - // Only add point if mouse moved enough to avoid too many points 120 169 let dx = position.0 - self.mouse_pos.0; 121 170 let dy = position.1 - self.mouse_pos.1; 122 171 let distance = (dx * dx + dy * dy).sqrt(); 123 172 124 173 if distance > 3.0 { 125 - // Minimum distance threshold 126 174 self.mouse_pos = position; 127 - let _ = self.tx.try_send(LaserMessage { 128 - x: position.0, 129 - y: position.1, 130 - color: [255, 0, 0], // Red laser 131 - id: self.current_line_id, 132 - }); 175 + self.needs_redraw = true; 176 + let msg = LaserMessage { 177 + x: position.0 as u32, 178 + y: position.1 as u32, 179 + id: self.client_id, 180 + line_id: self.current_line_id, 181 + }; 182 + let _ = self.in_chan.0.try_send(msg); 183 + let _ = self.out_tx.try_send(msg); 133 184 } 134 185 } 135 186 } ··· 140 191 141 192 fn calculate_point_max_age(point_index: usize, total_points: usize) -> Duration { 142 193 if total_points <= FAST_DECAY_THRESHOLD { 143 - // If we have few points, use base aging for all 144 194 return BASE_MAX_AGE; 145 195 } 146 196 147 - // Points are ordered oldest first (index 0) to newest last 148 - // Older points (lower indices) should have shorter lifespans 149 - 150 197 if point_index < FAST_DECAY_THRESHOLD { 151 - // These are the "far away" points that should decay faster 152 - // Create a gradient from MIN_AGE (oldest) to BASE_MAX_AGE (at threshold) 153 198 let progress = point_index as f32 / FAST_DECAY_THRESHOLD as f32; 154 199 let age_range = BASE_MAX_AGE.as_millis() - MIN_AGE.as_millis(); 155 200 let calculated_age = MIN_AGE.as_millis() + (age_range as f32 * progress) as u128; 156 201 Duration::from_millis(calculated_age as u64) 157 202 } else { 158 - // Recent points get full lifespan 159 203 BASE_MAX_AGE 160 204 } 161 205 } 162 206 207 + #[inline(always)] 163 208 fn ingest_points(&mut self) { 164 - let now = self.clock.now(); 209 + let mut has_any_points = false; 165 210 166 - // Clean up old points with variable aging 167 - for (_, points) in self.laser_points.iter_mut() { 168 - let original_len = points.len(); 211 + let should_cleanup = self.last_cleanup.elapsed().as_millis() >= FRAME_TIME_MS as u128; 169 212 170 - // Create a new vector with points that should be kept 171 - let mut new_points = Vec::with_capacity(points.len()); 172 - for (index, point) in points.iter().enumerate() { 173 - let max_age = Self::calculate_point_max_age(index, original_len); 174 - if now.duration_since(point.created_at) < max_age { 175 - new_points.push(point.clone()); 213 + if should_cleanup { 214 + self.last_cleanup = self.clock.now(); 215 + 216 + for (_, points) in self.laser_points.iter_mut() { 217 + let points_len = points.len(); 218 + if points_len == 0 { 219 + continue; 176 220 } 177 - } 178 - *points = new_points; 179 221 180 - // Also enforce maximum point limit by removing oldest points 181 - if points.len() > MAX_POINTS_PER_LINE { 182 - let excess = points.len() - MAX_POINTS_PER_LINE; 183 - points.drain(0..excess); 222 + let mut new_points = Vec::with_capacity(points_len); 223 + for (index, point) in points.iter().enumerate() { 224 + let max_age = Self::calculate_point_max_age(index, points_len); 225 + if point.created_at.elapsed() < max_age { 226 + new_points.push(point.clone()); 227 + } 228 + } 229 + 230 + if new_points.len() != points_len { 231 + self.needs_redraw = true; 232 + } 233 + *points = new_points; 234 + 235 + if !points.is_empty() { 236 + has_any_points = true; 237 + } 184 238 } 239 + } else { 240 + has_any_points = self.laser_points.values().any(|points| !points.is_empty()); 185 241 } 186 242 187 - // Remove empty lines 188 - self.laser_points.retain(|_, points| !points.is_empty()); 189 - 190 - // Add new points 191 - while let Ok(msg) = self.rx.try_recv() { 243 + while let Ok(msg) = self.in_chan.1.try_recv() { 192 244 self.laser_points 193 - .entry(msg.id) 245 + .entry((msg.id, msg.line_id)) 194 246 .or_default() 195 247 .push(LaserPoint::new(msg, self.clock.now())); 248 + has_any_points = true; 196 249 } 250 + 251 + self.has_any_points = has_any_points; 197 252 } 198 253 199 - fn draw_tapering_laser_line(pixmap: &mut PixmapMut, points: &[LaserPoint], now: Instant) { 254 + #[inline(always)] 255 + fn draw_tapering_laser_line(mut pixmap: PixmapMut, points: &[LaserPoint], now: Instant) { 200 256 if points.len() < 2 { 201 257 return; 202 258 } 203 259 204 - Self::draw_with_multiple_strokes(pixmap, points, now); 205 - } 206 - 207 - fn draw_with_multiple_strokes(pixmap: &mut PixmapMut, points: &[LaserPoint], now: Instant) { 208 260 let max_width = 8.0; 209 261 let min_width = 0.5; 262 + let points_len = points.len(); 210 263 211 - // Use chunks to create line segments from consecutive points 212 - for (i, chunk) in points.windows(2).enumerate() { 213 - let current = &chunk[0]; 214 - let next = &chunk[1]; 264 + let data = points 265 + .windows(2) 266 + .enumerate() 267 + .map(|(i, chunk)| { 268 + let current = &chunk[0]; 269 + let next = &chunk[1]; 215 270 216 - // Calculate thickness based on position in line 217 - // i=0 (oldest) should be thinnest, i=len-1 (newest) should be thickest 218 - let progress = i as f32 / (points.len() - 2) as f32; // -2 because windows(2) has len-1 elements 219 - let width = min_width + (max_width - min_width) * progress; 271 + let progress = i as f32 / (points_len - 2) as f32; 272 + let width = min_width + (max_width - min_width) * progress; 220 273 221 - // Calculate alpha based on age and position for smoother fading 222 - let point_index = i; 223 - let max_age = Self::calculate_point_max_age(point_index, points.len()); 224 - let age = now.duration_since(current.created_at); 225 - let age_progress = age.as_millis() as f32 / max_age.as_millis() as f32; 226 - let alpha = (255.0 * (1.0 - age_progress.clamp(0.0, 1.0))) as u8; 274 + let point_index = i; 275 + let max_age = Self::calculate_point_max_age(point_index, points_len); 276 + let age = now.duration_since(current.created_at); 277 + let age_progress = age.as_millis() as f32 / max_age.as_millis() as f32; 278 + let alpha = (255.0 * (1.0 - age_progress.clamp(0.0, 1.0))) as u8; 279 + 280 + let mut pb = PathBuilder::new(); 281 + pb.move_to(current.x, current.y); 282 + pb.line_to(next.x, next.y); 283 + 284 + (pb.finish(), width, next.color, alpha) 285 + }) 286 + .collect::<Vec<_>>(); 227 287 228 - // Create path for this single segment 229 - let mut pb = PathBuilder::new(); 230 - pb.move_to(current.x, current.y); 231 - pb.line_to(next.x, next.y); 288 + // draw glow first so we can draw the actual line on top 289 + // otherwise the glow would cover the line 290 + for (path, width, color, alpha) in data.iter().filter(|p| p.1 > 2.0) { 291 + let Some(path) = path else { 292 + continue; 293 + }; 232 294 233 - if let Some(path) = pb.finish() { 234 - // Main stroke with calculated alpha 235 - let mut paint = Paint::default(); 236 - paint.set_color_rgba8( 237 - next.color[0], 238 - next.color[1], 239 - next.color[2], 240 - alpha.max(10), // Ensure minimum visibility 241 - ); 242 - paint.anti_alias = true; 295 + let mut glow_paint = Paint::default(); 296 + glow_paint.set_color_rgba8(color[0], color[1], color[2], alpha / 5); 297 + glow_paint.anti_alias = true; 298 + // replace the existing alpha 299 + glow_paint.blend_mode = BlendMode::Source; 243 300 244 - let mut stroke = Stroke::default(); 245 - stroke.width = width; 246 - stroke.line_cap = LineCap::Round; 247 - stroke.line_join = LineJoin::Round; 301 + let mut glow_stroke = Stroke::default(); 302 + glow_stroke.width = width * 1.8; 303 + glow_stroke.line_cap = LineCap::Round; 304 + glow_stroke.line_join = LineJoin::Round; 248 305 249 - pixmap.stroke_path(&path, &paint, &stroke, Transform::identity(), None); 250 - } 306 + pixmap.stroke_path( 307 + &path, 308 + &glow_paint, 309 + &glow_stroke, 310 + Transform::identity(), 311 + None, 312 + ); 251 313 } 252 - } 253 314 254 - pub fn render(&mut self) { 255 - let Some(pixels) = self.pixels.as_mut() else { 256 - return; 257 - }; 315 + for (path, width, color, alpha) in data { 316 + let Some(path) = path else { 317 + continue; 318 + }; 258 319 259 - let frame = pixels.frame_mut(); 320 + let mut paint = Paint::default(); 321 + paint.set_color_rgba8(color[0], color[1], color[2], alpha.max(10)); 322 + paint.anti_alias = true; 323 + // replace the existing alpha (so it doesn't blend with existing pixels, looks bad) 324 + paint.blend_mode = BlendMode::Source; 260 325 261 - // Create tiny-skia pixmap from the frame buffer 262 - if let Some(mut pixmap) = PixmapMut::from_bytes(frame, self.width, self.height) { 263 - // Clear to transparent 264 - pixmap.fill(Color::TRANSPARENT); 326 + let mut stroke = Stroke::default(); 327 + stroke.width = width; 328 + stroke.line_cap = LineCap::Round; 329 + stroke.line_join = LineJoin::Round; 265 330 266 - // Draw all laser lines 267 - for points in self.laser_points.values() { 268 - Self::draw_tapering_laser_line(&mut pixmap, points, self.clock.now()); 269 - } 331 + pixmap.stroke_path(&path, &paint, &stroke, Transform::identity(), None); 270 332 } 333 + } 271 334 272 - if let Some(window) = self.window.as_ref() { 273 - window.pre_present_notify(); 335 + #[inline(always)] 336 + pub fn render(&mut self) -> AppResult<()> { 337 + let Some(gfx) = self.gfx.as_mut() else { 338 + return Ok(()); 339 + }; 340 + 341 + let mut frame = gfx.renderer.frame_mut()?; 342 + 343 + gfx.pixmap.fill(Color::TRANSPARENT); 344 + for points in self.laser_points.values() { 345 + Self::draw_tapering_laser_line(gfx.pixmap.as_mut(), points, self.clock.now()); 274 346 } 347 + skia_rgba_to_bgra_u32(gfx.pixmap.data(), frame.deref_mut()); 275 348 276 - // Render to screen 277 - if let Err(err) = pixels.render() { 278 - eprintln!("Render error: {err}"); 279 - } 349 + gfx.window.pre_present_notify(); 350 + gfx.renderer.present()?; 280 351 281 352 self.last_render = self.clock.now(); 353 + self.needs_redraw = false; 354 + 355 + Ok(()) 356 + } 357 + 358 + #[inline(always)] 359 + pub fn should_render(&self) -> bool { 360 + self.has_any_points || self.needs_redraw 282 361 } 283 362 } 284 363 285 364 impl ApplicationHandler for LaserOverlay { 286 365 fn resumed(&mut self, event_loop: &ActiveEventLoop) { 287 - let window_attributes = WindowAttributes::default() 288 - .with_title("Laser Overlay") 289 - .with_transparent(true) 290 - .with_decorations(true) 291 - .with_skip_taskbar(false) 292 - .with_window_level(WindowLevel::AlwaysOnTop) 293 - .with_inner_size(PhysicalSize::new(800, 600)); 366 + let attrs = WindowAttributes::default() 367 + .with_title("laser overlay") 368 + .with_transparent(true); 294 369 295 - let window = event_loop.create_window(window_attributes).unwrap(); 296 - let _ = window.set_cursor_hittest(true); 370 + #[cfg(feature = "server")] 371 + let attrs = attrs 372 + .with_fullscreen(Some(winit::window::Fullscreen::Borderless(None))) 373 + .with_window_level(winit::window::WindowLevel::AlwaysOnTop) 374 + .with_decorations(false); 297 375 298 - self.init_graphics(window.into()); 376 + #[cfg(target_arch = "wasm32")] 377 + let attrs = winit::platform::web::WindowAttributesExtWebSys::with_append(attrs, true); 378 + 379 + let window = event_loop.create_window(attrs).unwrap(); 380 + #[cfg(feature = "server")] 381 + let _ = window.set_cursor_hittest(false); 382 + 383 + self.init_graphics(window.into()).unwrap(); 384 + 385 + event_loop.set_control_flow(ControlFlow::wait_duration(Duration::from_millis( 386 + FRAME_TIME_MS, 387 + ))); 299 388 } 300 389 301 390 fn window_event( ··· 324 413 WindowEvent::CursorMoved { position, .. } => { 325 414 let pos = (position.x as f32, position.y as f32); 326 415 self.handle_mouse_move(pos); 327 - // Always update mouse position for when clicking starts 328 416 if !self.mouse_pressed { 329 417 self.mouse_pos = pos; 330 418 } 331 419 } 332 - WindowEvent::RedrawRequested if self.last_render.elapsed().as_millis() >= 16 => { 420 + WindowEvent::Resized(size) if let Some(gfx) = self.gfx.as_mut() => { 421 + gfx.resize(size.width, size.height).unwrap(); 422 + } 423 + WindowEvent::RedrawRequested => { 333 424 self.ingest_points(); 334 - self.render(); 425 + self.render().unwrap(); 335 426 } 336 427 _ => {} 337 428 } 429 + } 338 430 339 - // Request redraw if mouse is pressed (for continuous drawing) 340 - if self.mouse_pressed { 341 - if let Some(window) = self.window.as_ref() { 342 - window.request_redraw(); 431 + fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { 432 + if self.should_render() { 433 + if let Some(gfx) = self.gfx.as_ref() { 434 + if self.last_render.elapsed().as_millis() >= FRAME_TIME_MS as u128 { 435 + gfx.window.request_redraw(); 436 + } 343 437 } 438 + event_loop.set_control_flow(ControlFlow::wait_duration(Duration::from_millis( 439 + FRAME_TIME_MS, 440 + ))); 441 + } else { 442 + event_loop.set_control_flow(ControlFlow::Wait); 344 443 } 444 + } 445 + } 345 446 346 - match event_loop.control_flow() { 347 - ControlFlow::WaitUntil(instant) if instant.elapsed().as_millis() >= 16 => { 348 - event_loop.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(16))); 349 - } 350 - _ => {} 351 - } 447 + #[allow(unused_mut)] 448 + fn run_app(event_loop: EventLoop<()>, mut app: LaserOverlay) -> AppResult<()> { 449 + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] 450 + event_loop.run_app(&mut app)?; 451 + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] 452 + { 453 + console_error_panic_hook::set_once(); 454 + winit::platform::web::EventLoopExtWebSys::spawn_app(event_loop, app); 352 455 } 456 + Ok(()) 353 457 } 354 458 355 - // Example usage 356 - pub async fn run_laser_overlay() -> Result<(), Box<dyn std::error::Error>> { 459 + fn run() -> AppResult<()> { 357 460 let event_loop = EventLoop::new()?; 358 - event_loop.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(16))); 461 + let (_tx, _rx, app) = LaserOverlay::new(); 359 462 360 - let (mut app, _tx) = LaserOverlay::new(); 463 + #[cfg(any(feature = "server", feature = "client"))] 464 + let window = app.window_handle(); 361 465 362 - event_loop.run_app(&mut app)?; 466 + #[cfg(feature = "server")] 467 + tokio::spawn({ 468 + let window = window.clone(); 469 + let tx = _tx.clone(); 470 + async move { ws::server::listen(3111, window, tx).await.unwrap() } 471 + }); 472 + #[cfg(feature = "client")] 473 + { 474 + let client_id = app.client_id; 475 + let fut = async move { 476 + ws::client::connect("ws://localhost:3111", window, _rx, _tx, client_id) 477 + .await 478 + .unwrap() 479 + }; 480 + #[cfg(not(target_arch = "wasm32"))] 481 + tokio::spawn(fut); 482 + #[cfg(target_arch = "wasm32")] 483 + wasm_bindgen_futures::spawn_local(fut); 484 + } 485 + 486 + run_app(event_loop, app)?; 487 + 363 488 Ok(()) 364 489 } 365 490 491 + #[cfg(not(target_arch = "wasm32"))] 366 492 #[tokio::main] 367 - async fn main() -> Result<(), Box<dyn std::error::Error>> { 368 - run_laser_overlay().await 493 + async fn main() -> AppResult<()> { 494 + run() 495 + } 496 + 497 + #[cfg(target_arch = "wasm32")] 498 + fn main() -> AppResult<()> { 499 + run() 369 500 }
+48
src/renderer.rs
··· 1 + use super::*; 2 + use softbuffer::{Buffer, Context, Surface}; 3 + 4 + type W = Arc<Window>; 5 + 6 + pub struct Renderer { 7 + _ctx: Context<W>, 8 + surface: Surface<W, W>, 9 + } 10 + 11 + impl Renderer { 12 + pub fn new(window: Arc<Window>, width: u32, height: u32) -> AppResult<Self> { 13 + let ctx = Context::new(window.clone())?; 14 + let surface = Surface::new(&ctx, window)?; 15 + let mut this = Self { _ctx: ctx, surface }; 16 + this.resize(width, height)?; 17 + Ok(this) 18 + } 19 + 20 + #[inline(always)] 21 + pub fn resize(&mut self, width: u32, height: u32) -> AppResult<()> { 22 + // println!("resizing to {}x{}", width, height); 23 + Ok(self.surface.resize(width.try_into()?, height.try_into()?)?) 24 + } 25 + 26 + #[inline(always)] 27 + pub fn present(&mut self) -> AppResult<()> { 28 + Ok(self.surface.buffer_mut()?.present()?) 29 + } 30 + 31 + #[inline(always)] 32 + pub fn frame_mut(&mut self) -> AppResult<Buffer<'_, W, W>> { 33 + Ok(self.surface.buffer_mut()?) 34 + } 35 + } 36 + 37 + /// convert tiny-skia RGBA8888 buffer (premultiplied) to BGRA8888 u32 for softbuffer. 38 + #[inline(always)] 39 + pub fn skia_rgba_to_bgra_u32(rgba: &[u8], out_bgra: &mut [u32]) { 40 + debug_assert_eq!(rgba.len() / 4, out_bgra.len()); 41 + for (dst, src) in out_bgra.iter_mut().zip(rgba.chunks_exact(4)) { 42 + let r = src[0] as u32; 43 + let g = src[1] as u32; 44 + let b = src[2] as u32; 45 + let a = src[3] as u32; 46 + *dst = (a << 24) | (r << 16) | (g << 8) | (b << 0); // RGBA -> ARGB little-endian == BGRA bytes 47 + } 48 + }
+42
src/utils.rs
··· 1 + // id to rgb color 2 + pub fn id_to_color(id: u64) -> [u8; 3] { 3 + let mut hash = id; 4 + 5 + hash ^= hash >> 16; 6 + hash = hash.wrapping_mul(0x85ebca6b); 7 + hash ^= hash >> 13; 8 + hash = hash.wrapping_mul(0xb00b1355); 9 + hash ^= hash >> 16; 10 + 11 + let hue = (hash % 360) as f32; 12 + let saturation = 0.7 + ((hash >> 8) % 30) as f32 / 100.0; // 0.7-1.0 for vibrant colors 13 + let value = 0.6 + ((hash >> 16) % 40) as f32 / 100.0; // 0.6-1.0 to avoid dark colors 14 + 15 + hsv_to_rgb(hue, saturation, value) 16 + } 17 + 18 + fn hsv_to_rgb(h: f32, s: f32, v: f32) -> [u8; 3] { 19 + let c = v * s; 20 + let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()); 21 + let m = v - c; 22 + 23 + let (r_prime, g_prime, b_prime) = if h < 60.0 { 24 + (c, x, 0.0) 25 + } else if h < 120.0 { 26 + (x, c, 0.0) 27 + } else if h < 180.0 { 28 + (0.0, c, x) 29 + } else if h < 240.0 { 30 + (0.0, x, c) 31 + } else if h < 300.0 { 32 + (x, 0.0, c) 33 + } else { 34 + (c, 0.0, x) 35 + }; 36 + 37 + [ 38 + ((r_prime + m) * 255.0) as u8, 39 + ((g_prime + m) * 255.0) as u8, 40 + ((b_prime + m) * 255.0) as u8, 41 + ] 42 + }
+174
src/ws.rs
··· 1 + use bincode::{Decode, Encode}; 2 + 3 + #[cfg(any(feature = "client", feature = "server"))] 4 + const BINCODE_CFG: bincode::config::Configuration = bincode::config::standard(); 5 + 6 + #[derive(Debug, Clone, Copy, Encode, Decode)] 7 + pub struct LaserMessage { 8 + pub x: u32, 9 + pub y: u32, 10 + pub id: u64, 11 + pub line_id: u8, 12 + } 13 + 14 + #[cfg(feature = "client")] 15 + pub mod client { 16 + use futures_util::{SinkExt, StreamExt}; 17 + use tokio::sync::mpsc; 18 + use tokio_tungstenite_wasm::Message; 19 + 20 + use crate::{ 21 + AppResult, WindowHandle, 22 + ws::{BINCODE_CFG, LaserMessage}, 23 + }; 24 + 25 + pub async fn connect( 26 + server_url: &str, 27 + window: WindowHandle, 28 + mut overlay_rx: mpsc::Receiver<LaserMessage>, 29 + overlay_tx: mpsc::Sender<LaserMessage>, 30 + id: u64, 31 + ) -> AppResult<()> { 32 + let (mut tx, mut rx) = tokio_tungstenite_wasm::connect(server_url).await?.split(); 33 + let send_task = async move { 34 + while let Some(msg) = overlay_rx.recv().await { 35 + let Ok(encoded) = bincode::encode_to_vec(&msg, BINCODE_CFG) else { 36 + continue; 37 + }; 38 + let _ = tx.send(Message::Binary(encoded.into())).await; 39 + } 40 + }; 41 + let receive_task = async move { 42 + while let Some(ev) = rx.next().await { 43 + match ev { 44 + Ok(Message::Binary(payload)) => { 45 + let Ok((decoded, _)): Result<(LaserMessage, _), _> = 46 + bincode::decode_from_slice(&payload, BINCODE_CFG) 47 + else { 48 + continue; 49 + }; 50 + // don't send messages from the client we are on 51 + if decoded.id == id { 52 + continue; 53 + } 54 + let _ = overlay_tx.send(decoded).await; 55 + if let Some(window) = window.get() { 56 + window.request_redraw(); 57 + } 58 + } 59 + Ok(Message::Close(_)) => { 60 + eprintln!("server closed connection"); 61 + break; 62 + } 63 + Err(err) => { 64 + eprintln!("error receiving message: {}", err); 65 + } 66 + _ => {} 67 + } 68 + } 69 + }; 70 + let _ = futures_util::future::join(send_task, receive_task).await; 71 + Ok(()) 72 + } 73 + } 74 + 75 + #[cfg(feature = "server")] 76 + pub mod server { 77 + use std::net::SocketAddr; 78 + 79 + use futures_util::{SinkExt, StreamExt}; 80 + use tokio::{ 81 + net::{TcpListener, TcpStream}, 82 + sync::{broadcast, mpsc}, 83 + }; 84 + use tokio_websockets::Message; 85 + 86 + use crate::{ 87 + AppResult, WindowHandle, 88 + ws::{BINCODE_CFG, LaserMessage}, 89 + }; 90 + 91 + pub async fn listen( 92 + port: u16, 93 + window: WindowHandle, 94 + overlay_tx: mpsc::Sender<LaserMessage>, 95 + ) -> AppResult<impl Future> { 96 + let addr = SocketAddr::from(([0, 0, 0, 0], port)); 97 + let listener = TcpListener::bind(&addr).await?; 98 + println!("listening on {}", addr); 99 + 100 + let (tx, mut rx) = broadcast::channel(1024); 101 + 102 + let server_task = tokio::spawn(async move { 103 + loop { 104 + let conn = match listener.accept().await { 105 + Ok((conn, addr)) => { 106 + println!("accepted connection from {}", addr); 107 + conn 108 + } 109 + Err(err) => { 110 + eprintln!("error accepting connection: {}", err); 111 + continue; 112 + } 113 + }; 114 + tokio::spawn(handle_server_conn(conn, tx.clone(), tx.subscribe())); 115 + } 116 + }); 117 + let overlay_task = tokio::spawn(async move { 118 + while let Ok((_, msg)) = rx.recv().await { 119 + let _ = overlay_tx.send(msg).await; 120 + if let Some(window) = window.get() { 121 + window.request_redraw(); 122 + } 123 + } 124 + }); 125 + 126 + Ok(futures_util::future::join(server_task, overlay_task)) 127 + } 128 + 129 + async fn handle_server_conn( 130 + conn: TcpStream, 131 + msg_tx: broadcast::Sender<(u64, LaserMessage)>, 132 + mut msg_rx: broadcast::Receiver<(u64, LaserMessage)>, 133 + ) -> impl Future { 134 + let (_, server) = tokio_websockets::ServerBuilder::new() 135 + .accept(conn) 136 + .await 137 + .unwrap(); 138 + let (mut tx, mut rx) = server.split(); 139 + 140 + let id = fastrand::u64(..); 141 + 142 + let send_task = tokio::spawn(async move { 143 + while let Some(msg) = rx.next().await { 144 + match msg { 145 + Ok(msg) => { 146 + let payload = msg.into_payload(); 147 + let Ok((decoded, _)) = bincode::decode_from_slice(&payload, BINCODE_CFG) 148 + else { 149 + continue; 150 + }; 151 + let _ = msg_tx.send((id, decoded)); 152 + } 153 + Err(err) => { 154 + eprintln!("error receiving message: {}", err); 155 + } 156 + } 157 + } 158 + }); 159 + let receive_task = tokio::spawn(async move { 160 + while let Ok((msg_id, msg)) = msg_rx.recv().await { 161 + // skip if message is from self 162 + if msg_id == id { 163 + continue; 164 + } 165 + let Ok(encoded) = bincode::encode_to_vec(&msg, BINCODE_CFG) else { 166 + continue; 167 + }; 168 + let _ = tx.send(Message::binary(encoded)).await; 169 + } 170 + }); 171 + 172 + futures_util::future::join(send_task, receive_task) 173 + } 174 + }