Update glam to 0.29.2

Test: m
Change-Id: I21194d88b40dbe642ea788d942805ccdb5c32d3f
diff --git a/crates/glam/.android-checksum.json b/crates/glam/.android-checksum.json
new file mode 100644
index 0000000..5b27f2e
--- /dev/null
+++ b/crates/glam/.android-checksum.json
@@ -0,0 +1 @@
+{"package":null,"files":{"src/f32/scalar/mat2.rs":"2e9909d6b72b1e3b6591a67b317a3c217de545695f73f813d152aec14a66403e","src/swizzles/dvec3_impl.rs":"51b84f7303aa77fca31402e298770f9ccb30b34eb2f82f25ce9d41a645b83ca6","src/u8/u8vec3.rs":"7c285eebbd175bc095786577509a5da127546bc5f398aec130d1d974c8afc8cb","src/wasm32.rs":"a5cc46a676281d7267644d5759ba13eba7c84ea471b5617571f6c11dce6a832c","src/f32/wasm32/mat2.rs":"a123d1b65c52a5ab92061abf7d36f54a96a12f916791bc01482edb3155770def","tests/swizzles_u16.rs":"2ed9f41a1875751af64c21b1b53c97adc21c5d4945670d32b9f5a89374bb8361","tests/swizzles_i64.rs":"9c736068a8e7debe4715912c0e6a6c922fafd64816ca48b839a6baa07dfbafa2","src/swizzles/i8vec4_impl.rs":"9fec361ea974a583e9dc0f5beaa87eb89f9affda01f3d8fa60b6a9eb0c617924","src/swizzles/i16vec2_impl.rs":"2a48a6750ef722d22165bb60f51f26c1f8f7a18a45b8a7633fb4c04dc9137248","src/swizzles/ivec3_impl.rs":"8ac06d2281956e692a7479d6bfc04a136f80d2e14dc97818f8bc82b218b9c3a7","src/u8.rs":"26b2f5a08aa5e7cd09c34d030295398eee37765a5cbb140b7eaff543a3f23a0e","CONTRIBUTING.md":"b034e68df52c7a06fc30f5dcb5937debd9ebd1e9f5bedf6933681ea255a71c84","benches/vec3.rs":"09a76d47518830cc648bb87cc892d9ae73bda6cb172ea033f1f347d1d7112b68","src/features/impl_mint.rs":"c8bc65ed3103697b4e9d97c754e1b9759cb99d66d0ac533237b5a01417a2436b","src/f64/float.rs":"2fa506d501d803aca0ccaeee5aec479cec8bc0b06ba6c0068f86ab712828cbed","Cargo.toml":"b840fe2eafeeea57e6cbbf23001d138c30162810344ea29e1f6770b7161290af","tests/affine2.rs":"0919fdac2e8eb8dc08aa4a28f5841721fd1024df32a9f4fc28e42bc76ec27eeb","src/swizzles.rs":"49bb952acb43fee996fe66d818d263e08993d9439d84bec20fbf843f93527ebe","src/swizzles/dvec2_impl.rs":"6372530cf766128f6af1cabaf6617b5cf8d3e71b1da567b6fd1819271ac680ed","src/swizzles/u16vec4_impl.rs":"4e39718ce872788e693079d871c68448c06d0bcf0b68dc83ce71ca13a4e9558e","src/f64/math.rs":"39fb4f336af74ceb1bea269a559714108cf1081c8b3a4f90f9da413a54c82c50","src/f32/mat3.rs":"bcd5f875e5caa05b0f84fe7ae68b58af426bad0b04084e60f55ee481e943e044","benches/quat.rs":"df5ad38e88f13459654e40d56f94fb08bd813648756db19c8fc6a0f3514a5291","src/swizzles/uvec3_impl.rs":"d499e1c85cf07118d157070c1f286daa85b447ff3084741a4e335cf68b9bcdc9","src/features/impl_rand.rs":"a2c40008258c6c940763ba210a29954722d7f3672a2e27cbca25b3afeff628a0","src/i32.rs":"77f8a832de656ca5b7c19f6814320d283c84323e774a9ebc415b4ad87e028569","src/i32/ivec4.rs":"2094cc9bea04a8ab96415bf35258c827a9911c23891a168ef8bc6938c80ccd5d","src/swizzles/ivec4_impl.rs":"00e3bb730601a756e7b9fa5ee3cef166a39f5be7750651e98291b7b49e85fabb","src/bool/neon/bvec4a.rs":"b0ea68c835ce6bc56d181cb9ecfcf84c91aa327c47733bfb4c54f667e843c6ca","src/swizzles/dvec4_impl.rs":"f6978fa51fafba9e9dc030ff25121d2f9bce5b3a33a5d706175c043d80b32b81","src/f32/wasm32/mat4.rs":"8f24c79cd50676faf66fb99cde32a2c8c0d138c46fffa4cda54796e5dbe4158a","src/swizzles/i64vec2_impl.rs":"a8e570f200e22773c71790192e00b9417ad3e5d5ad51d4d324179a78c4f18892","src/f32/coresimd/vec4.rs":"c8b5b64511a22bdea31b1984e12be3153847d1aeab2e4f6f9ec33a68bd70404e","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","METADATA":"d38147b71faede49904e2346b265f6245db8edc590c18ad42752242fca4c2731","src/bool/sse2/bvec4a.rs":"763d6ab21615be17b6b24103b17dde2e88d3dcb12f7751f433e35f3f573e4c1b","src/swizzles/i16vec4_impl.rs":"23b6a50a625093f1ca4f04f5b3ff808e4ac784f14bc3b22e3d54eabca2cc503a","src/bool/sse2/bvec3a.rs":"be97915bb2654d11e2134b6a90816d7c3f19e15ce21d349c90974d19c31d8919","src/u16.rs":"8c7f16036cc69a45f4a3388c0c3b2bda0bbfd9b393c6f77f1aa6fd30049f42a5","CHANGELOG.md":"2e6c8e75a8da0d4076c798f5dcffafc6608a955635c19a2b907c67079000be30","src/bool/bvec4.rs":"e20a7f410118f61861b39373f966081fd06e117dcd70856b875be177c84cce5c","src/f32/wasm32/vec3a.rs":"4adc0d17bbedd1d9589cdaac1982d1a7b8b2baf6207a3ba2053bd5ae0ddbdec3","src/f32/coresimd/quat.rs":"7d41936be3c630c021d6e3297c50abacc85f8361e286ed8ffd3fe5182d66d327","src/i64/i64vec2.rs":"2375fb3c97c356a78c12b6d0b3319c4c2dd231e17f29170cf8a92c3583018bc6","src/i16.rs":"22bf65b210b7e60ee8233a891924920e5b6604acbd245c81e7e645af522cbdcb","src/f32/coresimd.rs":"c5b4c408788c9a557811e4e3e8d66aa4ffe73014025a7a7ba49351de39b4d856","src/f32/scalar/mat4.rs":"69b65fba41d819b4028434ec7a04ccdb0c48f4d6b341d1f5e47c55fe7d74ce1e","benches/vec3a.rs":"9c005e12aba9f4a56401c7f3f4ad489630c2e1b901a30f0a5f6d07d4a43290f6","src/i32/ivec2.rs":"5bac47dbc9205376d191c7346e7f9cf892d383f2b2a7e814c6cb9dace259f6eb","src/f32/affine3a.rs":"a545a1e9e98248e48fd20d16ed83c6ea1ba9d00c7c8e96469ed11c9397c5b6b1","src/swizzles/u16vec3_impl.rs":"9e60ba61477af0ed8fce104ccd5c279b53e7775dcba05f8cdb8de8481a0d4cea","src/f64/dmat4.rs":"5a026f84f050c605b45311d0c7dd085fdd969e5d88393c55f52ebb1a2728f223","src/f32/neon/vec4.rs":"0b1cf2e3e78e4d12faa232ec6c0554ebfc70395d90cc94a621500f4316a29f5d","build_all_msrv.sh":"27b5fe7fe1fa47ee75dc892542d9153057e9feaae843ee720cbfbd71726241e0","src/swizzles/neon/vec3a_impl.rs":"a34fa94f1c48d1ee9a70be2a8db8d154519cc7f1ca666a5c79efa122951e1e24","src/f32/coresimd/mat4.rs":"002e2e44cc488de76eae7180dc99d38ed03448c660a38849b027ac9ae9ba3305","benches/mat2.rs":"1acd3f8853be14fb35b9dca12603d4f32f309b0749e561c6d68d625ee9ac71e0","LICENSE":"0a4b5b8e2558ffc8d4b08cb0ed3a3c09acb37dfa72a72d2201e24d8ec18f8d8c","src/swizzles/i8vec2_impl.rs":"45ffa1faee3eaa0e2ccc4a411506796ea2ffad71ad2fcb8b707e32d66ed16f89","src/swizzles/sse2/vec4_impl.rs":"0c7bff110baba80f4220f3ed3804fbdf2eee91852d808b9084d4c92c4a9f95c8","src/f32/sse2/mat3a.rs":"56dea9c5a710d550443cdb7e8a138aec285233b0b50c65c92f6678bce80a5ddf","src/f32/sse2.rs":"c5b4c408788c9a557811e4e3e8d66aa4ffe73014025a7a7ba49351de39b4d856","src/f32/vec3.rs":"3c3291c0ffb222b362db26a8333e6dfe4b50914704ee7173bde741d1cace51e6","src/i64/i64vec4.rs":"977a23e8e40ad7a4ea2aab8faa99430277b4eea677a7e1a9b978c20dbbbf7fa1","src/u8/u8vec2.rs":"9b1c4cf3cc489004cdd2adb05a8344048572a3bc801396dfb55ac4889434fdf2","tests/vec4.rs":"bea96eb3ac1cd7a4d8fbd384b5c38e24453ac425552291246a470ae57868881b","src/f64/daffine3.rs":"a9eb7fae70c72f9429f7ab07c6412691b2c3fba00c4a61ce66661080c42d6dc9","src/swizzles/u8vec2_impl.rs":"f9da53c699e320fcb33b1e905261567288b2ed82a1a3095ce8d9922c1707b652","src/swizzles/u64vec2_impl.rs":"b56fa6a85c94a145f2c70f2513729501a3217f250d4d6949350b08c563832f6a","tests/swizzles_u8.rs":"11be7979deed66ac076c270fb74a148a28e1aa8a74daa103db255938cd417d41","src/u64/u64vec3.rs":"27a483dd329d8e6e7bced4ba18b7f5750f753cc6f009c46aceba305bac80e781","src/u32/uvec3.rs":"55e36f611fe4b0eb8a0d28deb234ecb32d0f9134d8a3062b4dd27cf6a45e54e0","src/i64/i64vec3.rs":"51bb84a177c34a3ea0eae8ffdd00f78fc72472d325264d231b5864f72e8a84e3","src/swizzles/vec3_impl.rs":"0d2bdf38e3f3eab3da7384612f2bd2a8970a9b94b0cb480e84a30752c01b7080","src/f32/coresimd/mat2.rs":"0c66511d79180860389894d392115886623520e257af1124680ba32e64a6265f","src/swizzles/uvec2_impl.rs":"588c731a0e7d2c01d46d8c769522cae58442bc471b0cdd69a98c63450e38760a","src/swizzles/wasm32/vec4_impl.rs":"ca44f5899ac6b256adf85ec111fd0ca5ad3c839120956816d1aaaf05fa8c2232","src/f32/scalar/vec4.rs":"45eb0974d21b5dd20d9ebb2215be732fda4b3523b348eeba422dd4222a85e7a0","src/f32/scalar/vec3a.rs":"9652c667ced759822db9192e0582e64fde33b450c0bd429994d817cbb10fc14c","tests/quat.rs":"e4e9cd2f197c4e286233895aa118e20b7fa80626259b46f7774d9ff1a8b6bb03","benches/support/macros.rs":"a5a4ff16b792c1857db9f1db4ea5c0a5c52a208d62334111726bb14b685d8fb4","src/swizzles/ivec2_impl.rs":"c5af639a31c6081b9fa6ad33fdc0bd5b8093d77fad5e082496e9aa6ddf4ac0e5","deny.toml":"74cd1432f0d447fbd898168bd3e3e6c52192128d2fa935483460a4f1b02d2baa","src/f32/sse2/mat4.rs":"cf31f768a0462a05ec71ba3b31973ede2dbc85765b9d985e32e597c9fd0476c0","src/u64/u64vec4.rs":"37289b0ba2690c2c6713687c489cd21e48f5fb4e8a8ee61a596fcbf27fb05745","src/f32/vec2.rs":"85ee55cd72a39f4601264a747f498debd7ad9e8163384f38a686fc4df4604dcb","benches/mat4.rs":"7173961ae3abc98a10b87d05132c35615936838f70951a2dda9e3bab98b472ea","src/swizzles/scalar.rs":"b2d62479dd699c08098a1400beb7653a38f64ff61bda3ce6fdc8dd9c7588ca93","src/f64/dvec3.rs":"3cfba7850d76a58b72a1d5ea0247f64cc5fe76450f2fa4db53b3bb3dbb7a4c2a","src/f32/sse2/vec3a.rs":"4088745016b28499be3d66526855d422b0de38f34c09009a887264d4ddc5953a","src/i16/i16vec3.rs":"ceb71d2d7ca54ac216d89a72e9dd7434df97ffae9efd8c4573fcee022746400c","src/f32/neon/quat.rs":"c800cb6bab5d63c322dffc10ce47b5f0ad1dcee2b59d7f24210e57547b9d0705","tests/support.rs":"f502a6c788bb669de5b39bdc71cda88a7ce1dccd0768c0fda582f1d499e983e2","src/swizzles/coresimd.rs":"b2d62479dd699c08098a1400beb7653a38f64ff61bda3ce6fdc8dd9c7588ca93","src/bool/scalar/bvec4a.rs":"eb967d9063f8a8f7de3db46c893f6cc7898b309e3b9ffa3e3abbbe0defcff27d","tests/affine3.rs":"ac202638561d67862a27039d516057040e5df264f7ffa0eb294ebd3bd6347572","src/f32/sse2/quat.rs":"ac21fc3a888d05da15de68e248d7b41b00a7e695edf07590b4626c9927774290","tests/swizzles_f64.rs":"83d4f2354512e0624844b0a931f201fbd8b97fc7f88883a0efbfa5fd712f02d3","src/u16/u16vec4.rs":"8b252e7a704fa3176d969f12c7435e7d08ccaf3bcb4c7e9c70044c1af9e246c6","src/i8.rs":"2c09d6e947b9924a8eb3f9ef4dbf80f906a68bfd0905be3fdb7a6d6a030b9be1","src/swizzles/vec_traits.rs":"c86715cd17fcd0de462fb9c53104e5e0f5aaf543f29d5d858f6ef8e2bcfe54e6","src/i8/i8vec4.rs":"35e65d51f012efffcd8ba07048ff143be461f4e25f2840b883a499eedce14865","src/swizzles/i64vec4_impl.rs":"f737360c845b7e58e9bd9e17ad7f98c67dfe7ac06d97285dac9e553b0a9d0a93","src/f32/coresimd/mat3a.rs":"6990f42d091baa72923f7abddac8cc19607f5dab916f0a4119df5f5e55a8454c","src/bool/wasm32/bvec4a.rs":"4c98f6498c6742a909004fc35b663a867bd80992e51f5eb58fc0566e0d0a089d","README.md":"249b4753c9d9662d6f607d23a8f973698b5b667a00e36ebe7f1c701802208691","src/swizzles/neon.rs":"b2d62479dd699c08098a1400beb7653a38f64ff61bda3ce6fdc8dd9c7588ca93","src/macros.rs":"3954a434a61e1ad20da04b807dd6fdfa8015558da845c7ddb307f303402ccbe8","src/i32/ivec3.rs":"3fd6195c9a73775149575a3dd4d39a062bfcccbaa16ef414a18e3bf60d6351f0","tests/support/macros.rs":"25c7807f69a927459aa2cb0d95cf941221381dbf6985557320191db42155228a","src/bool/coresimd/bvec3a.rs":"ade501e05c232b4123b446363741db08695083b9f1a6c2c3f880ebab4b258dbf","src/swizzles/wasm32/vec3a_impl.rs":"69b599cffb0a11dbaa42eb31f36f3e8b48b3fe4159811f1e8d7b081a01579649","src/u16/u16vec2.rs":"342f2f8e3af80878eac396e3159428ac72813f7a9ea47d4684d88ebf34a5f23e","src/i16/i16vec4.rs":"ce6dac19ab9ab6f5284f280434e0a3694dabb1d910e3f4987d5f201f62a2cd1b","src/f64/dmat2.rs":"2a27bc9209446b3af5cba1815b5d587f863a5e4ec06e8360aea61e79a28c5dd0","benches/iai.rs":"8301e19a24fc80eb3de0d365c4417e5120b02a4a0c405d66c868709fb1b2c77d","src/f64/daffine2.rs":"51241ccfbd32da9c692f3983481e3638a133680471cc986e67b3c21b8ad5d081","src/bool/neon/bvec3a.rs":"191965ed8a1dbb835de902f92b9aa94b895bebc5cd9fe36ecd07c23e7b747963","tests/swizzles_u32.rs":"8f175682898598d3ba3d0b4a9cbf5756751a7c26da6d79cc8dc750be34f26cc2","tests/mat3.rs":"534c40caa539fc9d3881eeef0bb8a69ca8c91e509ef21cc741299e6358f8b2fc","src/features/impl_approx.rs":"78b406d50a71e2e1ad659ddce289f855412156a976c482dc51d19bd8086f731e","src/f64/dquat.rs":"4d610b96163b749eefb98336b7ad16696de63ace20d30d2201ed45e48c0b335f","src/f32/neon/mat4.rs":"ba6f4d5df5c85ee2abe7d009f2351854573aac1eaf096ec7ffd7231aa7bb8e16","src/i8/i8vec2.rs":"77526abcfc5a6d40b2b4b8cb983a0724ef472b16a520ce639c9855adab99a23a","tests/swizzles_i16.rs":"d436749855f124263ce969dedfa911ff79556ba90a512e51fc7da217311541e4","src/f32/scalar/mat3a.rs":"62fb48855c7ed6e26e49f582e86e76d55844c2c846e8e2c77dacecf2560345ed","src/u8/u8vec4.rs":"bcb4a5bbd4464ecf3a6a25e9be6cc11c18d61b12675385e6dfb0fe08c323ecc2","src/f32/neon/vec3a.rs":"3644a6b4da24d3544f83821f5aa6bacd50b944f1cfb3eb07012746610712e926","src/u32/uvec2.rs":"9d4ed71121cfdfbc49b57dacbd916bd13c68dd7acb38598782f0ef033c8d3544","src/bool/coresimd/bvec4a.rs":"a6bb2d5cfc4bf47a4d95cb05c0e667f1255845879236c5fc2b3c4dc3296d8def","src/f32/wasm32/mat3a.rs":"4622b00610271a9ddef7f8604f8a1ad7619ef85eab3fd76e5d65138a41f29030","src/f32/scalar.rs":"c5b4c408788c9a557811e4e3e8d66aa4ffe73014025a7a7ba49351de39b4d856","tests/vec2.rs":"3a60224a99b638893f0ea5c08cb6d5a20b7571683a59a9ef470a3fff82607120","clippy.toml":"40ef87c643ca926e60249ae779d096c5a11b05c52ffb1cfb4dfebb534f2c9314","src/float.rs":"a9aef4b0b49b5d8dee3a2ec527b4008b54cfc44048f133160fdbab2fc312bdef","src/f32/scalar/quat.rs":"e452df176bd4b2e436d3a107c7f8a6ec6de3e669dbb61c263aa22127232d155a","src/swizzles/neon/vec4_impl.rs":"fb2216e4ad9690467792477e250a24095da89eff065776ee085b078ff095e45e","src/lib.rs":"df598dd5b4e5ea8bd17c4e25f1050b99c243eea6ef7fa318620a114c10b78da8","src/i16/i16vec2.rs":"7ff4b27e7ec2b401303d6de0782cc1b354feca7001e7a4da86a5bd21548fd969","src/swizzles/u8vec3_impl.rs":"1e4465fb2c4a93d48da9c968148d5168043b8025141a506c72bf9fa76490aaf6","src/swizzles/u16vec2_impl.rs":"e1ac603ab6e99b667da98243bc739cdd611e06cf2e8e8d3e4ef4b7da64877630","src/f32/neon/mat2.rs":"6f2a53bca079658fbf20b5b75a886b2b7747bad418627060e059ec9a36357f11","tests/swizzles_f32.rs":"dcb4a745816ec72d794eb3fc8c75fd0f2fa26f1ea06ab3889cf7438bfb99019e","src/euler.rs":"4ae0051961eadcb7d95475521a35836a6e5205257cfb1c3668bad6832c107a96","src/bool/wasm32.rs":"d6cd7887778deabcaddf4479a6b2bf5bf47143b0726459f4a67cc6ff038aa2a0","src/i8/i8vec3.rs":"85c0acbb7cd5277c6e8e4f2b0fea08dae2dbdf750385573482b59757d9b4d0d8","tests/swizzles_u64.rs":"2252610142b6482b65327c74116c82a0bf44b4daa65cc1a537d0965993cad816","src/swizzles/i16vec3_impl.rs":"d09e697a7c2407d3232596bbce57d065cfe61811e4a29ab876d93bf562b6ad6a","src/f64/dmat3.rs":"ad45b31e07d4523b21b10648af0223ae44655a621771d5bb350be5b2c927e239","src/u64/u64vec2.rs":"c76eea3813e7d99710d01ddda3b5d6f942f86c5b89db324073b25e26cfb90df9","tests/euler.rs":"98dd5c10bbec80ffb20f311b81358513b85bf8f079793db6a015cfefe1726fe1","benches/vec2.rs":"fab318070b1259354cb762c99d3755f6a00ec6b42b734b7a555be6de4c10af0f","src/f64.rs":"8bba8e3435de1b4d049e4e81046eb9ba7fc155de73a0349721124ccf947bf24b","tests/mat4.rs":"87e226c38c1de3f9587e56ad2b65e15908130bfe2b6fdbb3a17c1f420f76d984","src/i64.rs":"1c71d9921ee0246800beeeadf49a322da5bf85f2832ffa1934688e242e735626","src/bool.rs":"e7341a7aabfbca192ffb0d30e4e059fa516312fb2f5c5d493995ae7ae40763cc","src/f32/neon/mat3a.rs":"ff9052ded8c3ae8c0e9589e081ae0ee730e238c4b5986121ab3e74d5cee37f5d","src/f32/math.rs":"a90f78683eda9bd20b0844908687e5aaf8c9079c555c97c216b2e5f0dbc5c55c","src/u32/uvec4.rs":"3172e05da62a304566770d09c36c32278af3b8f76888030c8fc9322f68fe0d00","src/f32/wasm32.rs":"c5b4c408788c9a557811e4e3e8d66aa4ffe73014025a7a7ba49351de39b4d856","tests/float.rs":"312e1a2525a34ded8b47e9e040a07bebd84c201a93a5a9a59b6d078781c289ec","src/u32.rs":"0f3bc0a26144df8c25928b5aade55423ed219399d0adbb6ca0ef9a8a8477e389","src/swizzles/coresimd/vec3a_impl.rs":"8423e6b07ccc9ebfd72cd14e452ff669aa03a41517153934bdd6c3bf1cdfa383","tests/swizzles_i8.rs":"68693396495f10ab96e984642d48e33076f7e975a85f33935ed762839e476a6b","src/bool/scalar.rs":"d6cd7887778deabcaddf4479a6b2bf5bf47143b0726459f4a67cc6ff038aa2a0","src/swizzles/scalar/vec3a_impl.rs":"a34fa94f1c48d1ee9a70be2a8db8d154519cc7f1ca666a5c79efa122951e1e24","benches/support.rs":"282ab869c8e066884a6d32b1762c30b9533e1c873a59cffe9ba77d76ac1092d8","src/coresimd.rs":"cb848dbbd30ea3ea6766311ac18587cf2549830e09304d3828ef883ed2a3e198","src/f64/dvec4.rs":"21c6bad631eeed3e7b2415382ceaf4ddc5922c942a6df584a0e1fee06e40972c","src/bool/wasm32/bvec3a.rs":"fd5f8b18653219e6f1aa1b6ff53cf2ed6b0cc763d9c9f275e57face6e1691c42","src/features/impl_serde.rs":"cd152bd3967ab36e57d91433ab1ce483cbb53dedd523d740e8935ebd9dbf7eb5","tests/swizzles_i32.rs":"2989c2b04e8281810cf01b2a3a3444f15dd16f3b9ff03d2bce6648f4bc520899","src/deref.rs":"d0f569375c4621f6a8b0ba38a2e9fb29e6aeca50efd7247d226f1b1ae6d0f766","build_and_test_features.sh":"8097e80d4a115dd408c527b5b4a9c85334fa5ef886b729890b43eecfe85fb249","ATTRIBUTION.md":"68351d86724034ca10de19536d3110805928de42e3c34667573784212fed2429","benches/vec4.rs":"247ccd8f584edf26e9b8a495493b6060e7415fe47ce19b82a8012779fdc92201","LICENSE-APACHE":"0a4b5b8e2558ffc8d4b08cb0ed3a3c09acb37dfa72a72d2201e24d8ec18f8d8c","src/sse2.rs":"82be3f657293e41f7177ea16d8d2dabe67bd6d83f51df9a9174121616231b464","src/swizzles/u8vec4_impl.rs":"903ed42df6ff9bf28bc4c3ea7cf9de8e157622c820f4922edf8d0ed8841de4e6","src/u16/u16vec3.rs":"c87e1384bfbc70b5fc7258e80d36535f5862157697e1d2ed24f67a4ba64aa88b","src/swizzles/i64vec3_impl.rs":"1ad5180c37520577a7d60622a4c78e0b0ba830d1ac5df97f5928153d5e434a7e","src/align16.rs":"2e14d45f1c2bffc3c17ae0d08a78474c83dbee23236d1d3d2bcc54cb40aee6b8","src/swizzles/i8vec3_impl.rs":"274c50409c0fe6963fbfeb48d3540a725ea392c5ab31cdd3936e9d49d92fbdb4","src/swizzles/vec2_impl.rs":"3903cee652bab4f4274231819768d0b6f1af2767ef952ae1f09188cd0cc7e62a","src/bool/bvec3.rs":"8e79f9fdc72b2b3a7584b53e1866ab4223e821dcfa15f4794d92f602bb0b20b4","src/swizzles/wasm32.rs":"b2d62479dd699c08098a1400beb7653a38f64ff61bda3ce6fdc8dd9c7588ca93","src/f32.rs":"969ac5ed16361b01df5f9b62707d5c9e7eaa4bf99409a80824dbd93ee353ae2c","src/f32/wasm32/quat.rs":"1d2f8ca65c661aee4cd4007aff2b82fc136e34631f2f6ec997ef03161b4a0ca2","src/f32/neon.rs":"c5b4c408788c9a557811e4e3e8d66aa4ffe73014025a7a7ba49351de39b4d856","benches/affine2.rs":"258fcc2b26d17c03f117e62512c48f4f3c6edab58294ee7b42b5a00e15df120c","src/f64/dvec2.rs":"9617b63bc834c042e1ed1dff232bd00ef3370c278e30d7560c2d62b3e60f076d","src/f32/float.rs":"0589193ac5a2dbfa12d4e0aa0bbdc5fab701a8b9f8cc433dfbc5a388398f470b","tests/vec3.rs":"20d35b9957fbfde5624daee66e5bc4cd370dd4d6c33dfc8dc00997d77e1de64b","src/features.rs":"8484ef288a24713cb41269dc66beb5ebbc03670850a3fa371849d686ec6583f1","LICENSE-MIT":"38620a3cfaeec97a9197e8c39e436ea7f0bc86699b1f1c35f1aa41785b6d4eac","src/swizzles/scalar/vec4_impl.rs":"fb2216e4ad9690467792477e250a24095da89eff065776ee085b078ff095e45e","src/swizzles/sse2/vec3a_impl.rs":"faf9af46b466420bb90f992b5febeb5c67a495d0c2295572bf1a002179c3f073","src/f32/wasm32/vec4.rs":"884ce625e645b9fadca35c32a94909485b4b33ad31aa2130c41b796eaeef45c0","src/f32/affine2.rs":"b9a1f0605927c38bd3f99c62b1e0fbfa8f2529226eeda8903b5cd227be97a8a2","src/bool/sse2.rs":"d6cd7887778deabcaddf4479a6b2bf5bf47143b0726459f4a67cc6ff038aa2a0","build_and_test_wasm32_firefox.sh":"1a17c0878c478ce04dcf3083c4268cc747076962bdc82e1b86d9187cc9826723","src/features/impl_rkyv.rs":"f9792f74a905afe0895c0f36af22eadb3bbe208b2d7b63c457f7d3e06ca554e2","src/bool/scalar/bvec3a.rs":"2d297aef1d4ccd60d1f9e678087862c7e8996b20b42961c76faf943dec6bd9f8","Android.bp":"de09614d04819c52632320dc53fcf086b4b6e2b6b4a2d7cee119bec42469e56f","src/bool/bvec2.rs":"022104b80fd93c0fd9ca7d39a7fefdda7a534b2af12052259a8676e099feb4a2","tests/mat2.rs":"afce03547472e992ea3d60a2d9b1f7d221e1be00805cd4030830f05d8dfe428e",".cargo-checksum.json":"5561286ceca3cae3e7e719055d4aea9a93e86d5c4c499f82511cb755a216ed53","src/f32/sse2/vec4.rs":"cca0bd4b2c5cd17f29bcccf4d7d9e9e53d7a5812b703a3feadb3a326b7bbce10","CODE_OF_CONDUCT.md":"104c5c02a827d2c2916183b093e999b73e5e48c6925aae556416c52e87786a30","src/swizzles/coresimd/vec4_impl.rs":"1ca9f458d4dd2ba487b0eb7d828832d7b8e4aca0b6c82eae2d933c3337773346","benches/mat3.rs":"d6d443ca41ccfbec6d2ba8a55633fd05d81ad9221e36d25e20bfeba7417935ae","src/bool/coresimd.rs":"d6cd7887778deabcaddf4479a6b2bf5bf47143b0726459f4a67cc6ff038aa2a0","src/swizzles/uvec4_impl.rs":"c53e3ac1d39152f4474d1ef21014f8860fb02d616c7a51b1f17f39b482121f35","src/f32/coresimd/vec3a.rs":"4aafe28179cddd91b4ccf31d0aac98111257e0654a86fcc5542c4cd959f2dace","src/u64.rs":"666b677ecc47fca6406f7ff2c1e89898989a56fe755f9b92acd6a7ddf4ade22e","src/f32/sse2/mat2.rs":"ee5dc00c5939d4092136043adc1e5b269e14d5d0a607aca4f0c2a91ef91c62ee","benches/affine3.rs":"434cec45c1c89c57807970a275ea88e7bdb2827946e737913c1974f7ebc64fa4","src/spirv.rs":"9be963696fc3a6c5c75bdebcbd90cefcdb89d65b84e138b4540cf71c5f0a5502","build_and_test_wasm32_chrome.sh":"ee529572839b5e48171da9a6224d8f18804339974b53866bd08d732b096a55e6","src/neon.rs":"4d3e1e3b311101913cc7e31e1a4e7413bf1a21cfcceee4145217a3d4aaba6fc9","benches/mat3a.rs":"cab5b9f23d68a7e3d557b2ee82f41b76ca45d725eefe42f0de7866cc3cf47a17","src/swizzles/u64vec4_impl.rs":"9444b3003d42ed4d245c9a50ec4a51c0168c3f36985ab1297de9bdba435ecacc","cargo_embargo.json":"1a734fe479a7990d44ba5d28ca649ca5f881f2b8b682945032e896fe94810eb0","src/features/impl_bytemuck.rs":"f0f9720fce64b1def39697866d6f2b195155618522b8c72c395b46b71a572456","src/swizzles/u64vec3_impl.rs":"d27b3c5ead7b65e8fd620d362a09b80148ff5fae3f511806af0b29d790c044cc","src/swizzles/sse2.rs":"b2d62479dd699c08098a1400beb7653a38f64ff61bda3ce6fdc8dd9c7588ca93","src/bool/neon.rs":"d6cd7887778deabcaddf4479a6b2bf5bf47143b0726459f4a67cc6ff038aa2a0","ARCHITECTURE.md":"c966675696b1f919fbbf82dd156cd1f07f42d182e801235cc71ac9ff5b889db4"}}
\ No newline at end of file
diff --git a/crates/glam/.cargo-checksum.json b/crates/glam/.cargo-checksum.json
index 5e8d93a..6354d97 100644
--- a/crates/glam/.cargo-checksum.json
+++ b/crates/glam/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"ARCHITECTURE.md":"a96ed48f5d407355624d7b74facf4a1bb04c15aaec38045f4dca68092198518b","ATTRIBUTION.md":"9f0738ead3dcc72bac87afc652c2466e1bc130d235db7798f98da4d4ef013639","CHANGELOG.md":"f0730eda0bb34b95b646a35977763c286ba0d615e9f244e72294ce69eba3d9ab","CONTRIBUTING.md":"868a8e28e6fef5c1f050f9395b3366ecc8452f285a911beedd8753bedcb21501","Cargo.toml":"0b368d03238251599a7f0015d3733561e789afa535a9ee833b0cc254d364f6af","LICENSE-APACHE":"be33ddb87a30fd321ab100e2d922cba512e50ec7a63d8e62e5bfc0798dd4b585","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5b4bf9a266f7d020499fbc9aa7f6a7d93e0169f8fc121b70902cc662349bc3a5","benches/affine2.rs":"2827651bfc53fe2656fd7903396833fe414c900c5ceaf660a42c3c225703710e","benches/affine3.rs":"d964dfd46363c3b2c8071c3816ce6f947e7dfc9a79e8081c6a5549c57844706f","benches/mat2.rs":"7341b2ad178ddb497a359a49b542af09a7ce4b77f6680170f1f621dd3aa8a729","benches/mat3.rs":"4ca689ed8a6f6de61e65e276f422dc83e35801d582f747ac5fbedbecc353d623","benches/mat3a.rs":"c0314337fda316640402de961a7423da2a59c6bc570c96826ea2338438595538","benches/mat4.rs":"f31c6e1e150cf39cbda36afbc592d7734621841ecfe72051d50233d49a5e30bd","benches/quat.rs":"5dfb6021b0284b1f3fa09b4671358c4af8cdc2a206d36e87656cba527638857e","benches/support.rs":"370b4e19c81726fb6adb61e20f3451510656aa819190c811257edc2399f040e8","benches/support/macros.rs":"c05454927c2ff3e846d2d3dcd2605feb5293bdbba4767d7f352dc538ab369fc8","benches/vec2.rs":"96292b22045046f599d74f0b4fbb2053e78605fa0cb7865c7d3f8ae7c88494d1","benches/vec3.rs":"cc0664fc4d4293f1f337785ff2dc9a8fcea569b49a59e8517173e508b15a5178","benches/vec3a.rs":"fbede3670f77aa5bf1e4f6a59a921f6bfbde37ba9239fa14f0253ff486c1bc81","benches/vec4.rs":"07633a80e81e566c9f411be8b0669f8479f06084c541492e1b50e91e118b5c7a","build_all_msrv.sh":"1fb67ae0c3e48917f076605741078e9d442ac919803318d63c89878fdfed55ae","build_and_test_features.sh":"eb60ebea150a7b5ff2257dd44d04b203d3e3cf91298c7587cdd729b2631765ab","build_and_test_wasm32_chrome.sh":"503dc45a409348c02365bae3e67b4148874a69ff8bd7e0747702f8cb3d981cdb","build_and_test_wasm32_firefox.sh":"02effae982554c4e12449c5920706afface32e35b86e7cd654788dafe58e0a20","clippy.toml":"56a96dedba8cfd8c1367923913640452fee591f78f7eea9927fc90ac0f6fc361","deny.toml":"bc4db68ddf88f197ae05d9dac0f09fd90336aa33e0d19fcd0538e863f3d1bdd8","src/align16.rs":"41e75bd6cb6d96769dfcd8c3a5bcaaee3fc41da4bf36c2e893b939776d357050","src/bool.rs":"fa193e7bc40478f826b6936e91f7813523992b03656f3f9e72cf1820aae5a741","src/bool/bvec2.rs":"db5c3cb7efa41fef463beb7037df12aba6a7f8b38ea1656ecff2a4a904f7a10d","src/bool/bvec3.rs":"d029ecaa3ee1b8950479aa867481888ffe6d7ae6ba000d41f7d2d4d07de4d610","src/bool/bvec4.rs":"4fc34991b2989794d368ca63c83f9c523c6ca932e9adadd2031e49b58ac050ae","src/bool/coresimd.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/coresimd/bvec3a.rs":"dd0332ad05ed0133277a31730073b0b1067233c1a96d3703175c3ba21883d090","src/bool/coresimd/bvec4a.rs":"3427e22eccd7dc61f1d66f198bfdedb45c8f7f92e9657955fa59b2a97f1d97c1","src/bool/scalar.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/scalar/bvec3a.rs":"47a2d79b15679c13d6a410ff7f572e79ee344c02f8bd03bb8d1b5579bb3ee019","src/bool/scalar/bvec4a.rs":"64e2f5106a4c10fdcb6511cc761b04c23d57ecbc6d9caa83a63e6d40f9188771","src/bool/sse2.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/sse2/bvec3a.rs":"a06c9410a19182b8e99578e86de1feb1a70ce86fed9258bb306bfc3d7edcea29","src/bool/sse2/bvec4a.rs":"45d019481a7815eff92480462314e111f3b91a9a92ca63a2d15cda0c5d274c2a","src/bool/wasm32.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/wasm32/bvec3a.rs":"8b75d79876356ba62f0f3699d21827974f00debd1f7781734fab868609667b08","src/bool/wasm32/bvec4a.rs":"b5a1e63bba143f93e63f8763f48e46c6247f3cd138d05879403e39ba26699ed0","src/coresimd.rs":"ccd524501c85ea0d882221000096335fda1ab325cfb2ebfa37d0c60f927c975b","src/deref.rs":"43d7013d2c22c4dd3dced7caa10f65e3b502aaed513ecae49672037a701a6269","src/euler.rs":"a41c2d98272a5edee0c700f2ac32c3719f5e40786477261efc5dfbb437e8c0fa","src/f32.rs":"03bc48a85a6152dee6a8b4e340351aa61763138b20e7646d7131cdcb5f9693a3","src/f32/affine2.rs":"225319e25b749e6800e6fff07fdccf813bdeefd991c71e26aa743004099eb8d0","src/f32/affine3a.rs":"9a64db839ad7f12a9d4cd143b3245c37037c18e227150e0642d443a2c30eeefb","src/f32/coresimd.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/coresimd/mat2.rs":"9558590e7a80883f20d0739e21c2f718a6e4d307ec0267222394a1c9c7248a3b","src/f32/coresimd/mat3a.rs":"192c7a3ceca3da1e43143162c8b4f319e6c7b50785f64228646a158a894d1d30","src/f32/coresimd/mat4.rs":"b8acd02945d892b5cbcab32f0f14c764eb6309875fce7ec089287090802133d4","src/f32/coresimd/quat.rs":"dabf9c4ac29fa96d517e06594a18e9e34cd959d19e5d0a66d93d3ae1a79ac43e","src/f32/coresimd/vec3a.rs":"28f85a302a23708543d1a0be3cfe96f76f431c7b4fdf9ba0dd749037c10c1f55","src/f32/coresimd/vec4.rs":"e92fae6e1b013939d20b921e638387ebfd72f32204f39755753b170fa5a3ef72","src/f32/float.rs":"7b95c7e360d3e74c6059aa89cdd632f4413cfcdd417356fba28cb1996f078708","src/f32/mat3.rs":"97be74261417d3f8ac14e521aca31d3f3e97240cffea826f5c4a1ca4cbbed7f8","src/f32/math.rs":"162950b01d3799cd4e76a25fcd3ebcd83eeb27ffc114d51f5645c72cf6534c96","src/f32/scalar.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/scalar/mat2.rs":"425f9aa2750da3d858cd3465401133545dae3720748c19e0ccfe4b01aed4e97b","src/f32/scalar/mat3a.rs":"fcf505c3af3dc741d7a369fce82b3d6f1753e2e52175002bdaefb1bb3f751de6","src/f32/scalar/mat4.rs":"3c870d10deeaf13ae74e086569cd9a2b1818f4bd43adc9fa23d6aece78ad205c","src/f32/scalar/quat.rs":"9f64054d4c4bee9be233a396befdfcb7b65198be3c12a572e9d80d5311f095ed","src/f32/scalar/vec3a.rs":"4be5c9acf881dc55c2ceedd0199343e7f93597fed748297a7572083eef501e0d","src/f32/scalar/vec4.rs":"0db8286a4f5d3e203f1402d97d82200ee7fc231fbc88955102f4873dac64e88c","src/f32/sse2.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/sse2/mat2.rs":"e12e98ea3548df5aad4c2efdd7e71c669c45d3374b21aaf322cd1ed490c5b27c","src/f32/sse2/mat3a.rs":"e37aa56daf7dfe4aa753c9d866ca710aea2e23492cfcb1b6cf8069e00059af7c","src/f32/sse2/mat4.rs":"c122e278ab29ee75d73809d888a81be58a90f8e0a22e860575dca2d4c07e3ff1","src/f32/sse2/quat.rs":"0d866a0bf3e41509913cf9badef02741120de75736cc8261ab98262250b454e0","src/f32/sse2/vec3a.rs":"d2a316a218cd26a60a6fe1b7770e7ee10f8fbb0ff8bde7a8e72196f117248434","src/f32/sse2/vec4.rs":"709b67da6ac47a162afcf67931c3f69af5743892574f33cf8e515977260d5ba9","src/f32/vec2.rs":"db7312fcef284e70900caf6a12864aba4d7ff27595954ae8ec3e73df362c17d3","src/f32/vec3.rs":"7b6126b517084d09f4c41966debb09e64317369b438389a0ad0c764c9ebbb347","src/f32/wasm32.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/wasm32/mat2.rs":"033979c5197b6941c8ec626b82914dec3eb4af3b5799448b5d954cdb80eafa38","src/f32/wasm32/mat3a.rs":"3121a5ea18161b7d01c87e336ac7a8bd4fb69de504c15513134ac16eafee9d2a","src/f32/wasm32/mat4.rs":"9f91662024eda4e9d9aa80f87142be0997b634913e95727437bc1db497ad9075","src/f32/wasm32/quat.rs":"7246d03743fe68a45dacf950552c340bed4adc2d50914c65db74551c5ae35d87","src/f32/wasm32/vec3a.rs":"aa48aa6ab1846e9d0afd9681d2501483edffddcf677c72b5c4057674df270f2d","src/f32/wasm32/vec4.rs":"e541d18860a98b4d4e27fc9826bfae6ec3da19b2fbd3b13aab544e6b20eb08a4","src/f64.rs":"e15e434181625610ddc8ba517d9078f58b2c5ccc7beab8890110918e34a5672c","src/f64/daffine2.rs":"82d0a6f76da55d181b3eea367f73dcf46e3c168ae661ca35121e8166b71e986d","src/f64/daffine3.rs":"eb506f295aa1f65b4b11b5ed4bec78afa08779adefdc63f992df697d9a085f9f","src/f64/dmat2.rs":"68093a52d12ddd809709b32a8fbf2e9e3c8996bb68b2d3bab7907e4e9eed1eae","src/f64/dmat3.rs":"0062d847595bc7cc1970f5aa2b7bc1901ba78797b7934f9acc16e2423f27a2e5","src/f64/dmat4.rs":"5bf786284f4d614a06587a5fa94064c34393611a3f9db6b15e5105d309c3a577","src/f64/dquat.rs":"92028f3be49b890ef7890cb1188489a701b1d8118f253cb2535ccc2c1cb8bfc4","src/f64/dvec2.rs":"b141fa3f55b8b90d95ab4087e813d592dc9e57c81b9d45939388a59f48c689ff","src/f64/dvec3.rs":"2e66df01964c0caad0b28dc7d209457b026a78e2fdc0344ec4f87c89faf20bca","src/f64/dvec4.rs":"9cab4c3772f12b38a03be8a7c7589840ced8a76a1780f0e8845d871da4639779","src/f64/float.rs":"418d931fd8fb8b3822d669052930146301f5519b63d239eac41fddc5d2908c53","src/f64/math.rs":"9da57c514652282f77af31dd3195c50dbc4214cfa7c81e39a54782aef302f780","src/features.rs":"bdeec5e69c2d2ad7363f77a754f58299ee1b552d413f9b643e0bf2cbf5e6ebb0","src/features/impl_approx.rs":"f04289c086672da9593b8db2189a76228e348329f079035120a5ed3645107d62","src/features/impl_bytemuck.rs":"286b173c446fadbb2a92c8281acad6eb7d59948dd8a48d27206712322878a550","src/features/impl_mint.rs":"31eafcee314780c266c60cef022a2966e1471d008e8744fc1b2dacea0a8096dc","src/features/impl_rand.rs":"1f85fdfe5220a843bc51d649e9726a454d24dab1700914398cdd50015d2d1f45","src/features/impl_rkyv.rs":"450ee9d5b89bc9528ea2985fa0440470243323e5b3a1344efa2b3895decd10e8","src/features/impl_serde.rs":"a8316d78bd3454342892997cb2abb06c44f32a0373f6eb9048ae517b48fa1c78","src/float.rs":"ab457804cfc3b1f36ad2e0428c9a9afe3855ca26b88b255a2d5fe0ac8b6e12f3","src/i16.rs":"ca28e7f10f6b099c3ac26c40bf9b4fae758486a5c2372a22060fdaedc8fdb21e","src/i16/i16vec2.rs":"d2ba93f238f14a63e27c84ee6c7bc57b734dae473bb2205648f7b99b07c7c369","src/i16/i16vec3.rs":"b3063be229955858ce94ec57449cc813702e7e6405ada65c9b3966460994328c","src/i16/i16vec4.rs":"5c316826312e71e3d773e8f26a807cc99068e7f3c8c9350719bb3284eb8e0b62","src/i32.rs":"837ae56757baa4b9ca5d9b176b1c310dc38c612bb62541ec82db4556266fee49","src/i32/ivec2.rs":"5230d9b456e40e79008cf31cfbbef9cd4d4bc76f8d17588a753d37fb4e8045ea","src/i32/ivec3.rs":"de259f0b4920a36fca41ce9afe6094ad36e1951c37f37d0b3559f84038121f0d","src/i32/ivec4.rs":"8a3fb82e73417d26dbb6f7d6b0a56867aedd911b87b64b97904c9a475d4cb437","src/i64.rs":"cf9b09767f124ea71f6f47aa572f0b1114759fa098d997de2cc166c21840f6a0","src/i64/i64vec2.rs":"a447d4e3caf7dc96e403d7b2eef485814c1e4bc3549068ca6c01fac1cce92d7a","src/i64/i64vec3.rs":"80eadde5f0210ae2d32e72fa08430cde370698add9a6a47d42b24cb636b5328c","src/i64/i64vec4.rs":"a8c33c1e6311544ec3032636c291d7b1227075dfcca0438a6ce29b9c24e6c9f0","src/lib.rs":"3ffc07cb0ba94b4fd2abfed93616a39dd070aa8884eb46045101ea3a5f860a9e","src/macros.rs":"4926c68286db038d1ea7601be8b518cbfe7ca2777eb219531f395b74f7d34d3a","src/spirv.rs":"dc115904475c251b9143f0741e35ea1f025975313a81a5ea433098e8eedcf3a9","src/sse2.rs":"dc668462edb09ee6cd154a7616e0b7ab5f3ac66f9cee7ae1ba25f8a0c07d907d","src/swizzles.rs":"af8ebfb69d03fd1d0b3bcb54b68e30b23bde9c3c9071f865993e77072bf0a7e8","src/swizzles/coresimd.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/coresimd/vec3a_impl.rs":"670a611da06dc176e79419889c1730c50d9d01b1007694cf15284c0fac6c0011","src/swizzles/coresimd/vec4_impl.rs":"9e1ba334f6b8ff2577c58c7957a1398eccd422ea7ab1c17b76cc2b185c75a64f","src/swizzles/dvec2_impl.rs":"3197f08ee5eb4a1dd589b7bb4b8b44a0ff079a7292a4943ca9239010fa7f9e8a","src/swizzles/dvec3_impl.rs":"702514bf001c6fee4ac8bc57abaac506f51d78d5fd66479e34927a3f9e7261c7","src/swizzles/dvec4_impl.rs":"28ff68a28028adf0bbcfb7e229efc854d9c1bd8a1329a0ecf8eb97d2d361e009","src/swizzles/i16vec2_impl.rs":"b59f08a1d51356f8d543c39cbacbe29fe2e5ce14dcd5feb3d57609a5c0275a32","src/swizzles/i16vec3_impl.rs":"e9aa50e94ac055091b3ddf6b2d0ca74cb3d4cca86c0f66f810dc571113514a85","src/swizzles/i16vec4_impl.rs":"1edd6b9f59cfdcbb33b4b93344cb4a1b5f18885808e0fca04cae2dc25e0a1f8f","src/swizzles/i64vec2_impl.rs":"f5227c31ba2f219c2c5fe1a822f5d386d468dbcf01efa69129d2ab608777b85e","src/swizzles/i64vec3_impl.rs":"b1002d6629c34e2e7587223e8740a17143f7032fa89035777ec069b33463887b","src/swizzles/i64vec4_impl.rs":"496338937d112cc38a2f4f74716fc1f8152445ce5334eaad1f25f319f466dc5d","src/swizzles/ivec2_impl.rs":"733ff12c9691ec4042a247045e45f0f2172f67304bb8d9e33c097c4f102fae2b","src/swizzles/ivec3_impl.rs":"9a9ee8e165f9d7df85e5475512adc530db14740cf1fde3e70c9011e73f0775ee","src/swizzles/ivec4_impl.rs":"2d4af220294cf459d960055dea0a0a4e562130ef4e9fd95074bebf4d1c8e45bb","src/swizzles/scalar.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/scalar/vec3a_impl.rs":"2e9c78d940fef87277b09fbe037aa643a6cd0ca3d3c9bed7f712a490d0db48ba","src/swizzles/scalar/vec4_impl.rs":"1a2c117bdb47a673e9be414a259346bae221b106cd8b652efc1d158db71112d2","src/swizzles/sse2.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/sse2/vec3a_impl.rs":"1765f0c4f7bfa9849d8ab77542b42e318761cd781cfe6afff56f5800576cb331","src/swizzles/sse2/vec4_impl.rs":"905d78a7b449e225b24f0e346a9b0a70e167c15762b963c5e2d303b2413d6ccd","src/swizzles/u16vec2_impl.rs":"315bf2f88b2cea5a97dce7d56f64abec6321cb00b40ab3f0c51daa120e1e1be1","src/swizzles/u16vec3_impl.rs":"812dba0256c33d8d254f1b8447224b2ae17f1c27a33caf2cb321489e7a031efb","src/swizzles/u16vec4_impl.rs":"e3c693f436b3ed4db00bdb47231ed0ebe76b76f987ef6edb565fb70124947ec7","src/swizzles/u64vec2_impl.rs":"988c088ec14a61ae2450f92bd1ecac245216c9634c9bf2e58280158650cbc3a6","src/swizzles/u64vec3_impl.rs":"3724c6c96dd7a879ac866b8ddd424aaedca8255190034913695f7d972452bc6d","src/swizzles/u64vec4_impl.rs":"32d40d0c5c5bf2e69d350fec6a11fb09fdedc319b55c42a3ac54bc41e8fb644b","src/swizzles/uvec2_impl.rs":"96db447d153d8932ebc8227498bbee21c1a616547da767960093e77fbb9e3227","src/swizzles/uvec3_impl.rs":"84a3ff1403aa937c8cfd99cbdb42a165c59070d161e4c9dd96246f3b7ef68fb1","src/swizzles/uvec4_impl.rs":"270fb61ea0fc5279ff363f0a063a5bd407502893b6a49a0d75c29602de768ae1","src/swizzles/vec2_impl.rs":"328e058bcb3dbe17e17e3c94dbe98e5febad014109ce0d2013e0d9cb38a6560b","src/swizzles/vec3_impl.rs":"da584487b16e8a9e0da0919089afb2dd003c06b0bd9f5538a6fad124a90f4b8f","src/swizzles/vec_traits.rs":"a3292229d93ad3bf1923e8fff36fecfa4694b2c6d8136e16a6f431f2b2de7ed5","src/swizzles/wasm32.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/wasm32/vec3a_impl.rs":"a84bca589c56434b250336abb06d9a5eb814434530b80b300e0fe4a0c712cc9b","src/swizzles/wasm32/vec4_impl.rs":"38ca412b7df70deaa4e71974fa953df39cd66484f002b851c5f0be92a2cc3d21","src/u16.rs":"7cc7a1c89d1163fd1a61965bdbe5bd61360acb0606a3957b571f148f98380882","src/u16/u16vec2.rs":"e48a99b9855d58283b0012fc321c2775875cbd1c95d26857ac644f18a5316f80","src/u16/u16vec3.rs":"1cea2d23a2be3a21a74e7c58641bfc13898d81620e76c4bd39893d51c6411d63","src/u16/u16vec4.rs":"c230653d498bcf238e2fd7d818a48b081ceee44d0c86c5747a04f7b13fc1068c","src/u32.rs":"efc99a6ef496e73d810014654fd2c3e37ed0cbfcdec82987d1454328ef6ddfbc","src/u32/uvec2.rs":"1c63e5dc6b47af681a2e5e024138c746740990bcb7b9483ddf2fe30a98905ee1","src/u32/uvec3.rs":"c3f2ecd2157cfca4355508a9c7e16099eecaae17b08a4eeb6288920df5b2b8f0","src/u32/uvec4.rs":"a76ecf9dd48065c529f93b8e660b1456f3be8482d729b35a28456c1e591a624f","src/u64.rs":"f12ebe1fdd0ce33f459306678f1b90b34614923b3713451b4bcdb0dc1261f830","src/u64/u64vec2.rs":"d9fae370825bd4a09a116a39c44b0e4145cbf83c9e3f436af14407213084a36d","src/u64/u64vec3.rs":"c4b88adcd4d9ea18d1e2c3e97a44bcfde2ab294cc7c7da28666d81abb7bffea2","src/u64/u64vec4.rs":"0411979c356c29db191a823d001fe7158e7ea7d805dbd896c98b1d9eeb8c3b35","src/wasm32.rs":"5ac6177e5c468e86644be2c02c4f4caacfffe45a6a7b3958246f1c7c73790b30","tests/affine2.rs":"b05f30cd08b63739cd1551457f3be9c353c133a709292173446df837bdc15ea9","tests/affine3.rs":"201af213453c8717b456d4b0b4631e59da7d735968e5e889d551a4ef6c96e0b5","tests/euler.rs":"187aaf8d6bb0f5c3994482fd4bac52f38c439beec167471de44869676d14ea54","tests/float.rs":"d64c0502bceb455196e8f7070fe6b75dc195523995654c765f700895423ebaa2","tests/mat2.rs":"de44fcab927b8af13d5c625a280bed256ee911c33bb59aad6f3ce20adb3322c4","tests/mat3.rs":"c0646ba2f2b38052710f5fa36a508e2ea1ec6da471e02f23a1ef5c9b1c5077b0","tests/mat4.rs":"01ddd22bc95d4aa3e25694c6b72880c9d95eb83e6b6281a8ceece7fb13a54d07","tests/quat.rs":"f952b556006f8bdaefe25409d30753e48aa39285ef4df0195a6e4df5fd95a6fb","tests/support.rs":"dda98315b4048d990cd1315d6b6450f98689a906391c9daae2358a6038df8c0d","tests/support/macros.rs":"1f073dea2d1bdda205ee33e252d44ff7e86b1a9737c4e62db517d5eabc0da16b","tests/swizzles_f32.rs":"0e87a720070abe20fda65bbe60dc444d6a20cb18884ca09d6910433c35930cc0","tests/swizzles_f64.rs":"85975ab1842acaf67f146887e8fd72c40338408680dcf7d640089632141c89d6","tests/swizzles_i16.rs":"1a947eb1082259a5942c2c5752b0c791f9fd4c1f2c6a969ac19a59250c140a2d","tests/swizzles_i32.rs":"fb3c8221ff830c15147995f1276c59925712b5c22940e770082c3e02cfb95671","tests/swizzles_i64.rs":"96d80910b4727c92a596f376539161282d2b3b100c27ecdc50160a50d08022b8","tests/swizzles_u16.rs":"6cd4e72f75a103eb5b99ef697a789d3f52e7de5a783af1a0855121fc5530e888","tests/swizzles_u32.rs":"1235a1865d43c4ed4a49e5a0c2c9e99d50a4acacdf075e155b0d9ae261322f99","tests/swizzles_u64.rs":"daaee63aab6f1c6312732b358e01333c0dcccfc91271b7eb3aaa4876b05f34e6","tests/vec2.rs":"970899b7e65c464a4e3586c9f00d160aa97e15e26e181d6a895eee888daa6fdc","tests/vec3.rs":"cbfac5fae5bec6742ceed146d120484d76b27b8bc36f34bfc7b9cbcc5ccb519e","tests/vec4.rs":"f436a8116caf107d198ea6053697e7b52e2560705d3cbbcdfd46b0b87717b210"},"package":"151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"}
\ No newline at end of file
+{"files":{"ARCHITECTURE.md":"a96ed48f5d407355624d7b74facf4a1bb04c15aaec38045f4dca68092198518b","ATTRIBUTION.md":"9f0738ead3dcc72bac87afc652c2466e1bc130d235db7798f98da4d4ef013639","CHANGELOG.md":"947995646b5f1403a2156766fb5ecd9954b182130429d728c5d3a84de8682a76","CODE_OF_CONDUCT.md":"88504558eb3470566208af69870487d373e6687575e8c9b9863f517f16309d81","CONTRIBUTING.md":"868a8e28e6fef5c1f050f9395b3366ecc8452f285a911beedd8753bedcb21501","Cargo.toml":"f0842efe683c0fb9e8186c52afc76be07a3578c468ca31e1dbf76af7de05a89c","LICENSE-APACHE":"be33ddb87a30fd321ab100e2d922cba512e50ec7a63d8e62e5bfc0798dd4b585","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"86f0c5441a69ecc1050a5809db747a7d5403330709ca6a0c0fdd2e2533bd0cd6","benches/affine2.rs":"4ba9257aa4abad4d3c81fe25829df128c3fe0ba756a976f1cae7aac9ec433589","benches/affine3.rs":"0a1d764c5cc5eddafd8512f062b2bfa90535b8cc5d9d27d7908726a880269294","benches/iai.rs":"a6c962866706e325c108c810b263b2c148db0667508948f95a59f92076041b39","benches/mat2.rs":"7341b2ad178ddb497a359a49b542af09a7ce4b77f6680170f1f621dd3aa8a729","benches/mat3.rs":"4ca689ed8a6f6de61e65e276f422dc83e35801d582f747ac5fbedbecc353d623","benches/mat3a.rs":"c0314337fda316640402de961a7423da2a59c6bc570c96826ea2338438595538","benches/mat4.rs":"a26a609364f648d287d672f467929c75f0786e2fe25e7fccd5b05493ddda3e17","benches/quat.rs":"5dfb6021b0284b1f3fa09b4671358c4af8cdc2a206d36e87656cba527638857e","benches/support.rs":"370b4e19c81726fb6adb61e20f3451510656aa819190c811257edc2399f040e8","benches/support/macros.rs":"c05454927c2ff3e846d2d3dcd2605feb5293bdbba4767d7f352dc538ab369fc8","benches/vec2.rs":"ed4a4bdc22404beb00406484c0d60c240da6c276ecee9b48bf0e002469cf7fde","benches/vec3.rs":"a4cd5f3807af0f1d4e25bdb7fa96e6def41bfe847aee04920868ac4d6000282d","benches/vec3a.rs":"49cdb0575d51fb9f6f49b37765abe2292669df6dc2a1393583d3c6ef180f8ba1","benches/vec4.rs":"07633a80e81e566c9f411be8b0669f8479f06084c541492e1b50e91e118b5c7a","build_all_msrv.sh":"35fb2d91849e4d461a35975017dae223ce55dc9b06a89f59f3a418a71ba99861","build_and_test_features.sh":"eb60ebea150a7b5ff2257dd44d04b203d3e3cf91298c7587cdd729b2631765ab","build_and_test_wasm32_chrome.sh":"503dc45a409348c02365bae3e67b4148874a69ff8bd7e0747702f8cb3d981cdb","build_and_test_wasm32_firefox.sh":"02effae982554c4e12449c5920706afface32e35b86e7cd654788dafe58e0a20","clippy.toml":"07e0a01b7edd3ca1d49010353642068329f66a4da5d1020ef20f336552e94831","deny.toml":"bc4db68ddf88f197ae05d9dac0f09fd90336aa33e0d19fcd0538e863f3d1bdd8","src/align16.rs":"41e75bd6cb6d96769dfcd8c3a5bcaaee3fc41da4bf36c2e893b939776d357050","src/bool.rs":"a6f074bf78d24728c07539edcfc8d50429eb6bc97b9cb7d32ab1af550a4b14a4","src/bool/bvec2.rs":"b280dd2018ba955664ffaad3fc54ac8f603d61c6b5b8767100a0a8f45c22e971","src/bool/bvec3.rs":"7fbdca0f7b6feac3ea9260a847e177a7b7d6a0cd30b8d216c4ec0c511d03d16c","src/bool/bvec4.rs":"b79f01a5fe7d1ecfe8db442934bf94ef475f31fe99feff9e7533b2fca58dad18","src/bool/coresimd.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/coresimd/bvec3a.rs":"2c44d70cf7be1a906e2b98c2d0a8da56df1ddb5b9b6834082dd216497c048d51","src/bool/coresimd/bvec4a.rs":"77691b592b1bcd41bdb7d16e732ac90fb84a287835eeef3851c089b9d8b6043f","src/bool/neon.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/neon/bvec3a.rs":"b2c2aaf47022ce787c370e36f9d040658ad4ed5e0eae049fd0efc06a8ea3624d","src/bool/neon/bvec4a.rs":"fda60780fbf4fc968f5905c4157ddf471df4e13dc148c51e8083ca9c5e11f931","src/bool/scalar.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/scalar/bvec3a.rs":"56faef1b2948a984353c9e0e62b706bc201c371a3a0f23edfb4a9d8f2eb709db","src/bool/scalar/bvec4a.rs":"fc9be605cdcff77e2290493a024292ff9ecad1d629739179da9ae4e029120792","src/bool/sse2.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/sse2/bvec3a.rs":"e63e4e579bebdd8044dabc97033d8e1cd252e815b9c64034b768e2bcf7f6edc9","src/bool/sse2/bvec4a.rs":"14ff13b525f0af5932bd803d312b64d34195c26e49d055300e917eabd7326e54","src/bool/wasm32.rs":"38925753b3d6867bc63d2efa9133f04afa1590865add60192e0caadef14a7cda","src/bool/wasm32/bvec3a.rs":"c598f68d530896e3f491167cd48910b992765df4786ac138a6895e3b514fb27c","src/bool/wasm32/bvec4a.rs":"6004524859e1cbd4082a5ced61db0f862f3d28406bc2107c3f95287b30fdf4bf","src/coresimd.rs":"ccd524501c85ea0d882221000096335fda1ab325cfb2ebfa37d0c60f927c975b","src/deref.rs":"bea56fc27cabc3f7fdcd6a95bfee5c445419e83fbe4356b8c0979894556aa253","src/euler.rs":"ff47d3aecc4e10e76a7d9f9a0c94954d7c16ab898348bf7efb6d8d3d178380cd","src/f32.rs":"b6885829e99db3b3dd5e8245e856f5e8079e19b91bdebbcca398e6dee94a3231","src/f32/affine2.rs":"e66d60ceac74b18d9bcec6b74492e238706eef491a678af98b2965a256bee634","src/f32/affine3a.rs":"43dc7f7fd237a1091d62d67e03cb356181b4d7a944528426ec7185cf1a372c20","src/f32/coresimd.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/coresimd/mat2.rs":"e4ea9ab8185b687f9cd62bb7130e30517e7fede75d5aab55ef033ebfcd28457d","src/f32/coresimd/mat3a.rs":"46d8c407dfbb4b4525ee3125c09098419211ef66534b59579001ad1a0b5244c8","src/f32/coresimd/mat4.rs":"0139ffc1ffb3dc48da67cdf836848a332f413b843a4debba7cbc843934b9b268","src/f32/coresimd/quat.rs":"e290a58960fe4528eb55181ee8a5249952a48dd56ea2f8b94d9dedefc8e84299","src/f32/coresimd/vec3a.rs":"5dafd246c18d595ad29b5f6dcb148040e9917c06a20b161418a48ace64285e64","src/f32/coresimd/vec4.rs":"28512c1c23a1570bbd8a0beba587bed3e5797630b1646ce2f24aa635fd036152","src/f32/float.rs":"7b95c7e360d3e74c6059aa89cdd632f4413cfcdd417356fba28cb1996f078708","src/f32/mat3.rs":"d1fc7e6bdf4d7c17106288e58abc23125e0c630ead0232f24b9047b2c11c1128","src/f32/math.rs":"5506ae9014022406a57307d5d86f57d290642b43f667ccb596d0ecbeb4863690","src/f32/neon.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/neon/mat2.rs":"1789f6f89408d3fab821befba3bbfa8cf975388d5d120b5ab77b47fff27af917","src/f32/neon/mat3a.rs":"60248a661be9c697bfee0eb26ade22474d0adb6c0c6a57a943ad22245d381323","src/f32/neon/mat4.rs":"d2fa6a6226908e5feec1e8bd9ab391eb8462a339d598fc2008a17d57cde752c4","src/f32/neon/quat.rs":"f313d25f87c7ef1ea72d9d6e6c4772b589302e752dfa2f659227c54d00c4d044","src/f32/neon/vec3a.rs":"1ed0b224b7d48b5b0cd677075b3ba9fd778dedf994ffb3c7235558b9cb1fd41d","src/f32/neon/vec4.rs":"dfde9bdb993a9b9e73363a626bd0b7ec37c5d02ae14f8119d33fc91ef63bcedd","src/f32/scalar.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/scalar/mat2.rs":"0420999d22c73de55996753249aad9f5dbfe5f9cd5899eeea2c5bd0d150aaa87","src/f32/scalar/mat3a.rs":"f790fcd6ae3daa9b19b7841166d44642c366fbb0c4065997c2f3ea377c4ec7b8","src/f32/scalar/mat4.rs":"22c9b6125e38d73491baa7ff6750ee35c6ff8f5e51f0bd940612e102a6165fb1","src/f32/scalar/quat.rs":"23076e32e2f0bc3c5bcf91f8d68ae6c024e7fde558bf8b5d8156269aabf32f91","src/f32/scalar/vec3a.rs":"1db2fce6ad7c6fde6578d88154662075b9e3832ca6a0701a9fc66778b6b2bd2f","src/f32/scalar/vec4.rs":"00b7f20744f1d01a71a2c16698960f59c1671954f4ca76c5b48278e0134ae0d0","src/f32/sse2.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/sse2/mat2.rs":"e2371d296152a6bbb9cfe92c1956c08f7e54dfdfaae28d6e1528b36d41037be6","src/f32/sse2/mat3a.rs":"c62ac4e64c14ce1c77538001dffcc14d57f94bae34df31368a4647b3cb6be6e1","src/f32/sse2/mat4.rs":"2b4912ddd30d0a90ed0d9aad264e6fa6d645789ddc4718ed238603ab266348f7","src/f32/sse2/quat.rs":"3a34c23deae9c84eb7feefaf66445aebf9b1a324088a140a501ed6113b7dd2a2","src/f32/sse2/vec3a.rs":"f5c8bb0ca1341130bc568c376a2fc82fb4190f07d5ac4d175f8a32a09ea20fb4","src/f32/sse2/vec4.rs":"b2b0c8f596fb751608b51fa468d90c2cedf3128c2273241808c7ab11a50ce820","src/f32/vec2.rs":"0cc3879616c07aec826ef74e05abdf58afe32bba31a4934f97a59698a8fbe898","src/f32/vec3.rs":"d5436537f5b0f96a88f66744ec5aedae086ea9e3256bb2f18cffe03dd9778661","src/f32/wasm32.rs":"6b5035deec82e95168da54e8ab90da683e05c503763af85084d3af855b74baed","src/f32/wasm32/mat2.rs":"bd1fea0081d93455c909dddb3d1eab7b7fc3e963ef32c92c9275248cf53327d0","src/f32/wasm32/mat3a.rs":"3f56fc1a622639f84de6c60de5598005bae0a0caf9aaccf6382e0ff799f29d7c","src/f32/wasm32/mat4.rs":"1e39aaf2123fd37d3e6aa1739fd9d5c06a3576b8d9dce6cf2c96b8ae7bde2b71","src/f32/wasm32/quat.rs":"456bc97d9659014aaf4c8f9d070d07a7711b0294812e26a20e3f8306414da65a","src/f32/wasm32/vec3a.rs":"674a16bb37891ad50dd16a389a046ea506cc1d4e76cc414f76b02d86a3cfc26c","src/f32/wasm32/vec4.rs":"390ad0f17a9ce1d0927eba31d6e2705adb162f0542170dcc6356c217dc29c869","src/f64.rs":"e15e434181625610ddc8ba517d9078f58b2c5ccc7beab8890110918e34a5672c","src/f64/daffine2.rs":"d50ac3d560ea131a9db2b6da97a7f8000ede690c96e32fc44eafeebbba4c0ea3","src/f64/daffine3.rs":"0b119c0132723c4246f64cdcbf4e292368d5efa3b7ff12eb04fe98d045b6cf57","src/f64/dmat2.rs":"760d9c98978d81d82c86c8dcadb78d783932ee2f7af5e98d5457af6161264836","src/f64/dmat3.rs":"b62f4370f12418615ef0a8136f4a35fc0c3ed4006f60707db4426619eea70eb7","src/f64/dmat4.rs":"5e10c685b36470ab9d3388e7f2b299ec7e4f98f424ebb28716797b2212068e03","src/f64/dquat.rs":"47b73ecf6f2c9c88015671ddb6bd62da691239b189c86c213e02df7280a6f275","src/f64/dvec2.rs":"c233c75f9a113f54f09b57e2e8bb415fc43c1d9a67b314139a90fd44bc3885ed","src/f64/dvec3.rs":"a95554148df7049615892975bcdc46d1f6bb0d4391410bbab684721cc580f0e4","src/f64/dvec4.rs":"f3ad57d1347f883a17c272c6483a4973708e18333fe7785e0cd536f76f1d5c87","src/f64/float.rs":"418d931fd8fb8b3822d669052930146301f5519b63d239eac41fddc5d2908c53","src/f64/math.rs":"8cecda211346b6297473565039a9d83b0f6a8f727d51d2be555f9da5549ab8d4","src/features.rs":"bdeec5e69c2d2ad7363f77a754f58299ee1b552d413f9b643e0bf2cbf5e6ebb0","src/features/impl_approx.rs":"f04289c086672da9593b8db2189a76228e348329f079035120a5ed3645107d62","src/features/impl_bytemuck.rs":"2ac7f6352e4875fa16cf57a8172ee5eb898aa8f4ba31f72ce2f600524753a14c","src/features/impl_mint.rs":"cd05d345c6a869ca34c5bb796a60a588ff0be1c0d4ba94deea1adb5c2a7841fd","src/features/impl_rand.rs":"e741002e0737c2b20d8ed851ab398169f2a76cd7bb62bb68bbe8d9902a5a39d0","src/features/impl_rkyv.rs":"b83700858d9053956df2c42c37a2e5cbf863720612bcc79803a9493c93528620","src/features/impl_serde.rs":"125552172df1e498940cc8fb7cc376e2f654b2e19d5808ca0633b9cf00fc26b7","src/float.rs":"c3f0ad974bf3e31324b4af6f1d06c7c6ec42aafa753759331dad5679b946aebd","src/i16.rs":"ca28e7f10f6b099c3ac26c40bf9b4fae758486a5c2372a22060fdaedc8fdb21e","src/i16/i16vec2.rs":"95485bd16315020ad97cc8d2517ee35c4621fbdd4c2c7bd198fc369e151984ee","src/i16/i16vec3.rs":"5f4f222680faacde6ab8301d3c0c16ec883155138861725ffd14d01a39444c9c","src/i16/i16vec4.rs":"fe3bf2b48a9f63dd678e24bb8c5c9010d3233a340d97a6338a02cd15300a1779","src/i32.rs":"837ae56757baa4b9ca5d9b176b1c310dc38c612bb62541ec82db4556266fee49","src/i32/ivec2.rs":"671c795997cc880e751b03d15aed108f65e9129866eb4e17dfc6ba4225cb6213","src/i32/ivec3.rs":"48612623c0802428dc293f7df050fa1e19a4d1e27e6aa243c4ae0ddbb02a5ede","src/i32/ivec4.rs":"07be5438489b31848676ffbb827fb5ddadba2b73e832ea064c209157d5be3f7e","src/i64.rs":"cf9b09767f124ea71f6f47aa572f0b1114759fa098d997de2cc166c21840f6a0","src/i64/i64vec2.rs":"4ed577cd710c9df099112bc7830d0befa4b4a4a4717801ab25b059c5b8dcc197","src/i64/i64vec3.rs":"5e2639e8ee7dfd8e88aa966cd619203dff477238929e8409a53feec0fa4a046b","src/i64/i64vec4.rs":"583832616459361ab7ed7c5cd5b47e4f4fdb96b6ecb7aecb00632ab0ed846dd3","src/i8.rs":"752f3f7a211e383fedab23f0058483b78caf44a8c9ebe3f6b59a2b63dddb8aa9","src/i8/i8vec2.rs":"6ffb2d56dcb2d4d535ae6b5a937864e28199fdc7a48ed9533f21bc3a61ba851f","src/i8/i8vec3.rs":"09972eb05e839c139f9f2d03066e4176acb9da2a8cb578bd6585397a8d349550","src/i8/i8vec4.rs":"51422f1cb4ce19f006f0e2611e89a1e7cd3603a343deff05819d9355e3c237bf","src/lib.rs":"7b3bdcfa01a41ed2edc8474ec211162b1746b60134aa5ffeb77906928c989f80","src/macros.rs":"4926c68286db038d1ea7601be8b518cbfe7ca2777eb219531f395b74f7d34d3a","src/neon.rs":"37fdfee5ef3ef12a831b0290d3205c36c36c3a78dccc39bdee0f04963cb8f864","src/spirv.rs":"dc115904475c251b9143f0741e35ea1f025975313a81a5ea433098e8eedcf3a9","src/sse2.rs":"dc668462edb09ee6cd154a7616e0b7ab5f3ac66f9cee7ae1ba25f8a0c07d907d","src/swizzles.rs":"5bf5648b183296f72bab1b5f6f45043f967dbda8908e9573481f43b98267ee66","src/swizzles/coresimd.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/coresimd/vec3a_impl.rs":"c8318273c1e8aad291fdc0912cc215fb0741a101e61be26793727a4dc9ed3cb7","src/swizzles/coresimd/vec4_impl.rs":"fe2de18e48567f3f4a03b47422e692ed37f934b7900796aeed6ea536f640a60e","src/swizzles/dvec2_impl.rs":"276665398fdea97ccf227376875726c61d7c3c8bfa4bff4e3f49168a9d1af396","src/swizzles/dvec3_impl.rs":"4b60aa611abefec718fe600d35506ffc1546e87e7db602cfa06cf43b94399d1e","src/swizzles/dvec4_impl.rs":"97506f9d4f913cfb563405e5fe4d77197302593c0406af9cd140795e909e836d","src/swizzles/i16vec2_impl.rs":"a0a7ebda17771f28b8ef0ac438c1f79098997fc43e3267f0d44d7255f7e65e2b","src/swizzles/i16vec3_impl.rs":"6430fc6a1342753e177693ec65e3e998cbc271ffce2d162b8fcd3c44c7b54445","src/swizzles/i16vec4_impl.rs":"ad7e0b6429a6294830117607e6835848698a388b585b7bb439794a71b63a7736","src/swizzles/i64vec2_impl.rs":"341730a8e551bb112a0ee6d15b2848a43ed475dc2509915a2e9ced128bc672ed","src/swizzles/i64vec3_impl.rs":"638369c3d3c4c8edbd20b3f989781de2c4449754919ea7fe98a7eb6a94589b46","src/swizzles/i64vec4_impl.rs":"4aab7372947f43f86ad4124b1c62e4af0bac3b63fee69cf760f9ff67a1a29769","src/swizzles/i8vec2_impl.rs":"e49ed9d8e810f5ad27c6c0859740f1e96186443cef32fda9719b8792de8e490f","src/swizzles/i8vec3_impl.rs":"8d81b29018babe2bbd771a3662fc547053f31f0c22d9e6c67247d68efc47d673","src/swizzles/i8vec4_impl.rs":"fd13386a91b9ea1d6bdcb5f82054a297883099b9ef73531b66e52f4f7d8bddde","src/swizzles/ivec2_impl.rs":"7e2d2100a960e4a3fffb6194951ccf8a866c9cb26cc6612972bff8d51e369705","src/swizzles/ivec3_impl.rs":"a8ffd538557e56eab5122012ce07c49ffc2bf91260ce23a7179a40df8348c96c","src/swizzles/ivec4_impl.rs":"f1a3b30236ecbce8cc4816f9c55e69215cbce2e363adfada50d8e37076e34af6","src/swizzles/neon.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/neon/vec3a_impl.rs":"6bb01fd6fc5282c0e5a08d7011cfe6eb77dcde56a15ca80f8fc6510c932b22ee","src/swizzles/neon/vec4_impl.rs":"e39b9860a0f952854e87b46d92332bc555b47185a928b2f0e5e6b0ce140d502b","src/swizzles/scalar.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/scalar/vec3a_impl.rs":"6bb01fd6fc5282c0e5a08d7011cfe6eb77dcde56a15ca80f8fc6510c932b22ee","src/swizzles/scalar/vec4_impl.rs":"e39b9860a0f952854e87b46d92332bc555b47185a928b2f0e5e6b0ce140d502b","src/swizzles/sse2.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/sse2/vec3a_impl.rs":"bdbb507419ac5f90a0d4d9a8fe5ce874a0f15ee763c0a7bac5bef3522a0bd74f","src/swizzles/sse2/vec4_impl.rs":"5aa3bb45e7c62b6ed754626692a3b76365d2cb6c8452608100f66f1cf3bce7b5","src/swizzles/u16vec2_impl.rs":"4e0239360e4d7b2d59ad4f8f190721f740313d9e875c885bf8dce461864724cb","src/swizzles/u16vec3_impl.rs":"76d9b2371cc08318d177f6abd10748aca5f0d4cfda64ccc5acbf7efdcea6eaf1","src/swizzles/u16vec4_impl.rs":"aa69cf0b87959cd3b16151c54d286cbce2c6cdfa8952825665d3192389dbcc78","src/swizzles/u64vec2_impl.rs":"f97f18415975a8e0c271947552001c1d4347f71421955a7abc001933ac394054","src/swizzles/u64vec3_impl.rs":"912350c8687d9c99f2ef91810cc85a1b49f7dbf803966a260c50a888b1e40b25","src/swizzles/u64vec4_impl.rs":"c3b1566143f13b8cdeb0b8439d41dde9e60837dc5513c84460145aaea3ab4d42","src/swizzles/u8vec2_impl.rs":"17552a9f0a8014e988b86b926a436f0a57035ab361067f6135d1ad3a03e11188","src/swizzles/u8vec3_impl.rs":"fe4b8d88b0e7a468c942a50c0d81bbdc2e53acd3f2057e3f013154014848bd09","src/swizzles/u8vec4_impl.rs":"a6816068ff3ce6b6ac039424a37ea538dd8866306ba71bb3f02c498d9883120e","src/swizzles/uvec2_impl.rs":"f947844a5dd8380d0ce982044da89fe29534e9e438e561c8a561ba6751200e73","src/swizzles/uvec3_impl.rs":"0e92edd5a875bba0858867dc901e6d7ed9d7424d6b66144f867cc760c25d9eb4","src/swizzles/uvec4_impl.rs":"e9c6284ddc1699554b2434bc2abab4001759cab84809e64e933549bee7b68a51","src/swizzles/vec2_impl.rs":"60cf78dc7d612febcc6d288b08c3fdeb09e99f7ac0a0cd17be2328c9b4a639e8","src/swizzles/vec3_impl.rs":"8a1869c8abeb7e81b54ad6bfcb3765dd73eba4182c8291546f3085db75651f65","src/swizzles/vec_traits.rs":"a3292229d93ad3bf1923e8fff36fecfa4694b2c6d8136e16a6f431f2b2de7ed5","src/swizzles/wasm32.rs":"045925888e131cbef29ed7988f07f349e0fce2f76760289cd2ba8ad035ef124e","src/swizzles/wasm32/vec3a_impl.rs":"174ea920d4156df9c799ea280b7604e5494b7124a8d5ee16ed0337e456204368","src/swizzles/wasm32/vec4_impl.rs":"19045a62c0f80b02dbd659f7d10f4e95f393eff035425c7e724cc394d9638a86","src/u16.rs":"7cc7a1c89d1163fd1a61965bdbe5bd61360acb0606a3957b571f148f98380882","src/u16/u16vec2.rs":"eeda4fe206e3408a914941ca85a41ef678f58ce0cb28ac13850fe113599174b3","src/u16/u16vec3.rs":"5e523b96cbd6163e7ea3fd1c1c48df32ef85cdb4f8b9708c8b60adb18a61bc8b","src/u16/u16vec4.rs":"94a6109a02cc18346a547913c9402de20112a7f17c33df81418fa2cc925f110f","src/u32.rs":"efc99a6ef496e73d810014654fd2c3e37ed0cbfcdec82987d1454328ef6ddfbc","src/u32/uvec2.rs":"43ed2584a8f3c9fb582f058ac17babd27683ad914bde04b69bc462fb8c014b7e","src/u32/uvec3.rs":"9e303eee8874a04fccecc5c8217863e162406241fb358a0fec9703409b880064","src/u32/uvec4.rs":"fb4d3bf3137f7e43a3f531d7d0d77190b9f3bd380ebe03146dc2adca7201bad7","src/u64.rs":"f12ebe1fdd0ce33f459306678f1b90b34614923b3713451b4bcdb0dc1261f830","src/u64/u64vec2.rs":"d2dd5c066e1601d446b601ab6113bbde58cb27c1c773093f29f7bd38fce6338a","src/u64/u64vec3.rs":"4462f2f79517d1a1fe6f8dd73e6dd18f6c9413ab0376ef690389c6c06c21b340","src/u64/u64vec4.rs":"126a390509af39e6f082ad51786f5ef696efd9d3c7c115f74eabf0870a0fce76","src/u8.rs":"ee728b2a572e767fc29a910b01e5b5933f2615392bffac0e45dae8cab5dbee95","src/u8/u8vec2.rs":"95b88543d7febc821cc0b989636d8cc23cef09dd310697f65b09a0018c0f777d","src/u8/u8vec3.rs":"b3525bd915cd0da087cbcb9a44d2887f1112aa04c64723ef5e358da56ec0e441","src/u8/u8vec4.rs":"acc4420421a72562ca9d7a315db66b70517fe84f780432e0d37f4a1ea7d0b71c","src/wasm32.rs":"5ac6177e5c468e86644be2c02c4f4caacfffe45a6a7b3958246f1c7c73790b30","tests/affine2.rs":"a1280301deab852966a3c6d4f6519acf27cd50ef2c1b6eba61509f63bbca3d20","tests/affine3.rs":"132927fec7ddb7dde5e2d8f97469d705a5986a5e6b308f67143ef41321d58ccb","tests/euler.rs":"041fe3caf19aba6e2729203a4eb824b90215adb621cb09bef1a3d2e3b1269da2","tests/float.rs":"d64c0502bceb455196e8f7070fe6b75dc195523995654c765f700895423ebaa2","tests/mat2.rs":"fe66761e4341fae287f63b8b4ebdc0cd2c1f873d64e833baa8c31bc013ff44ed","tests/mat3.rs":"d270702063dee4305146765ab885b615341bd39cb573352841d156ac4366fcc3","tests/mat4.rs":"f285f267fdcb75721bfcda22b42bf34352af40e97ee7bdfba08a3c74bb0c6dc9","tests/quat.rs":"cfa4e7494972ab315f06ff6079d72f46a5fc289cd762798b385a2a6f8ab7a9a2","tests/support.rs":"3d93056060d9155f8950df199c19db1313fa2e8ed80526f593bedea441f7ecb2","tests/support/macros.rs":"bb92cc95881669a870b454b6a19849da7e825ec5795f39a189143eef46465d5e","tests/swizzles_f32.rs":"0e87a720070abe20fda65bbe60dc444d6a20cb18884ca09d6910433c35930cc0","tests/swizzles_f64.rs":"85975ab1842acaf67f146887e8fd72c40338408680dcf7d640089632141c89d6","tests/swizzles_i16.rs":"1a947eb1082259a5942c2c5752b0c791f9fd4c1f2c6a969ac19a59250c140a2d","tests/swizzles_i32.rs":"fb3c8221ff830c15147995f1276c59925712b5c22940e770082c3e02cfb95671","tests/swizzles_i64.rs":"96d80910b4727c92a596f376539161282d2b3b100c27ecdc50160a50d08022b8","tests/swizzles_i8.rs":"0b8b53ff52ad3632a4a2290efa82bab944117e8b3b5ef7d936434824be07837c","tests/swizzles_u16.rs":"6cd4e72f75a103eb5b99ef697a789d3f52e7de5a783af1a0855121fc5530e888","tests/swizzles_u32.rs":"1235a1865d43c4ed4a49e5a0c2c9e99d50a4acacdf075e155b0d9ae261322f99","tests/swizzles_u64.rs":"daaee63aab6f1c6312732b358e01333c0dcccfc91271b7eb3aaa4876b05f34e6","tests/swizzles_u8.rs":"a4e233c4da8b12455bacf9fc454c68b2a8ee039639b1065bb106a757ece3911e","tests/vec2.rs":"8357de1eea4f7478b708cd7369fb900ce240d9fff71da9a5261d96c00fd7104f","tests/vec3.rs":"4db1d3ce5c7ec8e6d2368d606c7a9329e13905de962d54dee4b422aef290026f","tests/vec4.rs":"f014c19d5f4a7d684cb98ca512067ac036e25127c60434daa9471e148b574a23"},"package":"dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"}
\ No newline at end of file
diff --git a/crates/glam/Android.bp b/crates/glam/Android.bp
index 8046849..00b9197 100644
--- a/crates/glam/Android.bp
+++ b/crates/glam/Android.bp
@@ -17,7 +17,7 @@
     name: "libglam",
     crate_name: "glam",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.25.0",
+    cargo_pkg_version: "0.29.2",
     crate_root: "src/lib.rs",
     edition: "2021",
     features: [
diff --git a/crates/glam/CHANGELOG.md b/crates/glam/CHANGELOG.md
index e0ff2f2..0760800 100644
--- a/crates/glam/CHANGELOG.md
+++ b/crates/glam/CHANGELOG.md
@@ -5,6 +5,154 @@
 The format is based on [Keep a Changelog], and this project adheres to
 [Semantic Versioning].
 
+## [0.29.2] - 2024-11-05
+
+### Fixed
+
+* Fix regression in vector `write_to_slice` methods where the destination had to
+  be the same size as the input, but it should support writing to a slice that
+  is the same size or larger than the input.
+
+## [0.29.1] - 2024-10-30
+
+### Added
+
+* Added `i8` and `u8` vector types, `I8Vec2`, `I8Vec3`, `I8Vec4`,
+  `U8Vec2`, `U8Vec3` and `U8Vec4`.
+
+* Added `Mat4::project_point3a(Vec3A)` method transforming points by
+  perspective projections.
+
+### Changed
+
+* Removed normalized assertions from quaternion multiplies as sometimes this is
+  valid.
+
+* Include `Debug` and `Display` implementations on `spirv` targets.
+
+* Optimized vector `from_slice` and `write_to_slice` methods.
+
+* Improved serde error messages.
+
+## [0.29.0] - 2024-08-20
+
+### Breaking changes
+
+* `EulerRot` has been reimplemented and now has support for 24 different
+  rotation order enum values.
+
+### Fixed
+
+* Reduced the dot threshold at which quaternion slerp uses lerp to improve
+  accuracy.
+
+### Added
+
+* Added 3x3 matrix `from_mat4_minor()` and 2x2 matrix `from_mat3_minor()`
+  methods.
+
+* Added `bvec2`, `bvec3`, `bvec3a`, `bvec4` and `bvec4a` vector mask creation
+  functions.
+
+* Added all 24 possible intrinsic and extrinsic Euler angle rotation
+  combinations to `EulerRot` enum.
+
+* Added `is_finite_mask` method to vector types which returns a vector mask.
+
+* Added `reflect` and `refract` methods to vector types.
+
+* Added `to_euler` methods to matrix types which extracts Euler angles from a
+  rotation matrix for a given `EulerRot`.
+
+* Added generic `map` method to vector types which applies a functor to all
+  vector elements.
+
+* Vector arithmetic ops are now implemented on references.
+
+### Changed
+
+* Vector and quaternion lerp now uses a precise lerp algorithm.
+
+## [0.28.0] - 2024-06-10
+
+### Breaking changes
+
+* Removed derives from `glam::deref` types used by `Deref` on SIMD vector
+  types.  These unintentionally added support for traits like `PartialOrd` to
+  SIMD vector types. This may break existing code that was depending on this.
+  Please use `cmple().all()` etc. instead of `PartialOrd` methods.
+
+* Removed `impl From<Vec4> for Vec3A` as this violated the `From` trait
+  contract that conversions should be lossless. Please use the explicit
+  `Vec3A::from_vec4` method instead.
+
+* Renamed 2D vector `angle_between` to `angle_to` to differentiate from the 3D
+  `angle_between` which has different semantics to the 2D version.
+
+### Added
+
+* Added aarch64 neon support.
+
+* Added `rotate_towards` methods for 2D vectors and quaternions.
+
+* Added `Vec3A::from_vec4` method which can perform a no-op conversion when
+  SIMD is used. This replaces the `impl From<Vec4> for Vec3A` implementation.
+
+## [0.27.0] - 2024-03-23
+
+### Breaking changes
+
+* Changed implementation of vector `fract` method to match the Rust
+  implementation instead of the GLSL implementation, that is `self -
+  self.trunc()` instead of `self - self.floor()`.
+
+### Added
+
+* Added vector `fract_gl` which uses the GLSL specification of fract,
+ `self - self.floor()`.
+
+## [0.26.0] - 2024-03-18
+
+### Breaking changes
+
+* Minimum Supported Rust Version bumped to 1.68.2 for
+ `impl From<bool> for {f32,f64}` support.
+
+### Fixed
+
+* Respect precision format specifier in Display implementations. Previously it
+  was ignored.
+
+* Corrected precision documentation for vector `is_normalized` methods and
+  changed the internal check to use `2e-4` to better match the documented
+  precision value of `1e-4`.
+
+### Added
+
+ * Added `with_x`, `with_y`, etc. to vector types which returns a copy of
+   the vector with the new component value.
+
+ * Added `midpoint` method to vector types that returns the point between two
+   points.
+
+ * Added `move_towards` for float vector types.
+
+ * Added saturating add and sub methods for signed and unsigned integer vector
+   types.
+
+ * Added element wise sum and product methods for vector types.
+
+ * Added element wise absolute values method for matrix types.
+
+ * Added `from_array` method for boolean vector types.
+
+ * Added `normalize_or` method to vector types that returns the specified value
+   if normalization failed.
+
+ * Added `From<BVecN>` support for all vector types.
+
+ * Added `Div` and `DivAssign` by scalar implementations to matrix types.
+
 ## [0.25.0] - 2023-12-19
 
 ### Breaking changes
@@ -1001,7 +1149,13 @@
 
 [Keep a Changelog]: https://keepachangelog.com/
 [Semantic Versioning]: https://semver.org/spec/v2.0.0.html
-[Unreleased]: https://github.com/bitshifter/glam-rs/compare/0.25.0...HEAD
+[Unreleased]: https://github.com/bitshifter/glam-rs/compare/0.29.2...HEAD
+[0.29.2]: https://github.com/bitshifter/glam-rs/compare/0.29.1...0.29.2
+[0.29.1]: https://github.com/bitshifter/glam-rs/compare/0.29.0...0.29.1
+[0.29.0]: https://github.com/bitshifter/glam-rs/compare/0.28.0...0.29.0
+[0.28.0]: https://github.com/bitshifter/glam-rs/compare/0.27.0...0.28.0
+[0.27.0]: https://github.com/bitshifter/glam-rs/compare/0.26.0...0.27.0
+[0.26.0]: https://github.com/bitshifter/glam-rs/compare/0.25.0...0.26.0
 [0.25.0]: https://github.com/bitshifter/glam-rs/compare/0.24.2...0.25.0
 [0.24.2]: https://github.com/bitshifter/glam-rs/compare/0.24.1...0.24.2
 [0.24.1]: https://github.com/bitshifter/glam-rs/compare/0.24.0...0.24.1
diff --git a/crates/glam/CODE_OF_CONDUCT.md b/crates/glam/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..18c9147
--- /dev/null
+++ b/crates/glam/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+  overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+  advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+  address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior,  harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/crates/glam/Cargo.toml b/crates/glam/Cargo.toml
index c34920a..8e550ab 100644
--- a/crates/glam/Cargo.toml
+++ b/crates/glam/Cargo.toml
@@ -11,10 +11,15 @@
 
 [package]
 edition = "2021"
-rust-version = "1.58.1"
+rust-version = "1.68.2"
 name = "glam"
-version = "0.25.0"
+version = "0.29.2"
 authors = ["Cameron Hart <cameron.hart@gmail.com>"]
+build = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "A simple and fast 3D math library for games and graphics"
 readme = "README.md"
 keywords = [
@@ -32,50 +37,161 @@
 repository = "https://github.com/bitshifter/glam-rs"
 
 [lib]
+name = "glam"
+path = "src/lib.rs"
 bench = false
 
-[[bench]]
+[[test]]
+name = "affine2"
+path = "tests/affine2.rs"
+
+[[test]]
+name = "affine3"
+path = "tests/affine3.rs"
+
+[[test]]
+name = "euler"
+path = "tests/euler.rs"
+
+[[test]]
+name = "float"
+path = "tests/float.rs"
+
+[[test]]
 name = "mat2"
-harness = false
+path = "tests/mat2.rs"
 
-[[bench]]
+[[test]]
 name = "mat3"
-harness = false
+path = "tests/mat3.rs"
 
-[[bench]]
-name = "mat3a"
-harness = false
+[[test]]
+name = "mat4"
+path = "tests/mat4.rs"
+
+[[test]]
+name = "quat"
+path = "tests/quat.rs"
+
+[[test]]
+name = "support"
+path = "tests/support.rs"
+
+[[test]]
+name = "swizzles_f32"
+path = "tests/swizzles_f32.rs"
+
+[[test]]
+name = "swizzles_f64"
+path = "tests/swizzles_f64.rs"
+
+[[test]]
+name = "swizzles_i16"
+path = "tests/swizzles_i16.rs"
+
+[[test]]
+name = "swizzles_i32"
+path = "tests/swizzles_i32.rs"
+
+[[test]]
+name = "swizzles_i64"
+path = "tests/swizzles_i64.rs"
+
+[[test]]
+name = "swizzles_i8"
+path = "tests/swizzles_i8.rs"
+
+[[test]]
+name = "swizzles_u16"
+path = "tests/swizzles_u16.rs"
+
+[[test]]
+name = "swizzles_u32"
+path = "tests/swizzles_u32.rs"
+
+[[test]]
+name = "swizzles_u64"
+path = "tests/swizzles_u64.rs"
+
+[[test]]
+name = "swizzles_u8"
+path = "tests/swizzles_u8.rs"
+
+[[test]]
+name = "vec2"
+path = "tests/vec2.rs"
+
+[[test]]
+name = "vec3"
+path = "tests/vec3.rs"
+
+[[test]]
+name = "vec4"
+path = "tests/vec4.rs"
 
 [[bench]]
 name = "affine2"
+path = "benches/affine2.rs"
 harness = false
 
 [[bench]]
 name = "affine3"
+path = "benches/affine3.rs"
+harness = false
+
+[[bench]]
+name = "iai"
+path = "benches/iai.rs"
+harness = false
+
+[[bench]]
+name = "mat2"
+path = "benches/mat2.rs"
+harness = false
+
+[[bench]]
+name = "mat3"
+path = "benches/mat3.rs"
+harness = false
+
+[[bench]]
+name = "mat3a"
+path = "benches/mat3a.rs"
 harness = false
 
 [[bench]]
 name = "mat4"
+path = "benches/mat4.rs"
 harness = false
 
 [[bench]]
 name = "quat"
+path = "benches/quat.rs"
 harness = false
 
 [[bench]]
+name = "support"
+path = "benches/support.rs"
+bench = false
+
+[[bench]]
 name = "vec2"
+path = "benches/vec2.rs"
 harness = false
 
 [[bench]]
 name = "vec3"
+path = "benches/vec3.rs"
 harness = false
 
 [[bench]]
 name = "vec3a"
+path = "benches/vec3a.rs"
 harness = false
 
 [[bench]]
 name = "vec4"
+path = "benches/vec4.rs"
 harness = false
 
 [dependencies.approx]
@@ -84,7 +200,7 @@
 default-features = false
 
 [dependencies.bytecheck]
-version = "0.6"
+version = "0.7"
 optional = true
 default-features = false
 
@@ -124,6 +240,7 @@
 [dev-dependencies.rkyv]
 version = "0.7"
 features = ["size_32"]
+default-features = false
 
 [dev-dependencies.serde_json]
 version = "1.0"
@@ -138,12 +255,20 @@
 scalar-math = []
 std = []
 
-[target."cfg(not(target_arch = \"wasm32\"))".dev-dependencies.criterion]
-version = "0.4"
+[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion]
+version = "0.5"
 features = ["html_reports"]
 
-[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test]
-version = "0.3.0"
+[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.iai-callgrind]
+version = "0.14"
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies.wasm-bindgen-test]
+version = "0.3"
 
 [badges.maintenance]
 status = "actively-developed"
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+priority = 0
+check-cfg = ['cfg(target_arch, values("spirv"))']
diff --git a/crates/glam/METADATA b/crates/glam/METADATA
index 24a519b..bcf7411 100644
--- a/crates/glam/METADATA
+++ b/crates/glam/METADATA
@@ -1,17 +1,17 @@
 name: "glam"
 description: "A simple and fast 3D math library for games and graphics"
 third_party {
-  version: "0.25.0"
+  version: "0.29.2"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 1
+    month: 12
+    day: 19
   }
   homepage: "https://crates.io/crates/glam"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/glam/glam-0.25.0.crate"
-    version: "0.25.0"
+    value: "https://static.crates.io/crates/glam/glam-0.29.2.crate"
+    version: "0.29.2"
   }
 }
diff --git a/crates/glam/README.md b/crates/glam/README.md
index a6d9613..929f72e 100644
--- a/crates/glam/README.md
+++ b/crates/glam/README.md
@@ -2,7 +2,7 @@
 
 [![Build Status]][github-ci] [![Coverage Status]][coveralls.io]
 [![Latest Version]][crates.io] [![docs]][docs.rs]
-[![Minimum Supported Rust Version]][Rust 1.58.1]
+[![Minimum Supported Rust Version]][Rust 1.68.2]
 
 A simple and fast 3D math library for games and graphics.
 
@@ -23,6 +23,10 @@
   * square matrices: `DMat2`, `DMat3` and `DMat4`
   * a quaternion type: `DQuat`
   * affine transformation types: `DAffine2` and `DAffine3`
+* `i8` types
+  * vectors: `I8Vec2`, `I8Vec3` and `I8Vec4`
+* `u8` types
+  * vectors: `U16Vec2`, `U16Vec3` and `U16Vec4`
 * `i16` types
   * vectors: `I16Vec2`, `I16Vec3` and `I16Vec4`
 * `u16` types
@@ -60,6 +64,8 @@
 * `SSE2` is enabled by default on `x86_64` targets.
 * To enable `SSE2` on `x86` targets add `-C target-feature=+sse2` to
   `RUSTCFLAGS`.
+* `NEON` is enabled by default on `aarch64` targets.
+* To enable `NEON` on `aarch64` targets add `-C target-feature=+neon` to `RUSTFLAGS`.
 * To enable `simd128` on `wasm32` targets add `-C target-feature=+simd128` to
   `RUSTFLAGS`.
 * Experimental [portable simd] support can be enabled with the `core-simd`
@@ -78,7 +84,7 @@
 
 ```toml
 [dependencies]
-glam = { version = "0.25", default-features = false, features = ["libm"] }
+glam = { version = "0.29.2", default-features = false, features = ["libm"] }
 ```
 
 To support both `std` and `no_std` builds in project, you can use the following
@@ -92,7 +98,7 @@
 libm = ["glam/libm"]
 
 [dependencies]
-glam = { version = "0.25", default-features = false }
+glam = { version = "0.29.2", default-features = false }
 ```
 
 ### Optional features
@@ -140,7 +146,7 @@
 
 ### Minimum Supported Rust Version (MSRV)
 
-The minimum supported version of Rust for `glam` is `1.58.1`.
+The minimum supported version of Rust for `glam` is `1.68.2`.
 
 ## Conventions
 
@@ -262,5 +268,5 @@
 [crates.io]: https://crates.io/crates/glam/
 [docs]: https://docs.rs/glam/badge.svg
 [docs.rs]: https://docs.rs/glam/
-[Minimum Supported Rust Version]: https://img.shields.io/badge/Rust-1.58.1-blue?color=fc8d62&logo=rust
-[Rust 1.58.1]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1581-2022-01-19
+[Minimum Supported Rust Version]: https://img.shields.io/badge/Rust-1.68.2-blue?color=fc8d62&logo=rust
+[Rust 1.68.2]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1682-2023-03-28
diff --git a/crates/glam/benches/affine2.rs b/crates/glam/benches/affine2.rs
index 9ea42a9..229719e 100644
--- a/crates/glam/benches/affine2.rs
+++ b/crates/glam/benches/affine2.rs
@@ -59,9 +59,9 @@
             unsafe {
                 let data = inputs.get_unchecked(i);
                 *outputs.get_unchecked_mut(i) =
-                    Affine2::from_scale_angle_translation(data.0, data.1, data.2)
+                    Affine2::from_scale_angle_translation(data.0, data.1, data.2);
             }
-        })
+        });
     });
 }
 
diff --git a/crates/glam/benches/affine3.rs b/crates/glam/benches/affine3.rs
index 1900684..c251adb 100644
--- a/crates/glam/benches/affine3.rs
+++ b/crates/glam/benches/affine3.rs
@@ -95,9 +95,9 @@
             unsafe {
                 let data = inputs.get_unchecked(i);
                 *outputs.get_unchecked_mut(i) =
-                    Affine3A::from_scale_rotation_translation(data.0, data.1, data.2)
+                    Affine3A::from_scale_rotation_translation(data.0, data.1, data.2);
             }
-        })
+        });
     });
 }
 
diff --git a/crates/glam/benches/iai.rs b/crates/glam/benches/iai.rs
new file mode 100644
index 0000000..d24a16d
--- /dev/null
+++ b/crates/glam/benches/iai.rs
@@ -0,0 +1,282 @@
+#![allow(clippy::all)]
+
+use core::hint::black_box;
+use iai_callgrind::{library_benchmark, library_benchmark_group, main};
+
+use glam::{BVec3A, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3A, Vec4};
+
+#[cfg(feature = "scalar-math")]
+use glam::BVec4 as BVec4A;
+
+#[cfg(not(feature = "scalar-math"))]
+use glam::BVec4A;
+
+#[inline]
+fn mat2() -> Mat2 {
+    black_box(Mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]))
+}
+
+#[inline]
+fn mat3a() -> Mat3A {
+    black_box(Mat3A::from_cols_array(&[
+        1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,
+    ]))
+}
+
+#[inline]
+fn mat4() -> Mat4 {
+    black_box(Mat4::from_cols_array(&[
+        1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
+    ]))
+}
+
+#[inline]
+fn quat() -> Quat {
+    black_box(Quat::from_xyzw(0.0, 0.0, 0.0, 1.0))
+}
+
+#[inline]
+fn vec2() -> Vec2 {
+    black_box(Vec2::new(1.0, 2.0))
+}
+
+#[inline]
+fn vec3a() -> Vec3A {
+    black_box(Vec3A::new(1.0, 2.0, 3.0))
+}
+
+#[inline]
+fn bvec3a() -> BVec3A {
+    black_box(BVec3A::new(true, false, true))
+}
+
+#[inline]
+fn vec4() -> Vec4 {
+    black_box(Vec4::new(1.0, 2.0, 3.0, 4.0))
+}
+
+#[inline]
+fn bvec4a() -> BVec4A {
+    black_box(BVec4A::new(true, false, true, false))
+}
+
+#[library_benchmark]
+#[bench::args(mat2())]
+fn mat2_determinant(m: Mat2) -> f32 {
+    black_box(m.determinant())
+}
+
+#[library_benchmark]
+#[bench::args(mat2())]
+fn mat2_inverse(m: Mat2) -> Mat2 {
+    black_box(m.inverse())
+}
+
+#[library_benchmark]
+#[bench::args(mat2())]
+fn mat2_transpose(m: Mat2) -> Mat2 {
+    black_box(m.transpose())
+}
+
+#[library_benchmark]
+#[bench::args(mat2(), mat2())]
+fn mat2_mul_mat2(m1: Mat2, m2: Mat2) -> Mat2 {
+    black_box(m1 * m2)
+}
+
+#[library_benchmark]
+#[bench::args(mat2(), vec2())]
+fn mat2_mul_vec2(m: Mat2, v: Vec2) -> Vec2 {
+    black_box(m * v)
+}
+
+#[library_benchmark]
+#[bench::args(mat3a())]
+fn mat3a_determinant(m: Mat3A) -> f32 {
+    black_box(m.determinant())
+}
+
+#[library_benchmark]
+#[bench::args(mat3a())]
+fn mat3a_inverse(m: Mat3A) -> Mat3A {
+    black_box(m.inverse())
+}
+
+#[library_benchmark]
+#[bench::args(mat3a())]
+fn mat3a_transpose(m: Mat3A) -> Mat3A {
+    black_box(m.transpose())
+}
+
+#[library_benchmark]
+#[bench::args(mat3a(), mat3a())]
+fn mat3a_mul_mat3a(m1: Mat3A, m2: Mat3A) -> Mat3A {
+    black_box(m1 * m2)
+}
+
+#[library_benchmark]
+#[bench::args(mat3a(), vec3a())]
+fn mat3a_mul_vec3a(m: Mat3A, v: Vec3A) -> Vec3A {
+    black_box(m * v)
+}
+
+#[library_benchmark]
+#[bench::args(mat4())]
+fn mat4_determinant(m: Mat4) -> f32 {
+    black_box(m.determinant())
+}
+
+#[library_benchmark]
+#[bench::args(mat4())]
+fn mat4_inverse(m: Mat4) -> Mat4 {
+    black_box(m.inverse())
+}
+
+#[library_benchmark]
+#[bench::args(mat4())]
+fn mat4_transpose(m: Mat4) -> Mat4 {
+    black_box(m.transpose())
+}
+
+#[library_benchmark]
+#[bench::args(mat4(), mat4())]
+fn mat4_mul_mat4(m1: Mat4, m2: Mat4) -> Mat4 {
+    black_box(m1 * m2)
+}
+
+#[library_benchmark]
+#[bench::args(mat4(), vec4())]
+fn mat4_mul_vec4(m: Mat4, v: Vec4) -> Vec4 {
+    black_box(m * v)
+}
+
+#[library_benchmark]
+#[bench::args(quat(), quat())]
+fn quat_mul_quat(q1: Quat, q2: Quat) -> Quat {
+    black_box(q1 * q2)
+}
+
+#[library_benchmark]
+#[bench::args(quat(), vec3a())]
+fn quat_mul_vec3a(q: Quat, v: Vec3A) -> Vec3A {
+    black_box(q * v)
+}
+
+#[library_benchmark]
+#[bench::args(vec3a(), vec3a())]
+fn vec3a_dot(v1: Vec3A, v2: Vec3A) -> f32 {
+    black_box(v1.dot(v2))
+}
+
+#[library_benchmark]
+#[bench::args(vec3a(), vec3a())]
+fn vec3a_cross(v1: Vec3A, v2: Vec3A) -> Vec3A {
+    black_box(v1.cross(v2))
+}
+
+#[library_benchmark]
+#[bench::args(vec3a())]
+fn vec3a_length(v: Vec3A) -> f32 {
+    black_box(v.length())
+}
+
+#[library_benchmark]
+#[bench::args(vec3a())]
+fn vec3a_normalize(v: Vec3A) -> Vec3A {
+    black_box(v.normalize())
+}
+
+#[library_benchmark]
+#[bench::args(bvec3a(), vec3a(), vec3a())]
+fn vec3a_select(b: BVec3A, v1: Vec3A, v2: Vec3A) -> Vec3A {
+    black_box(Vec3A::select(b, v1, v2))
+}
+
+#[library_benchmark]
+#[bench::args(vec4(), vec4())]
+fn vec4_dot(v1: Vec4, v2: Vec4) -> f32 {
+    black_box(v1.dot(v2))
+}
+
+#[library_benchmark]
+#[bench::args(vec4())]
+fn vec4_length(v: Vec4) -> f32 {
+    black_box(v.length())
+}
+
+#[library_benchmark]
+#[bench::args(vec4())]
+fn vec4_normalize(v: Vec4) -> Vec4 {
+    black_box(v.normalize())
+}
+
+#[library_benchmark]
+#[bench::args(bvec4a(), vec4(), vec4())]
+fn vec4_select(b: BVec4A, v1: Vec4, v2: Vec4) -> Vec4 {
+    black_box(Vec4::select(b, v1, v2))
+}
+
+library_benchmark_group!(
+    name = bench_mat2;
+    benchmarks =
+        mat2_determinant,
+        mat2_inverse,
+        mat2_mul_mat2,
+        mat2_mul_vec2,
+        mat2_transpose,
+);
+
+library_benchmark_group!(
+    name = bench_mat3a;
+    benchmarks =
+        mat3a_determinant,
+        mat3a_inverse,
+        mat3a_mul_mat3a,
+        mat3a_mul_vec3a,
+        mat3a_transpose,
+);
+
+library_benchmark_group!(
+    name = bench_mat4;
+    benchmarks =
+        mat4_determinant,
+        mat4_inverse,
+        mat4_mul_mat4,
+        mat4_mul_vec4,
+        mat4_transpose,
+);
+
+library_benchmark_group!(
+    name = bench_quat;
+    benchmarks =
+        quat_mul_quat,
+        quat_mul_vec3a,
+);
+
+library_benchmark_group!(
+    name = bench_vec3a;
+    benchmarks =
+        vec3a_dot,
+        vec3a_cross,
+        vec3a_length,
+        vec3a_normalize,
+        vec3a_select,
+);
+
+library_benchmark_group!(
+    name = bench_vec4;
+    benchmarks =
+        vec4_dot,
+        vec4_length,
+        vec4_normalize,
+        vec4_select,
+);
+
+main!(
+    library_benchmark_groups = bench_mat2,
+    bench_mat3a,
+    bench_mat4,
+    bench_quat,
+    bench_vec3a,
+    bench_vec4
+);
diff --git a/crates/glam/benches/mat4.rs b/crates/glam/benches/mat4.rs
index f5eb5e3..49ee112 100644
--- a/crates/glam/benches/mat4.rs
+++ b/crates/glam/benches/mat4.rs
@@ -105,9 +105,9 @@
             unsafe {
                 let data = inputs.get_unchecked(i);
                 *outputs.get_unchecked_mut(i) =
-                    Mat4::from_scale_rotation_translation(data.0, data.1, data.2)
+                    Mat4::from_scale_rotation_translation(data.0, data.1, data.2);
             }
-        })
+        });
     });
 }
 
diff --git a/crates/glam/benches/vec2.rs b/crates/glam/benches/vec2.rs
index a334e5d..478ac4a 100644
--- a/crates/glam/benches/vec2.rs
+++ b/crates/glam/benches/vec2.rs
@@ -25,9 +25,9 @@
 );
 
 bench_binop!(
-    vec2_angle_between,
-    "vec2 angle_between",
-    op => angle_between,
+    vec2_angle_to,
+    "vec2 angle_to",
+    op => angle_to,
     from1 => random_vec2,
     from2 => random_vec2
 );
@@ -45,7 +45,7 @@
     vec2_mul_vec2,
     vec2_euler,
     vec2_select,
-    vec2_angle_between
+    vec2_angle_to
 );
 
 criterion_main!(benches);
diff --git a/crates/glam/benches/vec3.rs b/crates/glam/benches/vec3.rs
index 78d5d63..58c013a 100644
--- a/crates/glam/benches/vec3.rs
+++ b/crates/glam/benches/vec3.rs
@@ -80,6 +80,18 @@
 );
 
 #[inline]
+fn vec3_normalize_or(v: Vec3) -> Vec3 {
+    v.normalize_or(Vec3::X)
+}
+
+bench_func!(
+    vec3_normalize_or_bench,
+    "vec3 normalize_or",
+    op => vec3_normalize_or,
+    from => random_vec3
+);
+
+#[inline]
 fn vec3_normalize_or_zero(v: Vec3) -> Vec3 {
     v.normalize_or_zero()
 }
@@ -141,6 +153,29 @@
     from2 => random_vec3
 );
 
+bench_binop!(
+    vec3_cross,
+    "vec3 cross",
+    op => cross,
+    from1 => random_vec3,
+    from2 => random_vec3
+);
+
+bench_binop!(
+    vec3_dot,
+    "vec3 dot",
+    op => dot,
+    from1 => random_vec3,
+    from2 => random_vec3
+);
+
+bench_unop!(
+    vec3_length,
+    "vec3 length",
+    op => length,
+    from => random_vec3
+);
+
 bench_select!(
     vec3_select,
     "vec3 select",
@@ -151,14 +186,18 @@
 
 criterion_group!(
     benches,
-    vec3_mul_vec3,
     vec3_angle_between,
-    vec3_normalize_bench,
-    vec3_normalize_or_zero_bench,
     vec3_any_orthogonal_vector_bench,
-    vec3_any_orthonormal_vector_bench,
     vec3_any_orthonormal_pair_bench,
+    vec3_any_orthonormal_vector_bench,
+    vec3_cross,
+    vec3_dot,
     vec3_euler,
+    vec3_length,
+    vec3_mul_vec3,
+    vec3_normalize_bench,
+    vec3_normalize_or_bench,
+    vec3_normalize_or_zero_bench,
     vec3_select,
     vec3_to_array_fields,
     vec3_to_array_into,
diff --git a/crates/glam/benches/vec3a.rs b/crates/glam/benches/vec3a.rs
index c0c5e25..6e03453 100644
--- a/crates/glam/benches/vec3a.rs
+++ b/crates/glam/benches/vec3a.rs
@@ -79,6 +79,42 @@
 
 euler!(vec3a_euler, "vec3a euler", ty => Vec3A, storage => Vec3A, zero => Vec3A::ZERO, rand => random_vec3a);
 
+#[inline]
+fn vec3a_normalize(v: Vec3A) -> Vec3A {
+    v.normalize()
+}
+
+bench_func!(
+    vec3a_normalize_bench,
+    "vec3a normalize",
+    op => vec3a_normalize,
+    from => random_vec3a
+);
+
+#[inline]
+fn vec3a_normalize_or(v: Vec3A) -> Vec3A {
+    v.normalize_or(Vec3A::X)
+}
+
+bench_func!(
+    vec3a_normalize_or_bench,
+    "vec3a normalize_or",
+    op => vec3a_normalize_or,
+    from => random_vec3a
+);
+
+#[inline]
+fn vec3a_normalize_or_zero(v: Vec3A) -> Vec3A {
+    v.normalize_or_zero()
+}
+
+bench_func!(
+    vec3a_normalize_or_zero_bench,
+    "vec3a normalize_or_zero",
+    op => vec3a_normalize_or_zero,
+    from => random_vec3a
+);
+
 bench_binop!(
     vec3a_angle_between,
     "vec3a angle_between",
@@ -87,6 +123,29 @@
     from2 => random_vec3a
 );
 
+bench_binop!(
+    vec3a_cross,
+    "vec3a cross",
+    op => cross,
+    from1 => random_vec3a,
+    from2 => random_vec3a
+);
+
+bench_binop!(
+    vec3a_dot,
+    "vec3a dot",
+    op => dot,
+    from1 => random_vec3a,
+    from2 => random_vec3a
+);
+
+bench_unop!(
+    vec3a_length,
+    "vec3a length",
+    op => length,
+    from => random_vec3a
+);
+
 bench_select!(
     vec3a_select,
     "vec3a select",
@@ -97,9 +156,15 @@
 
 criterion_group!(
     benches,
-    vec3a_mul_vec3a,
+    vec3a_normalize_bench,
+    vec3a_normalize_or_bench,
+    vec3a_normalize_or_zero_bench,
     vec3a_angle_between,
+    vec3a_cross,
+    vec3a_dot,
+    vec3a_length,
     vec3a_euler,
+    vec3a_mul_vec3a,
     vec3a_select,
     vec3a_to_array_deref,
     vec3a_to_array_into,
diff --git a/crates/glam/build_all_msrv.sh b/crates/glam/build_all_msrv.sh
index 402cf76..7963f7d 100755
--- a/crates/glam/build_all_msrv.sh
+++ b/crates/glam/build_all_msrv.sh
@@ -2,8 +2,7 @@
 
 set -e
 
-CARGO='rustup run 1.58.1 cargo'
-$CARGO test --features "bytemuck mint rand serde debug-glam-assert" && \
-$CARGO test --features "scalar-math bytemuck mint rand serde debug-glam-assert" && \
-$CARGO test --no-default-features --features "libm scalar-math bytemuck mint rand serde debug-glam-assert" && \
-$CARGO bench --no-run
+CARGO='rustup run 1.68.2 cargo'
+$CARGO check --features "bytemuck mint rand serde debug-glam-assert" && \
+$CARGO check --features "scalar-math bytemuck mint rand serde debug-glam-assert" && \
+$CARGO check --no-default-features --features "libm scalar-math bytemuck mint rand serde debug-glam-assert"
diff --git a/crates/glam/clippy.toml b/crates/glam/clippy.toml
index 5ff4f79..0c4b858 100644
--- a/crates/glam/clippy.toml
+++ b/crates/glam/clippy.toml
@@ -1 +1 @@
-msrv = "1.58.1"
+msrv = "1.68.2"
diff --git a/crates/glam/src/bool.rs b/crates/glam/src/bool.rs
index c3cbb9f..c920e0b 100644
--- a/crates/glam/src/bool.rs
+++ b/crates/glam/src/bool.rs
@@ -6,6 +6,12 @@
 mod coresimd;
 
 #[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+mod neon;
+
+#[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
@@ -20,6 +26,7 @@
 #[cfg(any(
     not(any(
         feature = "core-simd",
+        target_arch = "aarch64",
         target_feature = "sse2",
         target_feature = "simd128"
     )),
@@ -27,54 +34,69 @@
 ))]
 mod scalar;
 
-pub use bvec2::BVec2;
-pub use bvec3::BVec3;
-pub use bvec4::BVec4;
+pub use bvec2::{bvec2, BVec2};
+pub use bvec3::{bvec3, BVec3};
+pub use bvec4::{bvec4, BVec4};
+
+#[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+pub use neon::bvec3a::{bvec3a, BVec3A};
+#[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+pub use neon::bvec4a::{bvec4a, BVec4A};
 
 #[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
-pub use sse2::bvec3a::BVec3A;
+pub use sse2::bvec3a::{bvec3a, BVec3A};
 #[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
-pub use sse2::bvec4a::BVec4A;
+pub use sse2::bvec4a::{bvec4a, BVec4A};
 
 #[cfg(all(
     target_feature = "simd128",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
-pub use wasm32::bvec3a::BVec3A;
+pub use wasm32::bvec3a::{bvec3a, BVec3A};
 #[cfg(all(
     target_feature = "simd128",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
-pub use wasm32::bvec4a::BVec4A;
+pub use wasm32::bvec4a::{bvec4a, BVec4A};
 
 #[cfg(all(feature = "core-simd", not(feature = "scalar-math")))]
-pub use coresimd::bvec3a::BVec3A;
+pub use coresimd::bvec3a::{bvec3a, BVec3A};
 #[cfg(all(feature = "core-simd", not(feature = "scalar-math")))]
-pub use coresimd::bvec4a::BVec4A;
+pub use coresimd::bvec4a::{bvec4a, BVec4A};
 
 #[cfg(any(
     not(any(
         feature = "core-simd",
+        target_arch = "aarch64",
         target_feature = "sse2",
         target_feature = "simd128"
     )),
     feature = "scalar-math"
 ))]
-pub use scalar::bvec3a::BVec3A;
+pub use scalar::bvec3a::{bvec3a, BVec3A};
 
-#[cfg(not(any(
-    feature = "scalar-math",
-    feature = "core-simd",
-    target_feature = "sse2",
-    target_feature = "simd128"
-),))]
-pub use scalar::bvec4a::BVec4A;
+#[cfg(any(
+    not(any(
+        feature = "core-simd",
+        target_arch = "aarch64",
+        target_feature = "sse2",
+        target_feature = "simd128"
+    )),
+    feature = "scalar-math"
+))]
+pub use scalar::bvec4a::{bvec4a, BVec4A};
 
 mod const_test_bvec2 {
     const_assert_eq!(1, core::mem::align_of::<super::BVec2>());
diff --git a/crates/glam/src/bool/bvec2.rs b/crates/glam/src/bool/bvec2.rs
index e4fe0c0..791e192 100644
--- a/crates/glam/src/bool/bvec2.rs
+++ b/crates/glam/src/bool/bvec2.rs
@@ -1,9 +1,15 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
+/// Creates a 2-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec2(x: bool, y: bool) -> BVec2 {
+    BVec2::new(x, y)
+}
+
 /// A 2-dimensional `bool` vector mask.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(C, align(1))]
@@ -28,13 +34,20 @@
         Self { x, y }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 2]) -> Self {
+        Self::new(a[0], a[1])
+    }
+
     /// Returns a bitmask with the lowest 2 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -169,7 +182,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -177,7 +189,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -185,6 +196,13 @@
     }
 }
 
+impl From<[bool; 2]> for BVec2 {
+    #[inline]
+    fn from(a: [bool; 2]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec2> for [bool; 2] {
     #[inline]
     fn from(mask: BVec2) -> Self {
diff --git a/crates/glam/src/bool/bvec3.rs b/crates/glam/src/bool/bvec3.rs
index 983cd3f..5807f98 100644
--- a/crates/glam/src/bool/bvec3.rs
+++ b/crates/glam/src/bool/bvec3.rs
@@ -1,9 +1,15 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3(x: bool, y: bool, z: bool) -> BVec3 {
+    BVec3::new(x, y, z)
+}
+
 /// A 3-dimensional `bool` vector mask.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(C, align(1))]
@@ -29,13 +35,20 @@
         Self { x, y, z }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
     /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -180,7 +193,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -195,7 +207,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -203,6 +214,13 @@
     }
 }
 
+impl From<[bool; 3]> for BVec3 {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec3> for [bool; 3] {
     #[inline]
     fn from(mask: BVec3) -> Self {
diff --git a/crates/glam/src/bool/bvec4.rs b/crates/glam/src/bool/bvec4.rs
index b1e9144..0bc7528 100644
--- a/crates/glam/src/bool/bvec4.rs
+++ b/crates/glam/src/bool/bvec4.rs
@@ -1,9 +1,15 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4(x: bool, y: bool, z: bool, w: bool) -> BVec4 {
+    BVec4::new(x, y, z, w)
+}
+
 /// A 4-dimensional `bool` vector mask.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(C, align(1))]
@@ -30,13 +36,20 @@
         Self { x, y, z, w }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
     /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -188,7 +201,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -204,7 +216,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -212,6 +223,13 @@
     }
 }
 
+impl From<[bool; 4]> for BVec4 {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec4> for [bool; 4] {
     #[inline]
     fn from(mask: BVec4) -> Self {
diff --git a/crates/glam/src/bool/coresimd/bvec3a.rs b/crates/glam/src/bool/coresimd/bvec3a.rs
index 5167672..8347ec8 100644
--- a/crates/glam/src/bool/coresimd/bvec3a.rs
+++ b/crates/glam/src/bool/coresimd/bvec3a.rs
@@ -1,6 +1,5 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
@@ -12,6 +11,13 @@
     v: BVec3A,
 }
 
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3a(x: bool, y: bool, z: bool) -> BVec3A {
+    BVec3A::new(x, y, z)
+}
+
 /// A 3-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -40,13 +46,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
     /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -190,7 +203,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -205,7 +217,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -213,6 +224,13 @@
     }
 }
 
+impl From<[bool; 3]> for BVec3A {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec3A> for [bool; 3] {
     #[inline]
     fn from(mask: BVec3A) -> Self {
diff --git a/crates/glam/src/bool/coresimd/bvec4a.rs b/crates/glam/src/bool/coresimd/bvec4a.rs
index 123a003..42bff3e 100644
--- a/crates/glam/src/bool/coresimd/bvec4a.rs
+++ b/crates/glam/src/bool/coresimd/bvec4a.rs
@@ -1,6 +1,5 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
@@ -12,6 +11,13 @@
     v: BVec4A,
 }
 
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4a(x: bool, y: bool, z: bool, w: bool) -> BVec4A {
+    BVec4A::new(x, y, z, w)
+}
+
 /// A 4-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -45,13 +51,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
     /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -201,7 +214,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -217,7 +229,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -225,6 +236,13 @@
     }
 }
 
+impl From<[bool; 4]> for BVec4A {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec4A> for [bool; 4] {
     #[inline]
     fn from(mask: BVec4A) -> Self {
diff --git a/crates/glam/src/bool/neon.rs b/crates/glam/src/bool/neon.rs
new file mode 100644
index 0000000..9a9a329
--- /dev/null
+++ b/crates/glam/src/bool/neon.rs
@@ -0,0 +1,2 @@
+pub mod bvec3a;
+pub mod bvec4a;
diff --git a/crates/glam/src/bool/neon/bvec3a.rs b/crates/glam/src/bool/neon/bvec3a.rs
new file mode 100644
index 0000000..7a7bdbf
--- /dev/null
+++ b/crates/glam/src/bool/neon/bvec3a.rs
@@ -0,0 +1,265 @@
+// Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
+
+use core::fmt;
+use core::ops::*;
+
+use core::arch::aarch64::*;
+
+#[repr(C)]
+union UnionCast {
+    a: [u32; 4],
+    v: BVec3A,
+}
+
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3a(x: bool, y: bool, z: bool) -> BVec3A {
+    BVec3A::new(x, y, z)
+}
+
+/// A 3-dimensional SIMD vector mask.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct BVec3A(pub(crate) uint32x4_t);
+
+const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
+
+impl BVec3A {
+    /// All false.
+    pub const FALSE: Self = Self::splat(false);
+
+    /// All true.
+    pub const TRUE: Self = Self::splat(true);
+
+    /// Creates a new vector mask.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: bool, y: bool, z: bool) -> Self {
+        unsafe {
+            UnionCast {
+                a: [MASK[x as usize], MASK[y as usize], MASK[z as usize], 0],
+            }
+            .v
+        }
+    }
+
+    /// Creates a vector mask with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: bool) -> Self {
+        Self::new(v, v, v)
+    }
+
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
+    /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
+    ///
+    /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn bitmask(self) -> u32 {
+        let movemask = unsafe {
+            let mma = vandq_u32(self.0, vld1q_u32([1, 2, 4, 8].as_ptr())); // [0 1 2 3]
+            let mmb = vextq_u32(mma, mma, 2); // [2 3 0 1]
+            let mmc = vorrq_u32(mma, mmb); // [0+2 1+3 0+2 1+3]
+            let mmd = vextq_u32(mmc, mmc, 3); // [1+3 0+2 1+3 0+2]
+            let mme = vorrq_u32(mmc, mmd); // [0+1+2+3 ...]
+            vgetq_lane_u32(mme, 0)
+        };
+
+        movemask & 0x7
+    }
+
+    /// Returns true if any of the elements are true, false otherwise.
+    #[inline]
+    #[must_use]
+    pub fn any(self) -> bool {
+        self.bitmask() != 0
+    }
+
+    /// Returns true if all the elements are true, false otherwise.
+    #[inline]
+    #[must_use]
+    pub fn all(self) -> bool {
+        self.bitmask() == 0x7
+    }
+
+    /// Tests the value at `index`.
+    ///
+    /// Panics if `index` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn test(&self, index: usize) -> bool {
+        match index {
+            0 => (self.bitmask() & (1 << 0)) != 0,
+            1 => (self.bitmask() & (1 << 1)) != 0,
+            2 => (self.bitmask() & (1 << 2)) != 0,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Sets the element at `index`.
+    ///
+    /// Panics if `index` is greater than 2.
+    #[inline]
+    pub fn set(&mut self, index: usize, value: bool) {
+        self.0 = match index {
+            0 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 0) },
+            1 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 1) },
+            2 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 2) },
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn into_bool_array(self) -> [bool; 3] {
+        let bitmask = self.bitmask();
+        [(bitmask & 1) != 0, (bitmask & 2) != 0, (bitmask & 4) != 0]
+    }
+
+    #[inline]
+    #[must_use]
+    fn into_u32_array(self) -> [u32; 3] {
+        let bitmask = self.bitmask();
+        [
+            MASK[(bitmask & 1) as usize],
+            MASK[((bitmask >> 1) & 1) as usize],
+            MASK[((bitmask >> 2) & 1) as usize],
+        ]
+    }
+}
+
+impl Default for BVec3A {
+    #[inline]
+    fn default() -> Self {
+        Self::FALSE
+    }
+}
+
+impl PartialEq for BVec3A {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.bitmask().eq(&rhs.bitmask())
+    }
+}
+
+impl Eq for BVec3A {}
+
+impl core::hash::Hash for BVec3A {
+    #[inline]
+    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.bitmask().hash(state);
+    }
+}
+
+impl BitAnd for BVec3A {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self {
+        Self(unsafe { vandq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitAndAssign for BVec3A {
+    #[inline]
+    fn bitand_assign(&mut self, rhs: Self) {
+        *self = self.bitand(rhs);
+    }
+}
+
+impl BitOr for BVec3A {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self {
+        Self(unsafe { vorrq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitOrAssign for BVec3A {
+    #[inline]
+    fn bitor_assign(&mut self, rhs: Self) {
+        *self = self.bitor(rhs);
+    }
+}
+
+impl BitXor for BVec3A {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self {
+        Self(unsafe { veorq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitXorAssign for BVec3A {
+    #[inline]
+    fn bitxor_assign(&mut self, rhs: Self) {
+        *self = self.bitxor(rhs);
+    }
+}
+
+impl Not for BVec3A {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self {
+        Self(unsafe { vmvnq_u32(self.0) })
+    }
+}
+
+impl From<BVec3A> for uint32x4_t {
+    #[inline]
+    fn from(t: BVec3A) -> Self {
+        t.0
+    }
+}
+
+impl fmt::Debug for BVec3A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let arr = self.into_u32_array();
+        write!(
+            f,
+            "{}({:#x}, {:#x}, {:#x})",
+            stringify!(BVec3A),
+            arr[0],
+            arr[1],
+            arr[2]
+        )
+    }
+}
+
+impl fmt::Display for BVec3A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let arr = self.into_bool_array();
+        write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2])
+    }
+}
+
+impl From<[bool; 3]> for BVec3A {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
+impl From<BVec3A> for [bool; 3] {
+    #[inline]
+    fn from(mask: BVec3A) -> Self {
+        mask.into_bool_array()
+    }
+}
+
+impl From<BVec3A> for [u32; 3] {
+    #[inline]
+    fn from(mask: BVec3A) -> Self {
+        mask.into_u32_array()
+    }
+}
diff --git a/crates/glam/src/bool/neon/bvec4a.rs b/crates/glam/src/bool/neon/bvec4a.rs
new file mode 100644
index 0000000..2b2f40a
--- /dev/null
+++ b/crates/glam/src/bool/neon/bvec4a.rs
@@ -0,0 +1,277 @@
+// Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
+
+use core::fmt;
+use core::ops::*;
+
+use core::arch::aarch64::*;
+
+#[repr(C)]
+union UnionCast {
+    a: [u32; 4],
+    v: BVec4A,
+}
+
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4a(x: bool, y: bool, z: bool, w: bool) -> BVec4A {
+    BVec4A::new(x, y, z, w)
+}
+
+/// A 4-dimensional SIMD vector mask.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct BVec4A(pub(crate) uint32x4_t);
+
+const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
+
+impl BVec4A {
+    /// All false.
+    pub const FALSE: Self = Self::splat(false);
+
+    /// All true.
+    pub const TRUE: Self = Self::splat(true);
+
+    /// Creates a new vector mask.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: bool, y: bool, z: bool, w: bool) -> Self {
+        unsafe {
+            UnionCast {
+                a: [
+                    MASK[x as usize],
+                    MASK[y as usize],
+                    MASK[z as usize],
+                    MASK[w as usize],
+                ],
+            }
+            .v
+        }
+    }
+
+    /// Creates a vector mask with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: bool) -> Self {
+        Self::new(v, v, v, v)
+    }
+
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
+    /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
+    ///
+    /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn bitmask(self) -> u32 {
+        unsafe {
+            let mma = vandq_u32(self.0, vld1q_u32([1, 2, 4, 8].as_ptr())); // [0 1 2 3]
+            let mmb = vextq_u32(mma, mma, 2); // [2 3 0 1]
+            let mmc = vorrq_u32(mma, mmb); // [0+2 1+3 0+2 1+3]
+            let mmd = vextq_u32(mmc, mmc, 3); // [1+3 0+2 1+3 0+2]
+            let mme = vorrq_u32(mmc, mmd); // [0+1+2+3 ...]
+            vgetq_lane_u32(mme, 0)
+        }
+    }
+
+    /// Returns true if any of the elements are true, false otherwise.
+    #[inline]
+    #[must_use]
+    pub fn any(self) -> bool {
+        self.bitmask() != 0
+    }
+
+    /// Returns true if all the elements are true, false otherwise.
+    #[inline]
+    #[must_use]
+    pub fn all(self) -> bool {
+        self.bitmask() == 0xf
+    }
+
+    /// Tests the value at `index`.
+    ///
+    /// Panics if `index` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn test(&self, index: usize) -> bool {
+        match index {
+            0 => (self.bitmask() & (1 << 0)) != 0,
+            1 => (self.bitmask() & (1 << 1)) != 0,
+            2 => (self.bitmask() & (1 << 2)) != 0,
+            3 => (self.bitmask() & (1 << 3)) != 0,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Sets the element at `index`.
+    ///
+    /// Panics if `index` is greater than 3.
+    #[inline]
+    pub fn set(&mut self, index: usize, value: bool) {
+        self.0 = match index {
+            0 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 0) },
+            1 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 1) },
+            2 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 2) },
+            3 => unsafe { vsetq_lane_u32(MASK[value as usize], self.0, 3) },
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn into_bool_array(self) -> [bool; 4] {
+        let bitmask = self.bitmask();
+        [
+            (bitmask & 1) != 0,
+            (bitmask & 2) != 0,
+            (bitmask & 4) != 0,
+            (bitmask & 8) != 0,
+        ]
+    }
+
+    #[inline]
+    #[must_use]
+    fn into_u32_array(self) -> [u32; 4] {
+        let bitmask = self.bitmask();
+        [
+            MASK[(bitmask & 1) as usize],
+            MASK[((bitmask >> 1) & 1) as usize],
+            MASK[((bitmask >> 2) & 1) as usize],
+            MASK[((bitmask >> 3) & 1) as usize],
+        ]
+    }
+}
+
+impl Default for BVec4A {
+    #[inline]
+    fn default() -> Self {
+        Self::FALSE
+    }
+}
+
+impl PartialEq for BVec4A {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.bitmask().eq(&rhs.bitmask())
+    }
+}
+
+impl Eq for BVec4A {}
+
+impl core::hash::Hash for BVec4A {
+    #[inline]
+    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.bitmask().hash(state);
+    }
+}
+
+impl BitAnd for BVec4A {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self {
+        Self(unsafe { vandq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitAndAssign for BVec4A {
+    #[inline]
+    fn bitand_assign(&mut self, rhs: Self) {
+        *self = self.bitand(rhs);
+    }
+}
+
+impl BitOr for BVec4A {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self {
+        Self(unsafe { vorrq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitOrAssign for BVec4A {
+    #[inline]
+    fn bitor_assign(&mut self, rhs: Self) {
+        *self = self.bitor(rhs);
+    }
+}
+
+impl BitXor for BVec4A {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self {
+        Self(unsafe { veorq_u32(self.0, rhs.0) })
+    }
+}
+
+impl BitXorAssign for BVec4A {
+    #[inline]
+    fn bitxor_assign(&mut self, rhs: Self) {
+        *self = self.bitxor(rhs);
+    }
+}
+
+impl Not for BVec4A {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self {
+        Self(unsafe { vmvnq_u32(self.0) })
+    }
+}
+
+impl From<BVec4A> for uint32x4_t {
+    #[inline]
+    fn from(t: BVec4A) -> Self {
+        t.0
+    }
+}
+
+impl fmt::Debug for BVec4A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let arr = self.into_u32_array();
+        write!(
+            f,
+            "{}({:#x}, {:#x}, {:#x}, {:#x})",
+            stringify!(BVec4A),
+            arr[0],
+            arr[1],
+            arr[2],
+            arr[3]
+        )
+    }
+}
+
+impl fmt::Display for BVec4A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let arr = self.into_bool_array();
+        write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3])
+    }
+}
+
+impl From<[bool; 4]> for BVec4A {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
+impl From<BVec4A> for [bool; 4] {
+    #[inline]
+    fn from(mask: BVec4A) -> Self {
+        mask.into_bool_array()
+    }
+}
+
+impl From<BVec4A> for [u32; 4] {
+    #[inline]
+    fn from(mask: BVec4A) -> Self {
+        mask.into_u32_array()
+    }
+}
diff --git a/crates/glam/src/bool/scalar/bvec3a.rs b/crates/glam/src/bool/scalar/bvec3a.rs
index f2dc95f..ff18a6c 100644
--- a/crates/glam/src/bool/scalar/bvec3a.rs
+++ b/crates/glam/src/bool/scalar/bvec3a.rs
@@ -1,9 +1,15 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3a(x: bool, y: bool, z: bool) -> BVec3A {
+    BVec3A::new(x, y, z)
+}
+
 /// A 3-dimensional `u32` vector mask.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(C, align(16))]
@@ -33,13 +39,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
     /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -184,7 +197,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -199,7 +211,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -207,6 +218,13 @@
     }
 }
 
+impl From<[bool; 3]> for BVec3A {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec3A> for [bool; 3] {
     #[inline]
     fn from(mask: BVec3A) -> Self {
diff --git a/crates/glam/src/bool/scalar/bvec4a.rs b/crates/glam/src/bool/scalar/bvec4a.rs
index bdf8884..d3eaf11 100644
--- a/crates/glam/src/bool/scalar/bvec4a.rs
+++ b/crates/glam/src/bool/scalar/bvec4a.rs
@@ -1,9 +1,15 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4a(x: bool, y: bool, z: bool, w: bool) -> BVec4A {
+    BVec4A::new(x, y, z, w)
+}
+
 /// A 4-dimensional `u32` vector mask.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(C, align(16))]
@@ -35,13 +41,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
     /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -193,7 +206,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -209,7 +221,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -217,6 +228,13 @@
     }
 }
 
+impl From<[bool; 4]> for BVec4A {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec4A> for [bool; 4] {
     #[inline]
     fn from(mask: BVec4A) -> Self {
diff --git a/crates/glam/src/bool/sse2/bvec3a.rs b/crates/glam/src/bool/sse2/bvec3a.rs
index 0ac65a5..8883f8f 100644
--- a/crates/glam/src/bool/sse2/bvec3a.rs
+++ b/crates/glam/src/bool/sse2/bvec3a.rs
@@ -1,6 +1,5 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
@@ -15,6 +14,13 @@
     v: BVec3A,
 }
 
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3a(x: bool, y: bool, z: bool) -> BVec3A {
+    BVec3A::new(x, y, z)
+}
+
 /// A 3-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -43,13 +49,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
     /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -96,7 +109,7 @@
         use crate::Vec3A;
         let mut v = Vec3A(self.0);
         v[index] = f32::from_bits(MASK[value as usize]);
-        *self = Self(v.0);
+        self.0 = v.0;
     }
 
     #[inline]
@@ -201,7 +214,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -216,7 +228,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -224,6 +235,13 @@
     }
 }
 
+impl From<[bool; 3]> for BVec3A {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec3A> for [bool; 3] {
     #[inline]
     fn from(mask: BVec3A) -> Self {
diff --git a/crates/glam/src/bool/sse2/bvec4a.rs b/crates/glam/src/bool/sse2/bvec4a.rs
index 18f8a03..c12d0f8 100644
--- a/crates/glam/src/bool/sse2/bvec4a.rs
+++ b/crates/glam/src/bool/sse2/bvec4a.rs
@@ -1,6 +1,5 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
@@ -15,6 +14,13 @@
     v: BVec4A,
 }
 
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4a(x: bool, y: bool, z: bool, w: bool) -> BVec4A {
+    BVec4A::new(x, y, z, w)
+}
+
 /// A 4-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -48,13 +54,20 @@
         }
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
     /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -102,7 +115,7 @@
         use crate::Vec4;
         let mut v = Vec4(self.0);
         v[index] = f32::from_bits(MASK[value as usize]);
-        *self = Self(v.0);
+        self.0 = v.0;
     }
 
     #[inline]
@@ -213,7 +226,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -229,7 +241,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -237,6 +248,13 @@
     }
 }
 
+impl From<[bool; 4]> for BVec4A {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec4A> for [bool; 4] {
     #[inline]
     fn from(mask: BVec4A) -> Self {
diff --git a/crates/glam/src/bool/wasm32/bvec3a.rs b/crates/glam/src/bool/wasm32/bvec3a.rs
index a634670..cfeedf8 100644
--- a/crates/glam/src/bool/wasm32/bvec3a.rs
+++ b/crates/glam/src/bool/wasm32/bvec3a.rs
@@ -1,11 +1,17 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
 use core::arch::wasm32::*;
 
+/// Creates a 3-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec3a(x: bool, y: bool, z: bool) -> BVec3A {
+    BVec3A::new(x, y, z)
+}
+
 /// A 3-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -34,13 +40,20 @@
         ))
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
     /// Returns a bitmask with the lowest 3 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -87,7 +100,7 @@
         use crate::Vec3A;
         let mut v = Vec3A(self.0);
         v[index] = f32::from_bits(MASK[value as usize]);
-        *self = Self(v.0);
+        self.0 = v.0;
     }
 
     #[inline]
@@ -192,7 +205,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -207,7 +219,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -215,6 +226,13 @@
     }
 }
 
+impl From<[bool; 3]> for BVec3A {
+    #[inline]
+    fn from(a: [bool; 3]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec3A> for [bool; 3] {
     #[inline]
     fn from(mask: BVec3A) -> Self {
diff --git a/crates/glam/src/bool/wasm32/bvec4a.rs b/crates/glam/src/bool/wasm32/bvec4a.rs
index 3813354..792c5fb 100644
--- a/crates/glam/src/bool/wasm32/bvec4a.rs
+++ b/crates/glam/src/bool/wasm32/bvec4a.rs
@@ -1,11 +1,17 @@
 // Generated from vec_mask.rs.tera template. Edit the template, not the generated file.
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::ops::*;
 
 use core::arch::wasm32::*;
 
+/// Creates a 4-dimensional `bool` vector mask.
+#[inline(always)]
+#[must_use]
+pub const fn bvec4a(x: bool, y: bool, z: bool, w: bool) -> BVec4A {
+    BVec4A::new(x, y, z, w)
+}
+
 /// A 4-dimensional SIMD vector mask.
 ///
 /// This type is 16 byte aligned.
@@ -34,13 +40,20 @@
         ))
     }
 
-    /// Creates a vector with all elements set to `v`.
+    /// Creates a vector mask with all elements set to `v`.
     #[inline]
     #[must_use]
     pub const fn splat(v: bool) -> Self {
         Self::new(v, v, v, v)
     }
 
+    /// Creates a new vector mask from a bool array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [bool; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
     /// Returns a bitmask with the lowest 4 bits set from the elements of `self`.
     ///
     /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
@@ -88,7 +101,7 @@
         use crate::Vec4;
         let mut v = Vec4(self.0);
         v[index] = f32::from_bits(MASK[value as usize]);
-        *self = Self(v.0);
+        self.0 = v.0;
     }
 
     #[inline]
@@ -199,7 +212,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_u32_array();
@@ -215,7 +227,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for BVec4A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let arr = self.into_bool_array();
@@ -223,6 +234,13 @@
     }
 }
 
+impl From<[bool; 4]> for BVec4A {
+    #[inline]
+    fn from(a: [bool; 4]) -> Self {
+        Self::from_array(a)
+    }
+}
+
 impl From<BVec4A> for [bool; 4] {
     #[inline]
     fn from(mask: BVec4A) -> Self {
diff --git a/crates/glam/src/deref.rs b/crates/glam/src/deref.rs
index 34361f4..49ee54c 100644
--- a/crates/glam/src/deref.rs
+++ b/crates/glam/src/deref.rs
@@ -1,12 +1,4 @@
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd)]
-#[cfg_attr(target_arch = "spirv", repr(simd))]
-#[cfg_attr(not(target_arch = "spirv"), repr(C))]
-pub struct XY<T> {
-    pub x: T,
-    pub y: T,
-}
-
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd)]
+#[cfg(not(feature = "scalar-math"))]
 #[cfg_attr(target_arch = "spirv", repr(simd))]
 #[cfg_attr(not(target_arch = "spirv"), repr(C))]
 pub struct Vec3<T> {
@@ -15,7 +7,7 @@
     pub z: T,
 }
 
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd)]
+#[cfg(not(feature = "scalar-math"))]
 #[cfg_attr(target_arch = "spirv", repr(simd))]
 #[cfg_attr(not(target_arch = "spirv"), repr(C))]
 pub struct Vec4<T> {
@@ -25,14 +17,13 @@
     pub w: T,
 }
 
-#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)]
+#[cfg(not(feature = "scalar-math"))]
 #[cfg_attr(not(target_arch = "spirv"), repr(C))]
 pub struct Cols2<V> {
     pub x_axis: V,
     pub y_axis: V,
 }
 
-#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)]
 #[cfg_attr(not(target_arch = "spirv"), repr(C))]
 pub struct Cols3<V> {
     pub x_axis: V,
@@ -40,7 +31,6 @@
     pub z_axis: V,
 }
 
-#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd)]
 #[cfg_attr(not(target_arch = "spirv"), repr(C))]
 pub struct Cols4<V> {
     pub x_axis: V,
diff --git a/crates/glam/src/euler.rs b/crates/glam/src/euler.rs
index 85f8099..fba11a7 100644
--- a/crates/glam/src/euler.rs
+++ b/crates/glam/src/euler.rs
@@ -1,17 +1,28 @@
-/*
-Conversion from quaternions to Euler rotation sequences.
-
-From: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/
-*/
-
-use crate::{DQuat, Quat};
+// Based on Ken Shoemake. 1994. Euler angle conversion. Graphics gems IV.  Academic Press
+// Professional, Inc., USA, 222–229.
+use crate::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A, Vec3Swizzles};
 
 /// Euler rotation sequences.
 ///
-/// The angles are applied starting from the right.
-/// E.g. XYZ will first apply the z-axis rotation.
+/// The three elemental rotations may be extrinsic (rotations about the axes xyz of the original
+/// coordinate system, which is assumed to remain motionless), or intrinsic(rotations about the
+/// axes of the rotating coordinate system XYZ, solidary with the moving body, which changes its
+/// orientation after each elemental rotation).
 ///
-/// YXZ can be used for yaw (y-axis), pitch (x-axis), roll (z-axis).
+/// ```
+/// # use glam::{EulerRot, Mat3};
+/// # let i = core::f32::consts::FRAC_PI_2;
+/// # let j = core::f32::consts::FRAC_PI_4;
+/// # let k = core::f32::consts::FRAC_PI_8;
+/// let m_intrinsic = Mat3::from_rotation_x(i) * Mat3::from_rotation_y(j) * Mat3::from_rotation_z(k);
+/// let n_intrinsic = Mat3::from_euler(EulerRot::XYZ, i, j, k);
+/// assert!(m_intrinsic.abs_diff_eq(n_intrinsic, 2e-6));
+///
+/// let m_extrinsic = Mat3::from_rotation_z(k) * Mat3::from_rotation_y(j) * Mat3::from_rotation_x(i);
+/// let n_extrinsic = Mat3::from_euler(EulerRot::XYZEx, i, j, k);
+/// assert!(m_extrinsic.abs_diff_eq(n_extrinsic, 2e-6));
+/// ```
+///
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum EulerRot {
     /// Intrinsic three-axis rotation ZYX
@@ -26,6 +37,45 @@
     XYZ,
     /// Intrinsic three-axis rotation XZY
     XZY,
+
+    /// Intrinsic two-axis rotation ZYZ
+    ZYZ,
+    /// Intrinsic two-axis rotation ZXZ
+    ZXZ,
+    /// Intrinsic two-axis rotation YXY
+    YXY,
+    /// Intrinsic two-axis rotation YZY
+    YZY,
+    /// Intrinsic two-axis rotation XYX
+    XYX,
+    /// Intrinsic two-axis rotation XZX
+    XZX,
+
+    /// Extrinsic three-axis rotation ZYX
+    ZYXEx,
+    /// Extrinsic three-axis rotation ZXY
+    ZXYEx,
+    /// Extrinsic three-axis rotation YXZ
+    YXZEx,
+    /// Extrinsic three-axis rotation YZX
+    YZXEx,
+    /// Extrinsic three-axis rotation XYZ
+    XYZEx,
+    /// Extrinsic three-axis rotation XZY
+    XZYEx,
+
+    /// Extrinsic two-axis rotation ZYZ
+    ZYZEx,
+    /// Extrinsic two-axis rotation ZXZ
+    ZXZEx,
+    /// Extrinsic two-axis rotation YXY
+    YXYEx,
+    /// Extrinsic two-axis rotation YZY
+    YZYEx,
+    /// Extrinsic two-axis rotation XYX
+    XYXEx,
+    /// Extrinsic two-axis rotation XZX
+    XZXEx,
 }
 
 impl Default for EulerRot {
@@ -35,250 +85,360 @@
     }
 }
 
-/// Conversion from quaternion to euler angles.
-pub(crate) trait EulerFromQuaternion<Q: Copy>: Sized + Copy {
-    type Output;
-    /// Compute the angle of the first axis (X-x-x)
-    fn first(self, q: Q) -> Self::Output;
-    /// Compute then angle of the second axis (x-X-x)
-    fn second(self, q: Q) -> Self::Output;
-    /// Compute then angle of the third axis (x-x-X)
-    fn third(self, q: Q) -> Self::Output;
-
-    /// Compute all angles of a rotation in the notation order
-    fn convert_quat(self, q: Q) -> (Self::Output, Self::Output, Self::Output);
-
-    #[doc(hidden)]
-    fn sine_theta(self, q: Q) -> Self::Output;
+pub(crate) trait ToEuler {
+    type Scalar;
+    fn to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar);
 }
 
-/// Conversion from euler angles to quaternion.
-pub(crate) trait EulerToQuaternion<T>: Copy {
-    type Output;
-    /// Create the rotation quaternion for the three angles of this euler rotation sequence.
-    fn new_quat(self, u: T, v: T, w: T) -> Self::Output;
+pub(crate) trait FromEuler {
+    type Scalar;
+    fn from_euler_angles(
+        order: EulerRot,
+        i: Self::Scalar,
+        j: Self::Scalar,
+        k: Self::Scalar,
+    ) -> Self;
 }
 
-macro_rules! impl_from_quat {
-    ($t:ident, $quat:ident) => {
-        impl EulerFromQuaternion<$quat> for EulerRot {
-            type Output = $t;
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Axis {
+    X = 0,
+    Y = 1,
+    Z = 2,
+}
 
-            fn sine_theta(self, q: $quat) -> $t {
-                use EulerRot::*;
-                match self {
-                    ZYX => -2.0 * (q.x * q.z - q.w * q.y),
-                    ZXY => 2.0 * (q.y * q.z + q.w * q.x),
-                    YXZ => -2.0 * (q.y * q.z - q.w * q.x),
-                    YZX => 2.0 * (q.x * q.y + q.w * q.z),
-                    XYZ => 2.0 * (q.x * q.z + q.w * q.y),
-                    XZY => -2.0 * (q.x * q.y - q.w * q.z),
-                }
-                .clamp(-1.0, 1.0)
-            }
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Parity {
+    Odd = 0,
+    Even = 1,
+}
 
-            fn first(self, q: $quat) -> $t {
-                use crate::$t::math;
-                use EulerRot::*;
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Repeated {
+    No = 0,
+    Yes = 1,
+}
 
-                let sine_theta = self.sine_theta(q);
-                if math::abs(sine_theta) > 0.99999 {
-                    let scale = 2.0 * math::signum(sine_theta);
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Frame {
+    Relative = 0,
+    Static = 1,
+}
 
-                    match self {
-                        ZYX => scale * math::atan2(-q.x, q.w),
-                        ZXY => scale * math::atan2(q.y, q.w),
-                        YXZ => scale * math::atan2(-q.z, q.w),
-                        YZX => scale * math::atan2(q.x, q.w),
-                        XYZ => scale * math::atan2(q.z, q.w),
-                        XZY => scale * math::atan2(-q.y, q.w),
-                    }
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+struct Order {
+    initial_axis: Axis,
+    parity_even: bool,
+    initial_repeated: bool,
+    frame_static: bool,
+}
+
+impl Order {
+    const fn new(
+        initial_axis: Axis,
+        parity: Parity,
+        initial_repeated: Repeated,
+        frame: Frame,
+    ) -> Self {
+        Self {
+            initial_axis,
+            parity_even: parity as u32 == Parity::Even as u32,
+            initial_repeated: initial_repeated as u32 == Repeated::Yes as u32,
+            frame_static: frame as u32 == Frame::Static as u32,
+        }
+    }
+
+    const fn from_euler(euler: EulerRot) -> Self {
+        match euler {
+            EulerRot::XYZ => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Static),
+            EulerRot::XYX => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Static),
+            EulerRot::XZY => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Static),
+            EulerRot::XZX => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Static),
+            EulerRot::YZX => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Static),
+            EulerRot::YZY => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Static),
+            EulerRot::YXZ => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Static),
+            EulerRot::YXY => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Static),
+            EulerRot::ZXY => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Static),
+            EulerRot::ZXZ => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Static),
+            EulerRot::ZYX => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Static),
+            EulerRot::ZYZ => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Static),
+            EulerRot::ZYXEx => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Relative),
+            EulerRot::XYXEx => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Relative),
+            EulerRot::YZXEx => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Relative),
+            EulerRot::XZXEx => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Relative),
+            EulerRot::XZYEx => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Relative),
+            EulerRot::YZYEx => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Relative),
+            EulerRot::ZXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Relative),
+            EulerRot::YXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Relative),
+            EulerRot::YXZEx => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Relative),
+            EulerRot::ZXZEx => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Relative),
+            EulerRot::XYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Relative),
+            EulerRot::ZYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Relative),
+        }
+    }
+
+    const fn next_axis(i: usize) -> usize {
+        (i + 1) % 3
+    }
+
+    const fn prev_axis(i: usize) -> usize {
+        if i > 0 {
+            i - 1
+        } else {
+            2
+        }
+    }
+
+    const fn angle_order(self) -> (usize, usize, usize) {
+        let i = self.initial_axis as usize;
+        let j = if self.parity_even {
+            Order::next_axis(i)
+        } else {
+            Order::prev_axis(i)
+        };
+        let k = if self.parity_even {
+            Order::prev_axis(i)
+        } else {
+            Order::next_axis(i)
+        };
+        (i, j, k)
+    }
+}
+
+macro_rules! impl_mat3_from_euler {
+    ($scalar:ident, $mat3:ident, $vec3:ident) => {
+        impl FromEuler for $mat3 {
+            type Scalar = $scalar;
+            fn from_euler_angles(
+                euler: EulerRot,
+                x: Self::Scalar,
+                y: Self::Scalar,
+                z: Self::Scalar,
+            ) -> Self {
+                use crate::$scalar::math;
+
+                let order = Order::from_euler(euler);
+                let (i, j, k) = order.angle_order();
+
+                let mut angles = if order.frame_static {
+                    $vec3::new(x, y, z)
                 } else {
-                    match self {
-                        ZYX => math::atan2(
-                            2.0 * (q.x * q.y + q.w * q.z),
-                            q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                        ),
-                        ZXY => math::atan2(
-                            -2.0 * (q.x * q.y - q.w * q.z),
-                            q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                        ),
-                        YXZ => math::atan2(
-                            2.0 * (q.x * q.z + q.w * q.y),
-                            q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                        ),
-                        YZX => math::atan2(
-                            -2.0 * (q.x * q.z - q.w * q.y),
-                            q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                        ),
-                        XYZ => math::atan2(
-                            -2.0 * (q.y * q.z - q.w * q.x),
-                            q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                        ),
-                        XZY => math::atan2(
-                            2.0 * (q.y * q.z + q.w * q.x),
-                            q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                        ),
-                    }
-                }
-            }
-
-            fn second(self, q: $quat) -> $t {
-                use crate::$t::math;
-                math::asin(self.sine_theta(q))
-            }
-
-            fn third(self, q: $quat) -> $t {
-                use crate::$t::math;
-                use EulerRot::*;
-                if math::abs(self.sine_theta(q)) > 0.99999 {
-                    0.0
-                } else {
-                    match self {
-                        ZYX => math::atan2(
-                            2.0 * (q.y * q.z + q.w * q.x),
-                            q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                        ),
-                        ZXY => math::atan2(
-                            -2.0 * (q.x * q.z - q.w * q.y),
-                            q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                        ),
-                        YXZ => math::atan2(
-                            2.0 * (q.x * q.y + q.w * q.z),
-                            q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                        ),
-                        YZX => math::atan2(
-                            -2.0 * (q.y * q.z - q.w * q.x),
-                            q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                        ),
-                        XYZ => math::atan2(
-                            -2.0 * (q.x * q.y - q.w * q.z),
-                            q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                        ),
-                        XZY => math::atan2(
-                            2.0 * (q.x * q.z + q.w * q.y),
-                            q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                        ),
-                    }
-                }
-            }
-
-            fn convert_quat(self, q: $quat) -> ($t, $t, $t) {
-                use crate::$t::math;
-                use EulerRot::*;
-
-                let sine_theta = self.sine_theta(q);
-                let second = math::asin(sine_theta);
-
-                if math::abs(sine_theta) > 0.99999 {
-                    let scale = 2.0 * math::signum(sine_theta);
-
-                    return match self {
-                        ZYX => (scale * math::atan2(-q.x, q.w), second, 0.0),
-                        ZXY => (scale * math::atan2(q.y, q.w), second, 0.0),
-                        YXZ => (scale * math::atan2(-q.z, q.w), second, 0.0),
-                        YZX => (scale * math::atan2(q.x, q.w), second, 0.0),
-                        XYZ => (scale * math::atan2(q.z, q.w), second, 0.0),
-                        XZY => (scale * math::atan2(-q.y, q.w), second, 0.0),
-                    };
-                }
-
-                let first = match self {
-                    ZYX => math::atan2(
-                        2.0 * (q.x * q.y + q.w * q.z),
-                        q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                    ),
-                    ZXY => math::atan2(
-                        -2.0 * (q.x * q.y - q.w * q.z),
-                        q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                    ),
-                    YXZ => math::atan2(
-                        2.0 * (q.x * q.z + q.w * q.y),
-                        q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                    ),
-                    YZX => math::atan2(
-                        -2.0 * (q.x * q.z - q.w * q.y),
-                        q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                    ),
-                    XYZ => math::atan2(
-                        -2.0 * (q.y * q.z - q.w * q.x),
-                        q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                    ),
-                    XZY => math::atan2(
-                        2.0 * (q.y * q.z + q.w * q.x),
-                        q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                    ),
+                    $vec3::new(z, y, x)
                 };
 
-                let third = match self {
-                    ZYX => math::atan2(
-                        2.0 * (q.y * q.z + q.w * q.x),
-                        q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                    ),
-                    ZXY => math::atan2(
-                        -2.0 * (q.x * q.z - q.w * q.y),
-                        q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z,
-                    ),
-                    YXZ => math::atan2(
-                        2.0 * (q.x * q.y + q.w * q.z),
-                        q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                    ),
-                    YZX => math::atan2(
-                        -2.0 * (q.y * q.z - q.w * q.x),
-                        q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z,
-                    ),
-                    XYZ => math::atan2(
-                        -2.0 * (q.x * q.y - q.w * q.z),
-                        q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                    ),
-                    XZY => math::atan2(
-                        2.0 * (q.x * q.z + q.w * q.y),
-                        q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z,
-                    ),
-                };
+                // rotation direction is reverse from original paper
+                if order.parity_even {
+                    angles = -angles;
+                }
 
-                (first, second, third)
+                let (si, ci) = math::sin_cos(angles.x);
+                let (sj, cj) = math::sin_cos(angles.y);
+                let (sh, ch) = math::sin_cos(angles.z);
+
+                let cc = ci * ch;
+                let cs = ci * sh;
+                let sc = si * ch;
+                let ss = si * sh;
+
+                let mut m = [[0.0; 3]; 3];
+
+                if order.initial_repeated {
+                    m[i][i] = cj;
+                    m[i][j] = sj * si;
+                    m[i][k] = sj * ci;
+                    m[j][i] = sj * sh;
+                    m[j][j] = -cj * ss + cc;
+                    m[j][k] = -cj * cs - sc;
+                    m[k][i] = -sj * ch;
+                    m[k][j] = cj * sc + cs;
+                    m[k][k] = cj * cc - ss;
+                } else {
+                    m[i][i] = cj * ch;
+                    m[i][j] = sj * sc - cs;
+                    m[i][k] = sj * cc + ss;
+                    m[j][i] = cj * sh;
+                    m[j][j] = sj * ss + cc;
+                    m[j][k] = sj * cs - sc;
+                    m[k][i] = -sj;
+                    m[k][j] = cj * si;
+                    m[k][k] = cj * ci;
+                }
+
+                $mat3::from_cols_array_2d(&m)
             }
         }
-        // End - impl EulerFromQuaternion
     };
 }
 
-macro_rules! impl_to_quat {
-    ($t:ty, $quat:ident) => {
-        impl EulerToQuaternion<$t> for EulerRot {
-            type Output = $quat;
-            #[inline(always)]
-            fn new_quat(self, u: $t, v: $t, w: $t) -> $quat {
-                use EulerRot::*;
-                #[inline(always)]
-                fn rot_x(a: $t) -> $quat {
-                    $quat::from_rotation_x(a)
-                }
-                #[inline(always)]
-                fn rot_y(a: $t) -> $quat {
-                    $quat::from_rotation_y(a)
-                }
-                #[inline(always)]
-                fn rot_z(a: $t) -> $quat {
-                    $quat::from_rotation_z(a)
-                }
-                match self {
-                    ZYX => rot_z(u) * rot_y(v) * rot_x(w),
-                    ZXY => rot_z(u) * rot_x(v) * rot_y(w),
-                    YXZ => rot_y(u) * rot_x(v) * rot_z(w),
-                    YZX => rot_y(u) * rot_z(v) * rot_x(w),
-                    XYZ => rot_x(u) * rot_y(v) * rot_z(w),
-                    XZY => rot_x(u) * rot_z(v) * rot_y(w),
-                }
-                .normalize()
+macro_rules! impl_mat4_from_euler {
+    ($scalar:ident, $mat4:ident, $mat3:ident) => {
+        impl FromEuler for $mat4 {
+            type Scalar = $scalar;
+            fn from_euler_angles(
+                euler: EulerRot,
+                x: Self::Scalar,
+                y: Self::Scalar,
+                z: Self::Scalar,
+            ) -> Self {
+                $mat4::from_mat3($mat3::from_euler_angles(euler, x, y, z))
             }
         }
-        // End - impl EulerToQuaternion
     };
 }
 
-impl_from_quat!(f32, Quat);
-impl_from_quat!(f64, DQuat);
-impl_to_quat!(f32, Quat);
-impl_to_quat!(f64, DQuat);
+macro_rules! impl_quat_from_euler {
+    ($scalar:ident, $quat:ident, $vec3:ident) => {
+        impl FromEuler for $quat {
+            type Scalar = $scalar;
+            fn from_euler_angles(
+                euler: EulerRot,
+                x: Self::Scalar,
+                y: Self::Scalar,
+                z: Self::Scalar,
+            ) -> Self {
+                use crate::$scalar::math;
+
+                let order = Order::from_euler(euler);
+                let (i, j, k) = order.angle_order();
+
+                let mut angles = if order.frame_static {
+                    $vec3::new(x, y, z)
+                } else {
+                    $vec3::new(z, y, x)
+                };
+
+                if order.parity_even {
+                    angles.y = -angles.y;
+                }
+
+                let ti = angles.x * 0.5;
+                let tj = angles.y * 0.5;
+                let th = angles.z * 0.5;
+                let (si, ci) = math::sin_cos(ti);
+                let (sj, cj) = math::sin_cos(tj);
+                let (sh, ch) = math::sin_cos(th);
+                let cc = ci * ch;
+                let cs = ci * sh;
+                let sc = si * ch;
+                let ss = si * sh;
+
+                let parity = if !order.parity_even { 1.0 } else { -1.0 };
+
+                let mut a = [0.0; 4];
+
+                if order.initial_repeated {
+                    a[i] = cj * (cs + sc);
+                    a[j] = sj * (cc + ss) * parity;
+                    a[k] = sj * (cs - sc);
+                    a[3] = cj * (cc - ss);
+                } else {
+                    a[i] = cj * sc - sj * cs;
+                    a[j] = (cj * ss + sj * cc) * parity;
+                    a[k] = cj * cs - sj * sc;
+                    a[3] = cj * cc + sj * ss;
+                }
+
+                $quat::from_array(a)
+            }
+        }
+    };
+}
+
+macro_rules! impl_mat3_to_euler {
+    ($scalar:ident, $mat3:ident, $vec3:ident) => {
+        impl ToEuler for $mat3 {
+            type Scalar = $scalar;
+            fn to_euler_angles(
+                self,
+                euler: EulerRot,
+            ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
+                use crate::$scalar::math;
+
+                let order = Order::from_euler(euler);
+                let (i, j, k) = order.angle_order();
+
+                let mut ea = $vec3::ZERO;
+                if order.initial_repeated {
+                    let sy = math::sqrt(
+                        self.col(i)[j] * self.col(i)[j] + self.col(i)[k] * self.col(i)[k],
+                    );
+                    if (sy > 16.0 * $scalar::EPSILON) {
+                        ea.x = math::atan2(self.col(i)[j], self.col(i)[k]);
+                        ea.y = math::atan2(sy, self.col(i)[i]);
+                        ea.z = math::atan2(self.col(j)[i], -self.col(k)[i]);
+                    } else {
+                        ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
+                        ea.y = math::atan2(sy, self.col(i)[i]);
+                    }
+                } else {
+                    let cy = math::sqrt(
+                        self.col(i)[i] * self.col(i)[i] + self.col(j)[i] * self.col(j)[i],
+                    );
+                    if (cy > 16.0 * $scalar::EPSILON) {
+                        ea.x = math::atan2(self.col(k)[j], self.col(k)[k]);
+                        ea.y = math::atan2(-self.col(k)[i], cy);
+                        ea.z = math::atan2(self.col(j)[i], self.col(i)[i]);
+                    } else {
+                        ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
+                        ea.y = math::atan2(-self.col(k)[i], cy);
+                    }
+                }
+
+                // reverse rotation angle of original code
+                if order.parity_even {
+                    ea = -ea;
+                }
+
+                if !order.frame_static {
+                    ea = ea.zyx();
+                }
+
+                (ea.x, ea.y, ea.z)
+            }
+        }
+    };
+}
+
+macro_rules! impl_mat4_to_euler {
+    ($scalar:ident, $mat4:ident, $mat3:ident) => {
+        impl ToEuler for $mat4 {
+            type Scalar = $scalar;
+            fn to_euler_angles(
+                self,
+                order: EulerRot,
+            ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
+                $mat3::from_mat4(self).to_euler_angles(order)
+            }
+        }
+    };
+}
+
+macro_rules! impl_quat_to_euler {
+    ($scalar:ident, $quat:ident, $mat3:ident) => {
+        impl ToEuler for $quat {
+            type Scalar = $scalar;
+            fn to_euler_angles(
+                self,
+                order: EulerRot,
+            ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
+                $mat3::from_quat(self).to_euler_angles(order)
+            }
+        }
+    };
+}
+
+impl_mat3_to_euler!(f32, Mat3, Vec3);
+impl_mat3_from_euler!(f32, Mat3, Vec3);
+impl_mat3_to_euler!(f32, Mat3A, Vec3A);
+impl_mat3_from_euler!(f32, Mat3A, Vec3A);
+impl_mat4_from_euler!(f32, Mat4, Mat3);
+impl_mat4_to_euler!(f32, Mat4, Mat3);
+impl_quat_to_euler!(f32, Quat, Mat3);
+impl_quat_from_euler!(f32, Quat, Vec3);
+
+impl_mat3_to_euler!(f64, DMat3, DVec3);
+impl_mat3_from_euler!(f64, DMat3, DVec3);
+impl_mat4_to_euler!(f64, DMat4, DMat3);
+impl_mat4_from_euler!(f64, DMat4, DMat3);
+impl_quat_to_euler!(f64, DQuat, DMat3);
+impl_quat_from_euler!(f64, DQuat, DVec3);
diff --git a/crates/glam/src/f32.rs b/crates/glam/src/f32.rs
index 3a53381..890b2b6 100644
--- a/crates/glam/src/f32.rs
+++ b/crates/glam/src/f32.rs
@@ -12,6 +12,7 @@
 #[cfg(any(
     not(any(
         feature = "core-simd",
+        target_arch = "aarch64",
         target_feature = "sse2",
         target_feature = "simd128"
     )),
@@ -20,6 +21,12 @@
 mod scalar;
 
 #[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+mod neon;
+
+#[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
@@ -34,6 +41,7 @@
 #[cfg(any(
     not(any(
         feature = "core-simd",
+        target_arch = "aarch64",
         target_feature = "sse2",
         target_feature = "simd128"
     )),
@@ -42,6 +50,12 @@
 use scalar::*;
 
 #[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+use neon::*;
+
+#[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
diff --git a/crates/glam/src/f32/affine2.rs b/crates/glam/src/f32/affine2.rs
index c089586..b41db49 100644
--- a/crates/glam/src/f32/affine2.rs
+++ b/crates/glam/src/f32/affine2.rs
@@ -50,8 +50,8 @@
     #[must_use]
     pub fn from_cols_array(m: &[f32; 6]) -> Self {
         Self {
-            matrix2: Mat2::from_cols_slice(&m[0..4]),
-            translation: Vec2::from_slice(&m[4..6]),
+            matrix2: Mat2::from_cols_array(&[m[0], m[1], m[2], m[3]]),
+            translation: Vec2::from_array([m[4], m[5]]),
         }
     }
 
@@ -344,7 +344,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Debug for Affine2 {
     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         fmt.debug_struct(stringify!(Affine2))
@@ -354,14 +353,21 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Display for Affine2 {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}]",
-            self.matrix2.x_axis, self.matrix2.y_axis, self.translation
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.matrix2.x_axis, p, self.matrix2.y_axis, p, self.translation
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}]",
+                self.matrix2.x_axis, self.matrix2.y_axis, self.translation
+            )
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/affine3a.rs b/crates/glam/src/f32/affine3a.rs
index 1fdddd5..8110101 100644
--- a/crates/glam/src/f32/affine3a.rs
+++ b/crates/glam/src/f32/affine3a.rs
@@ -52,8 +52,10 @@
     #[must_use]
     pub fn from_cols_array(m: &[f32; 12]) -> Self {
         Self {
-            matrix3: Mat3A::from_cols_slice(&m[0..9]),
-            translation: Vec3A::from_slice(&m[9..12]),
+            matrix3: Mat3A::from_cols_array(&[
+                m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8],
+            ]),
+            translation: Vec3A::from_array([m[9], m[10], m[11]]),
         }
     }
 
@@ -486,7 +488,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Debug for Affine3A {
     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         fmt.debug_struct(stringify!(Affine3A))
@@ -496,14 +497,28 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Display for Affine3A {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p,
+                self.matrix3.x_axis,
+                p,
+                self.matrix3.y_axis,
+                p,
+                self.matrix3.z_axis,
+                p,
+                self.translation
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
+            )
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/coresimd/mat2.rs b/crates/glam/src/f32/coresimd/mat2.rs
index f8c0f91..440b722 100644
--- a/crates/glam/src/f32/coresimd/mat2.rs
+++ b/crates/glam/src/f32/coresimd/mat2.rs
@@ -1,10 +1,9 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::simd::*;
 
@@ -114,6 +113,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
     #[inline]
     #[must_use]
@@ -121,6 +143,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from the first 4 values in `slice`.
     ///
     /// # Panics
@@ -293,6 +338,13 @@
         Self(self.0 * f32x4::splat(rhs))
     }
 
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        Self(self.0 / f32x4::splat(rhs))
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -309,6 +361,13 @@
             && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat2(&self) -> DMat2 {
         DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
@@ -406,6 +465,29 @@
     }
 }
 
+impl Div<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn div(self, rhs: Mat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat2 {
     fn sum<I>(iter: I) -> Self
     where
@@ -480,7 +562,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat2))
@@ -490,9 +571,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/coresimd/mat3a.rs b/crates/glam/src/f32/coresimd/mat3a.rs
index 3c0645d..afeb5b8 100644
--- a/crates/glam/src/f32/coresimd/mat3a.rs
+++ b/crates/glam/src/f32/coresimd/mat3a.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::simd::*;
 
@@ -152,7 +156,105 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: Mat4) -> Self {
-        Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into())
+        Self::from_cols(
+            Vec3A::from_vec4(m.x_axis),
+            Vec3A::from_vec4(m.y_axis),
+            Vec3A::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (0, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (0, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (0, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (1, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (1, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (1, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (1, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (2, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (2, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (2, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (2, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (3, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+            ),
+            (3, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+            ),
+            (3, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+            ),
+            (3, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+            ),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -216,8 +318,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -559,6 +679,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3A::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -576,6 +708,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat3(&self) -> DMat3 {
         DMat3::from_cols(
@@ -677,6 +816,29 @@
     }
 }
 
+impl Div<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn div(self, rhs: Mat3A) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Mul<Vec3> for Mat3A {
     type Output = Vec3;
     #[inline]
@@ -739,7 +901,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat3A))
@@ -750,9 +911,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/coresimd/mat4.rs b/crates/glam/src/f32/coresimd/mat4.rs
index b430fcd..6082992 100644
--- a/crates/glam/src/f32/coresimd/mat4.rs
+++ b/crates/glam/src/f32/coresimd/mat4.rs
@@ -1,12 +1,15 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    coresimd::*, f32::math, swizzles::*, DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
+    coresimd::*,
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
 };
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::simd::*;
 
@@ -382,8 +385,27 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
@@ -826,7 +848,10 @@
         Self::look_to_rh(eye, center.sub(eye), up)
     }
 
-    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
     /// This is the same as the OpenGL `gluPerspective` function.
     /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
     #[inline]
@@ -852,6 +877,8 @@
 
     /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -874,6 +901,8 @@
 
     /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -896,9 +925,13 @@
 
     /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
     /// # Panics
     ///
-    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -914,7 +947,9 @@
         )
     }
 
-    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
     ///
     /// # Panics
     ///
@@ -938,8 +973,15 @@
         )
     }
 
-    /// Creates an infinite right-handed perspective projection matrix with
-    /// `[0,1]` depth range.
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -953,8 +995,13 @@
         )
     }
 
-    /// Creates an infinite reverse right-handed perspective projection matrix
-    /// with `[0,1]` depth range.
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_reverse_rh(
@@ -976,6 +1023,8 @@
     /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
     /// See
     /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
     #[inline]
     #[must_use]
     pub fn orthographic_rh_gl(
@@ -1002,6 +1051,8 @@
     }
 
     /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_lh(
@@ -1029,6 +1080,8 @@
     }
 
     /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_rh(
@@ -1068,7 +1121,7 @@
         res = self.y_axis.mul(rhs.y).add(res);
         res = self.z_axis.mul(rhs.z).add(res);
         res = self.w_axis.add(res);
-        res = res.mul(res.wwww().recip());
+        res = res.div(res.w);
         res.xyz()
     }
 
@@ -1078,7 +1131,7 @@
     /// `1.0`.
     ///
     /// This method assumes that `self` contains a valid affine transform. It does not perform
-    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
     /// the [`Self::project_point3()`] method should be used instead.
     ///
     /// # Panics
@@ -1115,6 +1168,23 @@
         res.xyz()
     }
 
+    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        res = self.w_axis.add(res);
+        res = res.div(res.wwww());
+        Vec3A::from_vec4(res)
+    }
+
     /// Transforms the given [`Vec3A`] as 3D point.
     ///
     /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
@@ -1126,7 +1196,7 @@
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
         res = self.w_axis.add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms the give [`Vec3A`] as 3D vector.
@@ -1139,7 +1209,7 @@
         let mut res = self.x_axis.mul(rhs.xxxx());
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms a 4D vector.
@@ -1201,6 +1271,19 @@
         )
     }
 
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -1219,6 +1302,18 @@
             && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
     #[inline]
     pub fn as_dmat4(&self) -> DMat4 {
         DMat4::from_cols(
@@ -1326,6 +1421,29 @@
     }
 }
 
+impl Div<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn div(self, rhs: Mat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat4 {
     fn sum<I>(iter: I) -> Self
     where
@@ -1388,7 +1506,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat4))
@@ -1400,13 +1517,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.x_axis, self.y_axis, self.z_axis, self.w_axis
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
     }
 }
diff --git a/crates/glam/src/f32/coresimd/quat.rs b/crates/glam/src/f32/coresimd/quat.rs
index 0d6d1af..7bcb0b5 100644
--- a/crates/glam/src/f32/coresimd/quat.rs
+++ b/crates/glam/src/f32/coresimd/quat.rs
@@ -2,14 +2,13 @@
 
 use crate::{
     coresimd::*,
-    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
+    euler::{EulerRot, FromEuler, ToEuler},
     f32::math,
     DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
 };
 
 use core::simd::*;
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub};
@@ -175,14 +174,22 @@
     #[inline]
     #[must_use]
     pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        euler.new_quat(a, b, c)
+        Self::from_euler_angles(euler, a, b, c)
     }
 
     /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
-        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
         let (m00, m01, m02) = x_axis.into();
         let (m10, m11, m12) = y_axis.into();
         let (m20, m21, m22) = z_axis.into();
@@ -240,6 +247,13 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3(mat: &Mat3) -> Self {
@@ -247,13 +261,28 @@
     }
 
     /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3a(mat: &Mat3A) -> Self {
         Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
     }
 
-    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat4(mat: &Mat4) -> Self {
@@ -282,13 +311,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPS {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPS {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             use core::f32::consts::PI; // half a turn = 𝛕/2 = 180°
             Self::from_axis_angle(from.any_orthonormal_vector(), PI)
         } else {
@@ -338,13 +367,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPSILON {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPSILON {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             const COS_FRAC_PI_2: f32 = 0.0;
             const SIN_FRAC_PI_2: f32 = 1.0;
             // rotation around z by PI radians
@@ -386,8 +415,8 @@
     /// Returns the rotation angles for the given euler rotation sequence.
     #[inline]
     #[must_use]
-    pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) {
-        euler.convert_quat(self)
+    pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
+        self.to_euler_angles(order)
     }
 
     /// `[x, y, z, w]`
@@ -486,6 +515,7 @@
         Vec4::from(self).is_finite()
     }
 
+    /// Returns `true` if any elements are `NAN`.
     #[inline]
     #[must_use]
     pub fn is_nan(self) -> bool {
@@ -538,6 +568,29 @@
         math::acos_approx(math::abs(self.dot(rhs))) * 2.0
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -553,6 +606,12 @@
         Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
     }
 
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f32) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
     /// Performs a linear interpolation between `self` and `rhs` based on
     /// the value `s`.
     ///
@@ -570,14 +629,11 @@
         glam_assert!(end.is_normalized());
 
         const NEG_ZERO: f32x4 = f32x4::from_array([-0.0; 4]);
-        let start = self.0;
-        let end = end.0;
-        let dot = dot4_into_f32x4(start, end);
+        let dot = dot4_into_f32x4(self.0, end.0);
         // Calculate the bias, if the dot product is positive or zero, there is no bias
         // but if it is negative, we want to flip the 'end' rotation XYZW components
         let bias = f32x4_bitand(dot, NEG_ZERO);
-        let interpolated = start + ((f32x4_bitxor(end, bias) - start) * f32x4::splat(s));
-        Quat(interpolated).normalize()
+        self.lerp_impl(Self(f32x4_bitxor(end.0, bias)), s)
     }
 
     /// Performs a spherical linear interpolation between `self` and `end`
@@ -596,8 +652,6 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        const DOT_THRESHOLD: f32 = 0.9995;
-
         // Note that a rotation can be represented by two quaternions: `q` and
         // `-q`. The slerp path between `q` and `end` will be different from the
         // path between `-q` and `end`. One path will take the long way around and
@@ -610,23 +664,17 @@
             dot = -dot;
         }
 
+        const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
         if dot > DOT_THRESHOLD {
-            // assumes lerp returns a normalized quaternion
-            self.lerp(end, s)
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
         } else {
             let theta = math::acos_approx(dot);
 
-            let x = math::sin(theta * (1.0 - s));
-            let y = math::sin(theta * s);
-            let z = math::sin(theta);
-            let w = 0.0;
-            let tmp = f32x4::from_array([x, y, z, w]);
-
-            let scale1 = simd_swizzle!(tmp, [0, 0, 0, 0]);
-            let scale2 = simd_swizzle!(tmp, [1, 1, 1, 1]);
-            let theta_sin = simd_swizzle!(tmp, [2, 2, 2, 2]);
-
-            Self(self.0.mul(scale1).add(end.0.mul(scale2)).div(theta_sin))
+            let scale1 = math::sin(theta * (1.0 - s));
+            let scale2 = math::sin(theta * s);
+            let theta_sin = math::sin(theta);
+            ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
         }
     }
 
@@ -654,9 +702,6 @@
     #[inline]
     #[must_use]
     pub fn mul_quat(self, rhs: Self) -> Self {
-        glam_assert!(self.is_normalized());
-        glam_assert!(rhs.is_normalized());
-
         let lhs = self.0;
         let rhs = rhs.0;
 
@@ -691,6 +736,14 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn from_affine3(a: &crate::Affine3A) -> Self {
@@ -723,16 +776,8 @@
     pub fn as_dquat(self) -> DQuat {
         DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
-
-    #[inline]
-    #[must_use]
-    #[deprecated(since = "0.24.2", note = "Use as_dquat() instead")]
-    pub fn as_f64(self) -> DQuat {
-        self.as_dquat()
-    }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Quat {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Quat))
@@ -744,10 +789,17 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Quat {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/coresimd/vec3a.rs b/crates/glam/src/f32/coresimd/vec3a.rs
index 559143e..3601af8 100644
--- a/crates/glam/src/f32/coresimd/vec3a.rs
+++ b/crates/glam/src/f32/coresimd/vec3a.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{coresimd::*, f32::math, BVec3A, Vec2, Vec3, Vec4};
+use crate::{coresimd::*, f32::math, BVec3, BVec3A, Vec2, Vec3, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -90,6 +89,16 @@
         Self(Simd::from_array([v; 4]))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -123,6 +132,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -133,16 +143,15 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
-    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
-    #[allow(dead_code)]
+    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
+    ///
+    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
     #[inline]
     #[must_use]
-    pub(crate) fn from_vec4(v: Vec4) -> Self {
+    pub fn from_vec4(v: Vec4) -> Self {
         Self(v.0)
     }
 
@@ -163,6 +172,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -245,6 +278,24 @@
         v[0]
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        simd_swizzle!(self.0, Self::ZERO.0, [0, 1, 2, 4]).reduce_sum()
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        simd_swizzle!(self.0, Self::ONE.0, [0, 1, 2, 4]).reduce_product()
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -351,9 +402,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        f32x4::is_finite(self.0)
-            .bitor(mask32x4::from_array([false, false, false, true]))
-            .all()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3A {
+        BVec3A(f32x4::is_finite(self.0))
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -365,7 +421,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3A {
@@ -441,13 +497,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -475,6 +531,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -484,22 +558,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -527,6 +595,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -557,6 +626,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -595,13 +665,27 @@
         Self(self.0.trunc())
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -640,7 +724,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -658,14 +767,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -677,10 +787,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -689,10 +804,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -714,7 +834,45 @@
         Self(self.0.mul_add(a.0, b.0))
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -788,6 +946,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -853,6 +1025,30 @@
     }
 }
 
+impl Div<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec3A> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -860,6 +1056,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -868,6 +1071,30 @@
     }
 }
 
+impl Div<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -875,6 +1102,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -883,6 +1117,30 @@
     }
 }
 
+impl Div<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -891,6 +1149,30 @@
     }
 }
 
+impl Mul<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec3A> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -898,6 +1180,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -906,6 +1195,30 @@
     }
 }
 
+impl Mul<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -913,6 +1226,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -921,6 +1241,30 @@
     }
 }
 
+impl Mul<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -929,6 +1273,30 @@
     }
 }
 
+impl Add<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec3A> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -936,6 +1304,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -944,6 +1319,30 @@
     }
 }
 
+impl Add<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -951,6 +1350,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -959,6 +1365,30 @@
     }
 }
 
+impl Add<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -967,6 +1397,30 @@
     }
 }
 
+impl Sub<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec3A> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec3A) {
@@ -974,6 +1428,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -982,6 +1443,30 @@
     }
 }
 
+impl Sub<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -989,6 +1474,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -997,6 +1489,30 @@
     }
 }
 
+impl Sub<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1005,6 +1521,30 @@
     }
 }
 
+impl Rem<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec3A> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1012,6 +1552,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1020,6 +1567,30 @@
     }
 }
 
+impl Rem<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1027,6 +1598,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1035,6 +1613,30 @@
     }
 }
 
+impl Rem<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 3]> for Vec3A {
     #[inline]
@@ -1099,6 +1701,14 @@
     }
 }
 
+impl Neg for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn neg(self) -> Vec3A {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec3A {
     type Output = f32;
     #[inline]
@@ -1114,14 +1724,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec3A))
@@ -1133,14 +1745,14 @@
 }
 
 impl From<Vec3A> for f32x4 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec3A) -> Self {
         t.0
     }
 }
 
 impl From<f32x4> for Vec3A {
-    #[inline]
+    #[inline(always)]
     fn from(t: f32x4) -> Self {
         Self(t)
     }
@@ -1181,16 +1793,6 @@
     }
 }
 
-impl From<Vec4> for Vec3A {
-    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
-    ///
-    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
-    #[inline]
-    fn from(v: Vec4) -> Self {
-        Self(v.0)
-    }
-}
-
 impl From<Vec3A> for Vec3 {
     #[inline]
     fn from(v: Vec3A) -> Self {
@@ -1219,3 +1821,22 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec3> for Vec3A {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3A {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/coresimd/vec4.rs b/crates/glam/src/f32/coresimd/vec4.rs
index 81b4e7e..824dc82 100644
--- a/crates/glam/src/f32/coresimd/vec4.rs
+++ b/crates/glam/src/f32/coresimd/vec4.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{coresimd::*, f32::math, BVec4A, Vec2, Vec3, Vec3A};
+use crate::{coresimd::*, f32::math, BVec4, BVec4A, Vec2, Vec3, Vec3A};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -92,6 +91,16 @@
         Self(Simd::from_array([v; 4]))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -125,6 +134,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -135,10 +145,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -153,6 +160,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -217,6 +256,24 @@
         self.0.reduce_max()
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        self.0.reduce_sum()
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        self.0.reduce_product()
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,7 +380,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        f32x4::is_finite(self.0).all()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4A {
+        BVec4A(f32x4::is_finite(self.0))
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -335,7 +399,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec4A {
@@ -413,13 +477,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -447,6 +511,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -456,22 +538,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -499,6 +575,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -529,6 +606,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -567,13 +645,27 @@
         Self(self.0.trunc())
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -618,7 +710,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -636,14 +753,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -655,10 +773,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -667,10 +790,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -692,6 +820,44 @@
         Self(self.0.mul_add(a.0, b.0))
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Casts all elements of `self` to `f64`.
     #[inline]
     #[must_use]
@@ -699,6 +865,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -764,6 +944,30 @@
     }
 }
 
+impl Div<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec4> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -771,6 +975,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -779,6 +990,30 @@
     }
 }
 
+impl Div<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -786,6 +1021,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -794,6 +1036,30 @@
     }
 }
 
+impl Div<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -802,6 +1068,30 @@
     }
 }
 
+impl Mul<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec4> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -809,6 +1099,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -817,6 +1114,30 @@
     }
 }
 
+impl Mul<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -824,6 +1145,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -832,6 +1160,30 @@
     }
 }
 
+impl Mul<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -840,6 +1192,30 @@
     }
 }
 
+impl Add<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec4> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -847,6 +1223,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -855,6 +1238,30 @@
     }
 }
 
+impl Add<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -862,6 +1269,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -870,6 +1284,30 @@
     }
 }
 
+impl Add<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -878,6 +1316,30 @@
     }
 }
 
+impl Sub<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec4> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec4) {
@@ -885,6 +1347,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -893,6 +1362,30 @@
     }
 }
 
+impl Sub<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -900,6 +1393,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -908,6 +1408,30 @@
     }
 }
 
+impl Sub<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -916,6 +1440,30 @@
     }
 }
 
+impl Rem<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec4> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -923,6 +1471,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -931,6 +1486,30 @@
     }
 }
 
+impl Rem<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -938,6 +1517,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -946,6 +1532,30 @@
     }
 }
 
+impl Rem<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 4]> for Vec4 {
     #[inline]
@@ -1010,6 +1620,14 @@
     }
 }
 
+impl Neg for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn neg(self) -> Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec4 {
     type Output = f32;
     #[inline]
@@ -1025,14 +1643,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec4))
@@ -1045,14 +1669,14 @@
 }
 
 impl From<Vec4> for f32x4 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec4) -> Self {
         t.0
     }
 }
 
 impl From<f32x4> for Vec4 {
-    #[inline]
+    #[inline(always)]
     fn from(t: f32x4) -> Self {
         Self(t)
     }
@@ -1142,3 +1766,30 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec4> for Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f32::from(v.x),
+            f32::from(v.y),
+            f32::from(v.z),
+            f32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+            f32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/mat3.rs b/crates/glam/src/f32/mat3.rs
index 20b3c53..131a71f 100644
--- a/crates/glam/src/f32/mat3.rs
+++ b/crates/glam/src/f32/mat3.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat3, EulerRot, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 3x3 matrix from three column vectors.
 #[inline(always)]
@@ -153,7 +157,41 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: Mat4) -> Self {
-        Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz())
+        Self::from_cols(
+            Vec3::from_vec4(m.x_axis),
+            Vec3::from_vec4(m.y_axis),
+            Vec3::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yzw(), m.z_axis.yzw(), m.w_axis.yzw()),
+            (0, 1) => Self::from_cols(m.y_axis.xzw(), m.z_axis.xzw(), m.w_axis.xzw()),
+            (0, 2) => Self::from_cols(m.y_axis.xyw(), m.z_axis.xyw(), m.w_axis.xyw()),
+            (0, 3) => Self::from_cols(m.y_axis.xyz(), m.z_axis.xyz(), m.w_axis.xyz()),
+            (1, 0) => Self::from_cols(m.x_axis.yzw(), m.z_axis.yzw(), m.w_axis.yzw()),
+            (1, 1) => Self::from_cols(m.x_axis.xzw(), m.z_axis.xzw(), m.w_axis.xzw()),
+            (1, 2) => Self::from_cols(m.x_axis.xyw(), m.z_axis.xyw(), m.w_axis.xyw()),
+            (1, 3) => Self::from_cols(m.x_axis.xyz(), m.z_axis.xyz(), m.w_axis.xyz()),
+            (2, 0) => Self::from_cols(m.x_axis.yzw(), m.y_axis.yzw(), m.w_axis.yzw()),
+            (2, 1) => Self::from_cols(m.x_axis.xzw(), m.y_axis.xzw(), m.w_axis.xzw()),
+            (2, 2) => Self::from_cols(m.x_axis.xyw(), m.y_axis.xyw(), m.w_axis.xyw()),
+            (2, 3) => Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.w_axis.xyz()),
+            (3, 0) => Self::from_cols(m.x_axis.yzw(), m.y_axis.yzw(), m.z_axis.yzw()),
+            (3, 1) => Self::from_cols(m.x_axis.xzw(), m.y_axis.xzw(), m.z_axis.xzw()),
+            (3, 2) => Self::from_cols(m.x_axis.xyw(), m.y_axis.xyw(), m.z_axis.xyw()),
+            (3, 3) => Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz()),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -217,8 +255,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -553,6 +609,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -570,6 +638,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat3(&self) -> DMat3 {
         DMat3::from_cols(
@@ -671,6 +746,29 @@
     }
 }
 
+impl Div<Mat3> for f32 {
+    type Output = Mat3;
+    #[inline]
+    fn div(self, rhs: Mat3) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Mul<Vec3A> for Mat3 {
     type Output = Vec3A;
     #[inline]
@@ -749,7 +847,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat3))
@@ -760,9 +857,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/math.rs b/crates/glam/src/f32/math.rs
index 3e25875..127c9af 100644
--- a/crates/glam/src/f32/math.rs
+++ b/crates/glam/src/f32/math.rs
@@ -45,11 +45,6 @@
     }
 
     #[inline(always)]
-    pub(crate) fn asin(f: f32) -> f32 {
-        libm::asinf(f)
-    }
-
-    #[inline(always)]
     pub(crate) fn atan2(f: f32, other: f32) -> f32 {
         libm::atan2f(f, other)
     }
@@ -158,11 +153,6 @@
     }
 
     #[inline(always)]
-    pub(crate) fn asin(f: f32) -> f32 {
-        f32::asin(f)
-    }
-
-    #[inline(always)]
     pub(crate) fn atan2(f: f32, other: f32) -> f32 {
         f32::atan2(f, other)
     }
diff --git a/crates/glam/src/f32/neon.rs b/crates/glam/src/f32/neon.rs
new file mode 100644
index 0000000..24171e5
--- /dev/null
+++ b/crates/glam/src/f32/neon.rs
@@ -0,0 +1,6 @@
+pub mod mat2;
+pub mod mat3a;
+pub mod mat4;
+pub mod quat;
+pub mod vec3a;
+pub mod vec4;
diff --git a/crates/glam/src/f32/neon/mat2.rs b/crates/glam/src/f32/neon/mat2.rs
new file mode 100644
index 0000000..ed3140c
--- /dev/null
+++ b/crates/glam/src/f32/neon/mat2.rs
@@ -0,0 +1,624 @@
+// Generated from mat.rs.tera template. Edit the template, not the generated file.
+
+use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+
+use core::arch::aarch64::*;
+
+#[repr(C)]
+union UnionCast {
+    a: [f32; 4],
+    v: Mat2,
+}
+
+/// Creates a 2x2 matrix from two column vectors.
+#[inline(always)]
+#[must_use]
+pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 {
+    Mat2::from_cols(x_axis, y_axis)
+}
+
+/// A 2x2 column major matrix.
+///
+/// SIMD vector types are used for storage on supported platforms.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct Mat2(pub(crate) float32x4_t);
+
+impl Mat2 {
+    /// A 2x2 matrix with all elements set to `0.0`.
+    pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO);
+
+    /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
+    pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y);
+
+    /// All NAN:s.
+    pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN);
+
+    #[allow(clippy::too_many_arguments)]
+    #[inline(always)]
+    #[must_use]
+    const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self {
+        unsafe {
+            UnionCast {
+                a: [m00, m01, m10, m11],
+            }
+            .v
+        }
+    }
+
+    /// Creates a 2x2 matrix from two column vectors.
+    #[inline(always)]
+    #[must_use]
+    pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self {
+        unsafe {
+            UnionCast {
+                a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y],
+            }
+            .v
+        }
+    }
+
+    /// Creates a 2x2 matrix from a `[f32; 4]` array stored in column major order.
+    /// If your data is stored in row major you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array(m: &[f32; 4]) -> Self {
+        Self::new(m[0], m[1], m[2], m[3])
+    }
+
+    /// Creates a `[f32; 4]` array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array(&self) -> [f32; 4] {
+        unsafe { *(self as *const Self as *const [f32; 4]) }
+    }
+
+    /// Creates a 2x2 matrix from a `[[f32; 2]; 2]` 2D array stored in column major order.
+    /// If your data is in row major order you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self {
+        Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1]))
+    }
+
+    /// Creates a `[[f32; 2]; 2]` 2D array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] {
+        unsafe { *(self as *const Self as *const [[f32; 2]; 2]) }
+    }
+
+    /// Creates a 2x2 matrix with its diagonal set to `diagonal` and all other entries set to 0.
+    #[doc(alias = "scale")]
+    #[inline]
+    #[must_use]
+    pub const fn from_diagonal(diagonal: Vec2) -> Self {
+        Self::new(diagonal.x, 0.0, 0.0, diagonal.y)
+    }
+
+    /// Creates a 2x2 matrix containing the combining non-uniform `scale` and rotation of
+    /// `angle` (in radians).
+    #[inline]
+    #[must_use]
+    pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self {
+        let (sin, cos) = math::sin_cos(angle);
+        Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y)
+    }
+
+    /// Creates a 2x2 matrix containing a rotation of `angle` (in radians).
+    #[inline]
+    #[must_use]
+    pub fn from_angle(angle: f32) -> Self {
+        let (sin, cos) = math::sin_cos(angle);
+        Self::new(cos, sin, -sin, cos)
+    }
+
+    /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3(m: Mat3) -> Self {
+        Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
+    }
+
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a(m: Mat3A) -> Self {
+        Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
+    }
+
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Creates a 2x2 matrix from the first 4 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_slice(slice: &[f32]) -> Self {
+        Self::new(slice[0], slice[1], slice[2], slice[3])
+    }
+
+    /// Writes the columns of `self` to the first 4 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    pub fn write_cols_to_slice(self, slice: &mut [f32]) {
+        slice[0] = self.x_axis.x;
+        slice[1] = self.x_axis.y;
+        slice[2] = self.y_axis.x;
+        slice[3] = self.y_axis.y;
+    }
+
+    /// Returns the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 1.
+    #[inline]
+    #[must_use]
+    pub fn col(&self, index: usize) -> Vec2 {
+        match index {
+            0 => self.x_axis,
+            1 => self.y_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns a mutable reference to the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 1.
+    #[inline]
+    pub fn col_mut(&mut self, index: usize) -> &mut Vec2 {
+        match index {
+            0 => &mut self.x_axis,
+            1 => &mut self.y_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns the matrix row for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 1.
+    #[inline]
+    #[must_use]
+    pub fn row(&self, index: usize) -> Vec2 {
+        match index {
+            0 => Vec2::new(self.x_axis.x, self.y_axis.x),
+            1 => Vec2::new(self.x_axis.y, self.y_axis.y),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.
+    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(&self) -> bool {
+        self.x_axis.is_finite() && self.y_axis.is_finite()
+    }
+
+    /// Returns `true` if any elements are `NaN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(&self) -> bool {
+        self.x_axis.is_nan() || self.y_axis.is_nan()
+    }
+
+    /// Returns the transpose of `self`.
+    #[inline]
+    #[must_use]
+    pub fn transpose(&self) -> Self {
+        Self(unsafe {
+            vsetq_lane_f32(
+                vgetq_lane_f32(self.0, 2),
+                vsetq_lane_f32(vgetq_lane_f32(self.0, 1), self.0, 2),
+                1,
+            )
+        })
+    }
+
+    /// Returns the determinant of `self`.
+    #[inline]
+    #[must_use]
+    pub fn determinant(&self) -> f32 {
+        unsafe {
+            let abcd = self.0;
+            let badc = vrev64q_f32(abcd);
+            let dcba = vextq_f32(badc, badc, 2);
+            let prod = vmulq_f32(abcd, dcba);
+            let det = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
+            vgetq_lane_f32(det, 0)
+        }
+    }
+
+    /// Returns the inverse of `self`.
+    ///
+    /// If the matrix is not invertible the returned matrix will be invalid.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn inverse(&self) -> Self {
+        unsafe {
+            const SIGN: float32x4_t = crate::neon::f32x4_from_array([1.0, -1.0, -1.0, 1.0]);
+            let abcd = self.0;
+            let badc = vrev64q_f32(abcd);
+            let dcba = vextq_f32(badc, badc, 2);
+            let prod = vmulq_f32(abcd, dcba);
+            let sub = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
+            let det = vdupq_laneq_f32(sub, 0);
+            let tmp = vdivq_f32(SIGN, det);
+            glam_assert!(Mat2(tmp).is_finite());
+            //let dbca = simd_swizzle!(abcd, [3, 1, 2, 0]);
+            let dbca = vsetq_lane_f32(
+                vgetq_lane_f32(abcd, 0),
+                vsetq_lane_f32(vgetq_lane_f32(abcd, 3), abcd, 0),
+                3,
+            );
+            Self(vmulq_f32(dbca, tmp))
+        }
+    }
+
+    /// Transforms a 2D vector.
+    #[inline]
+    #[must_use]
+    pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 {
+        unsafe {
+            let abcd = self.0;
+            let xxyy = vld1q_f32([rhs.x, rhs.x, rhs.y, rhs.y].as_ptr());
+            let axbxcydy = vmulq_f32(abcd, xxyy);
+            // let cydyaxbx = simd_swizzle!(axbxcydy, [2, 3, 0, 1]);
+            let cydyaxbx = vextq_f32(axbxcydy, axbxcydy, 2);
+            let result = vaddq_f32(axbxcydy, cydyaxbx);
+            *(&result as *const float32x4_t as *const Vec2)
+        }
+    }
+
+    /// Multiplies two 2x2 matrices.
+    #[inline]
+    #[must_use]
+    pub fn mul_mat2(&self, rhs: &Self) -> Self {
+        unsafe {
+            let abcd = self.0;
+            let xxyy0 = vzip1q_f32(rhs.0, rhs.0);
+            let xxyy1 = vzip2q_f32(rhs.0, rhs.0);
+            let axbxcydy0 = vmulq_f32(abcd, xxyy0);
+            let axbxcydy1 = vmulq_f32(abcd, xxyy1);
+            let cydyaxbx0 = vextq_f32(axbxcydy0, axbxcydy0, 2);
+            let cydyaxbx1 = vextq_f32(axbxcydy1, axbxcydy1, 2);
+            let result0 = vaddq_f32(axbxcydy0, cydyaxbx0);
+            let result1 = vaddq_f32(axbxcydy1, cydyaxbx1);
+            Self(vreinterpretq_f32_u64(vsetq_lane_u64(
+                vgetq_lane_u64(vreinterpretq_u64_f32(result1), 0),
+                vreinterpretq_u64_f32(result0),
+                1,
+            )))
+        }
+    }
+
+    /// Adds two 2x2 matrices.
+    #[inline]
+    #[must_use]
+    pub fn add_mat2(&self, rhs: &Self) -> Self {
+        Self(unsafe { vaddq_f32(self.0, rhs.0) })
+    }
+
+    /// Subtracts two 2x2 matrices.
+    #[inline]
+    #[must_use]
+    pub fn sub_mat2(&self, rhs: &Self) -> Self {
+        Self(unsafe { vsubq_f32(self.0, rhs.0) })
+    }
+
+    /// Multiplies a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn mul_scalar(&self, rhs: f32) -> Self {
+        Self(unsafe { vmulq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs`
+    /// is less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two matrices contain similar elements. It works best
+    /// when comparing with a known value. The `max_abs_diff` that should be used used
+    /// depends on the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
+        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
+            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
+    }
+
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
+    #[inline]
+    pub fn as_dmat2(&self) -> DMat2 {
+        DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
+    }
+}
+
+impl Default for Mat2 {
+    #[inline]
+    fn default() -> Self {
+        Self::IDENTITY
+    }
+}
+
+impl Add<Mat2> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self::Output {
+        self.add_mat2(&rhs)
+    }
+}
+
+impl AddAssign<Mat2> for Mat2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        *self = self.add_mat2(&rhs);
+    }
+}
+
+impl Sub<Mat2> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self::Output {
+        self.sub_mat2(&rhs)
+    }
+}
+
+impl SubAssign<Mat2> for Mat2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: Self) {
+        *self = self.sub_mat2(&rhs);
+    }
+}
+
+impl Neg for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self::Output {
+        Self(unsafe { vnegq_f32(self.0) })
+    }
+}
+
+impl Mul<Mat2> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self::Output {
+        self.mul_mat2(&rhs)
+    }
+}
+
+impl MulAssign<Mat2> for Mat2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        *self = self.mul_mat2(&rhs);
+    }
+}
+
+impl Mul<Vec2> for Mat2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: Vec2) -> Self::Output {
+        self.mul_vec2(rhs)
+    }
+}
+
+impl Mul<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn mul(self, rhs: Mat2) -> Self::Output {
+        rhs.mul_scalar(self)
+    }
+}
+
+impl Mul<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: f32) -> Self::Output {
+        self.mul_scalar(rhs)
+    }
+}
+
+impl MulAssign<f32> for Mat2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: f32) {
+        *self = self.mul_scalar(rhs);
+    }
+}
+
+impl Div<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn div(self, rhs: Mat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
+impl Sum<Self> for Mat2 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Mat2 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Mat2 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::IDENTITY, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Mat2 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl PartialEq for Mat2 {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[f32; 4]> for Mat2 {
+    #[inline]
+    fn as_ref(&self) -> &[f32; 4] {
+        unsafe { &*(self as *const Self as *const [f32; 4]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[f32; 4]> for Mat2 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [f32; 4] {
+        unsafe { &mut *(self as *mut Self as *mut [f32; 4]) }
+    }
+}
+
+impl core::ops::Deref for Mat2 {
+    type Target = crate::deref::Cols2<Vec2>;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*(self as *const Self as *const Self::Target) }
+    }
+}
+
+impl core::ops::DerefMut for Mat2 {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { &mut *(self as *mut Self as *mut Self::Target) }
+    }
+}
+
+impl fmt::Debug for Mat2 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct(stringify!(Mat2))
+            .field("x_axis", &self.x_axis)
+            .field("y_axis", &self.y_axis)
+            .finish()
+    }
+}
+
+impl fmt::Display for Mat2 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
+    }
+}
diff --git a/crates/glam/src/f32/neon/mat3a.rs b/crates/glam/src/f32/neon/mat3a.rs
new file mode 100644
index 0000000..6fa8563
--- /dev/null
+++ b/crates/glam/src/f32/neon/mat3a.rs
@@ -0,0 +1,937 @@
+// Generated from mat.rs.tera template. Edit the template, not the generated file.
+
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+
+use core::arch::aarch64::*;
+
+/// Creates a 3x3 matrix from three column vectors.
+#[inline(always)]
+#[must_use]
+pub const fn mat3a(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Mat3A {
+    Mat3A::from_cols(x_axis, y_axis, z_axis)
+}
+
+/// A 3x3 column major matrix.
+///
+/// This 3x3 matrix type features convenience methods for creating and using linear and
+/// affine transformations. If you are primarily dealing with 2D affine transformations the
+/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than
+/// using a 3x3 matrix.
+///
+/// Linear transformations including 3D rotation and scale can be created using methods
+/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`],
+/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or
+/// [`Self::from_rotation_z()`].
+///
+/// The resulting matrices can be use to transform 3D vectors using regular vector
+/// multiplication.
+///
+/// Affine transformations including 2D translation, rotation and scale can be created
+/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`],
+/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`].
+///
+/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods
+/// are provided for performing affine transforms on 2D vectors and points. These multiply
+/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for
+/// vectors respectively. These methods assume that `Self` contains a valid affine
+/// transform.
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct Mat3A {
+    pub x_axis: Vec3A,
+    pub y_axis: Vec3A,
+    pub z_axis: Vec3A,
+}
+
+impl Mat3A {
+    /// A 3x3 matrix with all elements set to `0.0`.
+    pub const ZERO: Self = Self::from_cols(Vec3A::ZERO, Vec3A::ZERO, Vec3A::ZERO);
+
+    /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
+    pub const IDENTITY: Self = Self::from_cols(Vec3A::X, Vec3A::Y, Vec3A::Z);
+
+    /// All NAN:s.
+    pub const NAN: Self = Self::from_cols(Vec3A::NAN, Vec3A::NAN, Vec3A::NAN);
+
+    #[allow(clippy::too_many_arguments)]
+    #[inline(always)]
+    #[must_use]
+    const fn new(
+        m00: f32,
+        m01: f32,
+        m02: f32,
+        m10: f32,
+        m11: f32,
+        m12: f32,
+        m20: f32,
+        m21: f32,
+        m22: f32,
+    ) -> Self {
+        Self {
+            x_axis: Vec3A::new(m00, m01, m02),
+            y_axis: Vec3A::new(m10, m11, m12),
+            z_axis: Vec3A::new(m20, m21, m22),
+        }
+    }
+
+    /// Creates a 3x3 matrix from three column vectors.
+    #[inline(always)]
+    #[must_use]
+    pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Self {
+        Self {
+            x_axis,
+            y_axis,
+            z_axis,
+        }
+    }
+
+    /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order.
+    /// If your data is stored in row major you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array(m: &[f32; 9]) -> Self {
+        Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8])
+    }
+
+    /// Creates a `[f32; 9]` array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array(&self) -> [f32; 9] {
+        let [x_axis_x, x_axis_y, x_axis_z] = self.x_axis.to_array();
+        let [y_axis_x, y_axis_y, y_axis_z] = self.y_axis.to_array();
+        let [z_axis_x, z_axis_y, z_axis_z] = self.z_axis.to_array();
+
+        [
+            x_axis_x, x_axis_y, x_axis_z, y_axis_x, y_axis_y, y_axis_z, z_axis_x, z_axis_y,
+            z_axis_z,
+        ]
+    }
+
+    /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order.
+    /// If your data is in row major order you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self {
+        Self::from_cols(
+            Vec3A::from_array(m[0]),
+            Vec3A::from_array(m[1]),
+            Vec3A::from_array(m[2]),
+        )
+    }
+
+    /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array_2d(&self) -> [[f32; 3]; 3] {
+        [
+            self.x_axis.to_array(),
+            self.y_axis.to_array(),
+            self.z_axis.to_array(),
+        ]
+    }
+
+    /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0.
+    #[doc(alias = "scale")]
+    #[inline]
+    #[must_use]
+    pub const fn from_diagonal(diagonal: Vec3) -> Self {
+        Self::new(
+            diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z,
+        )
+    }
+
+    /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 4th row and column.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4(m: Mat4) -> Self {
+        Self::from_cols(
+            Vec3A::from_vec4(m.x_axis),
+            Vec3A::from_vec4(m.y_axis),
+            Vec3A::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (0, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (0, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (0, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (1, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (1, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (1, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (1, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (2, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (2, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (2, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (2, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (3, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+            ),
+            (3, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+            ),
+            (3, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+            ),
+            (3, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+            ),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Creates a 3D rotation matrix from the given quaternion.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_quat(rotation: Quat) -> Self {
+        glam_assert!(rotation.is_normalized());
+
+        let x2 = rotation.x + rotation.x;
+        let y2 = rotation.y + rotation.y;
+        let z2 = rotation.z + rotation.z;
+        let xx = rotation.x * x2;
+        let xy = rotation.x * y2;
+        let xz = rotation.x * z2;
+        let yy = rotation.y * y2;
+        let yz = rotation.y * z2;
+        let zz = rotation.z * z2;
+        let wx = rotation.w * x2;
+        let wy = rotation.w * y2;
+        let wz = rotation.w * z2;
+
+        Self::from_cols(
+            Vec3A::new(1.0 - (yy + zz), xy + wz, xz - wy),
+            Vec3A::new(xy - wz, 1.0 - (xx + zz), yz + wx),
+            Vec3A::new(xz + wy, yz - wx, 1.0 - (xx + yy)),
+        )
+    }
+
+    /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in
+    /// radians).
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
+        glam_assert!(axis.is_normalized());
+
+        let (sin, cos) = math::sin_cos(angle);
+        let (xsin, ysin, zsin) = axis.mul(sin).into();
+        let (x, y, z) = axis.into();
+        let (x2, y2, z2) = axis.mul(axis).into();
+        let omc = 1.0 - cos;
+        let xyomc = x * y * omc;
+        let xzomc = x * z * omc;
+        let yzomc = y * z * omc;
+        Self::from_cols(
+            Vec3A::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin),
+            Vec3A::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin),
+            Vec3A::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos),
+        )
+    }
+
+    /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in
+    /// radians).
+    #[inline]
+    #[must_use]
+    pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
+    }
+
+    /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_x(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec3A::X,
+            Vec3A::new(0.0, cosa, sina),
+            Vec3A::new(0.0, -sina, cosa),
+        )
+    }
+
+    /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_y(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec3A::new(cosa, 0.0, -sina),
+            Vec3A::Y,
+            Vec3A::new(sina, 0.0, cosa),
+        )
+    }
+
+    /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_z(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec3A::new(cosa, sina, 0.0),
+            Vec3A::new(-sina, cosa, 0.0),
+            Vec3A::Z,
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 2D `translation`.
+    ///
+    /// The resulting matrix can be used to transform 2D points and vectors. See
+    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
+    #[inline]
+    #[must_use]
+    pub fn from_translation(translation: Vec2) -> Self {
+        Self::from_cols(
+            Vec3A::X,
+            Vec3A::Y,
+            Vec3A::new(translation.x, translation.y, 1.0),
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 2D rotation `angle` (in
+    /// radians).
+    ///
+    /// The resulting matrix can be used to transform 2D points and vectors. See
+    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
+    #[inline]
+    #[must_use]
+    pub fn from_angle(angle: f32) -> Self {
+        let (sin, cos) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec3A::new(cos, sin, 0.0),
+            Vec3A::new(-sin, cos, 0.0),
+            Vec3A::Z,
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in
+    /// radians) and `translation`.
+    ///
+    /// The resulting matrix can be used to transform 2D points and vectors. See
+    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
+    #[inline]
+    #[must_use]
+    pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self {
+        let (sin, cos) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec3A::new(cos * scale.x, sin * scale.x, 0.0),
+            Vec3A::new(-sin * scale.y, cos * scale.y, 0.0),
+            Vec3A::new(translation.x, translation.y, 1.0),
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given non-uniform 2D `scale`.
+    ///
+    /// The resulting matrix can be used to transform 2D points and vectors. See
+    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_scale(scale: Vec2) -> Self {
+        // Do not panic as long as any component is non-zero
+        glam_assert!(scale.cmpne(Vec2::ZERO).any());
+
+        Self::from_cols(
+            Vec3A::new(scale.x, 0.0, 0.0),
+            Vec3A::new(0.0, scale.y, 0.0),
+            Vec3A::Z,
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 2x2 matrix.
+    ///
+    /// The resulting matrix can be used to transform 2D points and vectors. See
+    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
+    #[inline]
+    pub fn from_mat2(m: Mat2) -> Self {
+        Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3A::Z)
+    }
+
+    /// Creates a 3x3 matrix from the first 9 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 9 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_slice(slice: &[f32]) -> Self {
+        Self::new(
+            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
+            slice[8],
+        )
+    }
+
+    /// Writes the columns of `self` to the first 9 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 9 elements long.
+    #[inline]
+    pub fn write_cols_to_slice(self, slice: &mut [f32]) {
+        slice[0] = self.x_axis.x;
+        slice[1] = self.x_axis.y;
+        slice[2] = self.x_axis.z;
+        slice[3] = self.y_axis.x;
+        slice[4] = self.y_axis.y;
+        slice[5] = self.y_axis.z;
+        slice[6] = self.z_axis.x;
+        slice[7] = self.z_axis.y;
+        slice[8] = self.z_axis.z;
+    }
+
+    /// Returns the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn col(&self, index: usize) -> Vec3A {
+        match index {
+            0 => self.x_axis,
+            1 => self.y_axis,
+            2 => self.z_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns a mutable reference to the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 2.
+    #[inline]
+    pub fn col_mut(&mut self, index: usize) -> &mut Vec3A {
+        match index {
+            0 => &mut self.x_axis,
+            1 => &mut self.y_axis,
+            2 => &mut self.z_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns the matrix row for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn row(&self, index: usize) -> Vec3A {
+        match index {
+            0 => Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x),
+            1 => Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y),
+            2 => Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.
+    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(&self) -> bool {
+        self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite()
+    }
+
+    /// Returns `true` if any elements are `NaN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(&self) -> bool {
+        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan()
+    }
+
+    /// Returns the transpose of `self`.
+    #[inline]
+    #[must_use]
+    pub fn transpose(&self) -> Self {
+        let x = self.x_axis.0;
+        let y = self.y_axis.0;
+        let z = self.z_axis.0;
+        unsafe {
+            let tmp0 = vreinterpretq_f32_u64(vsetq_lane_u64(
+                vgetq_lane_u64(vreinterpretq_u64_f32(y), 0),
+                vreinterpretq_u64_f32(x),
+                1,
+            ));
+            let tmp1 = vreinterpretq_f32_u64(vzip2q_u64(
+                vreinterpretq_u64_f32(x),
+                vreinterpretq_u64_f32(y),
+            ));
+            Mat3A::from_cols(
+                Vec3A::from(vsetq_lane_f32(vgetq_lane_f32(z, 0), vuzp1q_f32(tmp0, z), 3)),
+                Vec3A::from(vuzp2q_f32(tmp0, vdupq_laneq_f32(z, 1))),
+                Vec3A::from(vsetq_lane_f32(vgetq_lane_f32(z, 2), vuzp1q_f32(tmp1, z), 2)),
+            )
+        }
+    }
+
+    /// Returns the determinant of `self`.
+    #[inline]
+    #[must_use]
+    pub fn determinant(&self) -> f32 {
+        self.z_axis.dot(self.x_axis.cross(self.y_axis))
+    }
+
+    /// Returns the inverse of `self`.
+    ///
+    /// If the matrix is not invertible the returned matrix will be invalid.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn inverse(&self) -> Self {
+        let tmp0 = self.y_axis.cross(self.z_axis);
+        let tmp1 = self.z_axis.cross(self.x_axis);
+        let tmp2 = self.x_axis.cross(self.y_axis);
+        let det = self.z_axis.dot(tmp2);
+        glam_assert!(det != 0.0);
+        let inv_det = Vec3A::splat(det.recip());
+        Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose()
+    }
+
+    /// Transforms the given 2D vector as a point.
+    ///
+    /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`.
+    ///
+    /// This method assumes that `self` contains a valid affine transform.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn transform_point2(&self, rhs: Vec2) -> Vec2 {
+        glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6));
+        Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy()
+    }
+
+    /// Rotates the given 2D vector.
+    ///
+    /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`.
+    ///
+    /// This method assumes that `self` contains a valid affine transform.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 {
+        glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6));
+        Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs
+    }
+
+    /// Transforms a 3D vector.
+    #[inline]
+    #[must_use]
+    pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 {
+        self.mul_vec3a(rhs.into()).into()
+    }
+
+    /// Transforms a [`Vec3A`].
+    #[inline]
+    #[must_use]
+    pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A {
+        let mut res = self.x_axis.mul(rhs.xxx());
+        res = res.add(self.y_axis.mul(rhs.yyy()));
+        res = res.add(self.z_axis.mul(rhs.zzz()));
+        res
+    }
+
+    /// Multiplies two 3x3 matrices.
+    #[inline]
+    #[must_use]
+    pub fn mul_mat3(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.mul(rhs.x_axis),
+            self.mul(rhs.y_axis),
+            self.mul(rhs.z_axis),
+        )
+    }
+
+    /// Adds two 3x3 matrices.
+    #[inline]
+    #[must_use]
+    pub fn add_mat3(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.x_axis.add(rhs.x_axis),
+            self.y_axis.add(rhs.y_axis),
+            self.z_axis.add(rhs.z_axis),
+        )
+    }
+
+    /// Subtracts two 3x3 matrices.
+    #[inline]
+    #[must_use]
+    pub fn sub_mat3(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.x_axis.sub(rhs.x_axis),
+            self.y_axis.sub(rhs.y_axis),
+            self.z_axis.sub(rhs.z_axis),
+        )
+    }
+
+    /// Multiplies a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn mul_scalar(&self, rhs: f32) -> Self {
+        Self::from_cols(
+            self.x_axis.mul(rhs),
+            self.y_axis.mul(rhs),
+            self.z_axis.mul(rhs),
+        )
+    }
+
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3A::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs`
+    /// is less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two matrices contain similar elements. It works best
+    /// when comparing with a known value. The `max_abs_diff` that should be used used
+    /// depends on the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
+        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
+            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
+            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
+    }
+
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
+    #[inline]
+    pub fn as_dmat3(&self) -> DMat3 {
+        DMat3::from_cols(
+            self.x_axis.as_dvec3(),
+            self.y_axis.as_dvec3(),
+            self.z_axis.as_dvec3(),
+        )
+    }
+}
+
+impl Default for Mat3A {
+    #[inline]
+    fn default() -> Self {
+        Self::IDENTITY
+    }
+}
+
+impl Add<Mat3A> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self::Output {
+        self.add_mat3(&rhs)
+    }
+}
+
+impl AddAssign<Mat3A> for Mat3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        *self = self.add_mat3(&rhs);
+    }
+}
+
+impl Sub<Mat3A> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self::Output {
+        self.sub_mat3(&rhs)
+    }
+}
+
+impl SubAssign<Mat3A> for Mat3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: Self) {
+        *self = self.sub_mat3(&rhs);
+    }
+}
+
+impl Neg for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self::Output {
+        Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg())
+    }
+}
+
+impl Mul<Mat3A> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self::Output {
+        self.mul_mat3(&rhs)
+    }
+}
+
+impl MulAssign<Mat3A> for Mat3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        *self = self.mul_mat3(&rhs);
+    }
+}
+
+impl Mul<Vec3A> for Mat3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Self::Output {
+        self.mul_vec3a(rhs)
+    }
+}
+
+impl Mul<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn mul(self, rhs: Mat3A) -> Self::Output {
+        rhs.mul_scalar(self)
+    }
+}
+
+impl Mul<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: f32) -> Self::Output {
+        self.mul_scalar(rhs)
+    }
+}
+
+impl MulAssign<f32> for Mat3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: f32) {
+        *self = self.mul_scalar(rhs);
+    }
+}
+
+impl Div<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn div(self, rhs: Mat3A) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
+impl Mul<Vec3> for Mat3A {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: Vec3) -> Vec3 {
+        self.mul_vec3a(rhs.into()).into()
+    }
+}
+
+impl From<Mat3> for Mat3A {
+    #[inline]
+    fn from(m: Mat3) -> Self {
+        Self {
+            x_axis: m.x_axis.into(),
+            y_axis: m.y_axis.into(),
+            z_axis: m.z_axis.into(),
+        }
+    }
+}
+
+impl Sum<Self> for Mat3A {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Mat3A {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Mat3A {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::IDENTITY, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Mat3A {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl PartialEq for Mat3A {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis)
+    }
+}
+
+impl fmt::Debug for Mat3A {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct(stringify!(Mat3A))
+            .field("x_axis", &self.x_axis)
+            .field("y_axis", &self.y_axis)
+            .field("z_axis", &self.z_axis)
+            .finish()
+    }
+}
+
+impl fmt::Display for Mat3A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
+    }
+}
diff --git a/crates/glam/src/f32/neon/mat4.rs b/crates/glam/src/f32/neon/mat4.rs
new file mode 100644
index 0000000..670e198
--- /dev/null
+++ b/crates/glam/src/f32/neon/mat4.rs
@@ -0,0 +1,1541 @@
+// Generated from mat.rs.tera template. Edit the template, not the generated file.
+
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    neon::*,
+    swizzles::*,
+    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
+};
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+
+use core::arch::aarch64::*;
+
+/// Creates a 4x4 matrix from four column vectors.
+#[inline(always)]
+#[must_use]
+pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 {
+    Mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
+}
+
+/// A 4x4 column major matrix.
+///
+/// This 4x4 matrix type features convenience methods for creating and using affine transforms and
+/// perspective projections. If you are primarily dealing with 3D affine transformations
+/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix
+/// for some affine operations.
+///
+/// Affine transformations including 3D translation, rotation and scale can be created
+/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
+/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
+///
+/// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
+/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
+/// systems. The resulting matrix is also an affine transformation.
+///
+/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
+/// are provided for performing affine transformations on 3D vectors and points. These
+/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
+/// for vectors respectively. These methods assume that `Self` contains a valid affine
+/// transform.
+///
+/// Perspective projections can be created using methods such as
+/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
+/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
+/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
+/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
+///
+/// The resulting perspective project can be use to transform 3D vectors as points with
+/// perspective correction using the [`Self::project_point3()`] convenience method.
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct Mat4 {
+    pub x_axis: Vec4,
+    pub y_axis: Vec4,
+    pub z_axis: Vec4,
+    pub w_axis: Vec4,
+}
+
+impl Mat4 {
+    /// A 4x4 matrix with all elements set to `0.0`.
+    pub const ZERO: Self = Self::from_cols(Vec4::ZERO, Vec4::ZERO, Vec4::ZERO, Vec4::ZERO);
+
+    /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
+    pub const IDENTITY: Self = Self::from_cols(Vec4::X, Vec4::Y, Vec4::Z, Vec4::W);
+
+    /// All NAN:s.
+    pub const NAN: Self = Self::from_cols(Vec4::NAN, Vec4::NAN, Vec4::NAN, Vec4::NAN);
+
+    #[allow(clippy::too_many_arguments)]
+    #[inline(always)]
+    #[must_use]
+    const fn new(
+        m00: f32,
+        m01: f32,
+        m02: f32,
+        m03: f32,
+        m10: f32,
+        m11: f32,
+        m12: f32,
+        m13: f32,
+        m20: f32,
+        m21: f32,
+        m22: f32,
+        m23: f32,
+        m30: f32,
+        m31: f32,
+        m32: f32,
+        m33: f32,
+    ) -> Self {
+        Self {
+            x_axis: Vec4::new(m00, m01, m02, m03),
+            y_axis: Vec4::new(m10, m11, m12, m13),
+            z_axis: Vec4::new(m20, m21, m22, m23),
+            w_axis: Vec4::new(m30, m31, m32, m33),
+        }
+    }
+
+    /// Creates a 4x4 matrix from four column vectors.
+    #[inline(always)]
+    #[must_use]
+    pub const fn from_cols(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Self {
+        Self {
+            x_axis,
+            y_axis,
+            z_axis,
+            w_axis,
+        }
+    }
+
+    /// Creates a 4x4 matrix from a `[f32; 16]` array stored in column major order.
+    /// If your data is stored in row major you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array(m: &[f32; 16]) -> Self {
+        Self::new(
+            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
+            m[14], m[15],
+        )
+    }
+
+    /// Creates a `[f32; 16]` array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array(&self) -> [f32; 16] {
+        let [x_axis_x, x_axis_y, x_axis_z, x_axis_w] = self.x_axis.to_array();
+        let [y_axis_x, y_axis_y, y_axis_z, y_axis_w] = self.y_axis.to_array();
+        let [z_axis_x, z_axis_y, z_axis_z, z_axis_w] = self.z_axis.to_array();
+        let [w_axis_x, w_axis_y, w_axis_z, w_axis_w] = self.w_axis.to_array();
+
+        [
+            x_axis_x, x_axis_y, x_axis_z, x_axis_w, y_axis_x, y_axis_y, y_axis_z, y_axis_w,
+            z_axis_x, z_axis_y, z_axis_z, z_axis_w, w_axis_x, w_axis_y, w_axis_z, w_axis_w,
+        ]
+    }
+
+    /// Creates a 4x4 matrix from a `[[f32; 4]; 4]` 4D array stored in column major order.
+    /// If your data is in row major order you will need to `transpose` the returned
+    /// matrix.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_array_2d(m: &[[f32; 4]; 4]) -> Self {
+        Self::from_cols(
+            Vec4::from_array(m[0]),
+            Vec4::from_array(m[1]),
+            Vec4::from_array(m[2]),
+            Vec4::from_array(m[3]),
+        )
+    }
+
+    /// Creates a `[[f32; 4]; 4]` 4D array storing data in column major order.
+    /// If you require data in row major order `transpose` the matrix first.
+    #[inline]
+    #[must_use]
+    pub const fn to_cols_array_2d(&self) -> [[f32; 4]; 4] {
+        [
+            self.x_axis.to_array(),
+            self.y_axis.to_array(),
+            self.z_axis.to_array(),
+            self.w_axis.to_array(),
+        ]
+    }
+
+    /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
+    #[doc(alias = "scale")]
+    #[inline]
+    #[must_use]
+    pub const fn from_diagonal(diagonal: Vec4) -> Self {
+        // diagonal.x, diagonal.y etc can't be done in a const-context
+        let [x, y, z, w] = diagonal.to_array();
+        Self::new(
+            x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, w,
+        )
+    }
+
+    #[inline]
+    #[must_use]
+    fn quat_to_axes(rotation: Quat) -> (Vec4, Vec4, Vec4) {
+        glam_assert!(rotation.is_normalized());
+
+        let (x, y, z, w) = rotation.into();
+        let x2 = x + x;
+        let y2 = y + y;
+        let z2 = z + z;
+        let xx = x * x2;
+        let xy = x * y2;
+        let xz = x * z2;
+        let yy = y * y2;
+        let yz = y * z2;
+        let zz = z * z2;
+        let wx = w * x2;
+        let wy = w * y2;
+        let wz = w * z2;
+
+        let x_axis = Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
+        let y_axis = Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
+        let z_axis = Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
+        (x_axis, y_axis, z_axis)
+    }
+
+    /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
+    /// `translation`.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
+        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
+        Self::from_cols(
+            x_axis.mul(scale.x),
+            y_axis.mul(scale.y),
+            z_axis.mul(scale.z),
+            Vec4::from((translation, 1.0)),
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 3D `translation`.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
+        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
+        Self::from_cols(x_axis, y_axis, z_axis, Vec4::from((translation, 1.0)))
+    }
+
+    /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
+    /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the determinant of `self` is zero or if the resulting scale vector
+    /// contains any zero elements when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
+        let det = self.determinant();
+        glam_assert!(det != 0.0);
+
+        let scale = Vec3::new(
+            self.x_axis.length() * math::signum(det),
+            self.y_axis.length(),
+            self.z_axis.length(),
+        );
+
+        glam_assert!(scale.cmpne(Vec3::ZERO).all());
+
+        let inv_scale = scale.recip();
+
+        let rotation = Quat::from_rotation_axes(
+            self.x_axis.mul(inv_scale.x).xyz(),
+            self.y_axis.mul(inv_scale.y).xyz(),
+            self.z_axis.mul(inv_scale.z).xyz(),
+        );
+
+        let translation = self.w_axis.xyz();
+
+        (scale, rotation, translation)
+    }
+
+    /// Creates an affine transformation matrix from the given `rotation` quaternion.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_quat(rotation: Quat) -> Self {
+        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
+        Self::from_cols(x_axis, y_axis, z_axis, Vec4::W)
+    }
+
+    /// Creates an affine transformation matrix from the given 3x3 linear transformation
+    /// matrix.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_mat3(m: Mat3) -> Self {
+        Self::from_cols(
+            Vec4::from((m.x_axis, 0.0)),
+            Vec4::from((m.y_axis, 0.0)),
+            Vec4::from((m.z_axis, 0.0)),
+            Vec4::W,
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 3x3 linear transformation
+    /// matrix.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a(m: Mat3A) -> Self {
+        Self::from_cols(
+            Vec4::from((m.x_axis, 0.0)),
+            Vec4::from((m.y_axis, 0.0)),
+            Vec4::from((m.z_axis, 0.0)),
+            Vec4::W,
+        )
+    }
+
+    /// Creates an affine transformation matrix from the given 3D `translation`.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_translation(translation: Vec3) -> Self {
+        Self::from_cols(
+            Vec4::X,
+            Vec4::Y,
+            Vec4::Z,
+            Vec4::new(translation.x, translation.y, translation.z, 1.0),
+        )
+    }
+
+    /// Creates an affine transformation matrix containing a 3D rotation around a normalized
+    /// rotation `axis` of `angle` (in radians).
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
+        glam_assert!(axis.is_normalized());
+
+        let (sin, cos) = math::sin_cos(angle);
+        let axis_sin = axis.mul(sin);
+        let axis_sq = axis.mul(axis);
+        let omc = 1.0 - cos;
+        let xyomc = axis.x * axis.y * omc;
+        let xzomc = axis.x * axis.z * omc;
+        let yzomc = axis.y * axis.z * omc;
+        Self::from_cols(
+            Vec4::new(
+                axis_sq.x * omc + cos,
+                xyomc + axis_sin.z,
+                xzomc - axis_sin.y,
+                0.0,
+            ),
+            Vec4::new(
+                xyomc - axis_sin.z,
+                axis_sq.y * omc + cos,
+                yzomc + axis_sin.x,
+                0.0,
+            ),
+            Vec4::new(
+                xzomc + axis_sin.y,
+                yzomc - axis_sin.x,
+                axis_sq.z * omc + cos,
+                0.0,
+            ),
+            Vec4::W,
+        )
+    }
+
+    /// Creates a affine transformation matrix containing a rotation from the given euler
+    /// rotation sequence and angles (in radians).
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
+    }
+
+    /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
+    /// `angle` (in radians).
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_x(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec4::X,
+            Vec4::new(0.0, cosa, sina, 0.0),
+            Vec4::new(0.0, -sina, cosa, 0.0),
+            Vec4::W,
+        )
+    }
+
+    /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
+    /// `angle` (in radians).
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_y(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec4::new(cosa, 0.0, -sina, 0.0),
+            Vec4::Y,
+            Vec4::new(sina, 0.0, cosa, 0.0),
+            Vec4::W,
+        )
+    }
+
+    /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
+    /// `angle` (in radians).
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_z(angle: f32) -> Self {
+        let (sina, cosa) = math::sin_cos(angle);
+        Self::from_cols(
+            Vec4::new(cosa, sina, 0.0, 0.0),
+            Vec4::new(-sina, cosa, 0.0, 0.0),
+            Vec4::Z,
+            Vec4::W,
+        )
+    }
+
+    /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
+    ///
+    /// The resulting matrix can be used to transform 3D points and vectors. See
+    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
+    ///
+    /// # Panics
+    ///
+    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_scale(scale: Vec3) -> Self {
+        // Do not panic as long as any component is non-zero
+        glam_assert!(scale.cmpne(Vec3::ZERO).any());
+
+        Self::from_cols(
+            Vec4::new(scale.x, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, scale.y, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, scale.z, 0.0),
+            Vec4::W,
+        )
+    }
+
+    /// Creates a 4x4 matrix from the first 16 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 16 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_cols_slice(slice: &[f32]) -> Self {
+        Self::new(
+            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
+            slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
+        )
+    }
+
+    /// Writes the columns of `self` to the first 16 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 16 elements long.
+    #[inline]
+    pub fn write_cols_to_slice(self, slice: &mut [f32]) {
+        slice[0] = self.x_axis.x;
+        slice[1] = self.x_axis.y;
+        slice[2] = self.x_axis.z;
+        slice[3] = self.x_axis.w;
+        slice[4] = self.y_axis.x;
+        slice[5] = self.y_axis.y;
+        slice[6] = self.y_axis.z;
+        slice[7] = self.y_axis.w;
+        slice[8] = self.z_axis.x;
+        slice[9] = self.z_axis.y;
+        slice[10] = self.z_axis.z;
+        slice[11] = self.z_axis.w;
+        slice[12] = self.w_axis.x;
+        slice[13] = self.w_axis.y;
+        slice[14] = self.w_axis.z;
+        slice[15] = self.w_axis.w;
+    }
+
+    /// Returns the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn col(&self, index: usize) -> Vec4 {
+        match index {
+            0 => self.x_axis,
+            1 => self.y_axis,
+            2 => self.z_axis,
+            3 => self.w_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns a mutable reference to the matrix column for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 3.
+    #[inline]
+    pub fn col_mut(&mut self, index: usize) -> &mut Vec4 {
+        match index {
+            0 => &mut self.x_axis,
+            1 => &mut self.y_axis,
+            2 => &mut self.z_axis,
+            3 => &mut self.w_axis,
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns the matrix row for the given `index`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn row(&self, index: usize) -> Vec4 {
+        match index {
+            0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
+            1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
+            2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
+            3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.
+    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(&self) -> bool {
+        self.x_axis.is_finite()
+            && self.y_axis.is_finite()
+            && self.z_axis.is_finite()
+            && self.w_axis.is_finite()
+    }
+
+    /// Returns `true` if any elements are `NaN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(&self) -> bool {
+        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
+    }
+
+    /// Returns the transpose of `self`.
+    #[inline]
+    #[must_use]
+    pub fn transpose(&self) -> Self {
+        Self {
+            x_axis: Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
+            y_axis: Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
+            z_axis: Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
+            w_axis: Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
+        }
+    }
+
+    /// Returns the determinant of `self`.
+    #[must_use]
+    pub fn determinant(&self) -> f32 {
+        let (m00, m01, m02, m03) = self.x_axis.into();
+        let (m10, m11, m12, m13) = self.y_axis.into();
+        let (m20, m21, m22, m23) = self.z_axis.into();
+        let (m30, m31, m32, m33) = self.w_axis.into();
+
+        let a2323 = m22 * m33 - m23 * m32;
+        let a1323 = m21 * m33 - m23 * m31;
+        let a1223 = m21 * m32 - m22 * m31;
+        let a0323 = m20 * m33 - m23 * m30;
+        let a0223 = m20 * m32 - m22 * m30;
+        let a0123 = m20 * m31 - m21 * m30;
+
+        m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
+            - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
+            + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
+            - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
+    }
+
+    /// Returns the inverse of `self`.
+    ///
+    /// If the matrix is not invertible the returned matrix will be invalid.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
+    #[must_use]
+    pub fn inverse(&self) -> Self {
+        unsafe {
+            // Based on https://github.com/g-truc/glm `glm_mat4_inverse`
+            let swizzle3377 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vuzp2q_f32(a, b);
+                vtrn2q_f32(r, r)
+            };
+            let swizzle2266 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vuzp1q_f32(a, b);
+                vtrn2q_f32(r, r)
+            };
+            let swizzle0046 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vuzp1q_f32(a, a);
+                vuzp1q_f32(r, b)
+            };
+            let swizzle1155 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vzip1q_f32(a, b);
+                vzip2q_f32(r, r)
+            };
+            let swizzle0044 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vuzp1q_f32(a, b);
+                vtrn1q_f32(r, r)
+            };
+            let swizzle0266 = |a: float32x4_t, b: float32x4_t| -> float32x4_t {
+                let r = vuzp1q_f32(a, b);
+                vsetq_lane_f32(vgetq_lane_f32(b, 2), r, 2)
+            };
+            let swizzle0246 = |a: float32x4_t, b: float32x4_t| -> float32x4_t { vuzp1q_f32(a, b) };
+            let fac0 = {
+                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle2266(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle2266(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+            let fac1 = {
+                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle1155(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle1155(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+            let fac2 = {
+                let swp0a = swizzle2266(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle1155(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle1155(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle2266(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+            let fac3 = {
+                let swp0a = swizzle3377(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle3377(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+            let fac4 = {
+                let swp0a = swizzle2266(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle2266(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+            let fac5 = {
+                let swp0a = swizzle1155(self.w_axis.0, self.z_axis.0);
+                let swp0b = swizzle0044(self.w_axis.0, self.z_axis.0);
+
+                let swp00 = swizzle0044(self.z_axis.0, self.y_axis.0);
+                let swp01 = swizzle0046(swp0a, swp0a);
+                let swp02 = swizzle0046(swp0b, swp0b);
+                let swp03 = swizzle1155(self.z_axis.0, self.y_axis.0);
+
+                let mul00 = vmulq_f32(swp00, swp01);
+                let mul01 = vmulq_f32(swp02, swp03);
+                vsubq_f32(mul00, mul01)
+            };
+
+            const SIGN_A: float32x4_t = Vec4::new(-1.0, 1.0, -1.0, 1.0).0;
+            const SIGN_B: float32x4_t = Vec4::new(1.0, -1.0, 1.0, -1.0).0;
+
+            let temp0 = swizzle0044(self.y_axis.0, self.x_axis.0);
+            let vec0 = swizzle0266(temp0, temp0);
+
+            let temp1 = swizzle1155(self.y_axis.0, self.x_axis.0);
+            let vec1 = swizzle0266(temp1, temp1);
+
+            let temp2 = swizzle2266(self.y_axis.0, self.x_axis.0);
+            let vec2 = swizzle0266(temp2, temp2);
+
+            let temp3 = swizzle3377(self.y_axis.0, self.x_axis.0);
+            let vec3 = swizzle0266(temp3, temp3);
+
+            let mul00 = vmulq_f32(vec1, fac0);
+            let mul01 = vmulq_f32(vec2, fac1);
+            let mul02 = vmulq_f32(vec3, fac2);
+            let sub00 = vsubq_f32(mul00, mul01);
+            let add00 = vaddq_f32(sub00, mul02);
+            let inv0 = vmulq_f32(SIGN_B, add00);
+
+            let mul03 = vmulq_f32(vec0, fac0);
+            let mul04 = vmulq_f32(vec2, fac3);
+            let mul05 = vmulq_f32(vec3, fac4);
+            let sub01 = vsubq_f32(mul03, mul04);
+            let add01 = vaddq_f32(sub01, mul05);
+            let inv1 = vmulq_f32(SIGN_A, add01);
+
+            let mul06 = vmulq_f32(vec0, fac1);
+            let mul07 = vmulq_f32(vec1, fac3);
+            let mul08 = vmulq_f32(vec3, fac5);
+            let sub02 = vsubq_f32(mul06, mul07);
+            let add02 = vaddq_f32(sub02, mul08);
+            let inv2 = vmulq_f32(SIGN_B, add02);
+
+            let mul09 = vmulq_f32(vec0, fac2);
+            let mul10 = vmulq_f32(vec1, fac4);
+            let mul11 = vmulq_f32(vec2, fac5);
+            let sub03 = vsubq_f32(mul09, mul10);
+            let add03 = vaddq_f32(sub03, mul11);
+            let inv3 = vmulq_f32(SIGN_A, add03);
+
+            let row0 = swizzle0044(inv0, inv1);
+            let row1 = swizzle0044(inv2, inv3);
+            let row2 = swizzle0246(row0, row1);
+
+            let dot0 = dot4(self.x_axis.0, row2);
+            glam_assert!(dot0 != 0.0);
+
+            let rcp0 = dot0.recip();
+
+            Self {
+                x_axis: Vec4(vmulq_n_f32(inv0, rcp0)),
+                y_axis: Vec4(vmulq_n_f32(inv1, rcp0)),
+                z_axis: Vec4(vmulq_n_f32(inv2, rcp0)),
+                w_axis: Vec4(vmulq_n_f32(inv3, rcp0)),
+            }
+        }
+    }
+
+    /// Creates a left-handed view matrix using a camera position, an up direction, and a facing
+    /// direction.
+    ///
+    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
+    #[inline]
+    #[must_use]
+    pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
+        Self::look_to_rh(eye, -dir, up)
+    }
+
+    /// Creates a right-handed view matrix using a camera position, an up direction, and a facing
+    /// direction.
+    ///
+    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
+    #[inline]
+    #[must_use]
+    pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
+        let f = dir.normalize();
+        let s = f.cross(up).normalize();
+        let u = s.cross(f);
+
+        Self::from_cols(
+            Vec4::new(s.x, u.x, -f.x, 0.0),
+            Vec4::new(s.y, u.y, -f.y, 0.0),
+            Vec4::new(s.z, u.z, -f.z, 0.0),
+            Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
+        )
+    }
+
+    /// Creates a left-handed view matrix using a camera position, an up direction, and a focal
+    /// point.
+    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
+        glam_assert!(up.is_normalized());
+        Self::look_to_lh(eye, center.sub(eye), up)
+    }
+
+    /// Creates a right-handed view matrix using a camera position, an up direction, and a focal
+    /// point.
+    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
+        glam_assert!(up.is_normalized());
+        Self::look_to_rh(eye, center.sub(eye), up)
+    }
+
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
+    /// This is the same as the OpenGL `gluPerspective` function.
+    /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
+    #[inline]
+    #[must_use]
+    pub fn perspective_rh_gl(
+        fov_y_radians: f32,
+        aspect_ratio: f32,
+        z_near: f32,
+        z_far: f32,
+    ) -> Self {
+        let inv_length = 1.0 / (z_near - z_far);
+        let f = 1.0 / math::tan(0.5 * fov_y_radians);
+        let a = f / aspect_ratio;
+        let b = (z_near + z_far) * inv_length;
+        let c = (2.0 * z_near * z_far) * inv_length;
+        Self::from_cols(
+            Vec4::new(a, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, f, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, b, -1.0),
+            Vec4::new(0.0, 0.0, c, 0.0),
+        )
+    }
+
+    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
+        glam_assert!(z_near > 0.0 && z_far > 0.0);
+        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
+        let h = cos_fov / sin_fov;
+        let w = h / aspect_ratio;
+        let r = z_far / (z_far - z_near);
+        Self::from_cols(
+            Vec4::new(w, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, h, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, r, 1.0),
+            Vec4::new(0.0, 0.0, -r * z_near, 0.0),
+        )
+    }
+
+    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
+        glam_assert!(z_near > 0.0 && z_far > 0.0);
+        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
+        let h = cos_fov / sin_fov;
+        let w = h / aspect_ratio;
+        let r = z_far / (z_near - z_far);
+        Self::from_cols(
+            Vec4::new(w, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, h, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, r, -1.0),
+            Vec4::new(0.0, 0.0, r * z_near, 0.0),
+        )
+    }
+
+    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
+        glam_assert!(z_near > 0.0);
+        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
+        let h = cos_fov / sin_fov;
+        let w = h / aspect_ratio;
+        Self::from_cols(
+            Vec4::new(w, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, h, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, 1.0, 1.0),
+            Vec4::new(0.0, 0.0, -z_near, 0.0),
+        )
+    }
+
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_infinite_reverse_lh(
+        fov_y_radians: f32,
+        aspect_ratio: f32,
+        z_near: f32,
+    ) -> Self {
+        glam_assert!(z_near > 0.0);
+        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
+        let h = cos_fov / sin_fov;
+        let w = h / aspect_ratio;
+        Self::from_cols(
+            Vec4::new(w, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, h, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, 0.0, 1.0),
+            Vec4::new(0.0, 0.0, z_near, 0.0),
+        )
+    }
+
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
+        glam_assert!(z_near > 0.0);
+        let f = 1.0 / math::tan(0.5 * fov_y_radians);
+        Self::from_cols(
+            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, f, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, -1.0, -1.0),
+            Vec4::new(0.0, 0.0, -z_near, 0.0),
+        )
+    }
+
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn perspective_infinite_reverse_rh(
+        fov_y_radians: f32,
+        aspect_ratio: f32,
+        z_near: f32,
+    ) -> Self {
+        glam_assert!(z_near > 0.0);
+        let f = 1.0 / math::tan(0.5 * fov_y_radians);
+        Self::from_cols(
+            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, f, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, 0.0, -1.0),
+            Vec4::new(0.0, 0.0, z_near, 0.0),
+        )
+    }
+
+    /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
+    /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
+    /// See
+    /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
+    #[inline]
+    #[must_use]
+    pub fn orthographic_rh_gl(
+        left: f32,
+        right: f32,
+        bottom: f32,
+        top: f32,
+        near: f32,
+        far: f32,
+    ) -> Self {
+        let a = 2.0 / (right - left);
+        let b = 2.0 / (top - bottom);
+        let c = -2.0 / (far - near);
+        let tx = -(right + left) / (right - left);
+        let ty = -(top + bottom) / (top - bottom);
+        let tz = -(far + near) / (far - near);
+
+        Self::from_cols(
+            Vec4::new(a, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, b, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, c, 0.0),
+            Vec4::new(tx, ty, tz, 1.0),
+        )
+    }
+
+    /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
+    #[inline]
+    #[must_use]
+    pub fn orthographic_lh(
+        left: f32,
+        right: f32,
+        bottom: f32,
+        top: f32,
+        near: f32,
+        far: f32,
+    ) -> Self {
+        let rcp_width = 1.0 / (right - left);
+        let rcp_height = 1.0 / (top - bottom);
+        let r = 1.0 / (far - near);
+        Self::from_cols(
+            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, r, 0.0),
+            Vec4::new(
+                -(left + right) * rcp_width,
+                -(top + bottom) * rcp_height,
+                -r * near,
+                1.0,
+            ),
+        )
+    }
+
+    /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
+    #[inline]
+    #[must_use]
+    pub fn orthographic_rh(
+        left: f32,
+        right: f32,
+        bottom: f32,
+        top: f32,
+        near: f32,
+        far: f32,
+    ) -> Self {
+        let rcp_width = 1.0 / (right - left);
+        let rcp_height = 1.0 / (top - bottom);
+        let r = 1.0 / (near - far);
+        Self::from_cols(
+            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
+            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
+            Vec4::new(0.0, 0.0, r, 0.0),
+            Vec4::new(
+                -(left + right) * rcp_width,
+                -(top + bottom) * rcp_height,
+                r * near,
+                1.0,
+            ),
+        )
+    }
+
+    /// Transforms the given 3D vector as a point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3(&self, rhs: Vec3) -> Vec3 {
+        let mut res = self.x_axis.mul(rhs.x);
+        res = self.y_axis.mul(rhs.y).add(res);
+        res = self.z_axis.mul(rhs.z).add(res);
+        res = self.w_axis.add(res);
+        res = res.div(res.w);
+        res.xyz()
+    }
+
+    /// Transforms the given 3D vector as a point.
+    ///
+    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
+    /// `1.0`.
+    ///
+    /// This method assumes that `self` contains a valid affine transform. It does not perform
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// the [`Self::project_point3()`] method should be used instead.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
+        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
+        let mut res = self.x_axis.mul(rhs.x);
+        res = self.y_axis.mul(rhs.y).add(res);
+        res = self.z_axis.mul(rhs.z).add(res);
+        res = self.w_axis.add(res);
+        res.xyz()
+    }
+
+    /// Transforms the give 3D vector as a direction.
+    ///
+    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
+    /// `0.0`.
+    ///
+    /// This method assumes that `self` contains a valid affine transform.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
+        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
+        let mut res = self.x_axis.mul(rhs.x);
+        res = self.y_axis.mul(rhs.y).add(res);
+        res = self.z_axis.mul(rhs.z).add(res);
+        res.xyz()
+    }
+
+    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        res = self.w_axis.add(res);
+        res = res.div(res.wwww());
+        Vec3A::from_vec4(res)
+    }
+
+    /// Transforms the given [`Vec3A`] as 3D point.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    #[inline]
+    #[must_use]
+    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
+        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        res = self.w_axis.add(res);
+        Vec3A::from_vec4(res)
+    }
+
+    /// Transforms the give [`Vec3A`] as 3D vector.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `0.0`.
+    #[inline]
+    #[must_use]
+    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
+        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        Vec3A::from_vec4(res)
+    }
+
+    /// Transforms a 4D vector.
+    #[inline]
+    #[must_use]
+    pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 {
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = res.add(self.y_axis.mul(rhs.yyyy()));
+        res = res.add(self.z_axis.mul(rhs.zzzz()));
+        res = res.add(self.w_axis.mul(rhs.wwww()));
+        res
+    }
+
+    /// Multiplies two 4x4 matrices.
+    #[inline]
+    #[must_use]
+    pub fn mul_mat4(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.mul(rhs.x_axis),
+            self.mul(rhs.y_axis),
+            self.mul(rhs.z_axis),
+            self.mul(rhs.w_axis),
+        )
+    }
+
+    /// Adds two 4x4 matrices.
+    #[inline]
+    #[must_use]
+    pub fn add_mat4(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.x_axis.add(rhs.x_axis),
+            self.y_axis.add(rhs.y_axis),
+            self.z_axis.add(rhs.z_axis),
+            self.w_axis.add(rhs.w_axis),
+        )
+    }
+
+    /// Subtracts two 4x4 matrices.
+    #[inline]
+    #[must_use]
+    pub fn sub_mat4(&self, rhs: &Self) -> Self {
+        Self::from_cols(
+            self.x_axis.sub(rhs.x_axis),
+            self.y_axis.sub(rhs.y_axis),
+            self.z_axis.sub(rhs.z_axis),
+            self.w_axis.sub(rhs.w_axis),
+        )
+    }
+
+    /// Multiplies a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn mul_scalar(&self, rhs: f32) -> Self {
+        Self::from_cols(
+            self.x_axis.mul(rhs),
+            self.y_axis.mul(rhs),
+            self.z_axis.mul(rhs),
+            self.w_axis.mul(rhs),
+        )
+    }
+
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs`
+    /// is less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two matrices contain similar elements. It works best
+    /// when comparing with a known value. The `max_abs_diff` that should be used used
+    /// depends on the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
+        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
+            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
+            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
+            && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
+    }
+
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
+    #[inline]
+    pub fn as_dmat4(&self) -> DMat4 {
+        DMat4::from_cols(
+            self.x_axis.as_dvec4(),
+            self.y_axis.as_dvec4(),
+            self.z_axis.as_dvec4(),
+            self.w_axis.as_dvec4(),
+        )
+    }
+}
+
+impl Default for Mat4 {
+    #[inline]
+    fn default() -> Self {
+        Self::IDENTITY
+    }
+}
+
+impl Add<Mat4> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self::Output {
+        self.add_mat4(&rhs)
+    }
+}
+
+impl AddAssign<Mat4> for Mat4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        *self = self.add_mat4(&rhs);
+    }
+}
+
+impl Sub<Mat4> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self::Output {
+        self.sub_mat4(&rhs)
+    }
+}
+
+impl SubAssign<Mat4> for Mat4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: Self) {
+        *self = self.sub_mat4(&rhs);
+    }
+}
+
+impl Neg for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self::Output {
+        Self::from_cols(
+            self.x_axis.neg(),
+            self.y_axis.neg(),
+            self.z_axis.neg(),
+            self.w_axis.neg(),
+        )
+    }
+}
+
+impl Mul<Mat4> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self::Output {
+        self.mul_mat4(&rhs)
+    }
+}
+
+impl MulAssign<Mat4> for Mat4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        *self = self.mul_mat4(&rhs);
+    }
+}
+
+impl Mul<Vec4> for Mat4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Self::Output {
+        self.mul_vec4(rhs)
+    }
+}
+
+impl Mul<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn mul(self, rhs: Mat4) -> Self::Output {
+        rhs.mul_scalar(self)
+    }
+}
+
+impl Mul<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: f32) -> Self::Output {
+        self.mul_scalar(rhs)
+    }
+}
+
+impl MulAssign<f32> for Mat4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: f32) {
+        *self = self.mul_scalar(rhs);
+    }
+}
+
+impl Div<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn div(self, rhs: Mat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
+impl Sum<Self> for Mat4 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Mat4 {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Mat4 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::IDENTITY, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Mat4 {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl PartialEq for Mat4 {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.x_axis.eq(&rhs.x_axis)
+            && self.y_axis.eq(&rhs.y_axis)
+            && self.z_axis.eq(&rhs.z_axis)
+            && self.w_axis.eq(&rhs.w_axis)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[f32; 16]> for Mat4 {
+    #[inline]
+    fn as_ref(&self) -> &[f32; 16] {
+        unsafe { &*(self as *const Self as *const [f32; 16]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[f32; 16]> for Mat4 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [f32; 16] {
+        unsafe { &mut *(self as *mut Self as *mut [f32; 16]) }
+    }
+}
+
+impl fmt::Debug for Mat4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct(stringify!(Mat4))
+            .field("x_axis", &self.x_axis)
+            .field("y_axis", &self.y_axis)
+            .field("z_axis", &self.z_axis)
+            .field("w_axis", &self.w_axis)
+            .finish()
+    }
+}
+
+impl fmt::Display for Mat4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
+    }
+}
diff --git a/crates/glam/src/f32/neon/quat.rs b/crates/glam/src/f32/neon/quat.rs
new file mode 100644
index 0000000..76664ad
--- /dev/null
+++ b/crates/glam/src/f32/neon/quat.rs
@@ -0,0 +1,1035 @@
+// Generated from quat.rs.tera template. Edit the template, not the generated file.
+
+use crate::{
+    euler::{EulerRot, FromEuler, ToEuler},
+    f32::math,
+    neon::*,
+    DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
+};
+
+use core::arch::aarch64::*;
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub};
+
+#[repr(C)]
+union UnionCast {
+    a: [f32; 4],
+    v: Quat,
+}
+
+/// Creates a quaternion from `x`, `y`, `z` and `w` values.
+///
+/// This should generally not be called manually unless you know what you are doing. Use
+/// one of the other constructors instead such as `identity` or `from_axis_angle`.
+#[inline]
+#[must_use]
+pub const fn quat(x: f32, y: f32, z: f32, w: f32) -> Quat {
+    Quat::from_xyzw(x, y, z, w)
+}
+
+/// A quaternion representing an orientation.
+///
+/// This quaternion is intended to be of unit length but may denormalize due to
+/// floating point "error creep" which can occur when successive quaternion
+/// operations are applied.
+///
+/// SIMD vector types are used for storage on supported platforms.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct Quat(pub(crate) float32x4_t);
+
+impl Quat {
+    /// All zeros.
+    const ZERO: Self = Self::from_array([0.0; 4]);
+
+    /// The identity quaternion. Corresponds to no rotation.
+    pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0);
+
+    /// All NANs.
+    pub const NAN: Self = Self::from_array([f32::NAN; 4]);
+
+    /// Creates a new rotation quaternion.
+    ///
+    /// This should generally not be called manually unless you know what you are doing.
+    /// Use one of the other constructors instead such as `identity` or `from_axis_angle`.
+    ///
+    /// `from_xyzw` is mostly used by unit tests and `serde` deserialization.
+    ///
+    /// # Preconditions
+    ///
+    /// This function does not check if the input is normalized, it is up to the user to
+    /// provide normalized input or to normalized the resulting quaternion.
+    #[inline(always)]
+    #[must_use]
+    pub const fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
+        unsafe { UnionCast { a: [x, y, z, w] }.v }
+    }
+
+    /// Creates a rotation quaternion from an array.
+    ///
+    /// # Preconditions
+    ///
+    /// This function does not check if the input is normalized, it is up to the user to
+    /// provide normalized input or to normalized the resulting quaternion.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [f32; 4]) -> Self {
+        Self::from_xyzw(a[0], a[1], a[2], a[3])
+    }
+
+    /// Creates a new rotation quaternion from a 4D vector.
+    ///
+    /// # Preconditions
+    ///
+    /// This function does not check if the input is normalized, it is up to the user to
+    /// provide normalized input or to normalized the resulting quaternion.
+    #[inline]
+    #[must_use]
+    pub const fn from_vec4(v: Vec4) -> Self {
+        Self(v.0)
+    }
+
+    /// Creates a rotation quaternion from a slice.
+    ///
+    /// # Preconditions
+    ///
+    /// This function does not check if the input is normalized, it is up to the user to
+    /// provide normalized input or to normalized the resulting quaternion.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` length is less than 4.
+    #[inline]
+    #[must_use]
+    pub fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
+        Self(unsafe { vld1q_f32(slice.as_ptr()) })
+    }
+
+    /// Writes the quaternion to an unaligned slice.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` length is less than 4.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [f32]) {
+        assert!(slice.len() >= 4);
+        unsafe { vst1q_f32(slice.as_mut_ptr(), self.0) }
+    }
+
+    /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians).
+    ///
+    /// The axis must be a unit vector.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
+        glam_assert!(axis.is_normalized());
+        let (s, c) = math::sin_cos(angle * 0.5);
+        let v = axis * s;
+        Self::from_xyzw(v.x, v.y, v.z, c)
+    }
+
+    /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`.
+    ///
+    /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion.
+    #[inline]
+    #[must_use]
+    pub fn from_scaled_axis(v: Vec3) -> Self {
+        let length = v.length();
+        if length == 0.0 {
+            Self::IDENTITY
+        } else {
+            Self::from_axis_angle(v / length, length)
+        }
+    }
+
+    /// Creates a quaternion from the `angle` (in radians) around the x axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_x(angle: f32) -> Self {
+        let (s, c) = math::sin_cos(angle * 0.5);
+        Self::from_xyzw(s, 0.0, 0.0, c)
+    }
+
+    /// Creates a quaternion from the `angle` (in radians) around the y axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_y(angle: f32) -> Self {
+        let (s, c) = math::sin_cos(angle * 0.5);
+        Self::from_xyzw(0.0, s, 0.0, c)
+    }
+
+    /// Creates a quaternion from the `angle` (in radians) around the z axis.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_z(angle: f32) -> Self {
+        let (s, c) = math::sin_cos(angle * 0.5);
+        Self::from_xyzw(0.0, 0.0, s, c)
+    }
+
+    /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians).
+    #[inline]
+    #[must_use]
+    pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
+        Self::from_euler_angles(euler, a, b, c)
+    }
+
+    /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
+        let (m00, m01, m02) = x_axis.into();
+        let (m10, m11, m12) = y_axis.into();
+        let (m20, m21, m22) = z_axis.into();
+        if m22 <= 0.0 {
+            // x^2 + y^2 >= z^2 + w^2
+            let dif10 = m11 - m00;
+            let omm22 = 1.0 - m22;
+            if dif10 <= 0.0 {
+                // x^2 >= y^2
+                let four_xsq = omm22 - dif10;
+                let inv4x = 0.5 / math::sqrt(four_xsq);
+                Self::from_xyzw(
+                    four_xsq * inv4x,
+                    (m01 + m10) * inv4x,
+                    (m02 + m20) * inv4x,
+                    (m12 - m21) * inv4x,
+                )
+            } else {
+                // y^2 >= x^2
+                let four_ysq = omm22 + dif10;
+                let inv4y = 0.5 / math::sqrt(four_ysq);
+                Self::from_xyzw(
+                    (m01 + m10) * inv4y,
+                    four_ysq * inv4y,
+                    (m12 + m21) * inv4y,
+                    (m20 - m02) * inv4y,
+                )
+            }
+        } else {
+            // z^2 + w^2 >= x^2 + y^2
+            let sum10 = m11 + m00;
+            let opm22 = 1.0 + m22;
+            if sum10 <= 0.0 {
+                // z^2 >= w^2
+                let four_zsq = opm22 - sum10;
+                let inv4z = 0.5 / math::sqrt(four_zsq);
+                Self::from_xyzw(
+                    (m02 + m20) * inv4z,
+                    (m12 + m21) * inv4z,
+                    four_zsq * inv4z,
+                    (m01 - m10) * inv4z,
+                )
+            } else {
+                // w^2 >= z^2
+                let four_wsq = opm22 + sum10;
+                let inv4w = 0.5 / math::sqrt(four_wsq);
+                Self::from_xyzw(
+                    (m12 - m21) * inv4w,
+                    (m20 - m02) * inv4w,
+                    (m01 - m10) * inv4w,
+                    four_wsq * inv4w,
+                )
+            }
+        }
+    }
+
+    /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3(mat: &Mat3) -> Self {
+        Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
+    }
+
+    /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a(mat: &Mat3A) -> Self {
+        Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
+    }
+
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4(mat: &Mat4) -> Self {
+        Self::from_rotation_axes(
+            mat.x_axis.truncate(),
+            mat.y_axis.truncate(),
+            mat.z_axis.truncate(),
+        )
+    }
+
+    /// Gets the minimal rotation for transforming `from` to `to`.  The rotation is in the
+    /// plane spanned by the two vectors.  Will rotate at most 180 degrees.
+    ///
+    /// The inputs must be unit vectors.
+    ///
+    /// `from_rotation_arc(from, to) * from ≈ to`.
+    ///
+    /// For near-singular cases (from≈to and from≈-to) the current implementation
+    /// is only accurate to about 0.001 (for `f32`).
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
+    #[must_use]
+    pub fn from_rotation_arc(from: Vec3, to: Vec3) -> Self {
+        glam_assert!(from.is_normalized());
+        glam_assert!(to.is_normalized());
+
+        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
+        let dot = from.dot(to);
+        if dot > ONE_MINUS_EPS {
+            // 0° singularity: from ≈ to
+            Self::IDENTITY
+        } else if dot < -ONE_MINUS_EPS {
+            // 180° singularity: from ≈ -to
+            use core::f32::consts::PI; // half a turn = 𝛕/2 = 180°
+            Self::from_axis_angle(from.any_orthonormal_vector(), PI)
+        } else {
+            let c = from.cross(to);
+            Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize()
+        }
+    }
+
+    /// Gets the minimal rotation for transforming `from` to either `to` or `-to`.  This means
+    /// that the resulting quaternion will rotate `from` so that it is colinear with `to`.
+    ///
+    /// The rotation is in the plane spanned by the two vectors.  Will rotate at most 90
+    /// degrees.
+    ///
+    /// The inputs must be unit vectors.
+    ///
+    /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_rotation_arc_colinear(from: Vec3, to: Vec3) -> Self {
+        if from.dot(to) < 0.0 {
+            Self::from_rotation_arc(from, -to)
+        } else {
+            Self::from_rotation_arc(from, to)
+        }
+    }
+
+    /// Gets the minimal rotation for transforming `from` to `to`.  The resulting rotation is
+    /// around the z axis. Will rotate at most 180 degrees.
+    ///
+    /// The inputs must be unit vectors.
+    ///
+    /// `from_rotation_arc_2d(from, to) * from ≈ to`.
+    ///
+    /// For near-singular cases (from≈to and from≈-to) the current implementation
+    /// is only accurate to about 0.001 (for `f32`).
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
+    #[must_use]
+    pub fn from_rotation_arc_2d(from: Vec2, to: Vec2) -> Self {
+        glam_assert!(from.is_normalized());
+        glam_assert!(to.is_normalized());
+
+        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
+        let dot = from.dot(to);
+        if dot > ONE_MINUS_EPSILON {
+            // 0° singularity: from ≈ to
+            Self::IDENTITY
+        } else if dot < -ONE_MINUS_EPSILON {
+            // 180° singularity: from ≈ -to
+            const COS_FRAC_PI_2: f32 = 0.0;
+            const SIN_FRAC_PI_2: f32 = 1.0;
+            // rotation around z by PI radians
+            Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2)
+        } else {
+            // vector3 cross where z=0
+            let z = from.x * to.y - to.x * from.y;
+            let w = 1.0 + dot;
+            // calculate length with x=0 and y=0 to normalize
+            let len_rcp = 1.0 / math::sqrt(z * z + w * w);
+            Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp)
+        }
+    }
+
+    /// Returns the rotation axis (normalized) and angle (in radians) of `self`.
+    #[inline]
+    #[must_use]
+    pub fn to_axis_angle(self) -> (Vec3, f32) {
+        const EPSILON: f32 = 1.0e-8;
+        let v = Vec3::new(self.x, self.y, self.z);
+        let length = v.length();
+        if length >= EPSILON {
+            let angle = 2.0 * math::atan2(length, self.w);
+            let axis = v / length;
+            (axis, angle)
+        } else {
+            (Vec3::X, 0.0)
+        }
+    }
+
+    /// Returns the rotation axis scaled by the rotation in radians.
+    #[inline]
+    #[must_use]
+    pub fn to_scaled_axis(self) -> Vec3 {
+        let (axis, angle) = self.to_axis_angle();
+        axis * angle
+    }
+
+    /// Returns the rotation angles for the given euler rotation sequence.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
+        self.to_euler_angles(order)
+    }
+
+    /// `[x, y, z, w]`
+    #[inline]
+    #[must_use]
+    pub fn to_array(&self) -> [f32; 4] {
+        [self.x, self.y, self.z, self.w]
+    }
+
+    /// Returns the vector part of the quaternion.
+    #[inline]
+    #[must_use]
+    pub fn xyz(self) -> Vec3 {
+        Vec3::new(self.x, self.y, self.z)
+    }
+
+    /// Returns the quaternion conjugate of `self`. For a unit quaternion the
+    /// conjugate is also the inverse.
+    #[inline]
+    #[must_use]
+    pub fn conjugate(self) -> Self {
+        const SIGN: float32x4_t = f32x4_from_array([-1.0, -1.0, -1.0, 1.0]);
+        Self(unsafe { vmulq_f32(self.0, SIGN) })
+    }
+
+    /// Returns the inverse of a normalized quaternion.
+    ///
+    /// Typically quaternion inverse returns the conjugate of a normalized quaternion.
+    /// Because `self` is assumed to already be unit length this method *does not* normalize
+    /// before returning the conjugate.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn inverse(self) -> Self {
+        glam_assert!(self.is_normalized());
+        self.conjugate()
+    }
+
+    /// Computes the dot product of `self` and `rhs`. The dot product is
+    /// equal to the cosine of the angle between two quaternion rotations.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> f32 {
+        Vec4::from(self).dot(Vec4::from(rhs))
+    }
+
+    /// Computes the length of `self`.
+    #[doc(alias = "magnitude")]
+    #[inline]
+    #[must_use]
+    pub fn length(self) -> f32 {
+        Vec4::from(self).length()
+    }
+
+    /// Computes the squared length of `self`.
+    ///
+    /// This is generally faster than `length()` as it avoids a square
+    /// root operation.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> f32 {
+        Vec4::from(self).length_squared()
+    }
+
+    /// Computes `1.0 / length()`.
+    ///
+    /// For valid results, `self` must _not_ be of length zero.
+    #[inline]
+    #[must_use]
+    pub fn length_recip(self) -> f32 {
+        Vec4::from(self).length_recip()
+    }
+
+    /// Returns `self` normalized to length 1.0.
+    ///
+    /// For valid results, `self` must _not_ be of length zero.
+    ///
+    /// Panics
+    ///
+    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn normalize(self) -> Self {
+        Self::from_vec4(Vec4::from(self).normalize())
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.
+    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(self) -> bool {
+        Vec4::from(self).is_finite()
+    }
+
+    /// Returns `true` if any elements are `NAN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(self) -> bool {
+        Vec4::from(self).is_nan()
+    }
+
+    /// Returns whether `self` of length `1.0` or not.
+    ///
+    /// Uses a precision threshold of `1e-6`.
+    #[inline]
+    #[must_use]
+    pub fn is_normalized(self) -> bool {
+        Vec4::from(self).is_normalized()
+    }
+
+    #[inline]
+    #[must_use]
+    pub fn is_near_identity(self) -> bool {
+        // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity`
+        let threshold_angle = 0.002_847_144_6;
+        // Because of floating point precision, we cannot represent very small rotations.
+        // The closest f32 to 1.0 that is not 1.0 itself yields:
+        // 0.99999994.acos() * 2.0  = 0.000690533954 rad
+        //
+        // An error threshold of 1.e-6 is used by default.
+        // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad
+        // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad
+        //
+        // We don't really care about the angle value itself, only if it's close to 0.
+        // This will happen whenever quat.w is close to 1.0.
+        // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to
+        // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with
+        // the shortest path.
+        let positive_w_angle = math::acos_approx(math::abs(self.w)) * 2.0;
+        positive_w_angle < threshold_angle
+    }
+
+    /// Returns the angle (in radians) for the minimal rotation
+    /// for transforming this quaternion into another.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn angle_between(self, rhs: Self) -> f32 {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        math::acos_approx(math::abs(self.dot(rhs))) * 2.0
+    }
+
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs`
+    /// is less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two quaternions contain similar elements. It works
+    /// best when comparing with a known value. The `max_abs_diff` that should be used used
+    /// depends on the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
+        Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
+    }
+
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f32) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
+    /// Performs a linear interpolation between `self` and `rhs` based on
+    /// the value `s`.
+    ///
+    /// When `s` is `0.0`, the result will be equal to `self`.  When `s`
+    /// is `1.0`, the result will be equal to `rhs`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
+    #[doc(alias = "mix")]
+    #[inline]
+    #[must_use]
+    pub fn lerp(self, end: Self, s: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(end.is_normalized());
+
+        const NEG_ZERO: float32x4_t = f32x4_from_array([-0.0; 4]);
+        unsafe {
+            let dot = dot4_into_f32x4(self.0, end.0);
+            // Calculate the bias, if the dot product is positive or zero, there is no bias
+            // but if it is negative, we want to flip the 'end' rotation XYZW components
+            let bias = vandq_u32(vreinterpretq_u32_f32(dot), vreinterpretq_u32_f32(NEG_ZERO));
+            self.lerp_impl(
+                Self(vreinterpretq_f32_u32(veorq_u32(
+                    vreinterpretq_u32_f32(end.0),
+                    bias,
+                ))),
+                s,
+            )
+        }
+    }
+
+    /// Performs a spherical linear interpolation between `self` and `end`
+    /// based on the value `s`.
+    ///
+    /// When `s` is `0.0`, the result will be equal to `self`.  When `s`
+    /// is `1.0`, the result will be equal to `end`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn slerp(self, mut end: Self, s: f32) -> Self {
+        // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
+        glam_assert!(self.is_normalized());
+        glam_assert!(end.is_normalized());
+
+        // Note that a rotation can be represented by two quaternions: `q` and
+        // `-q`. The slerp path between `q` and `end` will be different from the
+        // path between `-q` and `end`. One path will take the long way around and
+        // one will take the short way. In order to correct for this, the `dot`
+        // product between `self` and `end` should be positive. If the `dot`
+        // product is negative, slerp between `self` and `-end`.
+        let mut dot = self.dot(end);
+        if dot < 0.0 {
+            end = -end;
+            dot = -dot;
+        }
+
+        const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
+        if dot > DOT_THRESHOLD {
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
+        } else {
+            let theta = math::acos_approx(dot);
+
+            let scale1 = math::sin(theta * (1.0 - s));
+            let scale2 = math::sin(theta * s);
+            let theta_sin = math::sin(theta);
+            ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
+        }
+    }
+
+    /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn mul_vec3(self, rhs: Vec3) -> Vec3 {
+        glam_assert!(self.is_normalized());
+
+        self.mul_vec3a(rhs.into()).into()
+    }
+
+    /// Multiplies two quaternions. If they each represent a rotation, the result will
+    /// represent the combined rotation.
+    ///
+    /// Note that due to floating point rounding the result may not be perfectly normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn mul_quat(self, rhs: Self) -> Self {
+        unsafe {
+            let lhs = self.0;
+            let rhs = rhs.0;
+
+            const CONTROL_WZYX: float32x4_t = f32x4_from_array([1.0, -1.0, 1.0, -1.0]);
+            const CONTROL_ZWXY: float32x4_t = f32x4_from_array([1.0, 1.0, -1.0, -1.0]);
+            const CONTROL_YXWZ: float32x4_t = f32x4_from_array([-1.0, 1.0, 1.0, -1.0]);
+
+            let r_xxxx = vdupq_laneq_f32(lhs, 0);
+            let r_yyyy = vdupq_laneq_f32(lhs, 1);
+            let r_zzzz = vdupq_laneq_f32(lhs, 2);
+            let r_wwww = vdupq_laneq_f32(lhs, 3);
+
+            let lxrw_lyrw_lzrw_lwrw = vmulq_f32(r_wwww, rhs);
+            //let l_wzyx = simd_swizzle!(rhs, [3, 2, 1, 0]);
+            let l_wzyx = vrev64q_f32(rhs);
+            let l_wzyx = vextq_f32(l_wzyx, l_wzyx, 2);
+
+            let lwrx_lzrx_lyrx_lxrx = vmulq_f32(r_xxxx, l_wzyx);
+            //let l_zwxy = simd_swizzle!(l_wzyx, [1, 0, 3, 2]);
+            let l_zwxy = vrev64q_f32(l_wzyx);
+
+            let lwrx_nlzrx_lyrx_nlxrx = vmulq_f32(lwrx_lzrx_lyrx_lxrx, CONTROL_WZYX);
+
+            let lzry_lwry_lxry_lyry = vmulq_f32(r_yyyy, l_zwxy);
+            // let l_yxwz = simd_swizzle!(l_zwxy, [3, 2, 1, 0]);
+            let l_yxwz = vrev64q_f32(l_zwxy);
+            let l_yxwz = vextq_f32(l_yxwz, l_yxwz, 2);
+
+            let lzry_lwry_nlxry_nlyry = vmulq_f32(lzry_lwry_lxry_lyry, CONTROL_ZWXY);
+
+            let lyrz_lxrz_lwrz_lzrz = vmulq_f32(r_zzzz, l_yxwz);
+            let result0 = vaddq_f32(lxrw_lyrw_lzrw_lwrw, lwrx_nlzrx_lyrx_nlxrx);
+
+            let nlyrz_lxrz_lwrz_wlzrz = vmulq_f32(lyrz_lxrz_lwrz_lzrz, CONTROL_YXWZ);
+            let result1 = vaddq_f32(lzry_lwry_nlxry_nlyry, nlyrz_lxrz_lwrz_wlzrz);
+            Self(vaddq_f32(result0, result1))
+        }
+    }
+
+    /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
+    #[inline]
+    #[must_use]
+    pub fn from_affine3(a: &crate::Affine3A) -> Self {
+        #[allow(clippy::useless_conversion)]
+        Self::from_rotation_axes(
+            a.matrix3.x_axis.into(),
+            a.matrix3.y_axis.into(),
+            a.matrix3.z_axis.into(),
+        )
+    }
+
+    /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
+    #[inline]
+    #[must_use]
+    pub fn mul_vec3a(self, rhs: Vec3A) -> Vec3A {
+        unsafe {
+            let w = self.w;
+            let b = Vec3A::from(self.0);
+            let b2 = b.length_squared();
+            Vec3A(vaddq_f32(
+                vaddq_f32(
+                    vmulq_n_f32(rhs.0, (w * w) - b2),
+                    vmulq_n_f32(b.0, rhs.dot(b) * 2.0),
+                ),
+                vmulq_n_f32(b.cross(rhs).0, w * 2.0),
+            ))
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    pub fn as_dquat(self) -> DQuat {
+        DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
+    }
+}
+
+impl fmt::Debug for Quat {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(Quat))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .field(&self.w)
+            .finish()
+    }
+}
+
+impl fmt::Display for Quat {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
+    }
+}
+
+impl Add<Quat> for Quat {
+    type Output = Self;
+    /// Adds two quaternions.
+    ///
+    /// The sum is not guaranteed to be normalized.
+    ///
+    /// Note that addition is not the same as combining the rotations represented by the
+    /// two quaternions! That corresponds to multiplication.
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self::from_vec4(Vec4::from(self) + Vec4::from(rhs))
+    }
+}
+
+impl Sub<Quat> for Quat {
+    type Output = Self;
+    /// Subtracts the `rhs` quaternion from `self`.
+    ///
+    /// The difference is not guaranteed to be normalized.
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self::from_vec4(Vec4::from(self) - Vec4::from(rhs))
+    }
+}
+
+impl Mul<f32> for Quat {
+    type Output = Self;
+    /// Multiplies a quaternion by a scalar value.
+    ///
+    /// The product is not guaranteed to be normalized.
+    #[inline]
+    fn mul(self, rhs: f32) -> Self {
+        Self::from_vec4(Vec4::from(self) * rhs)
+    }
+}
+
+impl Div<f32> for Quat {
+    type Output = Self;
+    /// Divides a quaternion by a scalar value.
+    /// The quotient is not guaranteed to be normalized.
+    #[inline]
+    fn div(self, rhs: f32) -> Self {
+        Self::from_vec4(Vec4::from(self) / rhs)
+    }
+}
+
+impl Mul<Quat> for Quat {
+    type Output = Self;
+    /// Multiplies two quaternions. If they each represent a rotation, the result will
+    /// represent the combined rotation.
+    ///
+    /// Note that due to floating point rounding the result may not be perfectly
+    /// normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        self.mul_quat(rhs)
+    }
+}
+
+impl MulAssign<Quat> for Quat {
+    /// Multiplies two quaternions. If they each represent a rotation, the result will
+    /// represent the combined rotation.
+    ///
+    /// Note that due to floating point rounding the result may not be perfectly
+    /// normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        *self = self.mul_quat(rhs);
+    }
+}
+
+impl Mul<Vec3> for Quat {
+    type Output = Vec3;
+    /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    fn mul(self, rhs: Vec3) -> Self::Output {
+        self.mul_vec3(rhs)
+    }
+}
+
+impl Neg for Quat {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        self * -1.0
+    }
+}
+
+impl Default for Quat {
+    #[inline]
+    fn default() -> Self {
+        Self::IDENTITY
+    }
+}
+
+impl PartialEq for Quat {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        Vec4::from(*self).eq(&Vec4::from(*rhs))
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[f32; 4]> for Quat {
+    #[inline]
+    fn as_ref(&self) -> &[f32; 4] {
+        unsafe { &*(self as *const Self as *const [f32; 4]) }
+    }
+}
+
+impl Sum<Self> for Quat {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Quat {
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Quat {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::IDENTITY, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Quat {
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Mul<Vec3A> for Quat {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Self::Output {
+        self.mul_vec3a(rhs)
+    }
+}
+
+impl From<Quat> for Vec4 {
+    #[inline]
+    fn from(q: Quat) -> Self {
+        Self(q.0)
+    }
+}
+
+impl From<Quat> for (f32, f32, f32, f32) {
+    #[inline]
+    fn from(q: Quat) -> Self {
+        Vec4::from(q).into()
+    }
+}
+
+impl From<Quat> for [f32; 4] {
+    #[inline]
+    fn from(q: Quat) -> Self {
+        Vec4::from(q).into()
+    }
+}
+
+impl From<Quat> for float32x4_t {
+    #[inline]
+    fn from(q: Quat) -> Self {
+        q.0
+    }
+}
+
+impl Deref for Quat {
+    type Target = crate::deref::Vec4<f32>;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*(self as *const Self).cast() }
+    }
+}
+
+impl DerefMut for Quat {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { &mut *(self as *mut Self).cast() }
+    }
+}
diff --git a/crates/glam/src/f32/neon/vec3a.rs b/crates/glam/src/f32/neon/vec3a.rs
new file mode 100644
index 0000000..fe08d2e
--- /dev/null
+++ b/crates/glam/src/f32/neon/vec3a.rs
@@ -0,0 +1,1917 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{f32::math, neon::*, BVec3, BVec3A, Vec2, Vec3, Vec4};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+use core::arch::aarch64::*;
+
+#[repr(C)]
+union UnionCast {
+    a: [f32; 4],
+    v: Vec3A,
+}
+
+/// Creates a 3-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn vec3a(x: f32, y: f32, z: f32) -> Vec3A {
+    Vec3A::new(x, y, z)
+}
+
+/// A 3-dimensional vector.
+///
+/// SIMD vector types are used for storage on supported platforms for better
+/// performance than the [`Vec3`] type.
+///
+/// It is possible to convert between [`Vec3`] and [`Vec3A`] types using [`From`]
+/// or [`Into`] trait implementations.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct Vec3A(pub(crate) float32x4_t);
+
+impl Vec3A {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0.0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1.0);
+
+    /// All negative ones.
+    pub const NEG_ONE: Self = Self::splat(-1.0);
+
+    /// All `f32::MIN`.
+    pub const MIN: Self = Self::splat(f32::MIN);
+
+    /// All `f32::MAX`.
+    pub const MAX: Self = Self::splat(f32::MAX);
+
+    /// All `f32::NAN`.
+    pub const NAN: Self = Self::splat(f32::NAN);
+
+    /// All `f32::INFINITY`.
+    pub const INFINITY: Self = Self::splat(f32::INFINITY);
+
+    /// All `f32::NEG_INFINITY`.
+    pub const NEG_INFINITY: Self = Self::splat(f32::NEG_INFINITY);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0.0, 1.0, 0.0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0.0, 0.0, 1.0);
+
+    /// A unit vector pointing along the negative X axis.
+    pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the negative Y axis.
+    pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0);
+
+    /// A unit vector pointing along the negative Z axis.
+    pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0);
+
+    /// The unit axes.
+    pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: f32, y: f32, z: f32) -> Self {
+        unsafe { UnionCast { a: [x, y, z, z] }.v }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: f32) -> Self {
+        unsafe { UnionCast { a: [v; 4] }.v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec3A, if_true: Self, if_false: Self) -> Self {
+        Self(unsafe { vbslq_f32(mask.0, if_true.0, if_false.0) })
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [f32; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
+    /// `[x, y, z]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [f32; 3] {
+        unsafe { *(self as *const Vec3A as *const [f32; 3]) }
+    }
+
+    /// Creates a vector from the first 3 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
+        Self::new(slice[0], slice[1], slice[2])
+    }
+
+    /// Writes the elements of `self` to the first 3 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [f32]) {
+        slice[..3].copy_from_slice(&self.to_array());
+    }
+
+    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
+    ///
+    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
+    #[inline]
+    #[must_use]
+    pub fn from_vec4(v: Vec4) -> Self {
+        Self(v.0)
+    }
+
+    /// Creates a 4D vector from `self` and the given `w` value.
+    #[inline]
+    #[must_use]
+    pub fn extend(self, w: f32) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, w)
+    }
+
+    /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`.
+    ///
+    /// Truncation may also be performed by using [`self.xy()`][crate::swizzles::Vec3Swizzles::xy()].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> Vec2 {
+        use crate::swizzles::Vec3Swizzles;
+        self.xy()
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> f32 {
+        // this was faster than intrinsics in testing
+        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self(unsafe { dot3_into_f32x4(self.0, rhs.0) })
+    }
+
+    /// Computes the cross product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn cross(self, rhs: Self) -> Self {
+        unsafe {
+            // Implementation taken from Realtime Math
+            let lhs = self.0;
+            let rhs = rhs.0;
+            // cross(a, b) = (a.yzx * b.zxy) - (a.zxy * b.yzx)
+            let lhs_yzwx = vextq_f32(lhs, lhs, 1);
+            let rhs_wxyz = vextq_f32(rhs, rhs, 3);
+
+            let lhs_yzx = vsetq_lane_f32(vgetq_lane_f32(lhs, 0), lhs_yzwx, 2);
+            let rhs_zxy = vsetq_lane_f32(vgetq_lane_f32(rhs, 2), rhs_wxyz, 0);
+
+            // part_a = (a.yzx * b.zxy)
+            let part_a = vmulq_f32(lhs_yzx, rhs_zxy);
+
+            let lhs_wxyz = vextq_f32(lhs, lhs, 3);
+            let rhs_yzwx = vextq_f32(rhs, rhs, 1);
+            let lhs_zxy = vsetq_lane_f32(vgetq_lane_f32(lhs, 2), lhs_wxyz, 0);
+            let rhs_yzx = vsetq_lane_f32(vgetq_lane_f32(rhs, 0), rhs_yzwx, 2);
+
+            // result = part_a - (a.zxy * b.yzx)
+            let result = vmlsq_f32(part_a, lhs_zxy, rhs_yzx);
+            Self(result)
+        }
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self(unsafe { vminq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self(unsafe { vmaxq_f32(self.0, rhs.0) })
+    }
+
+    /// Component-wise clamping of values, similar to [`f32::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> f32 {
+        self.x.min(self.y.min(self.z))
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> f32 {
+        self.x.max(self.y.max(self.z))
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        unsafe { vaddvq_f32(vsetq_lane_f32(0.0, self.0, 3)) }
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        unsafe {
+            let s = vmuls_laneq_f32(vgetq_lane_f32(self.0, 0), self.0, 1);
+            vmuls_laneq_f32(s, self.0, 2)
+        }
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vceqq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vmvnq_u32(vceqq_f32(self.0, rhs.0)) })
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vcgeq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vcgtq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vcleq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec3A {
+        BVec3A(unsafe { vcltq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector containing the absolute value of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn abs(self) -> Self {
+        Self(unsafe { vabsq_f32(self.0) })
+    }
+
+    /// Returns a vector with elements representing the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+    /// - `NAN` if the number is `NAN`
+    #[inline]
+    #[must_use]
+    pub fn signum(self) -> Self {
+        let result = Self(unsafe {
+            vreinterpretq_f32_u32(vorrq_u32(
+                vandq_u32(
+                    vreinterpretq_u32_f32(self.0),
+                    vreinterpretq_u32_f32(Self::NEG_ONE.0),
+                ),
+                vreinterpretq_u32_f32(Self::ONE.0),
+            ))
+        });
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
+    }
+
+    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
+    #[inline]
+    #[must_use]
+    pub fn copysign(self, rhs: Self) -> Self {
+        let mask = Self::splat(-0.0);
+        Self(unsafe {
+            vreinterpretq_f32_u32(vorrq_u32(
+                vandq_u32(vreinterpretq_u32_f32(rhs.0), vreinterpretq_u32_f32(mask.0)),
+                vandq_u32(
+                    vreinterpretq_u32_f32(self.0),
+                    vmvnq_u32(vreinterpretq_u32_f32(mask.0)),
+                ),
+            ))
+        })
+    }
+
+    /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
+    ///
+    /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn is_negative_bitmask(self) -> u32 {
+        unsafe {
+            let nmask = vreinterpretq_u32_f32(vdupq_n_f32(-0.0));
+            let m = vandq_u32(vreinterpretq_u32_f32(self.0), nmask);
+            let x = vgetq_lane_u32(m, 0) >> 31;
+            let y = vgetq_lane_u32(m, 1) >> 31;
+            let z = vgetq_lane_u32(m, 2) >> 31;
+
+            x | y << 1 | z << 2
+        }
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.  If any element is either
+    /// `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(self) -> bool {
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3A {
+        BVec3A(unsafe { vcltq_f32(vabsq_f32(self.0), Self::INFINITY.0) })
+    }
+
+    /// Returns `true` if any elements are `NaN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(self) -> bool {
+        self.is_nan_mask().any()
+    }
+
+    /// Performs `is_nan` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan_mask(self) -> BVec3A {
+        BVec3A(unsafe { vmvnq_u32(vceqq_f32(self.0, self.0)) })
+    }
+
+    /// Computes the length of `self`.
+    #[doc(alias = "magnitude")]
+    #[inline]
+    #[must_use]
+    pub fn length(self) -> f32 {
+        math::sqrt(self.dot(self))
+    }
+
+    /// Computes the squared length of `self`.
+    ///
+    /// This is faster than `length()` as it avoids a square root operation.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> f32 {
+        self.dot(self)
+    }
+
+    /// Computes `1.0 / length()`.
+    ///
+    /// For valid results, `self` must _not_ be of length zero.
+    #[inline]
+    #[must_use]
+    pub fn length_recip(self) -> f32 {
+        self.length().recip()
+    }
+
+    /// Computes the Euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance(self, rhs: Self) -> f32 {
+        (self - rhs).length()
+    }
+
+    /// Compute the squared euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance_squared(self, rhs: Self) -> f32 {
+        (self - rhs).length_squared()
+    }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    #[must_use]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns `self` normalized to length 1.0.
+    ///
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
+    ///
+    /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
+    ///
+    /// Panics
+    ///
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn normalize(self) -> Self {
+        #[allow(clippy::let_and_return)]
+        let normalized = self.mul(self.length_recip());
+        glam_assert!(normalized.is_finite());
+        normalized
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns `None`.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be `None`.
+    ///
+    /// See also [`Self::normalize_or_zero()`].
+    #[inline]
+    #[must_use]
+    pub fn try_normalize(self) -> Option<Self> {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            Some(self * rcp)
+        } else {
+            None
+        }
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns zero.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be zero.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or_zero(self) -> Self {
+        self.normalize_or(Self::ZERO)
+    }
+
+    /// Returns whether `self` is length `1.0` or not.
+    ///
+    /// Uses a precision threshold of approximately `1e-4`.
+    #[inline]
+    #[must_use]
+    pub fn is_normalized(self) -> bool {
+        math::abs(self.length_squared() - 1.0) <= 2e-4
+    }
+
+    /// Returns the vector projection of `self` onto `rhs`.
+    ///
+    /// `rhs` must be of non-zero length.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is zero length when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn project_onto(self, rhs: Self) -> Self {
+        let other_len_sq_rcp = rhs.dot(rhs).recip();
+        glam_assert!(other_len_sq_rcp.is_finite());
+        rhs * self.dot(rhs) * other_len_sq_rcp
+    }
+
+    /// Returns the vector rejection of `self` from `rhs`.
+    ///
+    /// The vector rejection is the vector perpendicular to the projection of `self` onto
+    /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`.
+    ///
+    /// `rhs` must be of non-zero length.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
+    #[inline]
+    #[must_use]
+    pub fn reject_from(self, rhs: Self) -> Self {
+        self - self.project_onto(rhs)
+    }
+
+    /// Returns the vector projection of `self` onto `rhs`.
+    ///
+    /// `rhs` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn project_onto_normalized(self, rhs: Self) -> Self {
+        glam_assert!(rhs.is_normalized());
+        rhs * self.dot(rhs)
+    }
+
+    /// Returns the vector rejection of `self` from `rhs`.
+    ///
+    /// The vector rejection is the vector perpendicular to the projection of `self` onto
+    /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`.
+    ///
+    /// `rhs` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
+    #[inline]
+    #[must_use]
+    pub fn reject_from_normalized(self, rhs: Self) -> Self {
+        self - self.project_onto_normalized(rhs)
+    }
+
+    /// Returns a vector containing the nearest integer to a number for each element of `self`.
+    /// Round half-way cases away from 0.0.
+    #[inline]
+    #[must_use]
+    pub fn round(self) -> Self {
+        Self(unsafe { vrndnq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the largest integer less than or equal to a number for each
+    /// element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn floor(self) -> Self {
+        Self(unsafe { vrndmq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the smallest integer greater than or equal to a number for
+    /// each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn ceil(self) -> Self {
+        Self(unsafe { vrndpq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the integer part each element of `self`. This means numbers are
+    /// always truncated towards zero.
+    #[inline]
+    #[must_use]
+    pub fn trunc(self) -> Self {
+        Self(unsafe { vrndq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
+        self - self.floor()
+    }
+
+    /// Returns a vector containing `e^self` (the exponential function) for each element of
+    /// `self`.
+    #[inline]
+    #[must_use]
+    pub fn exp(self) -> Self {
+        Self::new(math::exp(self.x), math::exp(self.y), math::exp(self.z))
+    }
+
+    /// Returns a vector containing each element of `self` raised to the power of `n`.
+    #[inline]
+    #[must_use]
+    pub fn powf(self, n: f32) -> Self {
+        Self::new(
+            math::powf(self.x, n),
+            math::powf(self.y, n),
+            math::powf(self.z, n),
+        )
+    }
+
+    /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn recip(self) -> Self {
+        Self(unsafe { vdivq_f32(Self::ONE.0, self.0) })
+    }
+
+    /// Performs a linear interpolation between `self` and `rhs` based on the value `s`.
+    ///
+    /// When `s` is `0.0`, the result will be equal to `self`.  When `s` is `1.0`, the result
+    /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly
+    /// extrapolated.
+    #[doc(alias = "mix")]
+    #[inline]
+    #[must_use]
+    pub fn lerp(self, rhs: Self, s: f32) -> Self {
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs` is
+    /// less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two vectors contain similar elements. It works best when
+    /// comparing with a known value. The `max_abs_diff` that should be used used depends on
+    /// the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
+        self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
+    }
+
+    /// Returns a vector with a length no less than `min` and no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
+        glam_assert!(min <= max);
+        let length_sq = self.length_squared();
+        if length_sq < min * min {
+            min * (self / math::sqrt(length_sq))
+        } else if length_sq > max * max {
+            max * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
+        let length_sq = self.length_squared();
+        if length_sq > max * max {
+            max * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
+        let length_sq = self.length_squared();
+        if length_sq < min * min {
+            min * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
+    /// architecture has a dedicated fma CPU instruction. However, this is not always true,
+    /// and will be heavily dependant on designing algorithms with specific target hardware in
+    /// mind.
+    #[inline]
+    #[must_use]
+    pub fn mul_add(self, a: Self, b: Self) -> Self {
+        Self(unsafe { vfmaq_f32(b.0, self.0, a.0) })
+    }
+
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
+    ///
+    /// The inputs do not need to be unit vectors however they must be non-zero.
+    #[inline]
+    #[must_use]
+    pub fn angle_between(self, rhs: Self) -> f32 {
+        math::acos_approx(
+            self.dot(rhs)
+                .div(math::sqrt(self.length_squared().mul(rhs.length_squared()))),
+        )
+    }
+
+    /// Returns some vector that is orthogonal to the given one.
+    ///
+    /// The input vector must be finite and non-zero.
+    ///
+    /// The output vector is not necessarily unit length. For that use
+    /// [`Self::any_orthonormal_vector()`] instead.
+    #[inline]
+    #[must_use]
+    pub fn any_orthogonal_vector(&self) -> Self {
+        // This can probably be optimized
+        if math::abs(self.x) > math::abs(self.y) {
+            Self::new(-self.z, 0.0, self.x) // self.cross(Self::Y)
+        } else {
+            Self::new(0.0, self.z, -self.y) // self.cross(Self::X)
+        }
+    }
+
+    /// Returns any unit vector that is orthogonal to the given one.
+    ///
+    /// The input vector must be unit length.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn any_orthonormal_vector(&self) -> Self {
+        glam_assert!(self.is_normalized());
+        // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf
+        let sign = math::signum(self.z);
+        let a = -1.0 / (sign + self.z);
+        let b = self.x * self.y * a;
+        Self::new(b, sign + self.y * self.y * a, -self.y)
+    }
+
+    /// Given a unit vector return two other vectors that together form an orthonormal
+    /// basis. That is, all three vectors are orthogonal to each other and are normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn any_orthonormal_pair(&self) -> (Self, Self) {
+        glam_assert!(self.is_normalized());
+        // From https://graphics.pixar.com/library/OrthonormalB/paper.pdf
+        let sign = math::signum(self.z);
+        let a = -1.0 / (sign + self.z);
+        let b = self.x * self.y * a;
+        (
+            Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x),
+            Self::new(b, sign + self.y * self.y * a, -self.y),
+        )
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec3(&self) -> crate::DVec3 {
+        crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
+    }
+
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec3(&self) -> crate::I16Vec3 {
+        crate::I16Vec3::new(self.x as i16, self.y as i16, self.z as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec3(&self) -> crate::U16Vec3 {
+        crate::U16Vec3::new(self.x as u16, self.y as u16, self.z as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec3(&self) -> crate::IVec3 {
+        crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec3(&self) -> crate::UVec3 {
+        crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec3(&self) -> crate::I64Vec3 {
+        crate::I64Vec3::new(self.x as i64, self.y as i64, self.z as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec3(&self) -> crate::U64Vec3 {
+        crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
+    }
+}
+
+impl Default for Vec3A {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl PartialEq for Vec3A {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.cmpeq(*rhs).all()
+    }
+}
+
+impl Div<Vec3A> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self(unsafe { vdivq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Div<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<Vec3A> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vdivq_f32(self.0, rhs.0) };
+    }
+}
+
+impl DivAssign<&Self> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<f32> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self {
+        Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Div<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl DivAssign<&f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        Vec3A(unsafe { vdivq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Div<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<Vec3A> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self(unsafe { vmulq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Mul<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<Vec3A> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vmulq_f32(self.0, rhs.0) };
+    }
+}
+
+impl MulAssign<&Self> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<f32> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: f32) -> Self {
+        Self(unsafe { vmulq_n_f32(self.0, rhs) })
+    }
+}
+
+impl Mul<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vmulq_n_f32(self.0, rhs) };
+    }
+}
+
+impl MulAssign<&f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        Vec3A(unsafe { vmulq_n_f32(rhs.0, self) })
+    }
+}
+
+impl Mul<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<Vec3A> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self(unsafe { vaddq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Add<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<Vec3A> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vaddq_f32(self.0, rhs.0) };
+    }
+}
+
+impl AddAssign<&Self> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<f32> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: f32) -> Self {
+        Self(unsafe { vaddq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Add<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vaddq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl AddAssign<&f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        Vec3A(unsafe { vaddq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Add<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<Vec3A> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self(unsafe { vsubq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Sub<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<Vec3A> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: Vec3A) {
+        self.0 = unsafe { vsubq_f32(self.0, rhs.0) };
+    }
+}
+
+impl SubAssign<&Self> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<f32> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: f32) -> Self {
+        Self(unsafe { vsubq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Sub<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vsubq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl SubAssign<&f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        Vec3A(unsafe { vsubq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Sub<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<Vec3A> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        unsafe {
+            let n = vrndmq_f32(vdivq_f32(self.0, rhs.0));
+            Self(vsubq_f32(self.0, vmulq_f32(n, rhs.0)))
+        }
+    }
+}
+
+impl Rem<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<Vec3A> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        *self = self.rem(rhs);
+    }
+}
+
+impl RemAssign<&Self> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<f32> for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: f32) -> Self {
+        self.rem(Self::splat(rhs))
+    }
+}
+
+impl Rem<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: f32) {
+        *self = self.rem(Self::splat(rhs));
+    }
+}
+
+impl RemAssign<&f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        Vec3A::splat(self).rem(rhs)
+    }
+}
+
+impl Rem<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[f32; 3]> for Vec3A {
+    #[inline]
+    fn as_ref(&self) -> &[f32; 3] {
+        unsafe { &*(self as *const Vec3A as *const [f32; 3]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[f32; 3]> for Vec3A {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [f32; 3] {
+        unsafe { &mut *(self as *mut Vec3A as *mut [f32; 3]) }
+    }
+}
+
+impl Sum for Vec3A {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Vec3A {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Vec3A {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Vec3A {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Neg for Vec3A {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self(unsafe { vnegq_f32(self.0) })
+    }
+}
+
+impl Neg for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn neg(self) -> Vec3A {
+        (*self).neg()
+    }
+}
+
+impl Index<usize> for Vec3A {
+    type Output = f32;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for Vec3A {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for Vec3A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
+    }
+}
+
+impl fmt::Debug for Vec3A {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(Vec3A))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .finish()
+    }
+}
+
+impl From<Vec3A> for float32x4_t {
+    #[inline(always)]
+    fn from(t: Vec3A) -> Self {
+        t.0
+    }
+}
+
+impl From<float32x4_t> for Vec3A {
+    #[inline(always)]
+    fn from(t: float32x4_t) -> Self {
+        Self(t)
+    }
+}
+
+impl From<[f32; 3]> for Vec3A {
+    #[inline]
+    fn from(a: [f32; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+}
+
+impl From<Vec3A> for [f32; 3] {
+    #[inline]
+    fn from(v: Vec3A) -> Self {
+        use crate::align16::Align16;
+        use core::mem::MaybeUninit;
+        let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+        unsafe {
+            vst1q_f32(out.as_mut_ptr().cast(), v.0);
+            out.assume_init().0
+        }
+    }
+}
+
+impl From<(f32, f32, f32)> for Vec3A {
+    #[inline]
+    fn from(t: (f32, f32, f32)) -> Self {
+        Self::new(t.0, t.1, t.2)
+    }
+}
+
+impl From<Vec3A> for (f32, f32, f32) {
+    #[inline]
+    fn from(v: Vec3A) -> Self {
+        use crate::align16::Align16;
+        use core::mem::MaybeUninit;
+        let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+        unsafe {
+            vst1q_f32(out.as_mut_ptr().cast(), v.0);
+            out.assume_init().0
+        }
+    }
+}
+
+impl From<Vec3> for Vec3A {
+    #[inline]
+    fn from(v: Vec3) -> Self {
+        Self::new(v.x, v.y, v.z)
+    }
+}
+
+impl From<Vec3A> for Vec3 {
+    #[inline]
+    fn from(v: Vec3A) -> Self {
+        use crate::align16::Align16;
+        use core::mem::MaybeUninit;
+        let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+        unsafe {
+            vst1q_f32(out.as_mut_ptr().cast(), v.0);
+            out.assume_init().0
+        }
+    }
+}
+
+impl From<(Vec2, f32)> for Vec3A {
+    #[inline]
+    fn from((v, z): (Vec2, f32)) -> Self {
+        Self::new(v.x, v.y, z)
+    }
+}
+
+impl Deref for Vec3A {
+    type Target = crate::deref::Vec3<f32>;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*(self as *const Self).cast() }
+    }
+}
+
+impl DerefMut for Vec3A {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { &mut *(self as *mut Self).cast() }
+    }
+}
+
+impl From<BVec3> for Vec3A {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3A {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/neon/vec4.rs b/crates/glam/src/f32/neon/vec4.rs
new file mode 100644
index 0000000..c98872e
--- /dev/null
+++ b/crates/glam/src/f32/neon/vec4.rs
@@ -0,0 +1,1859 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{f32::math, neon::*, BVec4, BVec4A, Vec2, Vec3, Vec3A};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+use core::arch::aarch64::*;
+
+#[repr(C)]
+union UnionCast {
+    a: [f32; 4],
+    v: Vec4,
+}
+
+/// Creates a 4-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec4 {
+    Vec4::new(x, y, z, w)
+}
+
+/// A 4-dimensional vector.
+///
+/// SIMD vector types are used for storage on supported platforms.
+///
+/// This type is 16 byte aligned.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct Vec4(pub(crate) float32x4_t);
+
+impl Vec4 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0.0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1.0);
+
+    /// All negative ones.
+    pub const NEG_ONE: Self = Self::splat(-1.0);
+
+    /// All `f32::MIN`.
+    pub const MIN: Self = Self::splat(f32::MIN);
+
+    /// All `f32::MAX`.
+    pub const MAX: Self = Self::splat(f32::MAX);
+
+    /// All `f32::NAN`.
+    pub const NAN: Self = Self::splat(f32::NAN);
+
+    /// All `f32::INFINITY`.
+    pub const INFINITY: Self = Self::splat(f32::INFINITY);
+
+    /// All `f32::NEG_INFINITY`.
+    pub const NEG_INFINITY: Self = Self::splat(f32::NEG_INFINITY);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0);
+
+    /// A unit vector pointing along the positive W axis.
+    pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0);
+
+    /// A unit vector pointing along the negative X axis.
+    pub const NEG_X: Self = Self::new(-1.0, 0.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the negative Y axis.
+    pub const NEG_Y: Self = Self::new(0.0, -1.0, 0.0, 0.0);
+
+    /// A unit vector pointing along the negative Z axis.
+    pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0, 0.0);
+
+    /// A unit vector pointing along the negative W axis.
+    pub const NEG_W: Self = Self::new(0.0, 0.0, 0.0, -1.0);
+
+    /// The unit axes.
+    pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
+        unsafe { UnionCast { a: [x, y, z, w] }.v }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: f32) -> Self {
+        unsafe { UnionCast { a: [v; 4] }.v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec4A, if_true: Self, if_false: Self) -> Self {
+        Self(unsafe { vbslq_f32(mask.0, if_true.0, if_false.0) })
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [f32; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
+    /// `[x, y, z, w]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [f32; 4] {
+        unsafe { *(self as *const Vec4 as *const [f32; 4]) }
+    }
+
+    /// Creates a vector from the first 4 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
+        Self::new(slice[0], slice[1], slice[2], slice[3])
+    }
+
+    /// Writes the elements of `self` to the first 4 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [f32]) {
+        assert!(slice.len() >= 4);
+        unsafe {
+            vst1q_f32(slice.as_mut_ptr(), self.0);
+        }
+    }
+
+    /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
+    ///
+    /// Truncation to [`Vec3`] may also be performed by using [`self.xyz()`][crate::swizzles::Vec4Swizzles::xyz()].
+    ///
+    /// To truncate to [`Vec3A`] use [`Vec3A::from()`].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> Vec3 {
+        use crate::swizzles::Vec4Swizzles;
+        self.xyz()
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f32) -> Self {
+        self.w = w;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> f32 {
+        unsafe { dot4(self.0, rhs.0) }
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self(unsafe { dot4_into_f32x4(self.0, rhs.0) })
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self(unsafe { vminq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self(unsafe { vmaxq_f32(self.0, rhs.0) })
+    }
+
+    /// Component-wise clamping of values, similar to [`f32::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> f32 {
+        unsafe { vminnmvq_f32(self.0) }
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> f32 {
+        unsafe { vmaxnmvq_f32(self.0) }
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        unsafe { vaddvq_f32(self.0) }
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        unsafe {
+            let s = vmuls_laneq_f32(vgetq_lane_f32(self.0, 0), self.0, 1);
+            let s = vmuls_laneq_f32(s, self.0, 2);
+            vmuls_laneq_f32(s, self.0, 3)
+        }
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vceqq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vmvnq_u32(vceqq_f32(self.0, rhs.0)) })
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vcgeq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vcgtq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vcleq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec4A {
+        BVec4A(unsafe { vcltq_f32(self.0, rhs.0) })
+    }
+
+    /// Returns a vector containing the absolute value of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn abs(self) -> Self {
+        Self(unsafe { vabsq_f32(self.0) })
+    }
+
+    /// Returns a vector with elements representing the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+    /// - `NAN` if the number is `NAN`
+    #[inline]
+    #[must_use]
+    pub fn signum(self) -> Self {
+        let result = Self(unsafe {
+            vreinterpretq_f32_u32(vorrq_u32(
+                vandq_u32(
+                    vreinterpretq_u32_f32(self.0),
+                    vreinterpretq_u32_f32(Self::NEG_ONE.0),
+                ),
+                vreinterpretq_u32_f32(Self::ONE.0),
+            ))
+        });
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
+    }
+
+    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
+    #[inline]
+    #[must_use]
+    pub fn copysign(self, rhs: Self) -> Self {
+        let mask = Self::splat(-0.0);
+        Self(unsafe {
+            vreinterpretq_f32_u32(vorrq_u32(
+                vandq_u32(vreinterpretq_u32_f32(rhs.0), vreinterpretq_u32_f32(mask.0)),
+                vandq_u32(
+                    vreinterpretq_u32_f32(self.0),
+                    vmvnq_u32(vreinterpretq_u32_f32(mask.0)),
+                ),
+            ))
+        })
+    }
+
+    /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
+    ///
+    /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn is_negative_bitmask(self) -> u32 {
+        unsafe {
+            let nmask = vreinterpretq_u32_f32(vdupq_n_f32(-0.0));
+            let m = vandq_u32(vreinterpretq_u32_f32(self.0), nmask);
+            let x = vgetq_lane_u32(m, 0) >> 31;
+            let y = vgetq_lane_u32(m, 1) >> 31;
+            let z = vgetq_lane_u32(m, 2) >> 31;
+
+            let w = vgetq_lane_u32(m, 3) >> 31;
+            x | y << 1 | z << 2 | w << 3
+        }
+    }
+
+    /// Returns `true` if, and only if, all elements are finite.  If any element is either
+    /// `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    #[must_use]
+    pub fn is_finite(self) -> bool {
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4A {
+        BVec4A(unsafe { vcltq_f32(vabsq_f32(self.0), Self::INFINITY.0) })
+    }
+
+    /// Returns `true` if any elements are `NaN`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan(self) -> bool {
+        self.is_nan_mask().any()
+    }
+
+    /// Performs `is_nan` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
+    #[inline]
+    #[must_use]
+    pub fn is_nan_mask(self) -> BVec4A {
+        BVec4A(unsafe { vmvnq_u32(vceqq_f32(self.0, self.0)) })
+    }
+
+    /// Computes the length of `self`.
+    #[doc(alias = "magnitude")]
+    #[inline]
+    #[must_use]
+    pub fn length(self) -> f32 {
+        math::sqrt(self.dot(self))
+    }
+
+    /// Computes the squared length of `self`.
+    ///
+    /// This is faster than `length()` as it avoids a square root operation.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> f32 {
+        self.dot(self)
+    }
+
+    /// Computes `1.0 / length()`.
+    ///
+    /// For valid results, `self` must _not_ be of length zero.
+    #[inline]
+    #[must_use]
+    pub fn length_recip(self) -> f32 {
+        self.length().recip()
+    }
+
+    /// Computes the Euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance(self, rhs: Self) -> f32 {
+        (self - rhs).length()
+    }
+
+    /// Compute the squared euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance_squared(self, rhs: Self) -> f32 {
+        (self - rhs).length_squared()
+    }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    #[must_use]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns `self` normalized to length 1.0.
+    ///
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
+    ///
+    /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
+    ///
+    /// Panics
+    ///
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn normalize(self) -> Self {
+        #[allow(clippy::let_and_return)]
+        let normalized = self.mul(self.length_recip());
+        glam_assert!(normalized.is_finite());
+        normalized
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns `None`.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be `None`.
+    ///
+    /// See also [`Self::normalize_or_zero()`].
+    #[inline]
+    #[must_use]
+    pub fn try_normalize(self) -> Option<Self> {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            Some(self * rcp)
+        } else {
+            None
+        }
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
+    /// Returns `self` normalized to length 1.0 if possible, else returns zero.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be zero.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or_zero(self) -> Self {
+        self.normalize_or(Self::ZERO)
+    }
+
+    /// Returns whether `self` is length `1.0` or not.
+    ///
+    /// Uses a precision threshold of approximately `1e-4`.
+    #[inline]
+    #[must_use]
+    pub fn is_normalized(self) -> bool {
+        math::abs(self.length_squared() - 1.0) <= 2e-4
+    }
+
+    /// Returns the vector projection of `self` onto `rhs`.
+    ///
+    /// `rhs` must be of non-zero length.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is zero length when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn project_onto(self, rhs: Self) -> Self {
+        let other_len_sq_rcp = rhs.dot(rhs).recip();
+        glam_assert!(other_len_sq_rcp.is_finite());
+        rhs * self.dot(rhs) * other_len_sq_rcp
+    }
+
+    /// Returns the vector rejection of `self` from `rhs`.
+    ///
+    /// The vector rejection is the vector perpendicular to the projection of `self` onto
+    /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`.
+    ///
+    /// `rhs` must be of non-zero length.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
+    #[inline]
+    #[must_use]
+    pub fn reject_from(self, rhs: Self) -> Self {
+        self - self.project_onto(rhs)
+    }
+
+    /// Returns the vector projection of `self` onto `rhs`.
+    ///
+    /// `rhs` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn project_onto_normalized(self, rhs: Self) -> Self {
+        glam_assert!(rhs.is_normalized());
+        rhs * self.dot(rhs)
+    }
+
+    /// Returns the vector rejection of `self` from `rhs`.
+    ///
+    /// The vector rejection is the vector perpendicular to the projection of `self` onto
+    /// `rhs`, in rhs words the result of `self - self.project_onto(rhs)`.
+    ///
+    /// `rhs` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
+    #[inline]
+    #[must_use]
+    pub fn reject_from_normalized(self, rhs: Self) -> Self {
+        self - self.project_onto_normalized(rhs)
+    }
+
+    /// Returns a vector containing the nearest integer to a number for each element of `self`.
+    /// Round half-way cases away from 0.0.
+    #[inline]
+    #[must_use]
+    pub fn round(self) -> Self {
+        Self(unsafe { vrndnq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the largest integer less than or equal to a number for each
+    /// element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn floor(self) -> Self {
+        Self(unsafe { vrndmq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the smallest integer greater than or equal to a number for
+    /// each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn ceil(self) -> Self {
+        Self(unsafe { vrndpq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the integer part each element of `self`. This means numbers are
+    /// always truncated towards zero.
+    #[inline]
+    #[must_use]
+    pub fn trunc(self) -> Self {
+        Self(unsafe { vrndq_f32(self.0) })
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
+        self - self.floor()
+    }
+
+    /// Returns a vector containing `e^self` (the exponential function) for each element of
+    /// `self`.
+    #[inline]
+    #[must_use]
+    pub fn exp(self) -> Self {
+        Self::new(
+            math::exp(self.x),
+            math::exp(self.y),
+            math::exp(self.z),
+            math::exp(self.w),
+        )
+    }
+
+    /// Returns a vector containing each element of `self` raised to the power of `n`.
+    #[inline]
+    #[must_use]
+    pub fn powf(self, n: f32) -> Self {
+        Self::new(
+            math::powf(self.x, n),
+            math::powf(self.y, n),
+            math::powf(self.z, n),
+            math::powf(self.w, n),
+        )
+    }
+
+    /// Returns a vector containing the reciprocal `1.0/n` of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn recip(self) -> Self {
+        Self(unsafe { vdivq_f32(Self::ONE.0, self.0) })
+    }
+
+    /// Performs a linear interpolation between `self` and `rhs` based on the value `s`.
+    ///
+    /// When `s` is `0.0`, the result will be equal to `self`.  When `s` is `1.0`, the result
+    /// will be equal to `rhs`. When `s` is outside of range `[0, 1]`, the result is linearly
+    /// extrapolated.
+    #[doc(alias = "mix")]
+    #[inline]
+    #[must_use]
+    pub fn lerp(self, rhs: Self, s: f32) -> Self {
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
+    }
+
+    /// Returns true if the absolute difference of all elements between `self` and `rhs` is
+    /// less than or equal to `max_abs_diff`.
+    ///
+    /// This can be used to compare if two vectors contain similar elements. It works best when
+    /// comparing with a known value. The `max_abs_diff` that should be used used depends on
+    /// the values being compared against.
+    ///
+    /// For more see
+    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
+    #[inline]
+    #[must_use]
+    pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
+        self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
+    }
+
+    /// Returns a vector with a length no less than `min` and no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
+        glam_assert!(min <= max);
+        let length_sq = self.length_squared();
+        if length_sq < min * min {
+            min * (self / math::sqrt(length_sq))
+        } else if length_sq > max * max {
+            max * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
+        let length_sq = self.length_squared();
+        if length_sq > max * max {
+            max * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
+        let length_sq = self.length_squared();
+        if length_sq < min * min {
+            min * (self / math::sqrt(length_sq))
+        } else {
+            self
+        }
+    }
+
+    /// Fused multiply-add. Computes `(self * a) + b` element-wise with only one rounding
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
+    /// architecture has a dedicated fma CPU instruction. However, this is not always true,
+    /// and will be heavily dependant on designing algorithms with specific target hardware in
+    /// mind.
+    #[inline]
+    #[must_use]
+    pub fn mul_add(self, a: Self, b: Self) -> Self {
+        Self(unsafe { vfmaq_f32(b.0, self.0, a.0) })
+    }
+
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec4(&self) -> crate::DVec4 {
+        crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
+    }
+
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec4(&self) -> crate::I16Vec4 {
+        crate::I16Vec4::new(self.x as i16, self.y as i16, self.z as i16, self.w as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec4(&self) -> crate::U16Vec4 {
+        crate::U16Vec4::new(self.x as u16, self.y as u16, self.z as u16, self.w as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec4(&self) -> crate::IVec4 {
+        crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec4(&self) -> crate::UVec4 {
+        crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec4(&self) -> crate::I64Vec4 {
+        crate::I64Vec4::new(self.x as i64, self.y as i64, self.z as i64, self.w as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec4(&self) -> crate::U64Vec4 {
+        crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
+    }
+}
+
+impl Default for Vec4 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl PartialEq for Vec4 {
+    #[inline]
+    fn eq(&self, rhs: &Self) -> bool {
+        self.cmpeq(*rhs).all()
+    }
+}
+
+impl Div<Vec4> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self(unsafe { vdivq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Div<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<Vec4> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vdivq_f32(self.0, rhs.0) };
+    }
+}
+
+impl DivAssign<&Self> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<f32> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self {
+        Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Div<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl DivAssign<&f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        Vec4(unsafe { vdivq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Div<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<Vec4> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self(unsafe { vmulq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Mul<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<Vec4> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vmulq_f32(self.0, rhs.0) };
+    }
+}
+
+impl MulAssign<&Self> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<f32> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: f32) -> Self {
+        Self(unsafe { vmulq_n_f32(self.0, rhs) })
+    }
+}
+
+impl Mul<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vmulq_n_f32(self.0, rhs) };
+    }
+}
+
+impl MulAssign<&f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        Vec4(unsafe { vmulq_n_f32(rhs.0, self) })
+    }
+}
+
+impl Mul<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<Vec4> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self(unsafe { vaddq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Add<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<Vec4> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.0 = unsafe { vaddq_f32(self.0, rhs.0) };
+    }
+}
+
+impl AddAssign<&Self> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<f32> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: f32) -> Self {
+        Self(unsafe { vaddq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Add<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vaddq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl AddAssign<&f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        Vec4(unsafe { vaddq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Add<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<Vec4> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self(unsafe { vsubq_f32(self.0, rhs.0) })
+    }
+}
+
+impl Sub<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<Vec4> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: Vec4) {
+        self.0 = unsafe { vsubq_f32(self.0, rhs.0) };
+    }
+}
+
+impl SubAssign<&Self> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<f32> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: f32) -> Self {
+        Self(unsafe { vsubq_f32(self.0, vld1q_dup_f32(&rhs)) })
+    }
+}
+
+impl Sub<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: f32) {
+        self.0 = unsafe { vsubq_f32(self.0, vld1q_dup_f32(&rhs)) };
+    }
+}
+
+impl SubAssign<&f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        Vec4(unsafe { vsubq_f32(vld1q_dup_f32(&self), rhs.0) })
+    }
+}
+
+impl Sub<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<Vec4> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        unsafe {
+            let n = vrndmq_f32(vdivq_f32(self.0, rhs.0));
+            Self(vsubq_f32(self.0, vmulq_f32(n, rhs.0)))
+        }
+    }
+}
+
+impl Rem<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<Vec4> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        *self = self.rem(rhs);
+    }
+}
+
+impl RemAssign<&Self> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<f32> for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: f32) -> Self {
+        self.rem(Self::splat(rhs))
+    }
+}
+
+impl Rem<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: f32) {
+        *self = self.rem(Self::splat(rhs));
+    }
+}
+
+impl RemAssign<&f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        Vec4::splat(self).rem(rhs)
+    }
+}
+
+impl Rem<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[f32; 4]> for Vec4 {
+    #[inline]
+    fn as_ref(&self) -> &[f32; 4] {
+        unsafe { &*(self as *const Vec4 as *const [f32; 4]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[f32; 4]> for Vec4 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [f32; 4] {
+        unsafe { &mut *(self as *mut Vec4 as *mut [f32; 4]) }
+    }
+}
+
+impl Sum for Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Neg for Vec4 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self(unsafe { vnegq_f32(self.0) })
+    }
+}
+
+impl Neg for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn neg(self) -> Vec4 {
+        (*self).neg()
+    }
+}
+
+impl Index<usize> for Vec4 {
+    type Output = f32;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            3 => &self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for Vec4 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            3 => &mut self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for Vec4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
+    }
+}
+
+impl fmt::Debug for Vec4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(Vec4))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .field(&self.w)
+            .finish()
+    }
+}
+
+impl From<Vec4> for float32x4_t {
+    #[inline(always)]
+    fn from(t: Vec4) -> Self {
+        t.0
+    }
+}
+
+impl From<float32x4_t> for Vec4 {
+    #[inline(always)]
+    fn from(t: float32x4_t) -> Self {
+        Self(t)
+    }
+}
+
+impl From<[f32; 4]> for Vec4 {
+    #[inline]
+    fn from(a: [f32; 4]) -> Self {
+        Self(unsafe { vld1q_f32(a.as_ptr()) })
+    }
+}
+
+impl From<Vec4> for [f32; 4] {
+    #[inline]
+    fn from(v: Vec4) -> Self {
+        use crate::align16::Align16;
+        use core::mem::MaybeUninit;
+        let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+        unsafe {
+            vst1q_f32(out.as_mut_ptr().cast(), v.0);
+            out.assume_init().0
+        }
+    }
+}
+
+impl From<(f32, f32, f32, f32)> for Vec4 {
+    #[inline]
+    fn from(t: (f32, f32, f32, f32)) -> Self {
+        Self::new(t.0, t.1, t.2, t.3)
+    }
+}
+
+impl From<Vec4> for (f32, f32, f32, f32) {
+    #[inline]
+    fn from(v: Vec4) -> Self {
+        use crate::align16::Align16;
+        use core::mem::MaybeUninit;
+        let mut out: MaybeUninit<Align16<Self>> = MaybeUninit::uninit();
+        unsafe {
+            vst1q_f32(out.as_mut_ptr().cast(), v.0);
+            out.assume_init().0
+        }
+    }
+}
+
+impl From<(Vec3A, f32)> for Vec4 {
+    #[inline]
+    fn from((v, w): (Vec3A, f32)) -> Self {
+        v.extend(w)
+    }
+}
+
+impl From<(f32, Vec3A)> for Vec4 {
+    #[inline]
+    fn from((x, v): (f32, Vec3A)) -> Self {
+        Self::new(x, v.x, v.y, v.z)
+    }
+}
+
+impl From<(Vec3, f32)> for Vec4 {
+    #[inline]
+    fn from((v, w): (Vec3, f32)) -> Self {
+        Self::new(v.x, v.y, v.z, w)
+    }
+}
+
+impl From<(f32, Vec3)> for Vec4 {
+    #[inline]
+    fn from((x, v): (f32, Vec3)) -> Self {
+        Self::new(x, v.x, v.y, v.z)
+    }
+}
+
+impl From<(Vec2, f32, f32)> for Vec4 {
+    #[inline]
+    fn from((v, z, w): (Vec2, f32, f32)) -> Self {
+        Self::new(v.x, v.y, z, w)
+    }
+}
+
+impl From<(Vec2, Vec2)> for Vec4 {
+    #[inline]
+    fn from((v, u): (Vec2, Vec2)) -> Self {
+        Self::new(v.x, v.y, u.x, u.y)
+    }
+}
+
+impl Deref for Vec4 {
+    type Target = crate::deref::Vec4<f32>;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*(self as *const Self).cast() }
+    }
+}
+
+impl DerefMut for Vec4 {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { &mut *(self as *mut Self).cast() }
+    }
+}
+
+impl From<BVec4> for Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f32::from(v.x),
+            f32::from(v.y),
+            f32::from(v.z),
+            f32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+            f32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/scalar/mat2.rs b/crates/glam/src/f32/scalar/mat2.rs
index 1205035..f650c69 100644
--- a/crates/glam/src/f32/scalar/mat2.rs
+++ b/crates/glam/src/f32/scalar/mat2.rs
@@ -1,10 +1,9 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 2x2 matrix from two column vectors.
 #[inline(always)]
@@ -119,6 +118,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
     #[inline]
     #[must_use]
@@ -126,6 +148,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from the first 4 values in `slice`.
     ///
     /// # Panics
@@ -288,6 +333,14 @@
         Self::from_cols(self.x_axis.mul(rhs), self.y_axis.mul(rhs))
     }
 
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec2::splat(rhs);
+        Self::from_cols(self.x_axis.div(rhs), self.y_axis.div(rhs))
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -304,6 +357,13 @@
             && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat2(&self) -> DMat2 {
         DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
@@ -401,6 +461,29 @@
     }
 }
 
+impl Div<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn div(self, rhs: Mat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat2 {
     fn sum<I>(iter: I) -> Self
     where
@@ -460,7 +543,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat2))
@@ -470,9 +552,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/scalar/mat3a.rs b/crates/glam/src/f32/scalar/mat3a.rs
index b443ae0..94b8cc7 100644
--- a/crates/glam/src/f32/scalar/mat3a.rs
+++ b/crates/glam/src/f32/scalar/mat3a.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 3x3 matrix from three column vectors.
 #[inline(always)]
@@ -153,7 +157,105 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: Mat4) -> Self {
-        Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into())
+        Self::from_cols(
+            Vec3A::from_vec4(m.x_axis),
+            Vec3A::from_vec4(m.y_axis),
+            Vec3A::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (0, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (0, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (0, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (1, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (1, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (1, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (1, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (2, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (2, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (2, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (2, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (3, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+            ),
+            (3, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+            ),
+            (3, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+            ),
+            (3, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+            ),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -217,8 +319,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -557,6 +677,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3A::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -574,6 +706,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat3(&self) -> DMat3 {
         DMat3::from_cols(
@@ -675,6 +814,29 @@
     }
 }
 
+impl Div<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn div(self, rhs: Mat3A) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Mul<Vec3> for Mat3A {
     type Output = Vec3;
     #[inline]
@@ -737,7 +899,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat3A))
@@ -748,9 +909,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/scalar/mat4.rs b/crates/glam/src/f32/scalar/mat4.rs
index 9b1d115..5541f26 100644
--- a/crates/glam/src/f32/scalar/mat4.rs
+++ b/crates/glam/src/f32/scalar/mat4.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 4x4 matrix from four column vectors.
 #[inline(always)]
@@ -393,8 +397,27 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
@@ -747,7 +770,10 @@
         Self::look_to_rh(eye, center.sub(eye), up)
     }
 
-    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
     /// This is the same as the OpenGL `gluPerspective` function.
     /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
     #[inline]
@@ -773,6 +799,8 @@
 
     /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -795,6 +823,8 @@
 
     /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -817,9 +847,13 @@
 
     /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
     /// # Panics
     ///
-    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -835,7 +869,9 @@
         )
     }
 
-    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
     ///
     /// # Panics
     ///
@@ -859,8 +895,15 @@
         )
     }
 
-    /// Creates an infinite right-handed perspective projection matrix with
-    /// `[0,1]` depth range.
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -874,8 +917,13 @@
         )
     }
 
-    /// Creates an infinite reverse right-handed perspective projection matrix
-    /// with `[0,1]` depth range.
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_reverse_rh(
@@ -897,6 +945,8 @@
     /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
     /// See
     /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
     #[inline]
     #[must_use]
     pub fn orthographic_rh_gl(
@@ -923,6 +973,8 @@
     }
 
     /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_lh(
@@ -950,6 +1002,8 @@
     }
 
     /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_rh(
@@ -989,7 +1043,7 @@
         res = self.y_axis.mul(rhs.y).add(res);
         res = self.z_axis.mul(rhs.z).add(res);
         res = self.w_axis.add(res);
-        res = res.mul(res.wwww().recip());
+        res = res.div(res.w);
         res.xyz()
     }
 
@@ -999,7 +1053,7 @@
     /// `1.0`.
     ///
     /// This method assumes that `self` contains a valid affine transform. It does not perform
-    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
     /// the [`Self::project_point3()`] method should be used instead.
     ///
     /// # Panics
@@ -1036,6 +1090,18 @@
         res.xyz()
     }
 
+    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
+        self.project_point3(rhs.into()).into()
+    }
+
     /// Transforms the given [`Vec3A`] as 3D point.
     ///
     /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
@@ -1113,6 +1179,19 @@
         )
     }
 
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -1131,6 +1210,18 @@
             && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
     #[inline]
     pub fn as_dmat4(&self) -> DMat4 {
         DMat4::from_cols(
@@ -1238,6 +1329,29 @@
     }
 }
 
+impl Div<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn div(self, rhs: Mat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat4 {
     fn sum<I>(iter: I) -> Self
     where
@@ -1300,7 +1414,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat4))
@@ -1312,13 +1425,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.x_axis, self.y_axis, self.z_axis, self.w_axis
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
     }
 }
diff --git a/crates/glam/src/f32/scalar/quat.rs b/crates/glam/src/f32/scalar/quat.rs
index d30e4a6..2cbeb4c 100644
--- a/crates/glam/src/f32/scalar/quat.rs
+++ b/crates/glam/src/f32/scalar/quat.rs
@@ -1,12 +1,11 @@
 // Generated from quat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
+    euler::{EulerRot, FromEuler, ToEuler},
     f32::math,
     DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
 };
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::ops::{Add, Div, Mul, MulAssign, Neg, Sub};
@@ -183,14 +182,22 @@
     #[inline]
     #[must_use]
     pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        euler.new_quat(a, b, c)
+        Self::from_euler_angles(euler, a, b, c)
     }
 
     /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
-        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
         let (m00, m01, m02) = x_axis.into();
         let (m10, m11, m12) = y_axis.into();
         let (m20, m21, m22) = z_axis.into();
@@ -248,6 +255,13 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3(mat: &Mat3) -> Self {
@@ -255,13 +269,28 @@
     }
 
     /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3a(mat: &Mat3A) -> Self {
         Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
     }
 
-    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat4(mat: &Mat4) -> Self {
@@ -290,13 +319,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPS {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPS {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             use core::f32::consts::PI; // half a turn = 𝛕/2 = 180°
             Self::from_axis_angle(from.any_orthonormal_vector(), PI)
         } else {
@@ -346,13 +375,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPSILON {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPSILON {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             const COS_FRAC_PI_2: f32 = 0.0;
             const SIN_FRAC_PI_2: f32 = 1.0;
             // rotation around z by PI radians
@@ -394,8 +423,8 @@
     /// Returns the rotation angles for the given euler rotation sequence.
     #[inline]
     #[must_use]
-    pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) {
-        euler.convert_quat(self)
+    pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
+        self.to_euler_angles(order)
     }
 
     /// `[x, y, z, w]`
@@ -498,6 +527,7 @@
         Vec4::from(self).is_finite()
     }
 
+    /// Returns `true` if any elements are `NAN`.
     #[inline]
     #[must_use]
     pub fn is_nan(self) -> bool {
@@ -550,6 +580,29 @@
         math::acos_approx(math::abs(self.dot(rhs))) * 2.0
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -565,6 +618,12 @@
         Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
     }
 
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f32) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
     /// Performs a linear interpolation between `self` and `rhs` based on
     /// the value `s`.
     ///
@@ -581,11 +640,9 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        let start = self;
-        let dot = start.dot(end);
+        let dot = self.dot(end);
         let bias = if dot >= 0.0 { 1.0 } else { -1.0 };
-        let interpolated = start.add(end.mul(bias).sub(start).mul(s));
-        interpolated.normalize()
+        self.lerp_impl(end * bias, s)
     }
 
     /// Performs a spherical linear interpolation between `self` and `end`
@@ -604,8 +661,6 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        const DOT_THRESHOLD: f32 = 0.9995;
-
         // Note that a rotation can be represented by two quaternions: `q` and
         // `-q`. The slerp path between `q` and `end` will be different from the
         // path between `-q` and `end`. One path will take the long way around and
@@ -618,17 +673,17 @@
             dot = -dot;
         }
 
+        const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
         if dot > DOT_THRESHOLD {
-            // assumes lerp returns a normalized quaternion
-            self.lerp(end, s)
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
         } else {
             let theta = math::acos_approx(dot);
 
             let scale1 = math::sin(theta * (1.0 - s));
             let scale2 = math::sin(theta * s);
             let theta_sin = math::sin(theta);
-
-            self.mul(scale1).add(end.mul(scale2)).mul(1.0 / theta_sin)
+            ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
         }
     }
 
@@ -661,9 +716,6 @@
     #[inline]
     #[must_use]
     pub fn mul_quat(self, rhs: Self) -> Self {
-        glam_assert!(self.is_normalized());
-        glam_assert!(rhs.is_normalized());
-
         let (x0, y0, z0, w0) = self.into();
         let (x1, y1, z1, w1) = rhs.into();
         Self::from_xyzw(
@@ -675,6 +727,14 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn from_affine3(a: &crate::Affine3A) -> Self {
@@ -698,16 +758,8 @@
     pub fn as_dquat(self) -> DQuat {
         DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
-
-    #[inline]
-    #[must_use]
-    #[deprecated(since = "0.24.2", note = "Use as_dquat() instead")]
-    pub fn as_f64(self) -> DQuat {
-        self.as_dquat()
-    }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Quat {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Quat))
@@ -719,10 +771,17 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Quat {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/scalar/vec3a.rs b/crates/glam/src/f32/scalar/vec3a.rs
index 040a140..4c1c0ce 100644
--- a/crates/glam/src/f32/scalar/vec3a.rs
+++ b/crates/glam/src/f32/scalar/vec3a.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, BVec3A, Vec2, Vec3, Vec4};
+use crate::{f32::math, BVec3, BVec3A, Vec2, Vec3, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -93,6 +92,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -130,6 +139,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -140,16 +150,15 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
-    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
-    #[allow(dead_code)]
+    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
+    ///
+    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
     #[inline]
     #[must_use]
-    pub(crate) fn from_vec4(v: Vec4) -> Self {
+    pub fn from_vec4(v: Vec4) -> Self {
         Self {
             x: v.x,
             y: v.y,
@@ -174,6 +183,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -257,6 +290,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -380,6 +431,13 @@
         self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3A {
+        BVec3A::new(self.x.is_finite(), self.y.is_finite(), self.z.is_finite())
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -389,7 +447,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3A {
@@ -463,13 +521,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -496,6 +554,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -505,22 +581,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -548,6 +618,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -578,6 +649,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -632,13 +704,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -681,7 +767,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -699,14 +810,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -718,10 +830,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -730,10 +847,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -759,7 +881,45 @@
         )
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -833,6 +993,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -895,6 +1069,30 @@
     }
 }
 
+impl Div<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec3A> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -904,6 +1102,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -916,6 +1121,30 @@
     }
 }
 
+impl Div<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -925,6 +1154,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -937,6 +1173,30 @@
     }
 }
 
+impl Div<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -949,6 +1209,30 @@
     }
 }
 
+impl Mul<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec3A> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -958,6 +1242,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -970,6 +1261,30 @@
     }
 }
 
+impl Mul<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -979,6 +1294,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -991,6 +1313,30 @@
     }
 }
 
+impl Mul<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1003,6 +1349,30 @@
     }
 }
 
+impl Add<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec3A> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -1012,6 +1382,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1024,6 +1401,30 @@
     }
 }
 
+impl Add<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -1033,6 +1434,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1045,6 +1453,30 @@
     }
 }
 
+impl Add<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1057,6 +1489,30 @@
     }
 }
 
+impl Sub<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec3A> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec3A) {
@@ -1066,6 +1522,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1078,6 +1541,30 @@
     }
 }
 
+impl Sub<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -1087,6 +1574,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1099,6 +1593,30 @@
     }
 }
 
+impl Sub<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1111,6 +1629,30 @@
     }
 }
 
+impl Rem<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec3A> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1120,6 +1662,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1132,6 +1681,30 @@
     }
 }
 
+impl Rem<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1141,6 +1714,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1153,6 +1733,30 @@
     }
 }
 
+impl Rem<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 3]> for Vec3A {
     #[inline]
@@ -1221,6 +1825,14 @@
     }
 }
 
+impl Neg for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn neg(self) -> Vec3A {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec3A {
     type Output = f32;
     #[inline]
@@ -1246,14 +1858,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec3A))
@@ -1299,20 +1913,6 @@
     }
 }
 
-impl From<Vec4> for Vec3A {
-    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
-    ///
-    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
-    #[inline]
-    fn from(v: Vec4) -> Self {
-        Self {
-            x: v.x,
-            y: v.y,
-            z: v.z,
-        }
-    }
-}
-
 impl From<Vec3A> for Vec3 {
     #[inline]
     fn from(v: Vec3A) -> Self {
@@ -1330,3 +1930,22 @@
         Self::new(v.x, v.y, z)
     }
 }
+
+impl From<BVec3> for Vec3A {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3A {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/scalar/vec4.rs b/crates/glam/src/f32/scalar/vec4.rs
index 499c3cc..bd41448 100644
--- a/crates/glam/src/f32/scalar/vec4.rs
+++ b/crates/glam/src/f32/scalar/vec4.rs
@@ -2,11 +2,11 @@
 
 #[cfg(feature = "scalar-math")]
 use crate::BVec4 as BVec4A;
+
 #[cfg(not(feature = "scalar-math"))]
 use crate::BVec4A;
-use crate::{f32::math, Vec2, Vec3, Vec3A};
+use crate::{f32::math, BVec4, Vec2, Vec3, Vec3A};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -110,6 +110,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -148,6 +158,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -158,10 +169,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -176,6 +184,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -250,6 +290,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -407,6 +465,18 @@
         self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4A {
+        BVec4A::new(
+            self.x.is_finite(),
+            self.y.is_finite(),
+            self.z.is_finite(),
+            self.w.is_finite(),
+        )
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -416,7 +486,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec4A {
@@ -497,13 +567,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -530,6 +600,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -539,22 +627,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -582,6 +664,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -612,6 +695,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -670,13 +754,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -726,7 +824,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -744,14 +867,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -763,10 +887,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -775,10 +904,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -805,6 +939,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Casts all elements of `self` to `f64`.
     #[inline]
     #[must_use]
@@ -812,6 +984,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -875,6 +1061,30 @@
     }
 }
 
+impl Div<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec4> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -885,6 +1095,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -898,6 +1115,30 @@
     }
 }
 
+impl Div<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -908,6 +1149,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -921,6 +1169,30 @@
     }
 }
 
+impl Div<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -934,6 +1206,30 @@
     }
 }
 
+impl Mul<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec4> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -944,6 +1240,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -957,6 +1260,30 @@
     }
 }
 
+impl Mul<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -967,6 +1294,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -980,6 +1314,30 @@
     }
 }
 
+impl Mul<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -993,6 +1351,30 @@
     }
 }
 
+impl Add<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec4> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -1003,6 +1385,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -1016,6 +1405,30 @@
     }
 }
 
+impl Add<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -1026,6 +1439,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -1039,6 +1459,30 @@
     }
 }
 
+impl Add<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -1052,6 +1496,30 @@
     }
 }
 
+impl Sub<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec4> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec4) {
@@ -1062,6 +1530,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -1075,6 +1550,30 @@
     }
 }
 
+impl Sub<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -1085,6 +1584,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -1098,6 +1604,30 @@
     }
 }
 
+impl Sub<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -1111,6 +1641,30 @@
     }
 }
 
+impl Rem<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec4> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1121,6 +1675,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -1134,6 +1695,30 @@
     }
 }
 
+impl Rem<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1144,6 +1729,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -1157,6 +1749,30 @@
     }
 }
 
+impl Rem<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 4]> for Vec4 {
     #[inline]
@@ -1226,6 +1842,14 @@
     }
 }
 
+impl Neg for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn neg(self) -> Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec4 {
     type Output = f32;
     #[inline]
@@ -1253,14 +1877,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec4))
@@ -1341,3 +1971,30 @@
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl From<BVec4> for Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f32::from(v.x),
+            f32::from(v.y),
+            f32::from(v.z),
+            f32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+            f32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/sse2/mat2.rs b/crates/glam/src/f32/sse2/mat2.rs
index ab63731..64e098a 100644
--- a/crates/glam/src/f32/sse2/mat2.rs
+++ b/crates/glam/src/f32/sse2/mat2.rs
@@ -1,10 +1,9 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 #[cfg(target_arch = "x86")]
 use core::arch::x86::*;
@@ -133,6 +132,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
     #[inline]
     #[must_use]
@@ -140,6 +162,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from the first 4 values in `slice`.
     ///
     /// # Panics
@@ -325,6 +370,13 @@
         Self(unsafe { _mm_mul_ps(self.0, _mm_set_ps1(rhs)) })
     }
 
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        Self(unsafe { _mm_div_ps(self.0, _mm_set_ps1(rhs)) })
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -341,6 +393,13 @@
             && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat2(&self) -> DMat2 {
         DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
@@ -438,6 +497,29 @@
     }
 }
 
+impl Div<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn div(self, rhs: Mat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat2 {
     fn sum<I>(iter: I) -> Self
     where
@@ -512,7 +594,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat2))
@@ -522,9 +603,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/sse2/mat3a.rs b/crates/glam/src/f32/sse2/mat3a.rs
index 56f762e..9eb64b8 100644
--- a/crates/glam/src/f32/sse2/mat3a.rs
+++ b/crates/glam/src/f32/sse2/mat3a.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 #[cfg(target_arch = "x86")]
 use core::arch::x86::*;
@@ -155,7 +159,105 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: Mat4) -> Self {
-        Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into())
+        Self::from_cols(
+            Vec3A::from_vec4(m.x_axis),
+            Vec3A::from_vec4(m.y_axis),
+            Vec3A::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (0, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (0, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (0, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (1, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (1, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (1, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (1, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (2, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (2, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (2, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (2, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (3, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+            ),
+            (3, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+            ),
+            (3, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+            ),
+            (3, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+            ),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -219,8 +321,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -564,6 +684,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3A::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -581,6 +713,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat3(&self) -> DMat3 {
         DMat3::from_cols(
@@ -682,6 +821,29 @@
     }
 }
 
+impl Div<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn div(self, rhs: Mat3A) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Mul<Vec3> for Mat3A {
     type Output = Vec3;
     #[inline]
@@ -744,7 +906,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat3A))
@@ -755,9 +916,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/sse2/mat4.rs b/crates/glam/src/f32/sse2/mat4.rs
index 490b981..062642c 100644
--- a/crates/glam/src/f32/sse2/mat4.rs
+++ b/crates/glam/src/f32/sse2/mat4.rs
@@ -1,12 +1,15 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    f32::math, sse2::*, swizzles::*, DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    sse2::*,
+    swizzles::*,
+    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
 };
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 #[cfg(target_arch = "x86")]
 use core::arch::x86::*;
@@ -385,8 +388,27 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
@@ -835,7 +857,10 @@
         Self::look_to_rh(eye, center.sub(eye), up)
     }
 
-    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
     /// This is the same as the OpenGL `gluPerspective` function.
     /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
     #[inline]
@@ -861,6 +886,8 @@
 
     /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -883,6 +910,8 @@
 
     /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -905,9 +934,13 @@
 
     /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
     /// # Panics
     ///
-    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -923,7 +956,9 @@
         )
     }
 
-    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
     ///
     /// # Panics
     ///
@@ -947,8 +982,15 @@
         )
     }
 
-    /// Creates an infinite right-handed perspective projection matrix with
-    /// `[0,1]` depth range.
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -962,8 +1004,13 @@
         )
     }
 
-    /// Creates an infinite reverse right-handed perspective projection matrix
-    /// with `[0,1]` depth range.
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_reverse_rh(
@@ -985,6 +1032,8 @@
     /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
     /// See
     /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
     #[inline]
     #[must_use]
     pub fn orthographic_rh_gl(
@@ -1011,6 +1060,8 @@
     }
 
     /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_lh(
@@ -1038,6 +1089,8 @@
     }
 
     /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_rh(
@@ -1077,7 +1130,7 @@
         res = self.y_axis.mul(rhs.y).add(res);
         res = self.z_axis.mul(rhs.z).add(res);
         res = self.w_axis.add(res);
-        res = res.mul(res.wwww().recip());
+        res = res.div(res.w);
         res.xyz()
     }
 
@@ -1087,7 +1140,7 @@
     /// `1.0`.
     ///
     /// This method assumes that `self` contains a valid affine transform. It does not perform
-    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
     /// the [`Self::project_point3()`] method should be used instead.
     ///
     /// # Panics
@@ -1124,6 +1177,23 @@
         res.xyz()
     }
 
+    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        res = self.w_axis.add(res);
+        res = res.div(res.wwww());
+        Vec3A::from_vec4(res)
+    }
+
     /// Transforms the given [`Vec3A`] as 3D point.
     ///
     /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
@@ -1135,7 +1205,7 @@
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
         res = self.w_axis.add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms the give [`Vec3A`] as 3D vector.
@@ -1148,7 +1218,7 @@
         let mut res = self.x_axis.mul(rhs.xxxx());
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms a 4D vector.
@@ -1210,6 +1280,19 @@
         )
     }
 
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -1228,6 +1311,18 @@
             && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
     #[inline]
     pub fn as_dmat4(&self) -> DMat4 {
         DMat4::from_cols(
@@ -1335,6 +1430,29 @@
     }
 }
 
+impl Div<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn div(self, rhs: Mat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat4 {
     fn sum<I>(iter: I) -> Self
     where
@@ -1397,7 +1515,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat4))
@@ -1409,13 +1526,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.x_axis, self.y_axis, self.z_axis, self.w_axis
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
     }
 }
diff --git a/crates/glam/src/f32/sse2/quat.rs b/crates/glam/src/f32/sse2/quat.rs
index ce032fe..634f780 100644
--- a/crates/glam/src/f32/sse2/quat.rs
+++ b/crates/glam/src/f32/sse2/quat.rs
@@ -1,7 +1,7 @@
 // Generated from quat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
+    euler::{EulerRot, FromEuler, ToEuler},
     f32::math,
     sse2::*,
     DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
@@ -12,7 +12,6 @@
 #[cfg(target_arch = "x86_64")]
 use core::arch::x86_64::*;
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub};
@@ -183,14 +182,22 @@
     #[inline]
     #[must_use]
     pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        euler.new_quat(a, b, c)
+        Self::from_euler_angles(euler, a, b, c)
     }
 
     /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
-        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
         let (m00, m01, m02) = x_axis.into();
         let (m10, m11, m12) = y_axis.into();
         let (m20, m21, m22) = z_axis.into();
@@ -248,6 +255,13 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3(mat: &Mat3) -> Self {
@@ -255,13 +269,28 @@
     }
 
     /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3a(mat: &Mat3A) -> Self {
         Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
     }
 
-    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat4(mat: &Mat4) -> Self {
@@ -290,13 +319,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPS {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPS {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             use core::f32::consts::PI; // half a turn = 𝛕/2 = 180°
             Self::from_axis_angle(from.any_orthonormal_vector(), PI)
         } else {
@@ -346,13 +375,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPSILON {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPSILON {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             const COS_FRAC_PI_2: f32 = 0.0;
             const SIN_FRAC_PI_2: f32 = 1.0;
             // rotation around z by PI radians
@@ -394,8 +423,8 @@
     /// Returns the rotation angles for the given euler rotation sequence.
     #[inline]
     #[must_use]
-    pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) {
-        euler.convert_quat(self)
+    pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
+        self.to_euler_angles(order)
     }
 
     /// `[x, y, z, w]`
@@ -494,6 +523,7 @@
         Vec4::from(self).is_finite()
     }
 
+    /// Returns `true` if any elements are `NAN`.
     #[inline]
     #[must_use]
     pub fn is_nan(self) -> bool {
@@ -546,6 +576,29 @@
         math::acos_approx(math::abs(self.dot(rhs))) * 2.0
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -561,6 +614,12 @@
         Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
     }
 
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f32) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
     /// Performs a linear interpolation between `self` and `rhs` based on
     /// the value `s`.
     ///
@@ -578,18 +637,12 @@
         glam_assert!(end.is_normalized());
 
         const NEG_ZERO: __m128 = m128_from_f32x4([-0.0; 4]);
-        let start = self.0;
-        let end = end.0;
         unsafe {
-            let dot = dot4_into_m128(start, end);
+            let dot = dot4_into_m128(self.0, end.0);
             // Calculate the bias, if the dot product is positive or zero, there is no bias
             // but if it is negative, we want to flip the 'end' rotation XYZW components
             let bias = _mm_and_ps(dot, NEG_ZERO);
-            let interpolated = _mm_add_ps(
-                _mm_mul_ps(_mm_sub_ps(_mm_xor_ps(end, bias), start), _mm_set_ps1(s)),
-                start,
-            );
-            Quat(interpolated).normalize()
+            self.lerp_impl(Self(_mm_xor_ps(end.0, bias)), s)
         }
     }
 
@@ -609,8 +662,6 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        const DOT_THRESHOLD: f32 = 0.9995;
-
         // Note that a rotation can be represented by two quaternions: `q` and
         // `-q`. The slerp path between `q` and `end` will be different from the
         // path between `-q` and `end`. One path will take the long way around and
@@ -623,9 +674,10 @@
             dot = -dot;
         }
 
+        const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
         if dot > DOT_THRESHOLD {
-            // assumes lerp returns a normalized quaternion
-            self.lerp(end, s)
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
         } else {
             let theta = math::acos_approx(dot);
 
@@ -673,9 +725,6 @@
     #[inline]
     #[must_use]
     pub fn mul_quat(self, rhs: Self) -> Self {
-        glam_assert!(self.is_normalized());
-        glam_assert!(rhs.is_normalized());
-
         // Based on https://github.com/nfrechette/rtm `rtm::quat_mul`
         const CONTROL_WZYX: __m128 = m128_from_f32x4([1.0, -1.0, 1.0, -1.0]);
         const CONTROL_ZWXY: __m128 = m128_from_f32x4([1.0, 1.0, -1.0, -1.0]);
@@ -714,6 +763,14 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn from_affine3(a: &crate::Affine3A) -> Self {
@@ -749,16 +806,8 @@
     pub fn as_dquat(self) -> DQuat {
         DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
-
-    #[inline]
-    #[must_use]
-    #[deprecated(since = "0.24.2", note = "Use as_dquat() instead")]
-    pub fn as_f64(self) -> DQuat {
-        self.as_dquat()
-    }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Quat {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Quat))
@@ -770,10 +819,17 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Quat {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/sse2/vec3a.rs b/crates/glam/src/f32/sse2/vec3a.rs
index 96c62a7..e9b5e47 100644
--- a/crates/glam/src/f32/sse2/vec3a.rs
+++ b/crates/glam/src/f32/sse2/vec3a.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, sse2::*, BVec3A, Vec2, Vec3, Vec4};
+use crate::{f32::math, sse2::*, BVec3, BVec3A, Vec2, Vec3, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -98,6 +97,16 @@
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -136,6 +145,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -146,16 +156,15 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
-    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
-    #[allow(dead_code)]
+    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
+    ///
+    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
     #[inline]
     #[must_use]
-    pub(crate) fn from_vec4(v: Vec4) -> Self {
+    pub fn from_vec4(v: Vec4) -> Self {
         Self(v.0)
     }
 
@@ -176,6 +185,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -269,6 +302,34 @@
         }
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        unsafe {
+            let v = self.0;
+            let v = _mm_add_ps(v, _mm_shuffle_ps(v, Self::ZERO.0, 0b00_11_00_01));
+            let v = _mm_add_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_10));
+            _mm_cvtss_f32(v)
+        }
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        unsafe {
+            let v = self.0;
+            let v = _mm_mul_ps(v, _mm_shuffle_ps(v, Self::ONE.0, 0b00_11_00_01));
+            let v = _mm_mul_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_10));
+            _mm_cvtss_f32(v)
+        }
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -350,24 +411,17 @@
     #[inline]
     #[must_use]
     pub fn signum(self) -> Self {
-        unsafe {
-            let result = Self(_mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0));
-            let mask = self.is_nan_mask();
-            Self::select(mask, self, result)
-        }
+        let result = Self(unsafe { _mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0) });
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
     }
 
     /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
     #[inline]
     #[must_use]
     pub fn copysign(self, rhs: Self) -> Self {
-        unsafe {
-            let mask = Self::splat(-0.0);
-            Self(_mm_or_ps(
-                _mm_and_ps(rhs.0, mask.0),
-                _mm_andnot_ps(mask.0, self.0),
-            ))
-        }
+        let mask = Self::splat(-0.0);
+        Self(unsafe { _mm_or_ps(_mm_and_ps(rhs.0, mask.0), _mm_andnot_ps(mask.0, self.0)) })
     }
 
     /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
@@ -385,7 +439,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3A {
+        BVec3A(unsafe { _mm_cmplt_ps(crate::sse2::m128_abs(self.0), Self::INFINITY.0) })
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -397,7 +458,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3A {
@@ -477,13 +538,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -513,6 +574,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -522,22 +601,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -565,6 +638,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -595,6 +669,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -633,13 +708,27 @@
         Self(unsafe { m128_trunc(self.0) })
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -678,7 +767,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -696,14 +810,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -715,10 +830,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -727,10 +847,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -761,7 +886,45 @@
         )
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -835,6 +998,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -900,6 +1077,30 @@
     }
 }
 
+impl Div<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec3A> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -907,6 +1108,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -915,6 +1123,30 @@
     }
 }
 
+impl Div<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -922,6 +1154,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -930,6 +1169,30 @@
     }
 }
 
+impl Div<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -938,6 +1201,30 @@
     }
 }
 
+impl Mul<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec3A> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -945,6 +1232,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -953,6 +1247,30 @@
     }
 }
 
+impl Mul<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -960,6 +1278,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -968,6 +1293,30 @@
     }
 }
 
+impl Mul<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -976,6 +1325,30 @@
     }
 }
 
+impl Add<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec3A> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -983,6 +1356,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -991,6 +1371,30 @@
     }
 }
 
+impl Add<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -998,6 +1402,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1006,6 +1417,30 @@
     }
 }
 
+impl Add<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1014,6 +1449,30 @@
     }
 }
 
+impl Sub<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec3A> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec3A) {
@@ -1021,6 +1480,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1029,6 +1495,30 @@
     }
 }
 
+impl Sub<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -1036,6 +1526,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1044,6 +1541,30 @@
     }
 }
 
+impl Sub<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1055,6 +1576,30 @@
     }
 }
 
+impl Rem<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec3A> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1062,6 +1607,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1070,6 +1622,30 @@
     }
 }
 
+impl Rem<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1077,6 +1653,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1085,6 +1668,30 @@
     }
 }
 
+impl Rem<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 3]> for Vec3A {
     #[inline]
@@ -1149,6 +1756,14 @@
     }
 }
 
+impl Neg for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn neg(self) -> Vec3A {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec3A {
     type Output = f32;
     #[inline]
@@ -1174,14 +1789,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec3A))
@@ -1193,14 +1810,14 @@
 }
 
 impl From<Vec3A> for __m128 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec3A) -> Self {
         t.0
     }
 }
 
 impl From<__m128> for Vec3A {
-    #[inline]
+    #[inline(always)]
     fn from(t: __m128) -> Self {
         Self(t)
     }
@@ -1253,16 +1870,6 @@
     }
 }
 
-impl From<Vec4> for Vec3A {
-    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
-    ///
-    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
-    #[inline]
-    fn from(v: Vec4) -> Self {
-        Self(v.0)
-    }
-}
-
 impl From<Vec3A> for Vec3 {
     #[inline]
     fn from(v: Vec3A) -> Self {
@@ -1297,3 +1904,22 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec3> for Vec3A {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3A {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/sse2/vec4.rs b/crates/glam/src/f32/sse2/vec4.rs
index 3792aae..dfab9f2 100644
--- a/crates/glam/src/f32/sse2/vec4.rs
+++ b/crates/glam/src/f32/sse2/vec4.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, sse2::*, BVec4A, Vec2, Vec3, Vec3A};
+use crate::{f32::math, sse2::*, BVec4, BVec4A, Vec2, Vec3, Vec3A};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -100,6 +99,16 @@
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -138,6 +147,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -148,8 +158,8 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
+        assert!(slice.len() >= 4);
         unsafe {
-            assert!(slice.len() >= 4);
             _mm_storeu_ps(slice.as_mut_ptr(), self.0);
         }
     }
@@ -166,6 +176,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -240,6 +282,34 @@
         }
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        unsafe {
+            let v = self.0;
+            let v = _mm_add_ps(v, _mm_shuffle_ps(v, v, 0b00_11_00_01));
+            let v = _mm_add_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_10));
+            _mm_cvtss_f32(v)
+        }
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        unsafe {
+            let v = self.0;
+            let v = _mm_mul_ps(v, _mm_shuffle_ps(v, v, 0b00_11_00_01));
+            let v = _mm_mul_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_10));
+            _mm_cvtss_f32(v)
+        }
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -321,24 +391,17 @@
     #[inline]
     #[must_use]
     pub fn signum(self) -> Self {
-        unsafe {
-            let result = Self(_mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0));
-            let mask = self.is_nan_mask();
-            Self::select(mask, self, result)
-        }
+        let result = Self(unsafe { _mm_or_ps(_mm_and_ps(self.0, Self::NEG_ONE.0), Self::ONE.0) });
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
     }
 
     /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
     #[inline]
     #[must_use]
     pub fn copysign(self, rhs: Self) -> Self {
-        unsafe {
-            let mask = Self::splat(-0.0);
-            Self(_mm_or_ps(
-                _mm_and_ps(rhs.0, mask.0),
-                _mm_andnot_ps(mask.0, self.0),
-            ))
-        }
+        let mask = Self::splat(-0.0);
+        Self(unsafe { _mm_or_ps(_mm_and_ps(rhs.0, mask.0), _mm_andnot_ps(mask.0, self.0)) })
     }
 
     /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
@@ -356,7 +419,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4A {
+        BVec4A(unsafe { _mm_cmplt_ps(crate::sse2::m128_abs(self.0), Self::INFINITY.0) })
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -368,7 +438,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec4A {
@@ -450,13 +520,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -486,6 +556,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -495,22 +583,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -538,6 +620,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -568,6 +651,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -606,13 +690,27 @@
         Self(unsafe { m128_trunc(self.0) })
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -657,7 +755,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -675,14 +798,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -694,10 +818,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -706,10 +835,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -741,6 +875,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Casts all elements of `self` to `f64`.
     #[inline]
     #[must_use]
@@ -748,6 +920,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -813,6 +999,30 @@
     }
 }
 
+impl Div<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec4> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -820,6 +1030,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -828,6 +1045,30 @@
     }
 }
 
+impl Div<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -835,6 +1076,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -843,6 +1091,30 @@
     }
 }
 
+impl Div<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -851,6 +1123,30 @@
     }
 }
 
+impl Mul<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec4> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -858,6 +1154,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -866,6 +1169,30 @@
     }
 }
 
+impl Mul<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -873,6 +1200,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -881,6 +1215,30 @@
     }
 }
 
+impl Mul<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -889,6 +1247,30 @@
     }
 }
 
+impl Add<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec4> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -896,6 +1278,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -904,6 +1293,30 @@
     }
 }
 
+impl Add<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -911,6 +1324,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -919,6 +1339,30 @@
     }
 }
 
+impl Add<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -927,6 +1371,30 @@
     }
 }
 
+impl Sub<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec4> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec4) {
@@ -934,6 +1402,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -942,6 +1417,30 @@
     }
 }
 
+impl Sub<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -949,6 +1448,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -957,6 +1463,30 @@
     }
 }
 
+impl Sub<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -968,6 +1498,30 @@
     }
 }
 
+impl Rem<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec4> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -975,6 +1529,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -983,6 +1544,30 @@
     }
 }
 
+impl Rem<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -990,6 +1575,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -998,6 +1590,30 @@
     }
 }
 
+impl Rem<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 4]> for Vec4 {
     #[inline]
@@ -1062,6 +1678,14 @@
     }
 }
 
+impl Neg for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn neg(self) -> Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec4 {
     type Output = f32;
     #[inline]
@@ -1089,14 +1713,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec4))
@@ -1109,14 +1739,14 @@
 }
 
 impl From<Vec4> for __m128 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec4) -> Self {
         t.0
     }
 }
 
 impl From<__m128> for Vec4 {
-    #[inline]
+    #[inline(always)]
     fn from(t: __m128) -> Self {
         Self(t)
     }
@@ -1218,3 +1848,30 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec4> for Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f32::from(v.x),
+            f32::from(v.y),
+            f32::from(v.z),
+            f32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+            f32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/vec2.rs b/crates/glam/src/f32/vec2.rs
index 85f7fbd..f4b7fdf 100644
--- a/crates/glam/src/f32/vec2.rs
+++ b/crates/glam/src/f32/vec2.rs
@@ -2,7 +2,6 @@
 
 use crate::{f32::math, BVec2, Vec3};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -78,6 +77,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -114,6 +123,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -124,8 +134,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -135,6 +144,22 @@
         Vec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -205,6 +230,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,6 +366,13 @@
         self.x.is_finite() && self.y.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec2 {
+        BVec2::new(self.x.is_finite(), self.y.is_finite())
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -332,7 +382,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec2 {
@@ -404,13 +454,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -437,6 +487,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -446,22 +514,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -489,6 +551,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -519,6 +582,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -569,13 +633,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -613,7 +691,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -631,14 +734,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -650,10 +754,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -662,10 +771,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -690,6 +804,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in
     /// conjunction with the [`rotate()`][Self::rotate()] method, e.g.
     /// `Vec2::from_angle(PI).rotate(Vec2::Y)` will create the vector `[-1, 0]`
@@ -710,12 +862,22 @@
         math::atan2(self.y, self.x)
     }
 
-    /// Returns the angle (in radians) between `self` and `rhs` in the range `[-π, +π]`.
+    #[inline]
+    #[must_use]
+    #[deprecated(
+        since = "0.27.0",
+        note = "Use angle_to() instead, the semantics of angle_between will change in the future."
+    )]
+    pub fn angle_between(self, rhs: Self) -> f32 {
+        self.angle_to(rhs)
+    }
+
+    /// Returns the angle of rotation (in radians) from `self` to `rhs` in the range `[-π, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
     #[must_use]
-    pub fn angle_between(self, rhs: Self) -> f32 {
+    pub fn angle_to(self, rhs: Self) -> f32 {
         let angle = math::acos_approx(
             self.dot(rhs) / math::sqrt(self.length_squared() * rhs.length_squared()),
         );
@@ -756,6 +918,24 @@
         }
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        let a = self.angle_to(rhs);
+        let abs_a = math::abs(a);
+        if abs_a <= 1e-4 {
+            return rhs;
+        }
+        // When `max_angle < 0`, rotate no further than `PI` radians away
+        let angle = max_angle.clamp(abs_a - core::f32::consts::PI, abs_a) * math::signum(a);
+        Self::from_angle(angle).rotate(*self)
+    }
+
     /// Casts all elements of `self` to `f64`.
     #[inline]
     #[must_use]
@@ -763,6 +943,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -824,6 +1018,30 @@
     }
 }
 
+impl Div<&Vec2> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &Vec2) -> Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &Vec2) -> Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: Vec2) -> Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec2> for Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -832,6 +1050,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec2 {
     type Output = Self;
     #[inline]
@@ -843,6 +1068,30 @@
     }
 }
 
+impl Div<&f32> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -851,6 +1100,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec2> for f32 {
     type Output = Vec2;
     #[inline]
@@ -862,6 +1118,30 @@
     }
 }
 
+impl Div<&Vec2> for f32 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &Vec2) -> Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: &Vec2) -> Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn div(self, rhs: Vec2) -> Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec2> for Vec2 {
     type Output = Self;
     #[inline]
@@ -873,6 +1153,30 @@
     }
 }
 
+impl Mul<&Vec2> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &Vec2) -> Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &Vec2) -> Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: Vec2) -> Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec2> for Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -881,6 +1185,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec2 {
     type Output = Self;
     #[inline]
@@ -892,6 +1203,30 @@
     }
 }
 
+impl Mul<&f32> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -900,6 +1235,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec2> for f32 {
     type Output = Vec2;
     #[inline]
@@ -911,6 +1253,30 @@
     }
 }
 
+impl Mul<&Vec2> for f32 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &Vec2) -> Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: &Vec2) -> Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn mul(self, rhs: Vec2) -> Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec2> for Vec2 {
     type Output = Self;
     #[inline]
@@ -922,6 +1288,30 @@
     }
 }
 
+impl Add<&Vec2> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &Vec2) -> Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &Vec2) -> Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: Vec2) -> Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec2> for Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -930,6 +1320,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec2 {
     type Output = Self;
     #[inline]
@@ -941,6 +1338,30 @@
     }
 }
 
+impl Add<&f32> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -949,6 +1370,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec2> for f32 {
     type Output = Vec2;
     #[inline]
@@ -960,6 +1388,30 @@
     }
 }
 
+impl Add<&Vec2> for f32 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &Vec2) -> Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: &Vec2) -> Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn add(self, rhs: Vec2) -> Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec2> for Vec2 {
     type Output = Self;
     #[inline]
@@ -971,6 +1423,30 @@
     }
 }
 
+impl Sub<&Vec2> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &Vec2) -> Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &Vec2) -> Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: Vec2) -> Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec2> for Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec2) {
@@ -979,6 +1455,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec2 {
     type Output = Self;
     #[inline]
@@ -990,6 +1473,30 @@
     }
 }
 
+impl Sub<&f32> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -998,6 +1505,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec2> for f32 {
     type Output = Vec2;
     #[inline]
@@ -1009,6 +1523,30 @@
     }
 }
 
+impl Sub<&Vec2> for f32 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &Vec2) -> Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: &Vec2) -> Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn sub(self, rhs: Vec2) -> Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec2> for Vec2 {
     type Output = Self;
     #[inline]
@@ -1020,6 +1558,30 @@
     }
 }
 
+impl Rem<&Vec2> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &Vec2) -> Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &Vec2) -> Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec2> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: Vec2) -> Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec2> for Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1028,6 +1590,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec2 {
     type Output = Self;
     #[inline]
@@ -1039,6 +1608,30 @@
     }
 }
 
+impl Rem<&f32> for Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1047,6 +1640,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec2> for f32 {
     type Output = Vec2;
     #[inline]
@@ -1058,6 +1658,30 @@
     }
 }
 
+impl Rem<&Vec2> for f32 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &Vec2) -> Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: &Vec2) -> Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec2> for &f32 {
+    type Output = Vec2;
+    #[inline]
+    fn rem(self, rhs: Vec2) -> Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 2]> for Vec2 {
     #[inline]
@@ -1125,6 +1749,14 @@
     }
 }
 
+impl Neg for &Vec2 {
+    type Output = Vec2;
+    #[inline]
+    fn neg(self) -> Vec2 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec2 {
     type Output = f32;
     #[inline]
@@ -1148,14 +1780,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x, self.y)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x, p, self.y)
+        } else {
+            write!(f, "[{}, {}]", self.x, self.y)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec2))
@@ -1192,3 +1826,10 @@
         (v.x, v.y)
     }
 }
+
+impl From<BVec2> for Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y))
+    }
+}
diff --git a/crates/glam/src/f32/vec3.rs b/crates/glam/src/f32/vec3.rs
index 8c3af6d..f475e1e 100644
--- a/crates/glam/src/f32/vec3.rs
+++ b/crates/glam/src/f32/vec3.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, BVec3, Vec2, Vec4};
+use crate::{f32::math, BVec3, BVec3A, Vec2, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -84,6 +83,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -121,6 +130,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -131,9 +141,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -165,6 +173,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -248,6 +280,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -371,6 +421,13 @@
         self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3 {
+        BVec3::new(self.x.is_finite(), self.y.is_finite(), self.z.is_finite())
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -380,7 +437,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3 {
@@ -454,13 +511,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -487,6 +544,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -496,22 +571,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -539,6 +608,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -569,6 +639,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -623,13 +694,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -672,7 +757,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -690,14 +800,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -709,10 +820,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -721,10 +837,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -750,7 +871,45 @@
         )
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -824,6 +983,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -886,6 +1059,30 @@
     }
 }
 
+impl Div<&Vec3> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &Vec3) -> Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &Vec3) -> Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: Vec3) -> Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec3> for Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -895,6 +1092,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec3 {
     type Output = Self;
     #[inline]
@@ -907,6 +1111,30 @@
     }
 }
 
+impl Div<&f32> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
@@ -916,6 +1144,13 @@
     }
 }
 
+impl DivAssign<&f32> for Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<Vec3> for f32 {
     type Output = Vec3;
     #[inline]
@@ -928,6 +1163,30 @@
     }
 }
 
+impl Div<&Vec3> for f32 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &Vec3) -> Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: &Vec3) -> Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn div(self, rhs: Vec3) -> Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec3> for Vec3 {
     type Output = Self;
     #[inline]
@@ -940,6 +1199,30 @@
     }
 }
 
+impl Mul<&Vec3> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &Vec3) -> Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &Vec3) -> Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: Vec3) -> Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec3> for Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -949,6 +1232,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec3 {
     type Output = Self;
     #[inline]
@@ -961,6 +1251,30 @@
     }
 }
 
+impl Mul<&f32> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -970,6 +1284,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec3> for f32 {
     type Output = Vec3;
     #[inline]
@@ -982,6 +1303,30 @@
     }
 }
 
+impl Mul<&Vec3> for f32 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &Vec3) -> Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: &Vec3) -> Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn mul(self, rhs: Vec3) -> Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec3> for Vec3 {
     type Output = Self;
     #[inline]
@@ -994,6 +1339,30 @@
     }
 }
 
+impl Add<&Vec3> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &Vec3) -> Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &Vec3) -> Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: Vec3) -> Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec3> for Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -1003,6 +1372,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec3 {
     type Output = Self;
     #[inline]
@@ -1015,6 +1391,30 @@
     }
 }
 
+impl Add<&f32> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -1024,6 +1424,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec3> for f32 {
     type Output = Vec3;
     #[inline]
@@ -1036,6 +1443,30 @@
     }
 }
 
+impl Add<&Vec3> for f32 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &Vec3) -> Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: &Vec3) -> Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn add(self, rhs: Vec3) -> Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec3> for Vec3 {
     type Output = Self;
     #[inline]
@@ -1048,6 +1479,30 @@
     }
 }
 
+impl Sub<&Vec3> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &Vec3) -> Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &Vec3) -> Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: Vec3) -> Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec3> for Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec3) {
@@ -1057,6 +1512,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec3 {
     type Output = Self;
     #[inline]
@@ -1069,6 +1531,30 @@
     }
 }
 
+impl Sub<&f32> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -1078,6 +1564,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec3> for f32 {
     type Output = Vec3;
     #[inline]
@@ -1090,6 +1583,30 @@
     }
 }
 
+impl Sub<&Vec3> for f32 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &Vec3) -> Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: &Vec3) -> Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn sub(self, rhs: Vec3) -> Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec3> for Vec3 {
     type Output = Self;
     #[inline]
@@ -1102,6 +1619,30 @@
     }
 }
 
+impl Rem<&Vec3> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &Vec3) -> Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &Vec3) -> Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: Vec3) -> Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec3> for Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1111,6 +1652,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec3 {
     type Output = Self;
     #[inline]
@@ -1123,6 +1671,30 @@
     }
 }
 
+impl Rem<&f32> for Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1132,6 +1704,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec3> for f32 {
     type Output = Vec3;
     #[inline]
@@ -1144,6 +1723,30 @@
     }
 }
 
+impl Rem<&Vec3> for f32 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &Vec3) -> Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: &Vec3) -> Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3> for &f32 {
+    type Output = Vec3;
+    #[inline]
+    fn rem(self, rhs: Vec3) -> Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 3]> for Vec3 {
     #[inline]
@@ -1212,6 +1815,14 @@
     }
 }
 
+impl Neg for &Vec3 {
+    type Output = Vec3;
+    #[inline]
+    fn neg(self) -> Vec3 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec3 {
     type Output = f32;
     #[inline]
@@ -1237,14 +1848,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec3))
@@ -1289,3 +1902,22 @@
         Self::new(v.x, v.y, z)
     }
 }
+
+impl From<BVec3> for Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/wasm32/mat2.rs b/crates/glam/src/f32/wasm32/mat2.rs
index f2a4cc3..2225c94 100644
--- a/crates/glam/src/f32/wasm32/mat2.rs
+++ b/crates/glam/src/f32/wasm32/mat2.rs
@@ -1,10 +1,9 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::arch::wasm32::*;
 
@@ -114,6 +113,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from a 3x3 matrix, discarding the 2nd row and column.
     #[inline]
     #[must_use]
@@ -121,6 +143,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from the first 4 values in `slice`.
     ///
     /// # Panics
@@ -299,6 +344,13 @@
         Self(f32x4_mul(self.0, f32x4_splat(rhs)))
     }
 
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        Self(f32x4_div(self.0, f32x4_splat(rhs)))
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -315,6 +367,13 @@
             && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat2(&self) -> DMat2 {
         DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
@@ -412,6 +471,29 @@
     }
 }
 
+impl Div<Mat2> for f32 {
+    type Output = Mat2;
+    #[inline]
+    fn div(self, rhs: Mat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat2 {
     fn sum<I>(iter: I) -> Self
     where
@@ -486,7 +568,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat2))
@@ -496,9 +577,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/wasm32/mat3a.rs b/crates/glam/src/f32/wasm32/mat3a.rs
index 96c039b..0bf3d67 100644
--- a/crates/glam/src/f32/wasm32/mat3a.rs
+++ b/crates/glam/src/f32/wasm32/mat3a.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, swizzles::*, DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    DMat3, EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::arch::wasm32::*;
 
@@ -152,7 +156,105 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: Mat4) -> Self {
-        Self::from_cols(m.x_axis.into(), m.y_axis.into(), m.z_axis.into())
+        Self::from_cols(
+            Vec3A::from_vec4(m.x_axis),
+            Vec3A::from_vec4(m.y_axis),
+            Vec3A::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (0, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (0, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (0, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (1, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (1, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (1, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (1, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (2, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.w_axis.yzww()),
+            ),
+            (2, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.w_axis.xzww()),
+            ),
+            (2, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.w_axis.xyww()),
+            ),
+            (2, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.w_axis.xyzw()),
+            ),
+            (3, 0) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.yzww()),
+                Vec3A::from_vec4(m.y_axis.yzww()),
+                Vec3A::from_vec4(m.z_axis.yzww()),
+            ),
+            (3, 1) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xzww()),
+                Vec3A::from_vec4(m.y_axis.xzww()),
+                Vec3A::from_vec4(m.z_axis.xzww()),
+            ),
+            (3, 2) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyww()),
+                Vec3A::from_vec4(m.y_axis.xyww()),
+                Vec3A::from_vec4(m.z_axis.xyww()),
+            ),
+            (3, 3) => Self::from_cols(
+                Vec3A::from_vec4(m.x_axis.xyzw()),
+                Vec3A::from_vec4(m.y_axis.xyzw()),
+                Vec3A::from_vec4(m.z_axis.xyzw()),
+            ),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -216,8 +318,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -559,6 +679,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec3A::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -576,6 +708,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_dmat3(&self) -> DMat3 {
         DMat3::from_cols(
@@ -677,6 +816,29 @@
     }
 }
 
+impl Div<Mat3A> for f32 {
+    type Output = Mat3A;
+    #[inline]
+    fn div(self, rhs: Mat3A) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat3A {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Mul<Vec3> for Mat3A {
     type Output = Vec3;
     #[inline]
@@ -739,7 +901,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat3A))
@@ -750,9 +911,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f32/wasm32/mat4.rs b/crates/glam/src/f32/wasm32/mat4.rs
index 22b67a7..46f970b 100644
--- a/crates/glam/src/f32/wasm32/mat4.rs
+++ b/crates/glam/src/f32/wasm32/mat4.rs
@@ -1,12 +1,15 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    f32::math, swizzles::*, wasm32::*, DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
+    euler::{FromEuler, ToEuler},
+    f32::math,
+    swizzles::*,
+    wasm32::*,
+    DMat4, EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
 };
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 use core::arch::wasm32::*;
 
@@ -382,8 +385,27 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        let quat = Quat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
@@ -826,7 +848,10 @@
         Self::look_to_rh(eye, center.sub(eye), up)
     }
 
-    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
     /// This is the same as the OpenGL `gluPerspective` function.
     /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
     #[inline]
@@ -852,6 +877,8 @@
 
     /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -874,6 +901,8 @@
 
     /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -896,9 +925,13 @@
 
     /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
     /// # Panics
     ///
-    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -914,7 +947,9 @@
         )
     }
 
-    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
     ///
     /// # Panics
     ///
@@ -938,8 +973,15 @@
         )
     }
 
-    /// Creates an infinite right-handed perspective projection matrix with
-    /// `[0,1]` depth range.
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
@@ -953,8 +995,13 @@
         )
     }
 
-    /// Creates an infinite reverse right-handed perspective projection matrix
-    /// with `[0,1]` depth range.
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_reverse_rh(
@@ -976,6 +1023,8 @@
     /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
     /// See
     /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
     #[inline]
     #[must_use]
     pub fn orthographic_rh_gl(
@@ -1002,6 +1051,8 @@
     }
 
     /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_lh(
@@ -1029,6 +1080,8 @@
     }
 
     /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_rh(
@@ -1068,7 +1121,7 @@
         res = self.y_axis.mul(rhs.y).add(res);
         res = self.z_axis.mul(rhs.z).add(res);
         res = self.w_axis.add(res);
-        res = res.mul(res.wwww().recip());
+        res = res.div(res.w);
         res.xyz()
     }
 
@@ -1078,7 +1131,7 @@
     /// `1.0`.
     ///
     /// This method assumes that `self` contains a valid affine transform. It does not perform
-    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
     /// the [`Self::project_point3()`] method should be used instead.
     ///
     /// # Panics
@@ -1115,6 +1168,23 @@
         res.xyz()
     }
 
+    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
+    ///
+    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
+    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
+    ///
+    /// This method assumes that `self` contains a projective transform.
+    #[inline]
+    #[must_use]
+    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
+        let mut res = self.x_axis.mul(rhs.xxxx());
+        res = self.y_axis.mul(rhs.yyyy()).add(res);
+        res = self.z_axis.mul(rhs.zzzz()).add(res);
+        res = self.w_axis.add(res);
+        res = res.div(res.wwww());
+        Vec3A::from_vec4(res)
+    }
+
     /// Transforms the given [`Vec3A`] as 3D point.
     ///
     /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
@@ -1126,7 +1196,7 @@
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
         res = self.w_axis.add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms the give [`Vec3A`] as 3D vector.
@@ -1139,7 +1209,7 @@
         let mut res = self.x_axis.mul(rhs.xxxx());
         res = self.y_axis.mul(rhs.yyyy()).add(res);
         res = self.z_axis.mul(rhs.zzzz()).add(res);
-        res.into()
+        Vec3A::from_vec4(res)
     }
 
     /// Transforms a 4D vector.
@@ -1201,6 +1271,19 @@
         )
     }
 
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f32) -> Self {
+        let rhs = Vec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -1219,6 +1302,18 @@
             && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
     #[inline]
     pub fn as_dmat4(&self) -> DMat4 {
         DMat4::from_cols(
@@ -1326,6 +1421,29 @@
     }
 }
 
+impl Div<Mat4> for f32 {
+    type Output = Mat4;
+    #[inline]
+    fn div(self, rhs: Mat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f32> for Mat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f32) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f32> for Mat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f32) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for Mat4 {
     fn sum<I>(iter: I) -> Self
     where
@@ -1388,7 +1506,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Mat4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(Mat4))
@@ -1400,13 +1517,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Mat4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.x_axis, self.y_axis, self.z_axis, self.w_axis
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
     }
 }
diff --git a/crates/glam/src/f32/wasm32/quat.rs b/crates/glam/src/f32/wasm32/quat.rs
index 7247b27..8d0e19f 100644
--- a/crates/glam/src/f32/wasm32/quat.rs
+++ b/crates/glam/src/f32/wasm32/quat.rs
@@ -1,7 +1,7 @@
 // Generated from quat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
+    euler::{EulerRot, FromEuler, ToEuler},
     f32::math,
     wasm32::*,
     DQuat, Mat3, Mat3A, Mat4, Vec2, Vec3, Vec3A, Vec4,
@@ -9,7 +9,6 @@
 
 use core::arch::wasm32::*;
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::ops::{Add, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub};
@@ -175,14 +174,22 @@
     #[inline]
     #[must_use]
     pub fn from_euler(euler: EulerRot, a: f32, b: f32, c: f32) -> Self {
-        euler.new_quat(a, b, c)
+        Self::from_euler_angles(euler, a, b, c)
     }
 
     /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
-        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
         let (m00, m01, m02) = x_axis.into();
         let (m10, m11, m12) = y_axis.into();
         let (m20, m21, m22) = z_axis.into();
@@ -240,6 +247,13 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3(mat: &Mat3) -> Self {
@@ -247,13 +261,28 @@
     }
 
     /// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3a(mat: &Mat3A) -> Self {
         Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
     }
 
-    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat4(mat: &Mat4) -> Self {
@@ -282,13 +311,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPS: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPS {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPS {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             use core::f32::consts::PI; // half a turn = 𝛕/2 = 180°
             Self::from_axis_angle(from.any_orthonormal_vector(), PI)
         } else {
@@ -338,13 +367,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * core::f32::EPSILON;
+        const ONE_MINUS_EPSILON: f32 = 1.0 - 2.0 * f32::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPSILON {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPSILON {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             const COS_FRAC_PI_2: f32 = 0.0;
             const SIN_FRAC_PI_2: f32 = 1.0;
             // rotation around z by PI radians
@@ -386,8 +415,8 @@
     /// Returns the rotation angles for the given euler rotation sequence.
     #[inline]
     #[must_use]
-    pub fn to_euler(self, euler: EulerRot) -> (f32, f32, f32) {
-        euler.convert_quat(self)
+    pub fn to_euler(self, order: EulerRot) -> (f32, f32, f32) {
+        self.to_euler_angles(order)
     }
 
     /// `[x, y, z, w]`
@@ -486,6 +515,7 @@
         Vec4::from(self).is_finite()
     }
 
+    /// Returns `true` if any elements are `NAN`.
     #[inline]
     #[must_use]
     pub fn is_nan(self) -> bool {
@@ -538,6 +568,29 @@
         math::acos_approx(math::abs(self.dot(rhs))) * 2.0
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f32) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -553,6 +606,12 @@
         Vec4::from(self).abs_diff_eq(Vec4::from(rhs), max_abs_diff)
     }
 
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f32) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
     /// Performs a linear interpolation between `self` and `rhs` based on
     /// the value `s`.
     ///
@@ -570,17 +629,11 @@
         glam_assert!(end.is_normalized());
 
         const NEG_ZERO: v128 = v128_from_f32x4([-0.0; 4]);
-        let start = self.0;
-        let end = end.0;
-        let dot = dot4_into_v128(start, end);
+        let dot = dot4_into_v128(self.0, end.0);
         // Calculate the bias, if the dot product is positive or zero, there is no bias
         // but if it is negative, we want to flip the 'end' rotation XYZW components
         let bias = v128_and(dot, NEG_ZERO);
-        let interpolated = f32x4_add(
-            f32x4_mul(f32x4_sub(v128_xor(end, bias), start), f32x4_splat(s)),
-            start,
-        );
-        Quat(interpolated).normalize()
+        self.lerp_impl(Self(v128_xor(end.0, bias)), s)
     }
 
     /// Performs a spherical linear interpolation between `self` and `end`
@@ -599,8 +652,6 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        const DOT_THRESHOLD: f32 = 0.9995;
-
         // Note that a rotation can be represented by two quaternions: `q` and
         // `-q`. The slerp path between `q` and `end` will be different from the
         // path between `-q` and `end`. One path will take the long way around and
@@ -613,33 +664,17 @@
             dot = -dot;
         }
 
+        const DOT_THRESHOLD: f32 = 1.0 - f32::EPSILON;
         if dot > DOT_THRESHOLD {
-            // assumes lerp returns a normalized quaternion
-            self.lerp(end, s)
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
         } else {
             let theta = math::acos_approx(dot);
 
-            // TODO: v128_sin is broken
-            // let x = 1.0 - s;
-            // let y = s;
-            // let z = 1.0;
-            // let w = 0.0;
-            // let tmp = f32x4_mul(f32x4_splat(theta), f32x4(x, y, z, w));
-            // let tmp = v128_sin(tmp);
-            let x = math::sin(theta * (1.0 - s));
-            let y = math::sin(theta * s);
-            let z = math::sin(theta);
-            let w = 0.0;
-            let tmp = f32x4(x, y, z, w);
-
-            let scale1 = i32x4_shuffle::<0, 0, 4, 4>(tmp, tmp);
-            let scale2 = i32x4_shuffle::<1, 1, 5, 5>(tmp, tmp);
-            let theta_sin = i32x4_shuffle::<2, 2, 6, 6>(tmp, tmp);
-
-            Self(f32x4_div(
-                f32x4_add(f32x4_mul(self.0, scale1), f32x4_mul(end.0, scale2)),
-                theta_sin,
-            ))
+            let scale1 = math::sin(theta * (1.0 - s));
+            let scale2 = math::sin(theta * s);
+            let theta_sin = math::sin(theta);
+            ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
         }
     }
 
@@ -667,9 +702,6 @@
     #[inline]
     #[must_use]
     pub fn mul_quat(self, rhs: Self) -> Self {
-        glam_assert!(self.is_normalized());
-        glam_assert!(rhs.is_normalized());
-
         let lhs = self.0;
         let rhs = rhs.0;
 
@@ -705,6 +737,14 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn from_affine3(a: &crate::Affine3A) -> Self {
@@ -738,16 +778,8 @@
     pub fn as_dquat(self) -> DQuat {
         DQuat::from_xyzw(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
-
-    #[inline]
-    #[must_use]
-    #[deprecated(since = "0.24.2", note = "Use as_dquat() instead")]
-    pub fn as_f64(self) -> DQuat {
-        self.as_dquat()
-    }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Quat {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Quat))
@@ -759,10 +791,17 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Quat {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
diff --git a/crates/glam/src/f32/wasm32/vec3a.rs b/crates/glam/src/f32/wasm32/vec3a.rs
index 70ae013..b1d6b90 100644
--- a/crates/glam/src/f32/wasm32/vec3a.rs
+++ b/crates/glam/src/f32/wasm32/vec3a.rs
@@ -1,20 +1,13 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, wasm32::*, BVec3A, Vec2, Vec3, Vec4};
+use crate::{f32::math, wasm32::*, BVec3, BVec3A, Vec2, Vec3, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
 
 use core::arch::wasm32::*;
 
-#[repr(C)]
-union UnionCast {
-    a: [f32; 4],
-    v: Vec3A,
-}
-
 /// Creates a 3-dimensional vector.
 #[inline(always)]
 #[must_use]
@@ -92,7 +85,17 @@
     #[inline]
     #[must_use]
     pub const fn splat(v: f32) -> Self {
-        unsafe { UnionCast { a: [v; 4] }.v }
+        Self(f32x4(v, v, v, v))
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
     }
 
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
@@ -128,6 +131,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -138,16 +142,15 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
-    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
-    #[allow(dead_code)]
+    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
+    ///
+    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
     #[inline]
     #[must_use]
-    pub(crate) fn from_vec4(v: Vec4) -> Self {
+    pub fn from_vec4(v: Vec4) -> Self {
         Self(v.0)
     }
 
@@ -168,6 +171,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -250,6 +277,30 @@
         f32x4_extract_lane::<0>(v)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        let v = self.0;
+        let v = f32x4_add(v, i32x4_shuffle::<1, 0, 4, 0>(v, Self::ZERO.0));
+        let v = f32x4_add(v, i32x4_shuffle::<2, 0, 0, 0>(v, v));
+        f32x4_extract_lane::<0>(v)
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        let v = self.0;
+        let v = f32x4_mul(v, i32x4_shuffle::<1, 0, 4, 0>(v, Self::ONE.0));
+        let v = f32x4_mul(v, i32x4_shuffle::<2, 0, 0, 0>(v, v));
+        f32x4_extract_lane::<0>(v)
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -331,24 +382,20 @@
     #[inline]
     #[must_use]
     pub fn signum(self) -> Self {
-        unsafe {
-            let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0));
-            let mask = self.is_nan_mask();
-            Self::select(mask, self, result)
-        }
+        let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0));
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
     }
 
     /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
     #[inline]
     #[must_use]
     pub fn copysign(self, rhs: Self) -> Self {
-        unsafe {
-            let mask = Self::splat(-0.0);
-            Self(v128_or(
-                v128_and(rhs.0, mask.0),
-                v128_andnot(self.0, mask.0),
-            ))
-        }
+        let mask = Self::splat(-0.0);
+        Self(v128_or(
+            v128_and(rhs.0, mask.0),
+            v128_andnot(self.0, mask.0),
+        ))
     }
 
     /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
@@ -366,7 +413,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3A {
+        BVec3A(f32x4_lt(f32x4_abs(self.0), Self::INFINITY.0))
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -378,7 +432,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3A {
@@ -454,13 +508,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -488,6 +542,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -497,22 +569,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -540,6 +606,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -570,6 +637,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -608,13 +676,27 @@
         Self(f32x4_trunc(self.0))
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -653,7 +735,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -671,14 +778,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -690,10 +798,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -702,10 +815,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -731,7 +849,45 @@
         )
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -805,6 +961,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -870,6 +1040,30 @@
     }
 }
 
+impl Div<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec3A> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -877,6 +1071,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -885,10 +1086,41 @@
     }
 }
 
+impl Div<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec3A {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
-        self.0 = f32x4_div(self.0, f32x4_splat(rhs))
+        self.0 = f32x4_div(self.0, f32x4_splat(rhs));
+    }
+}
+
+impl DivAssign<&f32> for Vec3A {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
     }
 }
 
@@ -900,6 +1132,30 @@
     }
 }
 
+impl Div<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: &Vec3A) -> Vec3A {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn div(self, rhs: Vec3A) -> Vec3A {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -908,6 +1164,30 @@
     }
 }
 
+impl Mul<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec3A> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -915,6 +1195,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -923,6 +1210,30 @@
     }
 }
 
+impl Mul<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec3A {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -930,6 +1241,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec3A {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -938,6 +1256,30 @@
     }
 }
 
+impl Mul<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: &Vec3A) -> Vec3A {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn mul(self, rhs: Vec3A) -> Vec3A {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -946,6 +1288,30 @@
     }
 }
 
+impl Add<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec3A> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -953,6 +1319,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -961,6 +1334,30 @@
     }
 }
 
+impl Add<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec3A {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -968,6 +1365,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec3A {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -976,6 +1380,30 @@
     }
 }
 
+impl Add<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: &Vec3A) -> Vec3A {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn add(self, rhs: Vec3A) -> Vec3A {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -984,6 +1412,30 @@
     }
 }
 
+impl Sub<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec3A> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec3A) {
@@ -991,6 +1443,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -999,6 +1458,30 @@
     }
 }
 
+impl Sub<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec3A {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -1006,6 +1489,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec3A {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1014,6 +1504,30 @@
     }
 }
 
+impl Sub<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: &Vec3A) -> Vec3A {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn sub(self, rhs: Vec3A) -> Vec3A {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec3A> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1023,6 +1537,30 @@
     }
 }
 
+impl Rem<&Vec3A> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec3A> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1030,6 +1568,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec3A {
     type Output = Self;
     #[inline]
@@ -1038,6 +1583,30 @@
     }
 }
 
+impl Rem<&f32> for Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec3A {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -1045,6 +1614,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec3A {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec3A> for f32 {
     type Output = Vec3A;
     #[inline]
@@ -1053,6 +1629,30 @@
     }
 }
 
+impl Rem<&Vec3A> for f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: &Vec3A) -> Vec3A {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec3A> for &f32 {
+    type Output = Vec3A;
+    #[inline]
+    fn rem(self, rhs: Vec3A) -> Vec3A {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 3]> for Vec3A {
     #[inline]
@@ -1117,6 +1717,14 @@
     }
 }
 
+impl Neg for &Vec3A {
+    type Output = Vec3A;
+    #[inline]
+    fn neg(self) -> Vec3A {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec3A {
     type Output = f32;
     #[inline]
@@ -1142,14 +1750,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec3A {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec3A {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec3A))
@@ -1161,14 +1771,14 @@
 }
 
 impl From<Vec3A> for v128 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec3A) -> Self {
         t.0
     }
 }
 
 impl From<v128> for Vec3A {
-    #[inline]
+    #[inline(always)]
     fn from(t: v128) -> Self {
         Self(t)
     }
@@ -1209,16 +1819,6 @@
     }
 }
 
-impl From<Vec4> for Vec3A {
-    /// Creates a [`Vec3A`] from the `x`, `y` and `z` elements of `self` discarding `w`.
-    ///
-    /// On architectures where SIMD is supported such as SSE2 on `x86_64` this conversion is a noop.
-    #[inline]
-    fn from(v: Vec4) -> Self {
-        Self(v.0)
-    }
-}
-
 impl From<Vec3A> for Vec3 {
     #[inline]
     fn from(v: Vec3A) -> Self {
@@ -1247,3 +1847,22 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec3> for Vec3A {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f32::from(v.x), f32::from(v.y), f32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for Vec3A {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f32/wasm32/vec4.rs b/crates/glam/src/f32/wasm32/vec4.rs
index 4608b34..cb1d90b 100644
--- a/crates/glam/src/f32/wasm32/vec4.rs
+++ b/crates/glam/src/f32/wasm32/vec4.rs
@@ -1,20 +1,13 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f32::math, wasm32::*, BVec4A, Vec2, Vec3, Vec3A};
+use crate::{f32::math, wasm32::*, BVec4, BVec4A, Vec2, Vec3, Vec3A};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
 
 use core::arch::wasm32::*;
 
-#[repr(C)]
-union UnionCast {
-    a: [f32; 4],
-    v: Vec4,
-}
-
 /// Creates a 4-dimensional vector.
 #[inline(always)]
 #[must_use]
@@ -94,7 +87,17 @@
     #[inline]
     #[must_use]
     pub const fn splat(v: f32) -> Self {
-        unsafe { UnionCast { a: [v; 4] }.v }
+        Self(f32x4(v, v, v, v))
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
     }
 
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
@@ -130,6 +133,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -140,10 +144,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -158,6 +159,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -228,6 +261,30 @@
         f32x4_extract_lane::<0>(v)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f32 {
+        let v = self.0;
+        let v = f32x4_add(v, i32x4_shuffle::<1, 0, 3, 0>(v, v));
+        let v = f32x4_add(v, i32x4_shuffle::<2, 0, 0, 0>(v, v));
+        f32x4_extract_lane::<0>(v)
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f32 {
+        let v = self.0;
+        let v = f32x4_mul(v, i32x4_shuffle::<1, 0, 3, 0>(v, v));
+        let v = f32x4_mul(v, i32x4_shuffle::<2, 0, 0, 0>(v, v));
+        f32x4_extract_lane::<0>(v)
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -309,24 +366,20 @@
     #[inline]
     #[must_use]
     pub fn signum(self) -> Self {
-        unsafe {
-            let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0));
-            let mask = self.is_nan_mask();
-            Self::select(mask, self, result)
-        }
+        let result = Self(v128_or(v128_and(self.0, Self::NEG_ONE.0), Self::ONE.0));
+        let mask = self.is_nan_mask();
+        Self::select(mask, self, result)
     }
 
     /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
     #[inline]
     #[must_use]
     pub fn copysign(self, rhs: Self) -> Self {
-        unsafe {
-            let mask = Self::splat(-0.0);
-            Self(v128_or(
-                v128_and(rhs.0, mask.0),
-                v128_andnot(self.0, mask.0),
-            ))
-        }
+        let mask = Self::splat(-0.0);
+        Self(v128_or(
+            v128_and(rhs.0, mask.0),
+            v128_andnot(self.0, mask.0),
+        ))
     }
 
     /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
@@ -344,7 +397,14 @@
     #[inline]
     #[must_use]
     pub fn is_finite(self) -> bool {
-        self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
+        self.is_finite_mask().all()
+    }
+
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4A {
+        BVec4A(f32x4_lt(f32x4_abs(self.0), Self::INFINITY.0))
     }
 
     /// Returns `true` if any elements are `NaN`.
@@ -356,7 +416,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec4A {
@@ -434,13 +494,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -468,6 +528,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -477,22 +555,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -520,6 +592,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -550,6 +623,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -588,13 +662,27 @@
         Self(f32x4_trunc(self.0))
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -639,7 +727,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f32) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -657,14 +770,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f32, max: f32) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -676,10 +790,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f32) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -688,10 +807,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f32) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -718,6 +842,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f32) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Casts all elements of `self` to `f64`.
     #[inline]
     #[must_use]
@@ -725,6 +887,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -790,6 +966,30 @@
     }
 }
 
+impl Div<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<Vec4> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -797,6 +997,13 @@
     }
 }
 
+impl DivAssign<&Self> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -805,10 +1012,41 @@
     }
 }
 
+impl Div<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &f32) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: f32) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f32> for Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
-        self.0 = f32x4_div(self.0, f32x4_splat(rhs))
+        self.0 = f32x4_div(self.0, f32x4_splat(rhs));
+    }
+}
+
+impl DivAssign<&f32> for Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f32) {
+        self.div_assign(*rhs)
     }
 }
 
@@ -820,6 +1058,30 @@
     }
 }
 
+impl Div<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: &Vec4) -> Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn div(self, rhs: Vec4) -> Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -828,6 +1090,30 @@
     }
 }
 
+impl Mul<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<Vec4> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -835,6 +1121,13 @@
     }
 }
 
+impl MulAssign<&Self> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -843,6 +1136,30 @@
     }
 }
 
+impl Mul<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &f32) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: f32) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f32> for Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
@@ -850,6 +1167,13 @@
     }
 }
 
+impl MulAssign<&f32> for Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -858,6 +1182,30 @@
     }
 }
 
+impl Mul<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: &Vec4) -> Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn mul(self, rhs: Vec4) -> Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -866,6 +1214,30 @@
     }
 }
 
+impl Add<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<Vec4> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -873,6 +1245,13 @@
     }
 }
 
+impl AddAssign<&Self> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -881,6 +1260,30 @@
     }
 }
 
+impl Add<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &f32) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: f32) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f32> for Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: f32) {
@@ -888,6 +1291,13 @@
     }
 }
 
+impl AddAssign<&f32> for Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -896,6 +1306,30 @@
     }
 }
 
+impl Add<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: &Vec4) -> Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn add(self, rhs: Vec4) -> Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -904,6 +1338,30 @@
     }
 }
 
+impl Sub<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<Vec4> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: Vec4) {
@@ -911,6 +1369,13 @@
     }
 }
 
+impl SubAssign<&Self> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -919,6 +1384,30 @@
     }
 }
 
+impl Sub<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &f32) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: f32) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f32> for Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: f32) {
@@ -926,6 +1415,13 @@
     }
 }
 
+impl SubAssign<&f32> for Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -934,6 +1430,30 @@
     }
 }
 
+impl Sub<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: &Vec4) -> Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn sub(self, rhs: Vec4) -> Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<Vec4> for Vec4 {
     type Output = Self;
     #[inline]
@@ -943,6 +1463,30 @@
     }
 }
 
+impl Rem<&Vec4> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<Vec4> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -950,6 +1494,13 @@
     }
 }
 
+impl RemAssign<&Self> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f32> for Vec4 {
     type Output = Self;
     #[inline]
@@ -958,6 +1509,30 @@
     }
 }
 
+impl Rem<&f32> for Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &f32) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f32> for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: f32) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f32> for Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: f32) {
@@ -965,6 +1540,13 @@
     }
 }
 
+impl RemAssign<&f32> for Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<Vec4> for f32 {
     type Output = Vec4;
     #[inline]
@@ -973,6 +1555,30 @@
     }
 }
 
+impl Rem<&Vec4> for f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: &Vec4) -> Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<Vec4> for &f32 {
+    type Output = Vec4;
+    #[inline]
+    fn rem(self, rhs: Vec4) -> Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f32; 4]> for Vec4 {
     #[inline]
@@ -1037,6 +1643,14 @@
     }
 }
 
+impl Neg for &Vec4 {
+    type Output = Vec4;
+    #[inline]
+    fn neg(self) -> Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for Vec4 {
     type Output = f32;
     #[inline]
@@ -1064,14 +1678,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(Vec4))
@@ -1084,14 +1704,14 @@
 }
 
 impl From<Vec4> for v128 {
-    #[inline]
+    #[inline(always)]
     fn from(t: Vec4) -> Self {
         t.0
     }
 }
 
 impl From<v128> for Vec4 {
-    #[inline]
+    #[inline(always)]
     fn from(t: v128) -> Self {
         Self(t)
     }
@@ -1181,3 +1801,30 @@
         unsafe { &mut *(self as *mut Self).cast() }
     }
 }
+
+impl From<BVec4> for Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f32::from(v.x),
+            f32::from(v.y),
+            f32::from(v.z),
+            f32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f32::from(bool_array[0]),
+            f32::from(bool_array[1]),
+            f32::from(bool_array[2]),
+            f32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f64/daffine2.rs b/crates/glam/src/f64/daffine2.rs
index cf9fe5f..fd29d5e 100644
--- a/crates/glam/src/f64/daffine2.rs
+++ b/crates/glam/src/f64/daffine2.rs
@@ -50,8 +50,8 @@
     #[must_use]
     pub fn from_cols_array(m: &[f64; 6]) -> Self {
         Self {
-            matrix2: DMat2::from_cols_slice(&m[0..4]),
-            translation: DVec2::from_slice(&m[4..6]),
+            matrix2: DMat2::from_cols_array(&[m[0], m[1], m[2], m[3]]),
+            translation: DVec2::from_array([m[4], m[5]]),
         }
     }
 
@@ -333,7 +333,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Debug for DAffine2 {
     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         fmt.debug_struct(stringify!(DAffine2))
@@ -343,14 +342,21 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Display for DAffine2 {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}]",
-            self.matrix2.x_axis, self.matrix2.y_axis, self.translation
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.matrix2.x_axis, p, self.matrix2.y_axis, p, self.translation
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}]",
+                self.matrix2.x_axis, self.matrix2.y_axis, self.translation
+            )
+        }
     }
 }
 
diff --git a/crates/glam/src/f64/daffine3.rs b/crates/glam/src/f64/daffine3.rs
index 6a261bf..25459ac 100644
--- a/crates/glam/src/f64/daffine3.rs
+++ b/crates/glam/src/f64/daffine3.rs
@@ -50,8 +50,10 @@
     #[must_use]
     pub fn from_cols_array(m: &[f64; 12]) -> Self {
         Self {
-            matrix3: DMat3::from_cols_slice(&m[0..9]),
-            translation: DVec3::from_slice(&m[9..12]),
+            matrix3: DMat3::from_cols_array(&[
+                m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8],
+            ]),
+            translation: DVec3::from_array([m[9], m[10], m[11]]),
         }
     }
 
@@ -471,7 +473,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Debug for DAffine3 {
     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         fmt.debug_struct(stringify!(DAffine3))
@@ -481,14 +482,28 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl core::fmt::Display for DAffine3 {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p,
+                self.matrix3.x_axis,
+                p,
+                self.matrix3.y_axis,
+                p,
+                self.matrix3.z_axis,
+                p,
+                self.translation
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
+            )
+        }
     }
 }
 
diff --git a/crates/glam/src/f64/dmat2.rs b/crates/glam/src/f64/dmat2.rs
index dbc61c5..2cf90d2 100644
--- a/crates/glam/src/f64/dmat2.rs
+++ b/crates/glam/src/f64/dmat2.rs
@@ -1,10 +1,9 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{f64::math, swizzles::*, DMat3, DVec2, Mat2};
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 2x2 matrix from two column vectors.
 #[inline(always)]
@@ -115,6 +114,29 @@
         Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
     }
 
+    /// Creates a 2x2 matrix from the minor of the given 3x3 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 2.
+    #[inline]
+    #[must_use]
+    pub fn from_mat3_minor(m: DMat3, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
+            (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
+            (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
+            (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
+            (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
+            (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
+            (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
+            (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
+            (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
+            _ => panic!("index out of bounds"),
+        }
+    }
+
     /// Creates a 2x2 matrix from the first 4 values in `slice`.
     ///
     /// # Panics
@@ -277,6 +299,14 @@
         Self::from_cols(self.x_axis.mul(rhs), self.y_axis.mul(rhs))
     }
 
+    /// Divides a 2x2 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f64) -> Self {
+        let rhs = DVec2::splat(rhs);
+        Self::from_cols(self.x_axis.div(rhs), self.y_axis.div(rhs))
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -293,6 +323,13 @@
             && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
+    }
+
     #[inline]
     pub fn as_mat2(&self) -> Mat2 {
         Mat2::from_cols(self.x_axis.as_vec2(), self.y_axis.as_vec2())
@@ -390,6 +427,29 @@
     }
 }
 
+impl Div<DMat2> for f64 {
+    type Output = DMat2;
+    #[inline]
+    fn div(self, rhs: DMat2) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f64> for DMat2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f64) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f64> for DMat2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f64) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for DMat2 {
     fn sum<I>(iter: I) -> Self
     where
@@ -449,7 +509,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DMat2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(DMat2))
@@ -459,9 +518,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DMat2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
+        } else {
+            write!(f, "[{}, {}]", self.x_axis, self.y_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f64/dmat3.rs b/crates/glam/src/f64/dmat3.rs
index c271886..f5e99a3 100644
--- a/crates/glam/src/f64/dmat3.rs
+++ b/crates/glam/src/f64/dmat3.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, swizzles::*, DMat2, DMat4, DQuat, DVec2, DVec3, EulerRot, Mat3};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f64::math,
+    swizzles::*,
+    DMat2, DMat4, DQuat, DVec2, DVec3, EulerRot, Mat3,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 3x3 matrix from three column vectors.
 #[inline(always)]
@@ -153,7 +157,41 @@
     #[inline]
     #[must_use]
     pub fn from_mat4(m: DMat4) -> Self {
-        Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz())
+        Self::from_cols(
+            DVec3::from_vec4(m.x_axis),
+            DVec3::from_vec4(m.y_axis),
+            DVec3::from_vec4(m.z_axis),
+        )
+    }
+
+    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
+    /// and `j`th row.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `i` or `j` is greater than 3.
+    #[inline]
+    #[must_use]
+    pub fn from_mat4_minor(m: DMat4, i: usize, j: usize) -> Self {
+        match (i, j) {
+            (0, 0) => Self::from_cols(m.y_axis.yzw(), m.z_axis.yzw(), m.w_axis.yzw()),
+            (0, 1) => Self::from_cols(m.y_axis.xzw(), m.z_axis.xzw(), m.w_axis.xzw()),
+            (0, 2) => Self::from_cols(m.y_axis.xyw(), m.z_axis.xyw(), m.w_axis.xyw()),
+            (0, 3) => Self::from_cols(m.y_axis.xyz(), m.z_axis.xyz(), m.w_axis.xyz()),
+            (1, 0) => Self::from_cols(m.x_axis.yzw(), m.z_axis.yzw(), m.w_axis.yzw()),
+            (1, 1) => Self::from_cols(m.x_axis.xzw(), m.z_axis.xzw(), m.w_axis.xzw()),
+            (1, 2) => Self::from_cols(m.x_axis.xyw(), m.z_axis.xyw(), m.w_axis.xyw()),
+            (1, 3) => Self::from_cols(m.x_axis.xyz(), m.z_axis.xyz(), m.w_axis.xyz()),
+            (2, 0) => Self::from_cols(m.x_axis.yzw(), m.y_axis.yzw(), m.w_axis.yzw()),
+            (2, 1) => Self::from_cols(m.x_axis.xzw(), m.y_axis.xzw(), m.w_axis.xzw()),
+            (2, 2) => Self::from_cols(m.x_axis.xyw(), m.y_axis.xyw(), m.w_axis.xyw()),
+            (2, 3) => Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.w_axis.xyz()),
+            (3, 0) => Self::from_cols(m.x_axis.yzw(), m.y_axis.yzw(), m.z_axis.yzw()),
+            (3, 1) => Self::from_cols(m.x_axis.xzw(), m.y_axis.xzw(), m.z_axis.xzw()),
+            (3, 2) => Self::from_cols(m.x_axis.xyw(), m.y_axis.xyw(), m.z_axis.xyw()),
+            (3, 3) => Self::from_cols(m.x_axis.xyz(), m.y_axis.xyz(), m.z_axis.xyz()),
+            _ => panic!("index out of bounds"),
+        }
     }
 
     /// Creates a 3D rotation matrix from the given quaternion.
@@ -217,8 +255,26 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self {
-        let quat = DQuat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
+    /// the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f64, f64, f64) {
+        glam_assert!(
+            self.x_axis.is_normalized()
+                && self.y_axis.is_normalized()
+                && self.z_axis.is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
@@ -550,6 +606,18 @@
         )
     }
 
+    /// Divides a 3x3 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f64) -> Self {
+        let rhs = DVec3::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -567,6 +635,13 @@
             && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
+    }
+
     #[inline]
     pub fn as_mat3(&self) -> Mat3 {
         Mat3::from_cols(
@@ -668,6 +743,29 @@
     }
 }
 
+impl Div<DMat3> for f64 {
+    type Output = DMat3;
+    #[inline]
+    fn div(self, rhs: DMat3) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f64> for DMat3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f64) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f64> for DMat3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f64) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for DMat3 {
     fn sum<I>(iter: I) -> Self
     where
@@ -727,7 +825,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DMat3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(DMat3))
@@ -738,9 +835,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DMat3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis
+            )
+        } else {
+            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
+        }
     }
 }
diff --git a/crates/glam/src/f64/dmat4.rs b/crates/glam/src/f64/dmat4.rs
index cc9147c..763b826 100644
--- a/crates/glam/src/f64/dmat4.rs
+++ b/crates/glam/src/f64/dmat4.rs
@@ -1,10 +1,14 @@
 // Generated from mat.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, swizzles::*, DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4};
-#[cfg(not(target_arch = "spirv"))]
+use crate::{
+    euler::{FromEuler, ToEuler},
+    f64::math,
+    swizzles::*,
+    DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4,
+};
 use core::fmt;
 use core::iter::{Product, Sum};
-use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 
 /// Creates a 4x4 matrix from four column vectors.
 #[inline(always)]
@@ -375,8 +379,27 @@
     #[inline]
     #[must_use]
     pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self {
-        let quat = DQuat::from_euler(order, a, b, c);
-        Self::from_quat(quat)
+        Self::from_euler_angles(order, a, b, c)
+    }
+
+    /// Extract Euler angles with the given Euler rotation order.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting Euler angles will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn to_euler(&self, order: EulerRot) -> (f64, f64, f64) {
+        glam_assert!(
+            self.x_axis.xyz().is_normalized()
+                && self.y_axis.xyz().is_normalized()
+                && self.z_axis.xyz().is_normalized()
+        );
+        self.to_euler_angles(order)
     }
 
     /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
@@ -729,7 +752,10 @@
         Self::look_to_rh(eye, center.sub(eye), up)
     }
 
-    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
+    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
+    ///
+    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
+    ///
     /// This is the same as the OpenGL `gluPerspective` function.
     /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
     #[inline]
@@ -755,6 +781,8 @@
 
     /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -777,6 +805,8 @@
 
     /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
+    ///
     /// # Panics
     ///
     /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
@@ -799,9 +829,13 @@
 
     /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
     ///
+    /// Like `perspective_lh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
     /// # Panics
     ///
-    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
@@ -817,7 +851,9 @@
         )
     }
 
-    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
+    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
     ///
     /// # Panics
     ///
@@ -841,8 +877,15 @@
         )
     }
 
-    /// Creates an infinite right-handed perspective projection matrix with
-    /// `[0,1]` depth range.
+    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Like `perspective_rh`, but with an infinite value for `z_far`.
+    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
@@ -856,8 +899,13 @@
         )
     }
 
-    /// Creates an infinite reverse right-handed perspective projection matrix
-    /// with `[0,1]` depth range.
+    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
+    ///
+    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn perspective_infinite_reverse_rh(
@@ -879,6 +927,8 @@
     /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
     /// See
     /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
     #[inline]
     #[must_use]
     pub fn orthographic_rh_gl(
@@ -905,6 +955,8 @@
     }
 
     /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_lh(
@@ -932,6 +984,8 @@
     }
 
     /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
+    ///
+    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
     #[inline]
     #[must_use]
     pub fn orthographic_rh(
@@ -971,7 +1025,7 @@
         res = self.y_axis.mul(rhs.y).add(res);
         res = self.z_axis.mul(rhs.z).add(res);
         res = self.w_axis.add(res);
-        res = res.mul(res.wwww().recip());
+        res = res.div(res.w);
         res.xyz()
     }
 
@@ -981,7 +1035,7 @@
     /// `1.0`.
     ///
     /// This method assumes that `self` contains a valid affine transform. It does not perform
-    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
+    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
     /// the [`Self::project_point3()`] method should be used instead.
     ///
     /// # Panics
@@ -1077,6 +1131,19 @@
         )
     }
 
+    /// Divides a 4x4 matrix by a scalar.
+    #[inline]
+    #[must_use]
+    pub fn div_scalar(&self, rhs: f64) -> Self {
+        let rhs = DVec4::splat(rhs);
+        Self::from_cols(
+            self.x_axis.div(rhs),
+            self.y_axis.div(rhs),
+            self.z_axis.div(rhs),
+            self.w_axis.div(rhs),
+        )
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -1095,6 +1162,18 @@
             && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
     }
 
+    /// Takes the absolute value of each element in `self`
+    #[inline]
+    #[must_use]
+    pub fn abs(&self) -> Self {
+        Self::from_cols(
+            self.x_axis.abs(),
+            self.y_axis.abs(),
+            self.z_axis.abs(),
+            self.w_axis.abs(),
+        )
+    }
+
     #[inline]
     pub fn as_mat4(&self) -> Mat4 {
         Mat4::from_cols(
@@ -1202,6 +1281,29 @@
     }
 }
 
+impl Div<DMat4> for f64 {
+    type Output = DMat4;
+    #[inline]
+    fn div(self, rhs: DMat4) -> Self::Output {
+        rhs.div_scalar(self)
+    }
+}
+
+impl Div<f64> for DMat4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: f64) -> Self::Output {
+        self.div_scalar(rhs)
+    }
+}
+
+impl DivAssign<f64> for DMat4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: f64) {
+        *self = self.div_scalar(rhs);
+    }
+}
+
 impl Sum<Self> for DMat4 {
     fn sum<I>(iter: I) -> Self
     where
@@ -1264,7 +1366,6 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DMat4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct(stringify!(DMat4))
@@ -1276,13 +1377,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DMat4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "[{}, {}, {}, {}]",
-            self.x_axis, self.y_axis, self.z_axis, self.w_axis
-        )
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
+            )
+        } else {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.x_axis, self.y_axis, self.z_axis, self.w_axis
+            )
+        }
     }
 }
diff --git a/crates/glam/src/f64/dquat.rs b/crates/glam/src/f64/dquat.rs
index eddcfa1..52b67e5 100644
--- a/crates/glam/src/f64/dquat.rs
+++ b/crates/glam/src/f64/dquat.rs
@@ -1,12 +1,11 @@
 // Generated from quat.rs.tera template. Edit the template, not the generated file.
 
 use crate::{
-    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
+    euler::{EulerRot, FromEuler, ToEuler},
     f64::math,
     DMat3, DMat4, DVec2, DVec3, DVec4, Quat,
 };
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::ops::{Add, Div, Mul, MulAssign, Neg, Sub};
@@ -179,14 +178,22 @@
     #[inline]
     #[must_use]
     pub fn from_euler(euler: EulerRot, a: f64, b: f64, c: f64) -> Self {
-        euler.new_quat(a, b, c)
+        Self::from_euler_angles(euler, a, b, c)
     }
 
     /// From the columns of a 3x3 rotation matrix.
+    ///
+    /// Note if the input axes contain scales, shears, or other non-rotation transformations then
+    /// the output of this function is ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any axis is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub(crate) fn from_rotation_axes(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3) -> Self {
-        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
+        glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
+        // Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
         let (m00, m01, m02) = x_axis.into();
         let (m10, m11, m12) = y_axis.into();
         let (m20, m21, m22) = z_axis.into();
@@ -244,13 +251,28 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix.
+    ///
+    /// Note if the input matrix contain scales, shears, or other non-rotation transformations then
+    /// the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat3(mat: &DMat3) -> Self {
         Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
     }
 
-    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    /// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
+    ///
+    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
+    /// then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
+    /// `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn from_mat4(mat: &DMat4) -> Self {
@@ -279,13 +301,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPS: f64 = 1.0 - 2.0 * core::f64::EPSILON;
+        const ONE_MINUS_EPS: f64 = 1.0 - 2.0 * f64::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPS {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPS {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             use core::f64::consts::PI; // half a turn = 𝛕/2 = 180°
             Self::from_axis_angle(from.any_orthonormal_vector(), PI)
         } else {
@@ -335,13 +357,13 @@
         glam_assert!(from.is_normalized());
         glam_assert!(to.is_normalized());
 
-        const ONE_MINUS_EPSILON: f64 = 1.0 - 2.0 * core::f64::EPSILON;
+        const ONE_MINUS_EPSILON: f64 = 1.0 - 2.0 * f64::EPSILON;
         let dot = from.dot(to);
         if dot > ONE_MINUS_EPSILON {
-            // 0° singulary: from ≈ to
+            // 0° singularity: from ≈ to
             Self::IDENTITY
         } else if dot < -ONE_MINUS_EPSILON {
-            // 180° singulary: from ≈ -to
+            // 180° singularity: from ≈ -to
             const COS_FRAC_PI_2: f64 = 0.0;
             const SIN_FRAC_PI_2: f64 = 1.0;
             // rotation around z by PI radians
@@ -383,8 +405,8 @@
     /// Returns the rotation angles for the given euler rotation sequence.
     #[inline]
     #[must_use]
-    pub fn to_euler(self, euler: EulerRot) -> (f64, f64, f64) {
-        euler.convert_quat(self)
+    pub fn to_euler(self, order: EulerRot) -> (f64, f64, f64) {
+        self.to_euler_angles(order)
     }
 
     /// `[x, y, z, w]`
@@ -487,6 +509,7 @@
         DVec4::from(self).is_finite()
     }
 
+    /// Returns `true` if any elements are `NAN`.
     #[inline]
     #[must_use]
     pub fn is_nan(self) -> bool {
@@ -539,6 +562,29 @@
         math::acos_approx(math::abs(self.dot(rhs))) * 2.0
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    ///
+    /// Both quaternions must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f64) -> Self {
+        glam_assert!(self.is_normalized() && rhs.is_normalized());
+        let angle = self.angle_between(rhs);
+        if angle <= 1e-4 {
+            return *self;
+        }
+        let s = (max_angle / angle).clamp(-1.0, 1.0);
+        self.slerp(rhs, s)
+    }
+
     /// Returns true if the absolute difference of all elements between `self` and `rhs`
     /// is less than or equal to `max_abs_diff`.
     ///
@@ -554,6 +600,12 @@
         DVec4::from(self).abs_diff_eq(DVec4::from(rhs), max_abs_diff)
     }
 
+    #[inline(always)]
+    #[must_use]
+    fn lerp_impl(self, end: Self, s: f64) -> Self {
+        (self * (1.0 - s) + end * s).normalize()
+    }
+
     /// Performs a linear interpolation between `self` and `rhs` based on
     /// the value `s`.
     ///
@@ -570,11 +622,9 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        let start = self;
-        let dot = start.dot(end);
+        let dot = self.dot(end);
         let bias = if dot >= 0.0 { 1.0 } else { -1.0 };
-        let interpolated = start.add(end.mul(bias).sub(start).mul(s));
-        interpolated.normalize()
+        self.lerp_impl(end * bias, s)
     }
 
     /// Performs a spherical linear interpolation between `self` and `end`
@@ -593,8 +643,6 @@
         glam_assert!(self.is_normalized());
         glam_assert!(end.is_normalized());
 
-        const DOT_THRESHOLD: f64 = 0.9995;
-
         // Note that a rotation can be represented by two quaternions: `q` and
         // `-q`. The slerp path between `q` and `end` will be different from the
         // path between `-q` and `end`. One path will take the long way around and
@@ -607,17 +655,17 @@
             dot = -dot;
         }
 
+        const DOT_THRESHOLD: f64 = 1.0 - f64::EPSILON;
         if dot > DOT_THRESHOLD {
-            // assumes lerp returns a normalized quaternion
-            self.lerp(end, s)
+            // if above threshold perform linear interpolation to avoid divide by zero
+            self.lerp_impl(end, s)
         } else {
             let theta = math::acos_approx(dot);
 
             let scale1 = math::sin(theta * (1.0 - s));
             let scale2 = math::sin(theta * s);
             let theta_sin = math::sin(theta);
-
-            self.mul(scale1).add(end.mul(scale2)).mul(1.0 / theta_sin)
+            ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
         }
     }
 
@@ -650,9 +698,6 @@
     #[inline]
     #[must_use]
     pub fn mul_quat(self, rhs: Self) -> Self {
-        glam_assert!(self.is_normalized());
-        glam_assert!(rhs.is_normalized());
-
         let (x0, y0, z0, w0) = self.into();
         let (x1, y1, z1, w1) = rhs.into();
         Self::from_xyzw(
@@ -664,6 +709,14 @@
     }
 
     /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
+    ///
+    /// Note if the input affine matrix contain scales, shears, or other non-rotation
+    /// transformations then the resulting quaternion will be ill-defined.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
+    /// enabled.
     #[inline]
     #[must_use]
     pub fn from_affine3(a: &crate::DAffine3) -> Self {
@@ -680,16 +733,8 @@
     pub fn as_quat(self) -> Quat {
         Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
     }
-
-    #[inline]
-    #[must_use]
-    #[deprecated(since = "0.24.2", note = "Use as_quat() instead")]
-    pub fn as_f32(self) -> Quat {
-        self.as_quat()
-    }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DQuat {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(DQuat))
@@ -701,10 +746,17 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DQuat {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
diff --git a/crates/glam/src/f64/dvec2.rs b/crates/glam/src/f64/dvec2.rs
index 33bf6ac..bdd615c 100644
--- a/crates/glam/src/f64/dvec2.rs
+++ b/crates/glam/src/f64/dvec2.rs
@@ -2,7 +2,6 @@
 
 use crate::{f64::math, BVec2, DVec3, IVec2, UVec2, Vec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -78,6 +77,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -114,6 +123,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f64]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -124,8 +134,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -135,6 +144,22 @@
         DVec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f64) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -205,6 +230,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f64 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f64 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,6 +366,13 @@
         self.x.is_finite() && self.y.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec2 {
+        BVec2::new(self.x.is_finite(), self.y.is_finite())
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -332,7 +382,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec2 {
@@ -404,13 +454,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -437,6 +487,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -446,22 +514,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -489,6 +551,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -519,6 +582,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -569,13 +633,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -613,7 +691,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f64) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -631,14 +734,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f64, max: f64) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -650,10 +754,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f64) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -662,10 +771,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f64) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -690,6 +804,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f64) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Creates a 2D vector containing `[angle.cos(), angle.sin()]`. This can be used in
     /// conjunction with the [`rotate()`][Self::rotate()] method, e.g.
     /// `DVec2::from_angle(PI).rotate(DVec2::Y)` will create the vector `[-1, 0]`
@@ -710,12 +862,22 @@
         math::atan2(self.y, self.x)
     }
 
-    /// Returns the angle (in radians) between `self` and `rhs` in the range `[-π, +π]`.
+    #[inline]
+    #[must_use]
+    #[deprecated(
+        since = "0.27.0",
+        note = "Use angle_to() instead, the semantics of angle_between will change in the future."
+    )]
+    pub fn angle_between(self, rhs: Self) -> f64 {
+        self.angle_to(rhs)
+    }
+
+    /// Returns the angle of rotation (in radians) from `self` to `rhs` in the range `[-π, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
     #[must_use]
-    pub fn angle_between(self, rhs: Self) -> f64 {
+    pub fn angle_to(self, rhs: Self) -> f64 {
         let angle = math::acos_approx(
             self.dot(rhs) / math::sqrt(self.length_squared() * rhs.length_squared()),
         );
@@ -756,6 +918,24 @@
         }
     }
 
+    /// Rotates towards `rhs` up to `max_angle` (in radians).
+    ///
+    /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
+    /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
+    /// rotates towards the exact opposite of `rhs`. Will not go past the target.
+    #[inline]
+    #[must_use]
+    pub fn rotate_towards(&self, rhs: Self, max_angle: f64) -> Self {
+        let a = self.angle_to(rhs);
+        let abs_a = math::abs(a);
+        if abs_a <= 1e-4 {
+            return rhs;
+        }
+        // When `max_angle < 0`, rotate no further than `PI` radians away
+        let angle = max_angle.clamp(abs_a - core::f64::consts::PI, abs_a) * math::signum(a);
+        Self::from_angle(angle).rotate(*self)
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     #[must_use]
@@ -763,6 +943,20 @@
         crate::Vec2::new(self.x as f32, self.y as f32)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -824,6 +1018,30 @@
     }
 }
 
+impl Div<&DVec2> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &DVec2) -> DVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &DVec2) -> DVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: DVec2) -> DVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<DVec2> for DVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -832,6 +1050,13 @@
     }
 }
 
+impl DivAssign<&Self> for DVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f64> for DVec2 {
     type Output = Self;
     #[inline]
@@ -843,6 +1068,30 @@
     }
 }
 
+impl Div<&f64> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: f64) -> DVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f64> for DVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: f64) {
@@ -851,6 +1100,13 @@
     }
 }
 
+impl DivAssign<&f64> for DVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<DVec2> for f64 {
     type Output = DVec2;
     #[inline]
@@ -862,6 +1118,30 @@
     }
 }
 
+impl Div<&DVec2> for f64 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &DVec2) -> DVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: &DVec2) -> DVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn div(self, rhs: DVec2) -> DVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<DVec2> for DVec2 {
     type Output = Self;
     #[inline]
@@ -873,6 +1153,30 @@
     }
 }
 
+impl Mul<&DVec2> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &DVec2) -> DVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &DVec2) -> DVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: DVec2) -> DVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<DVec2> for DVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -881,6 +1185,13 @@
     }
 }
 
+impl MulAssign<&Self> for DVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f64> for DVec2 {
     type Output = Self;
     #[inline]
@@ -892,6 +1203,30 @@
     }
 }
 
+impl Mul<&f64> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: f64) -> DVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f64> for DVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: f64) {
@@ -900,6 +1235,13 @@
     }
 }
 
+impl MulAssign<&f64> for DVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<DVec2> for f64 {
     type Output = DVec2;
     #[inline]
@@ -911,6 +1253,30 @@
     }
 }
 
+impl Mul<&DVec2> for f64 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &DVec2) -> DVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: &DVec2) -> DVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn mul(self, rhs: DVec2) -> DVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<DVec2> for DVec2 {
     type Output = Self;
     #[inline]
@@ -922,6 +1288,30 @@
     }
 }
 
+impl Add<&DVec2> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &DVec2) -> DVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &DVec2) -> DVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: DVec2) -> DVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<DVec2> for DVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -930,6 +1320,13 @@
     }
 }
 
+impl AddAssign<&Self> for DVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f64> for DVec2 {
     type Output = Self;
     #[inline]
@@ -941,6 +1338,30 @@
     }
 }
 
+impl Add<&f64> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: f64) -> DVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f64> for DVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: f64) {
@@ -949,6 +1370,13 @@
     }
 }
 
+impl AddAssign<&f64> for DVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<DVec2> for f64 {
     type Output = DVec2;
     #[inline]
@@ -960,6 +1388,30 @@
     }
 }
 
+impl Add<&DVec2> for f64 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &DVec2) -> DVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: &DVec2) -> DVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn add(self, rhs: DVec2) -> DVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<DVec2> for DVec2 {
     type Output = Self;
     #[inline]
@@ -971,6 +1423,30 @@
     }
 }
 
+impl Sub<&DVec2> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &DVec2) -> DVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &DVec2) -> DVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: DVec2) -> DVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<DVec2> for DVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: DVec2) {
@@ -979,6 +1455,13 @@
     }
 }
 
+impl SubAssign<&Self> for DVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f64> for DVec2 {
     type Output = Self;
     #[inline]
@@ -990,6 +1473,30 @@
     }
 }
 
+impl Sub<&f64> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: f64) -> DVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f64> for DVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: f64) {
@@ -998,6 +1505,13 @@
     }
 }
 
+impl SubAssign<&f64> for DVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<DVec2> for f64 {
     type Output = DVec2;
     #[inline]
@@ -1009,6 +1523,30 @@
     }
 }
 
+impl Sub<&DVec2> for f64 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &DVec2) -> DVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: &DVec2) -> DVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn sub(self, rhs: DVec2) -> DVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<DVec2> for DVec2 {
     type Output = Self;
     #[inline]
@@ -1020,6 +1558,30 @@
     }
 }
 
+impl Rem<&DVec2> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &DVec2) -> DVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &DVec2) -> DVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec2> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: DVec2) -> DVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<DVec2> for DVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1028,6 +1590,13 @@
     }
 }
 
+impl RemAssign<&Self> for DVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f64> for DVec2 {
     type Output = Self;
     #[inline]
@@ -1039,6 +1608,30 @@
     }
 }
 
+impl Rem<&f64> for DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f64> for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: f64) -> DVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f64> for DVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: f64) {
@@ -1047,6 +1640,13 @@
     }
 }
 
+impl RemAssign<&f64> for DVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<DVec2> for f64 {
     type Output = DVec2;
     #[inline]
@@ -1058,6 +1658,30 @@
     }
 }
 
+impl Rem<&DVec2> for f64 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &DVec2) -> DVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: &DVec2) -> DVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec2> for &f64 {
+    type Output = DVec2;
+    #[inline]
+    fn rem(self, rhs: DVec2) -> DVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f64; 2]> for DVec2 {
     #[inline]
@@ -1125,6 +1749,14 @@
     }
 }
 
+impl Neg for &DVec2 {
+    type Output = DVec2;
+    #[inline]
+    fn neg(self) -> DVec2 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for DVec2 {
     type Output = f64;
     #[inline]
@@ -1148,14 +1780,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DVec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}]", self.x, self.y)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}]", p, self.x, p, self.y)
+        } else {
+            write!(f, "[{}, {}]", self.x, self.y)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DVec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(DVec2))
@@ -1213,3 +1847,10 @@
         Self::new(f64::from(v.x), f64::from(v.y))
     }
 }
+
+impl From<BVec2> for DVec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y))
+    }
+}
diff --git a/crates/glam/src/f64/dvec3.rs b/crates/glam/src/f64/dvec3.rs
index a7b0c87..5a67ca0 100644
--- a/crates/glam/src/f64/dvec3.rs
+++ b/crates/glam/src/f64/dvec3.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, BVec3, DVec2, DVec4, IVec3, UVec3, Vec3};
+use crate::{f64::math, BVec3, BVec3A, DVec2, DVec4, IVec3, UVec3, Vec3};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -84,6 +83,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -121,6 +130,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f64]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -131,9 +141,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -165,6 +173,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f64) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -248,6 +280,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f64 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f64 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -371,6 +421,13 @@
         self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec3 {
+        BVec3::new(self.x.is_finite(), self.y.is_finite(), self.z.is_finite())
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -380,7 +437,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec3 {
@@ -454,13 +511,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -487,6 +544,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -496,22 +571,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -539,6 +608,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -569,6 +639,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -623,13 +694,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -672,7 +757,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f64) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -690,14 +800,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f64, max: f64) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -709,10 +820,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f64) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -721,10 +837,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f64) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -750,7 +871,45 @@
         )
     }
 
-    /// Returns the angle (in radians) between two vectors.
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f64) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
+    /// Returns the angle (in radians) between two vectors in the range `[0, +π]`.
     ///
     /// The inputs do not need to be unit vectors however they must be non-zero.
     #[inline]
@@ -831,6 +990,20 @@
         crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -893,6 +1066,30 @@
     }
 }
 
+impl Div<&DVec3> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &DVec3) -> DVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &DVec3) -> DVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: DVec3) -> DVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<DVec3> for DVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -902,6 +1099,13 @@
     }
 }
 
+impl DivAssign<&Self> for DVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f64> for DVec3 {
     type Output = Self;
     #[inline]
@@ -914,6 +1118,30 @@
     }
 }
 
+impl Div<&f64> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: f64) -> DVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f64> for DVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: f64) {
@@ -923,6 +1151,13 @@
     }
 }
 
+impl DivAssign<&f64> for DVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<DVec3> for f64 {
     type Output = DVec3;
     #[inline]
@@ -935,6 +1170,30 @@
     }
 }
 
+impl Div<&DVec3> for f64 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &DVec3) -> DVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: &DVec3) -> DVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn div(self, rhs: DVec3) -> DVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<DVec3> for DVec3 {
     type Output = Self;
     #[inline]
@@ -947,6 +1206,30 @@
     }
 }
 
+impl Mul<&DVec3> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &DVec3) -> DVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &DVec3) -> DVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: DVec3) -> DVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<DVec3> for DVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -956,6 +1239,13 @@
     }
 }
 
+impl MulAssign<&Self> for DVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f64> for DVec3 {
     type Output = Self;
     #[inline]
@@ -968,6 +1258,30 @@
     }
 }
 
+impl Mul<&f64> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: f64) -> DVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f64> for DVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: f64) {
@@ -977,6 +1291,13 @@
     }
 }
 
+impl MulAssign<&f64> for DVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<DVec3> for f64 {
     type Output = DVec3;
     #[inline]
@@ -989,6 +1310,30 @@
     }
 }
 
+impl Mul<&DVec3> for f64 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &DVec3) -> DVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: &DVec3) -> DVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn mul(self, rhs: DVec3) -> DVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<DVec3> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1001,6 +1346,30 @@
     }
 }
 
+impl Add<&DVec3> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &DVec3) -> DVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &DVec3) -> DVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: DVec3) -> DVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<DVec3> for DVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -1010,6 +1379,13 @@
     }
 }
 
+impl AddAssign<&Self> for DVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f64> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1022,6 +1398,30 @@
     }
 }
 
+impl Add<&f64> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: f64) -> DVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f64> for DVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: f64) {
@@ -1031,6 +1431,13 @@
     }
 }
 
+impl AddAssign<&f64> for DVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<DVec3> for f64 {
     type Output = DVec3;
     #[inline]
@@ -1043,6 +1450,30 @@
     }
 }
 
+impl Add<&DVec3> for f64 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &DVec3) -> DVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: &DVec3) -> DVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn add(self, rhs: DVec3) -> DVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<DVec3> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1055,6 +1486,30 @@
     }
 }
 
+impl Sub<&DVec3> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &DVec3) -> DVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &DVec3) -> DVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: DVec3) -> DVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<DVec3> for DVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: DVec3) {
@@ -1064,6 +1519,13 @@
     }
 }
 
+impl SubAssign<&Self> for DVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f64> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1076,6 +1538,30 @@
     }
 }
 
+impl Sub<&f64> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: f64) -> DVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f64> for DVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: f64) {
@@ -1085,6 +1571,13 @@
     }
 }
 
+impl SubAssign<&f64> for DVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<DVec3> for f64 {
     type Output = DVec3;
     #[inline]
@@ -1097,6 +1590,30 @@
     }
 }
 
+impl Sub<&DVec3> for f64 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &DVec3) -> DVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: &DVec3) -> DVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn sub(self, rhs: DVec3) -> DVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<DVec3> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1109,6 +1626,30 @@
     }
 }
 
+impl Rem<&DVec3> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &DVec3) -> DVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &DVec3) -> DVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec3> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: DVec3) -> DVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<DVec3> for DVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1118,6 +1659,13 @@
     }
 }
 
+impl RemAssign<&Self> for DVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f64> for DVec3 {
     type Output = Self;
     #[inline]
@@ -1130,6 +1678,30 @@
     }
 }
 
+impl Rem<&f64> for DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f64> for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: f64) -> DVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f64> for DVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: f64) {
@@ -1139,6 +1711,13 @@
     }
 }
 
+impl RemAssign<&f64> for DVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<DVec3> for f64 {
     type Output = DVec3;
     #[inline]
@@ -1151,6 +1730,30 @@
     }
 }
 
+impl Rem<&DVec3> for f64 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &DVec3) -> DVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: &DVec3) -> DVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec3> for &f64 {
+    type Output = DVec3;
+    #[inline]
+    fn rem(self, rhs: DVec3) -> DVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f64; 3]> for DVec3 {
     #[inline]
@@ -1219,6 +1822,14 @@
     }
 }
 
+impl Neg for &DVec3 {
+    type Output = DVec3;
+    #[inline]
+    fn neg(self) -> DVec3 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for DVec3 {
     type Output = f64;
     #[inline]
@@ -1244,14 +1855,16 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DVec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        if let Some(p) = f.precision() {
+            write!(f, "[{:.*}, {:.*}, {:.*}]", p, self.x, p, self.y, p, self.z)
+        } else {
+            write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DVec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(DVec3))
@@ -1317,3 +1930,22 @@
         Self::new(f64::from(v.x), f64::from(v.y), f64::from(v.z))
     }
 }
+
+impl From<BVec3> for DVec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y), f64::from(v.z))
+    }
+}
+
+impl From<BVec3A> for DVec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            f64::from(bool_array[0]),
+            f64::from(bool_array[1]),
+            f64::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/f64/dvec4.rs b/crates/glam/src/f64/dvec4.rs
index acd9ac5..f13647a 100644
--- a/crates/glam/src/f64/dvec4.rs
+++ b/crates/glam/src/f64/dvec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
 use crate::{f64::math, BVec4, DVec2, DVec3, IVec4, UVec4, Vec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -100,6 +101,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -138,6 +149,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[f64]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -148,10 +160,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [f64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -164,6 +173,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: f64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: f64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: f64) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: f64) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -238,6 +279,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> f64 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> f64 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -395,6 +454,18 @@
         self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
     }
 
+    /// Performs `is_finite` on each element of self, returning a vector mask of the results.
+    ///
+    /// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
+    pub fn is_finite_mask(self) -> BVec4 {
+        BVec4::new(
+            self.x.is_finite(),
+            self.y.is_finite(),
+            self.z.is_finite(),
+            self.w.is_finite(),
+        )
+    }
+
     /// Returns `true` if any elements are `NaN`.
     #[inline]
     #[must_use]
@@ -404,7 +475,7 @@
 
     /// Performs `is_nan` on each element of self, returning a vector mask of the results.
     ///
-    /// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
+    /// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
     #[inline]
     #[must_use]
     pub fn is_nan_mask(self) -> BVec4 {
@@ -485,13 +556,13 @@
 
     /// Returns `self` normalized to length 1.0.
     ///
-    /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
+    /// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
     ///
     /// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
     ///
     /// Panics
     ///
-    /// Will panic if `self` is zero length when `glam_assert` is enabled.
+    /// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn normalize(self) -> Self {
@@ -518,6 +589,24 @@
         }
     }
 
+    /// Returns `self` normalized to length 1.0 if possible, else returns a
+    /// fallback value.
+    ///
+    /// In particular, if the input is zero (or very close to zero), or non-finite,
+    /// the result of this operation will be the fallback value.
+    ///
+    /// See also [`Self::try_normalize()`].
+    #[inline]
+    #[must_use]
+    pub fn normalize_or(self, fallback: Self) -> Self {
+        let rcp = self.length_recip();
+        if rcp.is_finite() && rcp > 0.0 {
+            self * rcp
+        } else {
+            fallback
+        }
+    }
+
     /// Returns `self` normalized to length 1.0 if possible, else returns zero.
     ///
     /// In particular, if the input is zero (or very close to zero), or non-finite,
@@ -527,22 +616,16 @@
     #[inline]
     #[must_use]
     pub fn normalize_or_zero(self) -> Self {
-        let rcp = self.length_recip();
-        if rcp.is_finite() && rcp > 0.0 {
-            self * rcp
-        } else {
-            Self::ZERO
-        }
+        self.normalize_or(Self::ZERO)
     }
 
     /// Returns whether `self` is length `1.0` or not.
     ///
-    /// Uses a precision threshold of `1e-6`.
+    /// Uses a precision threshold of approximately `1e-4`.
     #[inline]
     #[must_use]
     pub fn is_normalized(self) -> bool {
-        // TODO: do something with epsilon
-        math::abs(self.length_squared() - 1.0) <= 1e-4
+        math::abs(self.length_squared() - 1.0) <= 2e-4
     }
 
     /// Returns the vector projection of `self` onto `rhs`.
@@ -570,6 +653,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` has a length of zero when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from(self, rhs: Self) -> Self {
@@ -600,6 +684,7 @@
     /// # Panics
     ///
     /// Will panic if `rhs` is not normalized when `glam_assert` is enabled.
+    #[doc(alias("plane"))]
     #[inline]
     #[must_use]
     pub fn reject_from_normalized(self, rhs: Self) -> Self {
@@ -658,13 +743,27 @@
         }
     }
 
-    /// Returns a vector containing the fractional part of the vector, e.g. `self -
-    /// self.floor()`.
+    /// Returns a vector containing the fractional part of the vector as `self - self.trunc()`.
+    ///
+    /// Note that this differs from the GLSL implementation of `fract` which returns
+    /// `self - self.floor()`.
     ///
     /// Note that this is fast but not precise for large numbers.
     #[inline]
     #[must_use]
     pub fn fract(self) -> Self {
+        self - self.trunc()
+    }
+
+    /// Returns a vector containing the fractional part of the vector as `self - self.floor()`.
+    ///
+    /// Note that this differs from the Rust implementation of `fract` which returns
+    /// `self - self.trunc()`.
+    ///
+    /// Note that this is fast but not precise for large numbers.
+    #[inline]
+    #[must_use]
+    pub fn fract_gl(self) -> Self {
         self - self.floor()
     }
 
@@ -714,7 +813,32 @@
     #[inline]
     #[must_use]
     pub fn lerp(self, rhs: Self, s: f64) -> Self {
-        self + ((rhs - self) * s)
+        self * (1.0 - s) + rhs * s
+    }
+
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
+    /// Calculates the midpoint between `self` and `rhs`.
+    ///
+    /// The midpoint is the average of, or halfway point between, two vectors.
+    /// `a.midpoint(b)` should yield the same result as `a.lerp(b, 0.5)`
+    /// while being slightly cheaper to compute.
+    #[inline]
+    pub fn midpoint(self, rhs: Self) -> Self {
+        (self + rhs) * 0.5
     }
 
     /// Returns true if the absolute difference of all elements between `self` and `rhs` is
@@ -732,14 +856,15 @@
         self.sub(rhs).abs().cmple(Self::splat(max_abs_diff)).all()
     }
 
-    /// Returns a vector with a length no less than `min` and no more than `max`
+    /// Returns a vector with a length no less than `min` and no more than `max`.
     ///
     /// # Panics
     ///
-    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    /// Will panic if `min` is greater than `max`, or if either `min` or `max` is negative, when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length(self, min: f64, max: f64) -> Self {
+        glam_assert!(0.0 <= min);
         glam_assert!(min <= max);
         let length_sq = self.length_squared();
         if length_sq < min * min {
@@ -751,10 +876,15 @@
         }
     }
 
-    /// Returns a vector with a length no more than `max`
+    /// Returns a vector with a length no more than `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `max` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_max(self, max: f64) -> Self {
+        glam_assert!(0.0 <= max);
         let length_sq = self.length_squared();
         if length_sq > max * max {
             max * (self / math::sqrt(length_sq))
@@ -763,10 +893,15 @@
         }
     }
 
-    /// Returns a vector with a length no less than `min`
+    /// Returns a vector with a length no less than `min`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is negative when `glam_assert` is enabled.
     #[inline]
     #[must_use]
     pub fn clamp_length_min(self, min: f64) -> Self {
+        glam_assert!(0.0 <= min);
         let length_sq = self.length_squared();
         if length_sq < min * min {
             min * (self / math::sqrt(length_sq))
@@ -793,6 +928,44 @@
         )
     }
 
+    /// Returns the reflection vector for a given incident vector `self` and surface normal
+    /// `normal`.
+    ///
+    /// `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn reflect(self, normal: Self) -> Self {
+        glam_assert!(normal.is_normalized());
+        self - 2.0 * self.dot(normal) * normal
+    }
+
+    /// Returns the refraction direction for a given incident vector `self`, surface normal
+    /// `normal` and ratio of indices of refraction, `eta`. When total internal reflection occurs,
+    /// a zero vector will be returned.
+    ///
+    /// `self` and `normal` must be normalized.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `self` or `normal` is not normalized when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn refract(self, normal: Self, eta: f64) -> Self {
+        glam_assert!(self.is_normalized());
+        glam_assert!(normal.is_normalized());
+        let n_dot_i = normal.dot(self);
+        let k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i);
+        if k >= 0.0 {
+            eta * self - (eta * n_dot_i + math::sqrt(k)) * normal
+        } else {
+            Self::ZERO
+        }
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     #[must_use]
@@ -800,6 +973,20 @@
         crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -863,6 +1050,30 @@
     }
 }
 
+impl Div<&DVec4> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &DVec4) -> DVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &DVec4) -> DVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: DVec4) -> DVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<DVec4> for DVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -873,6 +1084,13 @@
     }
 }
 
+impl DivAssign<&Self> for DVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<f64> for DVec4 {
     type Output = Self;
     #[inline]
@@ -886,6 +1104,30 @@
     }
 }
 
+impl Div<&f64> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &f64) -> DVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: f64) -> DVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<f64> for DVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: f64) {
@@ -896,6 +1138,13 @@
     }
 }
 
+impl DivAssign<&f64> for DVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &f64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<DVec4> for f64 {
     type Output = DVec4;
     #[inline]
@@ -909,6 +1158,30 @@
     }
 }
 
+impl Div<&DVec4> for f64 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &DVec4) -> DVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: &DVec4) -> DVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn div(self, rhs: DVec4) -> DVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<DVec4> for DVec4 {
     type Output = Self;
     #[inline]
@@ -922,6 +1195,30 @@
     }
 }
 
+impl Mul<&DVec4> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &DVec4) -> DVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &DVec4) -> DVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: DVec4) -> DVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<DVec4> for DVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -932,6 +1229,13 @@
     }
 }
 
+impl MulAssign<&Self> for DVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<f64> for DVec4 {
     type Output = Self;
     #[inline]
@@ -945,6 +1249,30 @@
     }
 }
 
+impl Mul<&f64> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &f64) -> DVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: f64) -> DVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<f64> for DVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: f64) {
@@ -955,6 +1283,13 @@
     }
 }
 
+impl MulAssign<&f64> for DVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &f64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<DVec4> for f64 {
     type Output = DVec4;
     #[inline]
@@ -968,6 +1303,30 @@
     }
 }
 
+impl Mul<&DVec4> for f64 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &DVec4) -> DVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: &DVec4) -> DVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn mul(self, rhs: DVec4) -> DVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<DVec4> for DVec4 {
     type Output = Self;
     #[inline]
@@ -981,6 +1340,30 @@
     }
 }
 
+impl Add<&DVec4> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &DVec4) -> DVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &DVec4) -> DVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: DVec4) -> DVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<DVec4> for DVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -991,6 +1374,13 @@
     }
 }
 
+impl AddAssign<&Self> for DVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<f64> for DVec4 {
     type Output = Self;
     #[inline]
@@ -1004,6 +1394,30 @@
     }
 }
 
+impl Add<&f64> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &f64) -> DVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: f64) -> DVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<f64> for DVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: f64) {
@@ -1014,6 +1428,13 @@
     }
 }
 
+impl AddAssign<&f64> for DVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &f64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<DVec4> for f64 {
     type Output = DVec4;
     #[inline]
@@ -1027,6 +1448,30 @@
     }
 }
 
+impl Add<&DVec4> for f64 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &DVec4) -> DVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: &DVec4) -> DVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn add(self, rhs: DVec4) -> DVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<DVec4> for DVec4 {
     type Output = Self;
     #[inline]
@@ -1040,6 +1485,30 @@
     }
 }
 
+impl Sub<&DVec4> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &DVec4) -> DVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &DVec4) -> DVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: DVec4) -> DVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<DVec4> for DVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: DVec4) {
@@ -1050,6 +1519,13 @@
     }
 }
 
+impl SubAssign<&Self> for DVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<f64> for DVec4 {
     type Output = Self;
     #[inline]
@@ -1063,6 +1539,30 @@
     }
 }
 
+impl Sub<&f64> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &f64) -> DVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: f64) -> DVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<f64> for DVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: f64) {
@@ -1073,6 +1573,13 @@
     }
 }
 
+impl SubAssign<&f64> for DVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &f64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<DVec4> for f64 {
     type Output = DVec4;
     #[inline]
@@ -1086,6 +1593,30 @@
     }
 }
 
+impl Sub<&DVec4> for f64 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &DVec4) -> DVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: &DVec4) -> DVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn sub(self, rhs: DVec4) -> DVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<DVec4> for DVec4 {
     type Output = Self;
     #[inline]
@@ -1099,6 +1630,30 @@
     }
 }
 
+impl Rem<&DVec4> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &DVec4) -> DVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &DVec4) -> DVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec4> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: DVec4) -> DVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<DVec4> for DVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -1109,6 +1664,13 @@
     }
 }
 
+impl RemAssign<&Self> for DVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<f64> for DVec4 {
     type Output = Self;
     #[inline]
@@ -1122,6 +1684,30 @@
     }
 }
 
+impl Rem<&f64> for DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &f64) -> DVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<f64> for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: f64) -> DVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<f64> for DVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: f64) {
@@ -1132,6 +1718,13 @@
     }
 }
 
+impl RemAssign<&f64> for DVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &f64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<DVec4> for f64 {
     type Output = DVec4;
     #[inline]
@@ -1145,6 +1738,30 @@
     }
 }
 
+impl Rem<&DVec4> for f64 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &DVec4) -> DVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: &DVec4) -> DVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<DVec4> for &f64 {
+    type Output = DVec4;
+    #[inline]
+    fn rem(self, rhs: DVec4) -> DVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[f64; 4]> for DVec4 {
     #[inline]
@@ -1214,6 +1831,14 @@
     }
 }
 
+impl Neg for &DVec4 {
+    type Output = DVec4;
+    #[inline]
+    fn neg(self) -> DVec4 {
+        (*self).neg()
+    }
+}
+
 impl Index<usize> for DVec4 {
     type Output = f64;
     #[inline]
@@ -1241,14 +1866,20 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for DVec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        if let Some(p) = f.precision() {
+            write!(
+                f,
+                "[{:.*}, {:.*}, {:.*}, {:.*}]",
+                p, self.x, p, self.y, p, self.z, p, self.w
+            )
+        } else {
+            write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+        }
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for DVec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(DVec4))
@@ -1351,3 +1982,30 @@
         )
     }
 }
+
+impl From<BVec4> for DVec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            f64::from(v.x),
+            f64::from(v.y),
+            f64::from(v.z),
+            f64::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for DVec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            f64::from(bool_array[0]),
+            f64::from(bool_array[1]),
+            f64::from(bool_array[2]),
+            f64::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/f64/math.rs b/crates/glam/src/f64/math.rs
index 45ace5c..2885342 100644
--- a/crates/glam/src/f64/math.rs
+++ b/crates/glam/src/f64/math.rs
@@ -11,11 +11,6 @@
     }
 
     #[inline(always)]
-    pub(crate) fn asin(f: f64) -> f64 {
-        libm::asin(f)
-    }
-
-    #[inline(always)]
     pub(crate) fn atan2(f: f64, other: f64) -> f64 {
         libm::atan2(f, other)
     }
@@ -123,11 +118,6 @@
     }
 
     #[inline(always)]
-    pub(crate) fn asin(f: f64) -> f64 {
-        f64::asin(f)
-    }
-
-    #[inline(always)]
     pub(crate) fn atan2(f: f64, other: f64) -> f64 {
         f64::atan2(f, other)
     }
diff --git a/crates/glam/src/features/impl_bytemuck.rs b/crates/glam/src/features/impl_bytemuck.rs
index 1b47029..da4a340 100644
--- a/crates/glam/src/features/impl_bytemuck.rs
+++ b/crates/glam/src/features/impl_bytemuck.rs
@@ -1,8 +1,8 @@
 use crate::{
     Affine2, Affine3A, DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4,
-    I16Vec2, I16Vec3, I16Vec4, I64Vec2, I64Vec3, I64Vec4, IVec2, IVec3, IVec4, Mat2, Mat3, Mat3A,
-    Mat4, Quat, U16Vec2, U16Vec3, U16Vec4, U64Vec2, U64Vec3, U64Vec4, UVec2, UVec3, UVec4, Vec2,
-    Vec3, Vec3A, Vec4,
+    I16Vec2, I16Vec3, I16Vec4, I64Vec2, I64Vec3, I64Vec4, I8Vec2, I8Vec3, I8Vec4, IVec2, IVec3,
+    IVec4, Mat2, Mat3, Mat3A, Mat4, Quat, U16Vec2, U16Vec3, U16Vec4, U64Vec2, U64Vec3, U64Vec4,
+    U8Vec2, U8Vec3, U8Vec4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4,
 };
 use bytemuck::{AnyBitPattern, Pod, Zeroable};
 
@@ -55,6 +55,20 @@
 unsafe impl Pod for DVec4 {}
 unsafe impl Zeroable for DVec4 {}
 
+unsafe impl Pod for I8Vec2 {}
+unsafe impl Zeroable for I8Vec2 {}
+unsafe impl Pod for I8Vec3 {}
+unsafe impl Zeroable for I8Vec3 {}
+unsafe impl Pod for I8Vec4 {}
+unsafe impl Zeroable for I8Vec4 {}
+
+unsafe impl Pod for U8Vec2 {}
+unsafe impl Zeroable for U8Vec2 {}
+unsafe impl Pod for U8Vec3 {}
+unsafe impl Zeroable for U8Vec3 {}
+unsafe impl Pod for U8Vec4 {}
+unsafe impl Zeroable for U8Vec4 {}
+
 unsafe impl Pod for I16Vec2 {}
 unsafe impl Zeroable for I16Vec2 {}
 unsafe impl Pod for I16Vec3 {}
@@ -101,9 +115,9 @@
 mod test {
     use crate::{
         Affine2, Affine3A, DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4,
-        I16Vec2, I16Vec3, I16Vec4, I64Vec2, I64Vec3, I64Vec4, IVec2, IVec3, IVec4, Mat2, Mat3,
-        Mat3A, Mat4, Quat, U16Vec2, U16Vec3, U16Vec4, U64Vec2, U64Vec3, U64Vec4, UVec2, UVec3,
-        UVec4, Vec2, Vec3, Vec3A, Vec4,
+        I16Vec2, I16Vec3, I16Vec4, I64Vec2, I64Vec3, I64Vec4, I8Vec2, I8Vec3, I8Vec4, IVec2, IVec3,
+        IVec4, Mat2, Mat3, Mat3A, Mat4, Quat, U16Vec2, U16Vec3, U16Vec4, U64Vec2, U64Vec3, U64Vec4,
+        U8Vec2, U8Vec3, U8Vec4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4,
     };
     use core::mem;
 
@@ -161,6 +175,14 @@
     test_pod_t!(dvec3, DVec3);
     test_pod_t!(dvec4, DVec4);
 
+    test_pod_t!(i8vec2, I8Vec2);
+    test_pod_t!(i8vec3, I8Vec3);
+    test_pod_t!(i8vec4, I8Vec4);
+
+    test_pod_t!(u8vec2, U8Vec2);
+    test_pod_t!(u8vec3, U8Vec3);
+    test_pod_t!(u8vec4, U8Vec4);
+
     test_pod_t!(i16vec2, I16Vec2);
     test_pod_t!(i16vec3, I16Vec3);
     test_pod_t!(i16vec4, I16Vec4);
diff --git a/crates/glam/src/features/impl_mint.rs b/crates/glam/src/features/impl_mint.rs
index 84cdcbd..a3835cc 100644
--- a/crates/glam/src/features/impl_mint.rs
+++ b/crates/glam/src/features/impl_mint.rs
@@ -2,8 +2,9 @@
 
 use crate::{
     DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, I16Vec2, I16Vec3, I16Vec4, I64Vec2, I64Vec3,
-    I64Vec4, IVec2, IVec3, IVec4, Mat2, Mat3, Mat3A, Mat4, Quat, U16Vec2, U16Vec3, U16Vec4,
-    U64Vec2, U64Vec3, U64Vec4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4,
+    I64Vec4, I8Vec2, I8Vec3, I8Vec4, IVec2, IVec3, IVec4, Mat2, Mat3, Mat3A, Mat4, Quat, U16Vec2,
+    U16Vec3, U16Vec4, U64Vec2, U64Vec3, U64Vec4, U8Vec2, U8Vec3, U8Vec4, UVec2, UVec3, UVec4, Vec2,
+    Vec3, Vec3A, Vec4,
 };
 
 macro_rules! impl_vec_types {
@@ -310,6 +311,8 @@
 
 impl_float_types!(f32, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4);
 impl_float_types!(f64, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4);
+impl_vec_types!(i8, I8Vec2, I8Vec3, I8Vec4);
+impl_vec_types!(u8, U8Vec2, U8Vec3, U8Vec4);
 impl_vec_types!(i16, I16Vec2, I16Vec3, I16Vec4);
 impl_vec_types!(u16, U16Vec2, U16Vec3, U16Vec4);
 impl_vec_types!(i32, IVec2, IVec3, IVec4);
diff --git a/crates/glam/src/features/impl_rand.rs b/crates/glam/src/features/impl_rand.rs
index 3c6c19a..88dceb3 100644
--- a/crates/glam/src/features/impl_rand.rs
+++ b/crates/glam/src/features/impl_rand.rs
@@ -84,10 +84,12 @@
         impl Distribution<$quat> for Standard {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $quat {
-                let yaw = -PI + rng.gen::<$t>() * 2.0 * PI;
-                let pitch = -PI + rng.gen::<$t>() * 2.0 * PI;
-                let roll = -PI + rng.gen::<$t>() * 2.0 * PI;
-                $quat::from_euler(crate::EulerRot::YXZ, yaw, pitch, roll)
+                let z = rng.gen_range::<$t, _>(-1.0..=1.0);
+                let (y, x) = math::sin_cos(rng.gen_range::<$t, _>(0.0..TAU));
+                let r = math::sqrt(1.0 - z * z);
+                let axis = $vec3::new(r * x, r * y, z);
+                let angle = rng.gen_range::<$t, _>(0.0..TAU);
+                $quat::from_axis_angle(axis, angle)
             }
         }
 
@@ -139,8 +141,9 @@
 }
 
 mod f32 {
+    use crate::f32::math;
     use crate::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4};
-    use core::f32::consts::PI;
+    use core::f32::consts::TAU;
     use rand::{
         distributions::{Distribution, Standard},
         Rng,
@@ -168,8 +171,9 @@
 }
 
 mod f64 {
+    use crate::f64::math;
     use crate::{DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4};
-    use core::f64::consts::PI;
+    use core::f64::consts::TAU;
     use rand::{
         distributions::{Distribution, Standard},
         Rng,
@@ -178,6 +182,16 @@
     impl_float_types!(f64, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4);
 }
 
+mod i8 {
+    use crate::{I8Vec2, I8Vec3, I8Vec4};
+    use rand::{
+        distributions::{Distribution, Standard},
+        Rng,
+    };
+
+    impl_vec_types!(i8, I8Vec2, I8Vec3, I8Vec4);
+}
+
 mod i16 {
     use crate::{I16Vec2, I16Vec3, I16Vec4};
     use rand::{
@@ -208,6 +222,16 @@
     impl_vec_types!(i64, I64Vec2, I64Vec3, I64Vec4);
 }
 
+mod u8 {
+    use crate::{U8Vec2, U8Vec3, U8Vec4};
+    use rand::{
+        distributions::{Distribution, Standard},
+        Rng,
+    };
+
+    impl_vec_types!(u8, U8Vec2, U8Vec3, U8Vec4);
+}
+
 mod u16 {
     use crate::{U16Vec2, U16Vec3, U16Vec4};
     use rand::{
diff --git a/crates/glam/src/features/impl_rkyv.rs b/crates/glam/src/features/impl_rkyv.rs
index fb72e37..5c62e17 100644
--- a/crates/glam/src/features/impl_rkyv.rs
+++ b/crates/glam/src/features/impl_rkyv.rs
@@ -90,6 +90,15 @@
     impl_rkyv!(DVec4);
 }
 
+mod i8 {
+    use crate::{I8Vec2, I8Vec3, I8Vec4};
+    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+
+    impl_rkyv!(I8Vec2);
+    impl_rkyv!(I8Vec3);
+    impl_rkyv!(I8Vec4);
+}
+
 mod i16 {
     use crate::{I16Vec2, I16Vec3, I16Vec4};
     use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
@@ -117,6 +126,15 @@
     impl_rkyv!(I64Vec4);
 }
 
+mod u8 {
+    use crate::{U8Vec2, U8Vec3, U8Vec4};
+    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+
+    impl_rkyv!(U8Vec2);
+    impl_rkyv!(U8Vec3);
+    impl_rkyv!(U8Vec4);
+}
+
 mod u16 {
     use crate::{U16Vec2, U16Vec3, U16Vec4};
     use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
@@ -211,6 +229,11 @@
         test_archive(&DVec3::new(1.0, 2.0, 3.0));
         test_archive(&DVec4::new(1.0, 2.0, 3.0, 4.0));
 
+        use crate::{I8Vec2, I8Vec3, I8Vec4};
+        test_archive(&I8Vec2::new(-1, 2));
+        test_archive(&I8Vec3::new(-1, 2, 3));
+        test_archive(&I8Vec4::new(-1, 2, 3, 4));
+
         use crate::{I16Vec2, I16Vec3, I16Vec4};
         test_archive(&I16Vec2::new(-1, 2));
         test_archive(&I16Vec3::new(-1, 2, 3));
@@ -226,6 +249,11 @@
         test_archive(&I64Vec3::new(-1, 2, 3));
         test_archive(&I64Vec4::new(-1, 2, 3, 4));
 
+        use crate::{U8Vec2, U8Vec3, U8Vec4};
+        test_archive(&U8Vec2::new(1, 2));
+        test_archive(&U8Vec3::new(1, 2, 3));
+        test_archive(&U8Vec4::new(1, 2, 3, 4));
+
         use crate::{U16Vec2, U16Vec3, U16Vec4};
         test_archive(&U16Vec2::new(1, 2));
         test_archive(&U16Vec3::new(1, 2, 3));
diff --git a/crates/glam/src/features/impl_serde.rs b/crates/glam/src/features/impl_serde.rs
index ab0db6c..08ed73d 100644
--- a/crates/glam/src/features/impl_serde.rs
+++ b/crates/glam/src/features/impl_serde.rs
@@ -1,5 +1,6 @@
 macro_rules! impl_serde_vec2 {
     ($t:ty, $vec2:ident) => {
+        /// Serialize as a sequence of 2 values.
         impl Serialize for $vec2 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -12,6 +13,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 2 values.
         impl<'de> Deserialize<'de> for $vec2 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -23,7 +25,7 @@
                     type Value = $vec2;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($vec2)))
+                        formatter.write_str(&concat!("a sequence of 2 ", stringify!($t), " values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$vec2, V::Error>
@@ -57,6 +59,9 @@
             assert!(deserialized.is_err());
             let deserialized = serde_json::from_str::<$vec2>(SX3);
             assert!(deserialized.is_err());
+
+            let deserialized = serde_json::from_str::<$vec2>(ST0);
+            assert!(deserialized.is_err());
         }
     };
 }
@@ -66,6 +71,7 @@
         impl_serde_vec3!($t, $vec3, test_vec3_serde);
     };
     ($t:ty, $vec3:ident, $test_name:ident) => {
+        /// Serialize as a sequence of 3 values.
         impl Serialize for $vec3 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -79,6 +85,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 3 values.
         impl<'de> Deserialize<'de> for $vec3 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -90,7 +97,7 @@
                     type Value = $vec3;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($vec3)))
+                        formatter.write_str(&concat!("a sequence of 3 ", stringify!($t), " values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$vec3, V::Error>
@@ -129,12 +136,15 @@
             assert!(deserialized.is_err());
             let deserialized = serde_json::from_str::<$vec3>(SX4);
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$vec3>(ST0);
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_vec4 {
     ($t:ty, $vec4:ident) => {
+        /// Serialize as a sequence of 4 values.
         impl Serialize for $vec4 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -149,6 +159,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 4 values.
         impl<'de> Deserialize<'de> for $vec4 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -160,7 +171,7 @@
                     type Value = $vec4;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($vec4)))
+                        formatter.write_str(&concat!("a sequence of 4 ", stringify!($t), " values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$vec4, V::Error>
@@ -204,12 +215,15 @@
             assert!(deserialized.is_err());
             let deserialized = serde_json::from_str::<$vec4>(SX5);
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$vec4>(ST0);
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_quat {
     ($t:ty, $quat:ident) => {
+        /// Serialize as a sequence of 4 values.
         impl Serialize for $quat {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -224,6 +238,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 4 values.
         impl<'de> Deserialize<'de> for $quat {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -235,7 +250,7 @@
                     type Value = $quat;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($quat)))
+                        formatter.write_str(&concat!("a sequence of 4 ", stringify!($t), " values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$quat, V::Error>
@@ -279,12 +294,15 @@
             assert!(deserialized.is_err());
             let deserialized = serde_json::from_str::<$quat>("[1.0,2.0,3.0,4.0,5.0]");
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$quat>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_mat2 {
     ($t:ty, $mat2:ident) => {
+        /// Serialize as a sequence of 4 values.
         impl Serialize for $mat2 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -300,6 +318,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 4 values.
         impl<'de> Deserialize<'de> for $mat2 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -311,7 +330,7 @@
                     type Value = $mat2;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($mat2)))
+                        formatter.write_str(&concat!("a sequence of 4 ", stringify!($t), "values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$mat2, V::Error>
@@ -351,6 +370,8 @@
             assert!(deserialized.is_err());
             let deserialized = serde_json::from_str::<$mat2>("[[1.0,2.0],[3.0,4.0]]");
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$mat2>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
@@ -360,6 +381,7 @@
         impl_serde_mat3!($t, $mat3, test_mat3_serde);
     };
     ($t:ty, $mat3:ident, $test_name:ident) => {
+        /// Serialize as a sequence of 9 values.
         impl Serialize for $mat3 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -383,6 +405,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 9 values.
         impl<'de> Deserialize<'de> for $mat3 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -394,7 +417,7 @@
                     type Value = $mat3;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($mat3)))
+                        formatter.write_str(&concat!("a sequence of 9 ", stringify!($t), "values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$mat3, V::Error>
@@ -435,12 +458,15 @@
             let deserialized =
                 serde_json::from_str::<$mat3>("[[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0]]");
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$mat3>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_mat4 {
     ($t:ty, $mat4:ident) => {
+        /// Serialize as a sequence of 16 values.
         impl Serialize for $mat4 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -454,6 +480,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 16 values.
         impl<'de> Deserialize<'de> for $mat4 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -465,7 +492,7 @@
                     type Value = $mat4;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str(concat!("struct ", stringify!($mat4)))
+                        formatter.write_str(&concat!("a sequence of 16 ", stringify!($t), "values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$mat4, V::Error>
@@ -516,12 +543,15 @@
                 "[[1.0,2.0,3.0,4.0],[5.0,6.0,7.0,8.0],[9.0,10.0,11.0,12.0][13.0,14.0,15.0,16.0]]",
             );
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$mat4>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_affine2 {
     ($t:ty, $affine2:ident) => {
+        /// Serialize as a sequence of 6 values.
         impl Serialize for $affine2 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -539,6 +569,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 6 values.
         impl<'de> Deserialize<'de> for $affine2 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -550,7 +581,7 @@
                     type Value = $affine2;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str("struct $affine2")
+                        formatter.write_str(&concat!("a sequence of 6 ", stringify!($t), "values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$affine2, V::Error>
@@ -595,12 +626,15 @@
                 "[[1.0,2.0,3.0,4.0],[5.0,6.0,7.0,8.0],[9.0,10.0,11.0,12.0][13.0,14.0,15.0,16.0]]",
             );
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$affine2>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
 
 macro_rules! impl_serde_affine3 {
     ($t:ty, $affine3:ident) => {
+        /// Serialize as a sequence of 12 values.
         impl Serialize for $affine3 {
             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
@@ -624,6 +658,7 @@
             }
         }
 
+        /// Deserialize expects a sequence of 12 values.
         impl<'de> Deserialize<'de> for $affine3 {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -635,7 +670,7 @@
                     type Value = $affine3;
 
                     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        formatter.write_str("struct $affine3")
+                        formatter.write_str(&concat!("a sequence of 12 ", stringify!($t), "values"))
                     }
 
                     fn visit_seq<V>(self, mut seq: V) -> Result<$affine3, V::Error>
@@ -686,6 +721,8 @@
                 "[[1.0,2.0,3.0,4.0],[5.0,6.0,7.0,8.0],[9.0,10.0,11.0,12.0][13.0,14.0,15.0,16.0]]",
             );
             assert!(deserialized.is_err());
+            let deserialized = serde_json::from_str::<$affine3>("{}");
+            assert!(deserialized.is_err());
         }
     };
 }
@@ -727,6 +764,14 @@
 }
 
 #[cfg(test)]
+mod test_i8 {
+    pub const V1: i8 = 1;
+    pub const V2: i8 = 2;
+    pub const V3: i8 = 3;
+    pub const V4: i8 = 4;
+}
+
+#[cfg(test)]
 mod test_i16 {
     pub const V1: i16 = 1;
     pub const V2: i16 = 2;
@@ -751,6 +796,14 @@
 }
 
 #[cfg(test)]
+mod test_u8 {
+    pub const V1: u8 = 1;
+    pub const V2: u8 = 2;
+    pub const V3: u8 = 3;
+    pub const V4: u8 = 4;
+}
+
+#[cfg(test)]
 mod test_u16 {
     pub const V1: u16 = 1;
     pub const V2: u16 = 2;
@@ -782,6 +835,7 @@
     pub const SX3: &str = "[1.0,2.0,3.0]";
     pub const SX4: &str = "[1.0,2.0,3.0,4.0]";
     pub const SX5: &str = "[1.0,2.0,3.0,4.0,5.0]";
+    pub const ST0: &str = "{}";
 }
 
 #[cfg(test)]
@@ -792,6 +846,7 @@
     pub const SX3: &str = "[1,2,3]";
     pub const SX4: &str = "[1,2,3,4]";
     pub const SX5: &str = "[1,2,3,4,5]";
+    pub const ST0: &str = "{}";
 }
 
 #[cfg(test)]
@@ -802,6 +857,7 @@
     pub const SX3: &str = "[true,true,true]";
     pub const SX4: &str = "[true,true,true,true]";
     pub const SX5: &str = "[true,true,true,true,true]";
+    pub const ST0: &str = "{}";
     pub const V1: bool = true;
     pub const V2: bool = true;
     pub const V3: bool = true;
@@ -851,7 +907,7 @@
                 type Value = BVec3A;
 
                 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    formatter.write_str("struct BVec3A")
+                    formatter.write_str(&concat!("a sequence of 3 ", stringify!($t), "values"))
                 }
 
                 fn visit_seq<V>(self, mut seq: V) -> Result<BVec3A, V::Error>
@@ -921,7 +977,7 @@
                 type Value = BVec4A;
 
                 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    formatter.write_str(concat!("struct ", stringify!(BVec4A)))
+                    formatter.write_str(&concat!("a sequence of 4 ", stringify!($t), "values"))
                 }
 
                 fn visit_seq<V>(self, mut seq: V) -> Result<BVec4A, V::Error>
@@ -1003,6 +1059,21 @@
     );
 }
 
+mod i8 {
+    #[cfg(test)]
+    use super::test_i8::*;
+    #[cfg(test)]
+    use super::test_int::*;
+    use crate::{I8Vec2, I8Vec3, I8Vec4};
+    use core::fmt;
+    use serde::{
+        de::{self, Deserialize, Deserializer, SeqAccess, Visitor},
+        ser::{Serialize, SerializeTupleStruct, Serializer},
+    };
+
+    impl_serde_vec_types!(i8, I8Vec2, I8Vec3, I8Vec4);
+}
+
 mod i16 {
     #[cfg(test)]
     use super::test_i16::*;
@@ -1048,6 +1119,21 @@
     impl_serde_vec_types!(i64, I64Vec2, I64Vec3, I64Vec4);
 }
 
+mod u8 {
+    #[cfg(test)]
+    use super::test_int::*;
+    #[cfg(test)]
+    use super::test_u8::*;
+    use crate::{U8Vec2, U8Vec3, U8Vec4};
+    use core::fmt;
+    use serde::{
+        de::{self, Deserialize, Deserializer, SeqAccess, Visitor},
+        ser::{Serialize, SerializeTupleStruct, Serializer},
+    };
+
+    impl_serde_vec_types!(u8, U8Vec2, U8Vec3, U8Vec4);
+}
+
 mod u16 {
     #[cfg(test)]
     use super::test_int::*;
@@ -1117,6 +1203,60 @@
                 EulerRot::XZY => {
                     serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 5u32, "XZY")
                 }
+                EulerRot::ZYZ => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 6u32, "ZYZ")
+                }
+                EulerRot::ZXZ => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 7u32, "ZXZ")
+                }
+                EulerRot::YXY => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 8u32, "YXY")
+                }
+                EulerRot::YZY => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 9u32, "YZY")
+                }
+                EulerRot::XYX => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 10u32, "XYX")
+                }
+                EulerRot::XZX => {
+                    serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 11u32, "XZX")
+                }
+                EulerRot::ZYXEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 12u32, "ZYXEx",
+                ),
+                EulerRot::ZXYEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 13u32, "ZXYEx",
+                ),
+                EulerRot::YXZEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 14u32, "YXZEx",
+                ),
+                EulerRot::YZXEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 15u32, "YZXEx",
+                ),
+                EulerRot::XYZEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 16u32, "XYZEx",
+                ),
+                EulerRot::XZYEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 17u32, "XZYEx",
+                ),
+                EulerRot::ZYZEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 18u32, "ZYZEx",
+                ),
+                EulerRot::ZXZEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 19u32, "ZXZEx",
+                ),
+                EulerRot::YXYEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 20u32, "YXYEx",
+                ),
+                EulerRot::YZYEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 21u32, "YZYEx",
+                ),
+                EulerRot::XYXEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 22u32, "XYXEx",
+                ),
+                EulerRot::XZXEx => serde::Serializer::serialize_unit_variant(
+                    serializer, "EulerRot", 23u32, "XZXEx",
+                ),
             }
         }
     }
@@ -1134,13 +1274,31 @@
                 YZX,
                 XYZ,
                 XZY,
+                ZYZ,
+                ZXZ,
+                YXY,
+                YZY,
+                XYX,
+                XZX,
+                ZYXEx,
+                ZXYEx,
+                YXZEx,
+                YZXEx,
+                XYZEx,
+                XZYEx,
+                ZYZEx,
+                ZXZEx,
+                YXYEx,
+                YZYEx,
+                XYXEx,
+                XZXEx,
             }
             struct FieldVisitor;
 
             impl<'de> serde::de::Visitor<'de> for FieldVisitor {
                 type Value = Field;
                 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-                    core::fmt::Formatter::write_str(formatter, "variant identifier")
+                    core::fmt::Formatter::write_str(formatter, "a variant identifier")
                 }
                 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
                 where
@@ -1153,9 +1311,28 @@
                         3u64 => Ok(Field::YZX),
                         4u64 => Ok(Field::XYZ),
                         5u64 => Ok(Field::XZY),
+                        6u64 => Ok(Field::ZYZ),
+                        7u64 => Ok(Field::ZXZ),
+                        8u64 => Ok(Field::YXY),
+                        9u64 => Ok(Field::YZY),
+                        10u64 => Ok(Field::XYX),
+                        11u64 => Ok(Field::XZX),
+
+                        12u64 => Ok(Field::ZYXEx),
+                        13u64 => Ok(Field::ZXYEx),
+                        14u64 => Ok(Field::YXZEx),
+                        15u64 => Ok(Field::YZXEx),
+                        16u64 => Ok(Field::XYZEx),
+                        17u64 => Ok(Field::XZYEx),
+                        18u64 => Ok(Field::ZYZEx),
+                        19u64 => Ok(Field::ZXZEx),
+                        20u64 => Ok(Field::YXYEx),
+                        21u64 => Ok(Field::YZYEx),
+                        22u64 => Ok(Field::XYXEx),
+                        23u64 => Ok(Field::XZXEx),
                         _ => Err(serde::de::Error::invalid_value(
                             serde::de::Unexpected::Unsigned(value),
-                            &"variant index 0 <= i < 6",
+                            &"variant index 0 <= i < 24",
                         )),
                     }
                 }
@@ -1170,6 +1347,24 @@
                         "YZX" => Ok(Field::YZX),
                         "XYZ" => Ok(Field::XYZ),
                         "XZY" => Ok(Field::XZY),
+                        "ZYZ" => Ok(Field::ZYZ),
+                        "ZXZ" => Ok(Field::ZXZ),
+                        "YXY" => Ok(Field::YXY),
+                        "YZY" => Ok(Field::YZY),
+                        "XYX" => Ok(Field::XYX),
+                        "XZX" => Ok(Field::XZX),
+                        "ZYXEx" => Ok(Field::ZYXEx),
+                        "ZXYEx" => Ok(Field::ZXYEx),
+                        "YXZEx" => Ok(Field::YXZEx),
+                        "YZXEx" => Ok(Field::YZXEx),
+                        "XYZEx" => Ok(Field::XYZEx),
+                        "XZYEx" => Ok(Field::XZYEx),
+                        "ZYZEx" => Ok(Field::ZYZEx),
+                        "ZXZEx" => Ok(Field::ZXZEx),
+                        "YXYEx" => Ok(Field::YXYEx),
+                        "YZYEx" => Ok(Field::YZYEx),
+                        "XYXEx" => Ok(Field::XYXEx),
+                        "XZXEx" => Ok(Field::XZXEx),
                         _ => Err(serde::de::Error::unknown_variant(value, VARIANTS)),
                     }
                 }
@@ -1184,6 +1379,24 @@
                         b"YZX" => Ok(Field::YZX),
                         b"XYZ" => Ok(Field::XYZ),
                         b"XZY" => Ok(Field::XZY),
+                        b"ZYZ" => Ok(Field::ZYZ),
+                        b"ZXZ" => Ok(Field::ZXZ),
+                        b"YXY" => Ok(Field::YXY),
+                        b"YZY" => Ok(Field::YZY),
+                        b"XYX" => Ok(Field::XYX),
+                        b"XZX" => Ok(Field::XZX),
+                        b"ZYXEx" => Ok(Field::ZYXEx),
+                        b"ZXYEx" => Ok(Field::ZXYEx),
+                        b"YXZEx" => Ok(Field::YXZEx),
+                        b"YZXEx" => Ok(Field::YZXEx),
+                        b"XYZEx" => Ok(Field::XYZEx),
+                        b"XZYEx" => Ok(Field::XZYEx),
+                        b"ZYZEx" => Ok(Field::ZYZEx),
+                        b"ZXZEx" => Ok(Field::ZXZEx),
+                        b"YXYEx" => Ok(Field::YXYEx),
+                        b"YZYEx" => Ok(Field::YZYEx),
+                        b"XYXEx" => Ok(Field::XYXEx),
+                        b"XZXEx" => Ok(Field::XZXEx),
                         _ => {
                             #[cfg(feature = "std")]
                             let value = &String::from_utf8_lossy(value);
@@ -1214,7 +1427,7 @@
                     &self,
                     __formatter: &mut core::fmt::Formatter<'_>,
                 ) -> core::fmt::Result {
-                    core::fmt::Formatter::write_str(__formatter, "enum EulerRot")
+                    core::fmt::Formatter::write_str(__formatter, "an EulerRot enum")
                 }
                 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
                 where
@@ -1245,10 +1458,87 @@
                             serde::de::VariantAccess::unit_variant(variant)?;
                             Ok(EulerRot::XZY)
                         }
+
+                        (Field::ZYZ, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZYZ)
+                        }
+                        (Field::ZXZ, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZXZ)
+                        }
+                        (Field::YXY, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YXY)
+                        }
+                        (Field::YZY, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YZY)
+                        }
+                        (Field::XYX, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XYX)
+                        }
+                        (Field::XZX, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XZX)
+                        }
+                        (Field::ZYXEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZYXEx)
+                        }
+                        (Field::ZXYEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZXYEx)
+                        }
+                        (Field::YXZEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YXZEx)
+                        }
+                        (Field::YZXEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YZXEx)
+                        }
+                        (Field::XYZEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XYZEx)
+                        }
+                        (Field::XZYEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XZYEx)
+                        }
+                        (Field::ZYZEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZYZEx)
+                        }
+                        (Field::ZXZEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::ZXZEx)
+                        }
+                        (Field::YXYEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YXYEx)
+                        }
+                        (Field::YZYEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::YZYEx)
+                        }
+                        (Field::XYXEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XYXEx)
+                        }
+                        (Field::XZXEx, variant) => {
+                            serde::de::VariantAccess::unit_variant(variant)?;
+                            Ok(EulerRot::XZXEx)
+                        }
                     }
                 }
             }
-            const VARIANTS: &[&str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"];
+            const VARIANTS: &[&str] = &[
+                "ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY", "ZYZ", "ZXZ", "YXY", "YZY", "XYX", "XZX",
+                "ZYXEx", "ZXYEx", "YXZEx", "YZXEx", "XYZEx", "XZYEx", "ZYZEx", "ZXZEx", "YXYEx",
+                "YZYEx", "XYXEx", "XZXEx",
+            ];
             serde::Deserializer::deserialize_enum(
                 deserializer,
                 "EulerRot",
@@ -1263,10 +1553,37 @@
 
     #[test]
     fn test_euler_rot_serde() {
-        let a = EulerRot::XYZ;
-        let serialized = serde_json::to_string(&a).unwrap();
-        assert_eq!("\"XYZ\"", serialized);
-        let deserialized = serde_json::from_str(&serialized).unwrap();
-        assert_eq!(a, deserialized);
+        const PAIRS: [(EulerRot, &str); 24] = [
+            (EulerRot::ZYX, "\"ZYX\""),
+            (EulerRot::ZXY, "\"ZXY\""),
+            (EulerRot::YXZ, "\"YXZ\""),
+            (EulerRot::YZX, "\"YZX\""),
+            (EulerRot::XYZ, "\"XYZ\""),
+            (EulerRot::XZY, "\"XZY\""),
+            (EulerRot::ZYZ, "\"ZYZ\""),
+            (EulerRot::ZXZ, "\"ZXZ\""),
+            (EulerRot::YXY, "\"YXY\""),
+            (EulerRot::YZY, "\"YZY\""),
+            (EulerRot::XYX, "\"XYX\""),
+            (EulerRot::XZX, "\"XZX\""),
+            (EulerRot::ZYXEx, "\"ZYXEx\""),
+            (EulerRot::ZXYEx, "\"ZXYEx\""),
+            (EulerRot::YXZEx, "\"YXZEx\""),
+            (EulerRot::YZXEx, "\"YZXEx\""),
+            (EulerRot::XYZEx, "\"XYZEx\""),
+            (EulerRot::XZYEx, "\"XZYEx\""),
+            (EulerRot::ZYZEx, "\"ZYZEx\""),
+            (EulerRot::ZXZEx, "\"ZXZEx\""),
+            (EulerRot::YXYEx, "\"YXYEx\""),
+            (EulerRot::YZYEx, "\"YZYEx\""),
+            (EulerRot::XYXEx, "\"XYXEx\""),
+            (EulerRot::XZXEx, "\"XZXEx\""),
+        ];
+        for (enum_value, enum_string) in PAIRS {
+            let serialized = serde_json::to_string(&enum_value).unwrap();
+            assert_eq!(enum_string, serialized);
+            let deserialized = serde_json::from_str(&serialized).unwrap();
+            assert_eq!(enum_value, deserialized);
+        }
     }
 }
diff --git a/crates/glam/src/float.rs b/crates/glam/src/float.rs
index 231b616..fdee810 100644
--- a/crates/glam/src/float.rs
+++ b/crates/glam/src/float.rs
@@ -1,9 +1,9 @@
 /// A trait for extending [`prim@f32`] and [`prim@f64`] with extra methods.
 pub trait FloatExt {
-    /// Performs a linear interpolation between `self` and `rhs` based on the value `t`.
+    /// Performs a linear interpolation between `self` and `rhs` based on the value `s`.
     ///
-    /// When `t` is `0`, the result will be `self`.  When `t` is `1`, the result
-    /// will be `rhs`. When `t` is outside of the range `[0, 1]`, the result is linearly
+    /// When `s` is `0`, the result will be `self`.  When `s` is `1`, the result
+    /// will be `rhs`. When `s` is outside of the range `[0, 1]`, the result is linearly
     /// extrapolated.
     #[must_use]
     fn lerp(self, rhs: Self, s: Self) -> Self;
diff --git a/crates/glam/src/i16/i16vec2.rs b/crates/glam/src/i16/i16vec2.rs
index 7f06c1c..dc6d6ad 100644
--- a/crates/glam/src/i16/i16vec2.rs
+++ b/crates/glam/src/i16/i16vec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec3, I64Vec2, IVec2, U16Vec2, U64Vec2, UVec2};
+use crate::{BVec2, I16Vec3, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -70,6 +69,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -106,6 +115,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i16]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -116,8 +126,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -127,6 +136,22 @@
         I16Vec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i16) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -197,6 +222,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i16 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i16 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -381,6 +424,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `u16`.
     #[inline]
     #[must_use]
@@ -511,6 +568,54 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U16Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U16Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U16Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U16Vec2) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+        }
+    }
 }
 
 impl Default for I16Vec2 {
@@ -531,6 +636,30 @@
     }
 }
 
+impl Div<&I16Vec2> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I16Vec2> for I16Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -539,6 +668,13 @@
     }
 }
 
+impl DivAssign<&Self> for I16Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i16> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -550,6 +686,30 @@
     }
 }
 
+impl Div<&i16> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: i16) -> I16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i16> for I16Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: i16) {
@@ -558,6 +718,13 @@
     }
 }
 
+impl DivAssign<&i16> for I16Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I16Vec2> for i16 {
     type Output = I16Vec2;
     #[inline]
@@ -569,6 +736,30 @@
     }
 }
 
+impl Div<&I16Vec2> for i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn div(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I16Vec2> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -580,6 +771,30 @@
     }
 }
 
+impl Mul<&I16Vec2> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I16Vec2> for I16Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -588,6 +803,13 @@
     }
 }
 
+impl MulAssign<&Self> for I16Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i16> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -599,6 +821,30 @@
     }
 }
 
+impl Mul<&i16> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: i16) -> I16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i16> for I16Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: i16) {
@@ -607,6 +853,13 @@
     }
 }
 
+impl MulAssign<&i16> for I16Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I16Vec2> for i16 {
     type Output = I16Vec2;
     #[inline]
@@ -618,6 +871,30 @@
     }
 }
 
+impl Mul<&I16Vec2> for i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn mul(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I16Vec2> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -629,6 +906,30 @@
     }
 }
 
+impl Add<&I16Vec2> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I16Vec2> for I16Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -637,6 +938,13 @@
     }
 }
 
+impl AddAssign<&Self> for I16Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i16> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -648,6 +956,30 @@
     }
 }
 
+impl Add<&i16> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: i16) -> I16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i16> for I16Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: i16) {
@@ -656,6 +988,13 @@
     }
 }
 
+impl AddAssign<&i16> for I16Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I16Vec2> for i16 {
     type Output = I16Vec2;
     #[inline]
@@ -667,6 +1006,30 @@
     }
 }
 
+impl Add<&I16Vec2> for i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn add(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I16Vec2> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -678,6 +1041,30 @@
     }
 }
 
+impl Sub<&I16Vec2> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I16Vec2> for I16Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: I16Vec2) {
@@ -686,6 +1073,13 @@
     }
 }
 
+impl SubAssign<&Self> for I16Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i16> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -697,6 +1091,30 @@
     }
 }
 
+impl Sub<&i16> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: i16) -> I16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i16> for I16Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: i16) {
@@ -705,6 +1123,13 @@
     }
 }
 
+impl SubAssign<&i16> for I16Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I16Vec2> for i16 {
     type Output = I16Vec2;
     #[inline]
@@ -716,6 +1141,30 @@
     }
 }
 
+impl Sub<&I16Vec2> for i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn sub(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I16Vec2> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -727,6 +1176,30 @@
     }
 }
 
+impl Rem<&I16Vec2> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec2> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I16Vec2> for I16Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -735,6 +1208,13 @@
     }
 }
 
+impl RemAssign<&Self> for I16Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i16> for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -746,6 +1226,30 @@
     }
 }
 
+impl Rem<&i16> for I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i16> for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: i16) -> I16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i16> for I16Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: i16) {
@@ -754,6 +1258,13 @@
     }
 }
 
+impl RemAssign<&i16> for I16Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I16Vec2> for i16 {
     type Output = I16Vec2;
     #[inline]
@@ -765,6 +1276,30 @@
     }
 }
 
+impl Rem<&I16Vec2> for i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &I16Vec2) -> I16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: &I16Vec2) -> I16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec2> for &i16 {
+    type Output = I16Vec2;
+    #[inline]
+    fn rem(self, rhs: I16Vec2) -> I16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i16; 2]> for I16Vec2 {
     #[inline]
@@ -832,6 +1367,14 @@
     }
 }
 
+impl Neg for &I16Vec2 {
+    type Output = I16Vec2;
+    #[inline]
+    fn neg(self) -> I16Vec2 {
+        (*self).neg()
+    }
+}
+
 impl Not for I16Vec2 {
     type Output = Self;
     #[inline]
@@ -1152,14 +1695,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I16Vec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I16Vec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I16Vec2))
@@ -1197,6 +1738,20 @@
     }
 }
 
+impl From<I8Vec2> for I16Vec2 {
+    #[inline]
+    fn from(v: I8Vec2) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y))
+    }
+}
+
+impl From<U8Vec2> for I16Vec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y))
+    }
+}
+
 impl TryFrom<U16Vec2> for I16Vec2 {
     type Error = core::num::TryFromIntError;
 
@@ -1241,3 +1796,10 @@
         Ok(Self::new(i16::try_from(v.x)?, i16::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for I16Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y))
+    }
+}
diff --git a/crates/glam/src/i16/i16vec3.rs b/crates/glam/src/i16/i16vec3.rs
index 5bdc6a7..0168311 100644
--- a/crates/glam/src/i16/i16vec3.rs
+++ b/crates/glam/src/i16/i16vec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec2, I16Vec4, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+use crate::{
+    BVec3, BVec3A, I16Vec2, I16Vec4, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -76,6 +77,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -113,6 +124,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i16]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -123,9 +135,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -157,6 +167,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i16) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i16) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -240,6 +274,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i16 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i16 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -410,6 +462,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `u16`.
     #[inline]
     #[must_use]
@@ -548,6 +614,58 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U16Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U16Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U16Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U16Vec3) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+        }
+    }
 }
 
 impl Default for I16Vec3 {
@@ -569,6 +687,30 @@
     }
 }
 
+impl Div<&I16Vec3> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I16Vec3> for I16Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -578,6 +720,13 @@
     }
 }
 
+impl DivAssign<&Self> for I16Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i16> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +739,30 @@
     }
 }
 
+impl Div<&i16> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: i16) -> I16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i16> for I16Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: i16) {
@@ -599,6 +772,13 @@
     }
 }
 
+impl DivAssign<&i16> for I16Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I16Vec3> for i16 {
     type Output = I16Vec3;
     #[inline]
@@ -611,6 +791,30 @@
     }
 }
 
+impl Div<&I16Vec3> for i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn div(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I16Vec3> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -623,6 +827,30 @@
     }
 }
 
+impl Mul<&I16Vec3> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I16Vec3> for I16Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -632,6 +860,13 @@
     }
 }
 
+impl MulAssign<&Self> for I16Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i16> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +879,30 @@
     }
 }
 
+impl Mul<&i16> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: i16) -> I16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i16> for I16Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: i16) {
@@ -653,6 +912,13 @@
     }
 }
 
+impl MulAssign<&i16> for I16Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I16Vec3> for i16 {
     type Output = I16Vec3;
     #[inline]
@@ -665,6 +931,30 @@
     }
 }
 
+impl Mul<&I16Vec3> for i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn mul(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I16Vec3> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -677,6 +967,30 @@
     }
 }
 
+impl Add<&I16Vec3> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I16Vec3> for I16Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -686,6 +1000,13 @@
     }
 }
 
+impl AddAssign<&Self> for I16Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i16> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1019,30 @@
     }
 }
 
+impl Add<&i16> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: i16) -> I16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i16> for I16Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: i16) {
@@ -707,6 +1052,13 @@
     }
 }
 
+impl AddAssign<&i16> for I16Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I16Vec3> for i16 {
     type Output = I16Vec3;
     #[inline]
@@ -719,6 +1071,30 @@
     }
 }
 
+impl Add<&I16Vec3> for i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn add(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I16Vec3> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -731,6 +1107,30 @@
     }
 }
 
+impl Sub<&I16Vec3> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I16Vec3> for I16Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: I16Vec3) {
@@ -740,6 +1140,13 @@
     }
 }
 
+impl SubAssign<&Self> for I16Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i16> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -752,6 +1159,30 @@
     }
 }
 
+impl Sub<&i16> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: i16) -> I16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i16> for I16Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: i16) {
@@ -761,6 +1192,13 @@
     }
 }
 
+impl SubAssign<&i16> for I16Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I16Vec3> for i16 {
     type Output = I16Vec3;
     #[inline]
@@ -773,6 +1211,30 @@
     }
 }
 
+impl Sub<&I16Vec3> for i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn sub(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I16Vec3> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -785,6 +1247,30 @@
     }
 }
 
+impl Rem<&I16Vec3> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec3> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I16Vec3> for I16Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -794,6 +1280,13 @@
     }
 }
 
+impl RemAssign<&Self> for I16Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i16> for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -806,6 +1299,30 @@
     }
 }
 
+impl Rem<&i16> for I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i16> for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: i16) -> I16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i16> for I16Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: i16) {
@@ -815,6 +1332,13 @@
     }
 }
 
+impl RemAssign<&i16> for I16Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I16Vec3> for i16 {
     type Output = I16Vec3;
     #[inline]
@@ -827,6 +1351,30 @@
     }
 }
 
+impl Rem<&I16Vec3> for i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &I16Vec3) -> I16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: &I16Vec3) -> I16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec3> for &i16 {
+    type Output = I16Vec3;
+    #[inline]
+    fn rem(self, rhs: I16Vec3) -> I16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i16; 3]> for I16Vec3 {
     #[inline]
@@ -895,6 +1443,14 @@
     }
 }
 
+impl Neg for &I16Vec3 {
+    type Output = I16Vec3;
+    #[inline]
+    fn neg(self) -> I16Vec3 {
+        (*self).neg()
+    }
+}
+
 impl Not for I16Vec3 {
     type Output = Self;
     #[inline]
@@ -1244,14 +1800,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I16Vec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I16Vec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I16Vec3))
@@ -1297,6 +1851,20 @@
     }
 }
 
+impl From<I8Vec3> for I16Vec3 {
+    #[inline]
+    fn from(v: I8Vec3) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y), i16::from(v.z))
+    }
+}
+
+impl From<U8Vec3> for I16Vec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y), i16::from(v.z))
+    }
+}
+
 impl TryFrom<U16Vec3> for I16Vec3 {
     type Error = core::num::TryFromIntError;
 
@@ -1361,3 +1929,22 @@
         ))
     }
 }
+
+impl From<BVec3> for I16Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(i16::from(v.x), i16::from(v.y), i16::from(v.z))
+    }
+}
+
+impl From<BVec3A> for I16Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            i16::from(bool_array[0]),
+            i16::from(bool_array[1]),
+            i16::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/i16/i16vec4.rs b/crates/glam/src/i16/i16vec4.rs
index 9db87cc..b82ef78 100644
--- a/crates/glam/src/i16/i16vec4.rs
+++ b/crates/glam/src/i16/i16vec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec2, I16Vec3, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec4};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec2, I16Vec3, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -92,6 +93,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -130,6 +141,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i16]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -140,10 +152,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -156,6 +165,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i16) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i16) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: i16) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -230,6 +271,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i16 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i16 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -428,6 +487,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `u16`.
     #[inline]
     #[must_use]
@@ -574,6 +647,62 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U16Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+            w: self.w.wrapping_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U16Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+            w: self.w.wrapping_sub_unsigned(rhs.w),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U16Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+            w: self.w.saturating_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U16Vec4) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+            w: self.w.saturating_sub_unsigned(rhs.w),
+        }
+    }
 }
 
 impl Default for I16Vec4 {
@@ -596,6 +725,30 @@
     }
 }
 
+impl Div<&I16Vec4> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I16Vec4> for I16Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -606,6 +759,13 @@
     }
 }
 
+impl DivAssign<&Self> for I16Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i16> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +779,30 @@
     }
 }
 
+impl Div<&i16> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &i16) -> I16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: i16) -> I16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i16> for I16Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: i16) {
@@ -629,6 +813,13 @@
     }
 }
 
+impl DivAssign<&i16> for I16Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I16Vec4> for i16 {
     type Output = I16Vec4;
     #[inline]
@@ -642,6 +833,30 @@
     }
 }
 
+impl Div<&I16Vec4> for i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn div(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I16Vec4> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -655,6 +870,30 @@
     }
 }
 
+impl Mul<&I16Vec4> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I16Vec4> for I16Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -665,6 +904,13 @@
     }
 }
 
+impl MulAssign<&Self> for I16Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i16> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +924,30 @@
     }
 }
 
+impl Mul<&i16> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &i16) -> I16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: i16) -> I16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i16> for I16Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: i16) {
@@ -688,6 +958,13 @@
     }
 }
 
+impl MulAssign<&i16> for I16Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I16Vec4> for i16 {
     type Output = I16Vec4;
     #[inline]
@@ -701,6 +978,30 @@
     }
 }
 
+impl Mul<&I16Vec4> for i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn mul(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I16Vec4> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -714,6 +1015,30 @@
     }
 }
 
+impl Add<&I16Vec4> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I16Vec4> for I16Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -724,6 +1049,13 @@
     }
 }
 
+impl AddAssign<&Self> for I16Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i16> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1069,30 @@
     }
 }
 
+impl Add<&i16> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &i16) -> I16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: i16) -> I16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i16> for I16Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: i16) {
@@ -747,6 +1103,13 @@
     }
 }
 
+impl AddAssign<&i16> for I16Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I16Vec4> for i16 {
     type Output = I16Vec4;
     #[inline]
@@ -760,6 +1123,30 @@
     }
 }
 
+impl Add<&I16Vec4> for i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn add(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I16Vec4> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -773,6 +1160,30 @@
     }
 }
 
+impl Sub<&I16Vec4> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I16Vec4> for I16Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: I16Vec4) {
@@ -783,6 +1194,13 @@
     }
 }
 
+impl SubAssign<&Self> for I16Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i16> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -796,6 +1214,30 @@
     }
 }
 
+impl Sub<&i16> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &i16) -> I16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: i16) -> I16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i16> for I16Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: i16) {
@@ -806,6 +1248,13 @@
     }
 }
 
+impl SubAssign<&i16> for I16Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I16Vec4> for i16 {
     type Output = I16Vec4;
     #[inline]
@@ -819,6 +1268,30 @@
     }
 }
 
+impl Sub<&I16Vec4> for i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn sub(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I16Vec4> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -832,6 +1305,30 @@
     }
 }
 
+impl Rem<&I16Vec4> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec4> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I16Vec4> for I16Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -842,6 +1339,13 @@
     }
 }
 
+impl RemAssign<&Self> for I16Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i16> for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -855,6 +1359,30 @@
     }
 }
 
+impl Rem<&i16> for I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &i16) -> I16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i16> for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: i16) -> I16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i16> for I16Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: i16) {
@@ -865,6 +1393,13 @@
     }
 }
 
+impl RemAssign<&i16> for I16Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I16Vec4> for i16 {
     type Output = I16Vec4;
     #[inline]
@@ -878,6 +1413,30 @@
     }
 }
 
+impl Rem<&I16Vec4> for i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &I16Vec4) -> I16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: &I16Vec4) -> I16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I16Vec4> for &i16 {
+    type Output = I16Vec4;
+    #[inline]
+    fn rem(self, rhs: I16Vec4) -> I16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i16; 4]> for I16Vec4 {
     #[inline]
@@ -947,6 +1506,14 @@
     }
 }
 
+impl Neg for &I16Vec4 {
+    type Output = I16Vec4;
+    #[inline]
+    fn neg(self) -> I16Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Not for I16Vec4 {
     type Output = Self;
     #[inline]
@@ -1325,14 +1892,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I16Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I16Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I16Vec4))
@@ -1400,6 +1965,30 @@
     }
 }
 
+impl From<I8Vec4> for I16Vec4 {
+    #[inline]
+    fn from(v: I8Vec4) -> Self {
+        Self::new(
+            i16::from(v.x),
+            i16::from(v.y),
+            i16::from(v.z),
+            i16::from(v.w),
+        )
+    }
+}
+
+impl From<U8Vec4> for I16Vec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            i16::from(v.x),
+            i16::from(v.y),
+            i16::from(v.z),
+            i16::from(v.w),
+        )
+    }
+}
+
 impl TryFrom<U16Vec4> for I16Vec4 {
     type Error = core::num::TryFromIntError;
 
@@ -1469,3 +2058,30 @@
         ))
     }
 }
+
+impl From<BVec4> for I16Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            i16::from(v.x),
+            i16::from(v.y),
+            i16::from(v.z),
+            i16::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for I16Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            i16::from(bool_array[0]),
+            i16::from(bool_array[1]),
+            i16::from(bool_array[2]),
+            i16::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/i32/ivec2.rs b/crates/glam/src/i32/ivec2.rs
index fdc4c81..f220d1d 100644
--- a/crates/glam/src/i32/ivec2.rs
+++ b/crates/glam/src/i32/ivec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec2, I64Vec2, IVec3, U16Vec2, U64Vec2, UVec2};
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec2, IVec3, U16Vec2, U64Vec2, U8Vec2, UVec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -70,6 +69,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -106,6 +115,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i32]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -116,8 +126,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -127,6 +136,22 @@
         IVec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i32) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -197,6 +222,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i32 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i32 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -381,6 +424,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -511,6 +568,54 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: UVec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: UVec2) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: UVec2) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: UVec2) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+        }
+    }
 }
 
 impl Default for IVec2 {
@@ -531,6 +636,30 @@
     }
 }
 
+impl Div<&IVec2> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &IVec2) -> IVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &IVec2) -> IVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: IVec2) -> IVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<IVec2> for IVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -539,6 +668,13 @@
     }
 }
 
+impl DivAssign<&Self> for IVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i32> for IVec2 {
     type Output = Self;
     #[inline]
@@ -550,6 +686,30 @@
     }
 }
 
+impl Div<&i32> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: i32) -> IVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i32> for IVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: i32) {
@@ -558,6 +718,13 @@
     }
 }
 
+impl DivAssign<&i32> for IVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<IVec2> for i32 {
     type Output = IVec2;
     #[inline]
@@ -569,6 +736,30 @@
     }
 }
 
+impl Div<&IVec2> for i32 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &IVec2) -> IVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: &IVec2) -> IVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn div(self, rhs: IVec2) -> IVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<IVec2> for IVec2 {
     type Output = Self;
     #[inline]
@@ -580,6 +771,30 @@
     }
 }
 
+impl Mul<&IVec2> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &IVec2) -> IVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &IVec2) -> IVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: IVec2) -> IVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<IVec2> for IVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -588,6 +803,13 @@
     }
 }
 
+impl MulAssign<&Self> for IVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i32> for IVec2 {
     type Output = Self;
     #[inline]
@@ -599,6 +821,30 @@
     }
 }
 
+impl Mul<&i32> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: i32) -> IVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i32> for IVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: i32) {
@@ -607,6 +853,13 @@
     }
 }
 
+impl MulAssign<&i32> for IVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<IVec2> for i32 {
     type Output = IVec2;
     #[inline]
@@ -618,6 +871,30 @@
     }
 }
 
+impl Mul<&IVec2> for i32 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &IVec2) -> IVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: &IVec2) -> IVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn mul(self, rhs: IVec2) -> IVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<IVec2> for IVec2 {
     type Output = Self;
     #[inline]
@@ -629,6 +906,30 @@
     }
 }
 
+impl Add<&IVec2> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &IVec2) -> IVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &IVec2) -> IVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: IVec2) -> IVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<IVec2> for IVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -637,6 +938,13 @@
     }
 }
 
+impl AddAssign<&Self> for IVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i32> for IVec2 {
     type Output = Self;
     #[inline]
@@ -648,6 +956,30 @@
     }
 }
 
+impl Add<&i32> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: i32) -> IVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i32> for IVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: i32) {
@@ -656,6 +988,13 @@
     }
 }
 
+impl AddAssign<&i32> for IVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<IVec2> for i32 {
     type Output = IVec2;
     #[inline]
@@ -667,6 +1006,30 @@
     }
 }
 
+impl Add<&IVec2> for i32 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &IVec2) -> IVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: &IVec2) -> IVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn add(self, rhs: IVec2) -> IVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<IVec2> for IVec2 {
     type Output = Self;
     #[inline]
@@ -678,6 +1041,30 @@
     }
 }
 
+impl Sub<&IVec2> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &IVec2) -> IVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &IVec2) -> IVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: IVec2) -> IVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<IVec2> for IVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: IVec2) {
@@ -686,6 +1073,13 @@
     }
 }
 
+impl SubAssign<&Self> for IVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i32> for IVec2 {
     type Output = Self;
     #[inline]
@@ -697,6 +1091,30 @@
     }
 }
 
+impl Sub<&i32> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: i32) -> IVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i32> for IVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: i32) {
@@ -705,6 +1123,13 @@
     }
 }
 
+impl SubAssign<&i32> for IVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<IVec2> for i32 {
     type Output = IVec2;
     #[inline]
@@ -716,6 +1141,30 @@
     }
 }
 
+impl Sub<&IVec2> for i32 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &IVec2) -> IVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: &IVec2) -> IVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn sub(self, rhs: IVec2) -> IVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<IVec2> for IVec2 {
     type Output = Self;
     #[inline]
@@ -727,6 +1176,30 @@
     }
 }
 
+impl Rem<&IVec2> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &IVec2) -> IVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &IVec2) -> IVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec2> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: IVec2) -> IVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<IVec2> for IVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -735,6 +1208,13 @@
     }
 }
 
+impl RemAssign<&Self> for IVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i32> for IVec2 {
     type Output = Self;
     #[inline]
@@ -746,6 +1226,30 @@
     }
 }
 
+impl Rem<&i32> for IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i32> for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: i32) -> IVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i32> for IVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: i32) {
@@ -754,6 +1258,13 @@
     }
 }
 
+impl RemAssign<&i32> for IVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<IVec2> for i32 {
     type Output = IVec2;
     #[inline]
@@ -765,6 +1276,30 @@
     }
 }
 
+impl Rem<&IVec2> for i32 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &IVec2) -> IVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: &IVec2) -> IVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec2> for &i32 {
+    type Output = IVec2;
+    #[inline]
+    fn rem(self, rhs: IVec2) -> IVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i32; 2]> for IVec2 {
     #[inline]
@@ -832,6 +1367,14 @@
     }
 }
 
+impl Neg for &IVec2 {
+    type Output = IVec2;
+    #[inline]
+    fn neg(self) -> IVec2 {
+        (*self).neg()
+    }
+}
+
 impl Not for IVec2 {
     type Output = Self;
     #[inline]
@@ -1152,14 +1695,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for IVec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for IVec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(IVec2))
@@ -1197,6 +1738,20 @@
     }
 }
 
+impl From<I8Vec2> for IVec2 {
+    #[inline]
+    fn from(v: I8Vec2) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y))
+    }
+}
+
+impl From<U8Vec2> for IVec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y))
+    }
+}
+
 impl From<I16Vec2> for IVec2 {
     #[inline]
     fn from(v: I16Vec2) -> Self {
@@ -1237,3 +1792,10 @@
         Ok(Self::new(i32::try_from(v.x)?, i32::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for IVec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y))
+    }
+}
diff --git a/crates/glam/src/i32/ivec3.rs b/crates/glam/src/i32/ivec3.rs
index 1a8425b..bc15b11 100644
--- a/crates/glam/src/i32/ivec3.rs
+++ b/crates/glam/src/i32/ivec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec3, I64Vec3, IVec2, IVec4, U16Vec3, U64Vec3, UVec3};
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec3, IVec2, IVec4, U16Vec3, U64Vec3, U8Vec3, UVec3,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -76,6 +77,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -113,6 +124,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -123,9 +135,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -157,6 +167,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -240,6 +274,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i32 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i32 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -410,6 +462,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -548,6 +614,58 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: UVec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: UVec3) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: UVec3) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: UVec3) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+        }
+    }
 }
 
 impl Default for IVec3 {
@@ -569,6 +687,30 @@
     }
 }
 
+impl Div<&IVec3> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &IVec3) -> IVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &IVec3) -> IVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: IVec3) -> IVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<IVec3> for IVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -578,6 +720,13 @@
     }
 }
 
+impl DivAssign<&Self> for IVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i32> for IVec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +739,30 @@
     }
 }
 
+impl Div<&i32> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: i32) -> IVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i32> for IVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: i32) {
@@ -599,6 +772,13 @@
     }
 }
 
+impl DivAssign<&i32> for IVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<IVec3> for i32 {
     type Output = IVec3;
     #[inline]
@@ -611,6 +791,30 @@
     }
 }
 
+impl Div<&IVec3> for i32 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &IVec3) -> IVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: &IVec3) -> IVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn div(self, rhs: IVec3) -> IVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<IVec3> for IVec3 {
     type Output = Self;
     #[inline]
@@ -623,6 +827,30 @@
     }
 }
 
+impl Mul<&IVec3> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &IVec3) -> IVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &IVec3) -> IVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: IVec3) -> IVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<IVec3> for IVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -632,6 +860,13 @@
     }
 }
 
+impl MulAssign<&Self> for IVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i32> for IVec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +879,30 @@
     }
 }
 
+impl Mul<&i32> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: i32) -> IVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i32> for IVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: i32) {
@@ -653,6 +912,13 @@
     }
 }
 
+impl MulAssign<&i32> for IVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<IVec3> for i32 {
     type Output = IVec3;
     #[inline]
@@ -665,6 +931,30 @@
     }
 }
 
+impl Mul<&IVec3> for i32 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &IVec3) -> IVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: &IVec3) -> IVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn mul(self, rhs: IVec3) -> IVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<IVec3> for IVec3 {
     type Output = Self;
     #[inline]
@@ -677,6 +967,30 @@
     }
 }
 
+impl Add<&IVec3> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &IVec3) -> IVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &IVec3) -> IVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: IVec3) -> IVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<IVec3> for IVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -686,6 +1000,13 @@
     }
 }
 
+impl AddAssign<&Self> for IVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i32> for IVec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1019,30 @@
     }
 }
 
+impl Add<&i32> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: i32) -> IVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i32> for IVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: i32) {
@@ -707,6 +1052,13 @@
     }
 }
 
+impl AddAssign<&i32> for IVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<IVec3> for i32 {
     type Output = IVec3;
     #[inline]
@@ -719,6 +1071,30 @@
     }
 }
 
+impl Add<&IVec3> for i32 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &IVec3) -> IVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: &IVec3) -> IVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn add(self, rhs: IVec3) -> IVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<IVec3> for IVec3 {
     type Output = Self;
     #[inline]
@@ -731,6 +1107,30 @@
     }
 }
 
+impl Sub<&IVec3> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &IVec3) -> IVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &IVec3) -> IVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: IVec3) -> IVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<IVec3> for IVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: IVec3) {
@@ -740,6 +1140,13 @@
     }
 }
 
+impl SubAssign<&Self> for IVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i32> for IVec3 {
     type Output = Self;
     #[inline]
@@ -752,6 +1159,30 @@
     }
 }
 
+impl Sub<&i32> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: i32) -> IVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i32> for IVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: i32) {
@@ -761,6 +1192,13 @@
     }
 }
 
+impl SubAssign<&i32> for IVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<IVec3> for i32 {
     type Output = IVec3;
     #[inline]
@@ -773,6 +1211,30 @@
     }
 }
 
+impl Sub<&IVec3> for i32 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &IVec3) -> IVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: &IVec3) -> IVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn sub(self, rhs: IVec3) -> IVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<IVec3> for IVec3 {
     type Output = Self;
     #[inline]
@@ -785,6 +1247,30 @@
     }
 }
 
+impl Rem<&IVec3> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &IVec3) -> IVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &IVec3) -> IVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec3> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: IVec3) -> IVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<IVec3> for IVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -794,6 +1280,13 @@
     }
 }
 
+impl RemAssign<&Self> for IVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i32> for IVec3 {
     type Output = Self;
     #[inline]
@@ -806,6 +1299,30 @@
     }
 }
 
+impl Rem<&i32> for IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i32> for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: i32) -> IVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i32> for IVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: i32) {
@@ -815,6 +1332,13 @@
     }
 }
 
+impl RemAssign<&i32> for IVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<IVec3> for i32 {
     type Output = IVec3;
     #[inline]
@@ -827,6 +1351,30 @@
     }
 }
 
+impl Rem<&IVec3> for i32 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &IVec3) -> IVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: &IVec3) -> IVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec3> for &i32 {
+    type Output = IVec3;
+    #[inline]
+    fn rem(self, rhs: IVec3) -> IVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i32; 3]> for IVec3 {
     #[inline]
@@ -895,6 +1443,14 @@
     }
 }
 
+impl Neg for &IVec3 {
+    type Output = IVec3;
+    #[inline]
+    fn neg(self) -> IVec3 {
+        (*self).neg()
+    }
+}
+
 impl Not for IVec3 {
     type Output = Self;
     #[inline]
@@ -1244,14 +1800,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for IVec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for IVec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(IVec3))
@@ -1297,6 +1851,20 @@
     }
 }
 
+impl From<I8Vec3> for IVec3 {
+    #[inline]
+    fn from(v: I8Vec3) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y), i32::from(v.z))
+    }
+}
+
+impl From<U8Vec3> for IVec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y), i32::from(v.z))
+    }
+}
+
 impl From<I16Vec3> for IVec3 {
     #[inline]
     fn from(v: I16Vec3) -> Self {
@@ -1349,3 +1917,22 @@
         ))
     }
 }
+
+impl From<BVec3> for IVec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(i32::from(v.x), i32::from(v.y), i32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for IVec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            i32::from(bool_array[0]),
+            i32::from(bool_array[1]),
+            i32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/i32/ivec4.rs b/crates/glam/src/i32/ivec4.rs
index 5ebdd69..eef4c8d 100644
--- a/crates/glam/src/i32/ivec4.rs
+++ b/crates/glam/src/i32/ivec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec4, I64Vec4, IVec2, IVec3, U16Vec4, U64Vec4, UVec4};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec4, IVec2, IVec3, U16Vec4, U64Vec4, U8Vec4, UVec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -92,6 +93,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -130,6 +141,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -140,10 +152,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -156,6 +165,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: i32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -230,6 +271,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i32 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i32 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -428,6 +487,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -574,6 +647,62 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: UVec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+            w: self.w.wrapping_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: UVec4) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+            w: self.w.wrapping_sub_unsigned(rhs.w),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: UVec4) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+            w: self.w.saturating_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: UVec4) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+            w: self.w.saturating_sub_unsigned(rhs.w),
+        }
+    }
 }
 
 impl Default for IVec4 {
@@ -596,6 +725,30 @@
     }
 }
 
+impl Div<&IVec4> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &IVec4) -> IVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &IVec4) -> IVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: IVec4) -> IVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<IVec4> for IVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -606,6 +759,13 @@
     }
 }
 
+impl DivAssign<&Self> for IVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i32> for IVec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +779,30 @@
     }
 }
 
+impl Div<&i32> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &i32) -> IVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: i32) -> IVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i32> for IVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: i32) {
@@ -629,6 +813,13 @@
     }
 }
 
+impl DivAssign<&i32> for IVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<IVec4> for i32 {
     type Output = IVec4;
     #[inline]
@@ -642,6 +833,30 @@
     }
 }
 
+impl Div<&IVec4> for i32 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &IVec4) -> IVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: &IVec4) -> IVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn div(self, rhs: IVec4) -> IVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<IVec4> for IVec4 {
     type Output = Self;
     #[inline]
@@ -655,6 +870,30 @@
     }
 }
 
+impl Mul<&IVec4> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &IVec4) -> IVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &IVec4) -> IVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: IVec4) -> IVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<IVec4> for IVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -665,6 +904,13 @@
     }
 }
 
+impl MulAssign<&Self> for IVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i32> for IVec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +924,30 @@
     }
 }
 
+impl Mul<&i32> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &i32) -> IVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: i32) -> IVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i32> for IVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: i32) {
@@ -688,6 +958,13 @@
     }
 }
 
+impl MulAssign<&i32> for IVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<IVec4> for i32 {
     type Output = IVec4;
     #[inline]
@@ -701,6 +978,30 @@
     }
 }
 
+impl Mul<&IVec4> for i32 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &IVec4) -> IVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: &IVec4) -> IVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn mul(self, rhs: IVec4) -> IVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<IVec4> for IVec4 {
     type Output = Self;
     #[inline]
@@ -714,6 +1015,30 @@
     }
 }
 
+impl Add<&IVec4> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &IVec4) -> IVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &IVec4) -> IVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: IVec4) -> IVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<IVec4> for IVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -724,6 +1049,13 @@
     }
 }
 
+impl AddAssign<&Self> for IVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i32> for IVec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1069,30 @@
     }
 }
 
+impl Add<&i32> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &i32) -> IVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: i32) -> IVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i32> for IVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: i32) {
@@ -747,6 +1103,13 @@
     }
 }
 
+impl AddAssign<&i32> for IVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<IVec4> for i32 {
     type Output = IVec4;
     #[inline]
@@ -760,6 +1123,30 @@
     }
 }
 
+impl Add<&IVec4> for i32 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &IVec4) -> IVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: &IVec4) -> IVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn add(self, rhs: IVec4) -> IVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<IVec4> for IVec4 {
     type Output = Self;
     #[inline]
@@ -773,6 +1160,30 @@
     }
 }
 
+impl Sub<&IVec4> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &IVec4) -> IVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &IVec4) -> IVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: IVec4) -> IVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<IVec4> for IVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: IVec4) {
@@ -783,6 +1194,13 @@
     }
 }
 
+impl SubAssign<&Self> for IVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i32> for IVec4 {
     type Output = Self;
     #[inline]
@@ -796,6 +1214,30 @@
     }
 }
 
+impl Sub<&i32> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &i32) -> IVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: i32) -> IVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i32> for IVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: i32) {
@@ -806,6 +1248,13 @@
     }
 }
 
+impl SubAssign<&i32> for IVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<IVec4> for i32 {
     type Output = IVec4;
     #[inline]
@@ -819,6 +1268,30 @@
     }
 }
 
+impl Sub<&IVec4> for i32 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &IVec4) -> IVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: &IVec4) -> IVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn sub(self, rhs: IVec4) -> IVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<IVec4> for IVec4 {
     type Output = Self;
     #[inline]
@@ -832,6 +1305,30 @@
     }
 }
 
+impl Rem<&IVec4> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &IVec4) -> IVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &IVec4) -> IVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec4> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: IVec4) -> IVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<IVec4> for IVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -842,6 +1339,13 @@
     }
 }
 
+impl RemAssign<&Self> for IVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i32> for IVec4 {
     type Output = Self;
     #[inline]
@@ -855,6 +1359,30 @@
     }
 }
 
+impl Rem<&i32> for IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &i32) -> IVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i32> for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: i32) -> IVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i32> for IVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: i32) {
@@ -865,6 +1393,13 @@
     }
 }
 
+impl RemAssign<&i32> for IVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<IVec4> for i32 {
     type Output = IVec4;
     #[inline]
@@ -878,6 +1413,30 @@
     }
 }
 
+impl Rem<&IVec4> for i32 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &IVec4) -> IVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: &IVec4) -> IVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<IVec4> for &i32 {
+    type Output = IVec4;
+    #[inline]
+    fn rem(self, rhs: IVec4) -> IVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i32; 4]> for IVec4 {
     #[inline]
@@ -947,6 +1506,14 @@
     }
 }
 
+impl Neg for &IVec4 {
+    type Output = IVec4;
+    #[inline]
+    fn neg(self) -> IVec4 {
+        (*self).neg()
+    }
+}
+
 impl Not for IVec4 {
     type Output = Self;
     #[inline]
@@ -1325,14 +1892,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for IVec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for IVec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(IVec4))
@@ -1400,6 +1965,30 @@
     }
 }
 
+impl From<I8Vec4> for IVec4 {
+    #[inline]
+    fn from(v: I8Vec4) -> Self {
+        Self::new(
+            i32::from(v.x),
+            i32::from(v.y),
+            i32::from(v.z),
+            i32::from(v.w),
+        )
+    }
+}
+
+impl From<U8Vec4> for IVec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            i32::from(v.x),
+            i32::from(v.y),
+            i32::from(v.z),
+            i32::from(v.w),
+        )
+    }
+}
+
 impl From<I16Vec4> for IVec4 {
     #[inline]
     fn from(v: I16Vec4) -> Self {
@@ -1465,3 +2054,30 @@
         ))
     }
 }
+
+impl From<BVec4> for IVec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            i32::from(v.x),
+            i32::from(v.y),
+            i32::from(v.z),
+            i32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for IVec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            i32::from(bool_array[0]),
+            i32::from(bool_array[1]),
+            i32::from(bool_array[2]),
+            i32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/i64/i64vec2.rs b/crates/glam/src/i64/i64vec2.rs
index b1355d1..0873aa3 100644
--- a/crates/glam/src/i64/i64vec2.rs
+++ b/crates/glam/src/i64/i64vec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec2, I64Vec3, IVec2, U16Vec2, U64Vec2, UVec2};
+use crate::{BVec2, I16Vec2, I64Vec3, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -70,6 +69,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -106,6 +115,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i64]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -116,8 +126,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -127,6 +136,22 @@
         I64Vec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i64) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -197,6 +222,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i64 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i64 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -381,6 +424,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -511,6 +568,54 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U64Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U64Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U64Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U64Vec2) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+        }
+    }
 }
 
 impl Default for I64Vec2 {
@@ -531,6 +636,30 @@
     }
 }
 
+impl Div<&I64Vec2> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I64Vec2> for I64Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -539,6 +668,13 @@
     }
 }
 
+impl DivAssign<&Self> for I64Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i64> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -550,6 +686,30 @@
     }
 }
 
+impl Div<&i64> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: i64) -> I64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i64> for I64Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: i64) {
@@ -558,6 +718,13 @@
     }
 }
 
+impl DivAssign<&i64> for I64Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I64Vec2> for i64 {
     type Output = I64Vec2;
     #[inline]
@@ -569,6 +736,30 @@
     }
 }
 
+impl Div<&I64Vec2> for i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn div(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I64Vec2> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -580,6 +771,30 @@
     }
 }
 
+impl Mul<&I64Vec2> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I64Vec2> for I64Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -588,6 +803,13 @@
     }
 }
 
+impl MulAssign<&Self> for I64Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i64> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -599,6 +821,30 @@
     }
 }
 
+impl Mul<&i64> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: i64) -> I64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i64> for I64Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: i64) {
@@ -607,6 +853,13 @@
     }
 }
 
+impl MulAssign<&i64> for I64Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I64Vec2> for i64 {
     type Output = I64Vec2;
     #[inline]
@@ -618,6 +871,30 @@
     }
 }
 
+impl Mul<&I64Vec2> for i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn mul(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I64Vec2> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -629,6 +906,30 @@
     }
 }
 
+impl Add<&I64Vec2> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I64Vec2> for I64Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -637,6 +938,13 @@
     }
 }
 
+impl AddAssign<&Self> for I64Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i64> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -648,6 +956,30 @@
     }
 }
 
+impl Add<&i64> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: i64) -> I64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i64> for I64Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: i64) {
@@ -656,6 +988,13 @@
     }
 }
 
+impl AddAssign<&i64> for I64Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I64Vec2> for i64 {
     type Output = I64Vec2;
     #[inline]
@@ -667,6 +1006,30 @@
     }
 }
 
+impl Add<&I64Vec2> for i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn add(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I64Vec2> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -678,6 +1041,30 @@
     }
 }
 
+impl Sub<&I64Vec2> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I64Vec2> for I64Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: I64Vec2) {
@@ -686,6 +1073,13 @@
     }
 }
 
+impl SubAssign<&Self> for I64Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i64> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -697,6 +1091,30 @@
     }
 }
 
+impl Sub<&i64> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: i64) -> I64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i64> for I64Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: i64) {
@@ -705,6 +1123,13 @@
     }
 }
 
+impl SubAssign<&i64> for I64Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I64Vec2> for i64 {
     type Output = I64Vec2;
     #[inline]
@@ -716,6 +1141,30 @@
     }
 }
 
+impl Sub<&I64Vec2> for i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn sub(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I64Vec2> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -727,6 +1176,30 @@
     }
 }
 
+impl Rem<&I64Vec2> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec2> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I64Vec2> for I64Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -735,6 +1208,13 @@
     }
 }
 
+impl RemAssign<&Self> for I64Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i64> for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -746,6 +1226,30 @@
     }
 }
 
+impl Rem<&i64> for I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i64> for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: i64) -> I64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i64> for I64Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: i64) {
@@ -754,6 +1258,13 @@
     }
 }
 
+impl RemAssign<&i64> for I64Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I64Vec2> for i64 {
     type Output = I64Vec2;
     #[inline]
@@ -765,6 +1276,30 @@
     }
 }
 
+impl Rem<&I64Vec2> for i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &I64Vec2) -> I64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: &I64Vec2) -> I64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec2> for &i64 {
+    type Output = I64Vec2;
+    #[inline]
+    fn rem(self, rhs: I64Vec2) -> I64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i64; 2]> for I64Vec2 {
     #[inline]
@@ -832,6 +1367,14 @@
     }
 }
 
+impl Neg for &I64Vec2 {
+    type Output = I64Vec2;
+    #[inline]
+    fn neg(self) -> I64Vec2 {
+        (*self).neg()
+    }
+}
+
 impl Not for I64Vec2 {
     type Output = Self;
     #[inline]
@@ -1152,14 +1695,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I64Vec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I64Vec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I64Vec2))
@@ -1197,6 +1738,20 @@
     }
 }
 
+impl From<I8Vec2> for I64Vec2 {
+    #[inline]
+    fn from(v: I8Vec2) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y))
+    }
+}
+
+impl From<U8Vec2> for I64Vec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y))
+    }
+}
+
 impl From<I16Vec2> for I64Vec2 {
     #[inline]
     fn from(v: I16Vec2) -> Self {
@@ -1233,3 +1788,10 @@
         Ok(Self::new(i64::try_from(v.x)?, i64::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for I64Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y))
+    }
+}
diff --git a/crates/glam/src/i64/i64vec3.rs b/crates/glam/src/i64/i64vec3.rs
index 336e817..5f42aee 100644
--- a/crates/glam/src/i64/i64vec3.rs
+++ b/crates/glam/src/i64/i64vec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec3, I64Vec2, I64Vec4, IVec3, U16Vec3, U64Vec3, UVec3};
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec2, I64Vec4, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -76,6 +77,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -113,6 +124,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i64]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -123,9 +135,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -157,6 +167,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i64) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -240,6 +274,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i64 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i64 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -410,6 +462,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -548,6 +614,58 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U64Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U64Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U64Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U64Vec3) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+        }
+    }
 }
 
 impl Default for I64Vec3 {
@@ -569,6 +687,30 @@
     }
 }
 
+impl Div<&I64Vec3> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I64Vec3> for I64Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -578,6 +720,13 @@
     }
 }
 
+impl DivAssign<&Self> for I64Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i64> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +739,30 @@
     }
 }
 
+impl Div<&i64> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: i64) -> I64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i64> for I64Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: i64) {
@@ -599,6 +772,13 @@
     }
 }
 
+impl DivAssign<&i64> for I64Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I64Vec3> for i64 {
     type Output = I64Vec3;
     #[inline]
@@ -611,6 +791,30 @@
     }
 }
 
+impl Div<&I64Vec3> for i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn div(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I64Vec3> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -623,6 +827,30 @@
     }
 }
 
+impl Mul<&I64Vec3> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I64Vec3> for I64Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -632,6 +860,13 @@
     }
 }
 
+impl MulAssign<&Self> for I64Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i64> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +879,30 @@
     }
 }
 
+impl Mul<&i64> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: i64) -> I64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i64> for I64Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: i64) {
@@ -653,6 +912,13 @@
     }
 }
 
+impl MulAssign<&i64> for I64Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I64Vec3> for i64 {
     type Output = I64Vec3;
     #[inline]
@@ -665,6 +931,30 @@
     }
 }
 
+impl Mul<&I64Vec3> for i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn mul(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I64Vec3> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -677,6 +967,30 @@
     }
 }
 
+impl Add<&I64Vec3> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I64Vec3> for I64Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -686,6 +1000,13 @@
     }
 }
 
+impl AddAssign<&Self> for I64Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i64> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1019,30 @@
     }
 }
 
+impl Add<&i64> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: i64) -> I64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i64> for I64Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: i64) {
@@ -707,6 +1052,13 @@
     }
 }
 
+impl AddAssign<&i64> for I64Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I64Vec3> for i64 {
     type Output = I64Vec3;
     #[inline]
@@ -719,6 +1071,30 @@
     }
 }
 
+impl Add<&I64Vec3> for i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn add(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I64Vec3> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -731,6 +1107,30 @@
     }
 }
 
+impl Sub<&I64Vec3> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I64Vec3> for I64Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: I64Vec3) {
@@ -740,6 +1140,13 @@
     }
 }
 
+impl SubAssign<&Self> for I64Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i64> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -752,6 +1159,30 @@
     }
 }
 
+impl Sub<&i64> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: i64) -> I64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i64> for I64Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: i64) {
@@ -761,6 +1192,13 @@
     }
 }
 
+impl SubAssign<&i64> for I64Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I64Vec3> for i64 {
     type Output = I64Vec3;
     #[inline]
@@ -773,6 +1211,30 @@
     }
 }
 
+impl Sub<&I64Vec3> for i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn sub(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I64Vec3> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -785,6 +1247,30 @@
     }
 }
 
+impl Rem<&I64Vec3> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec3> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I64Vec3> for I64Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -794,6 +1280,13 @@
     }
 }
 
+impl RemAssign<&Self> for I64Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i64> for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -806,6 +1299,30 @@
     }
 }
 
+impl Rem<&i64> for I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i64> for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: i64) -> I64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i64> for I64Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: i64) {
@@ -815,6 +1332,13 @@
     }
 }
 
+impl RemAssign<&i64> for I64Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I64Vec3> for i64 {
     type Output = I64Vec3;
     #[inline]
@@ -827,6 +1351,30 @@
     }
 }
 
+impl Rem<&I64Vec3> for i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &I64Vec3) -> I64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: &I64Vec3) -> I64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec3> for &i64 {
+    type Output = I64Vec3;
+    #[inline]
+    fn rem(self, rhs: I64Vec3) -> I64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i64; 3]> for I64Vec3 {
     #[inline]
@@ -895,6 +1443,14 @@
     }
 }
 
+impl Neg for &I64Vec3 {
+    type Output = I64Vec3;
+    #[inline]
+    fn neg(self) -> I64Vec3 {
+        (*self).neg()
+    }
+}
+
 impl Not for I64Vec3 {
     type Output = Self;
     #[inline]
@@ -1244,14 +1800,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I64Vec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I64Vec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I64Vec3))
@@ -1297,6 +1851,20 @@
     }
 }
 
+impl From<I8Vec3> for I64Vec3 {
+    #[inline]
+    fn from(v: I8Vec3) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y), i64::from(v.z))
+    }
+}
+
+impl From<U8Vec3> for I64Vec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y), i64::from(v.z))
+    }
+}
+
 impl From<I16Vec3> for I64Vec3 {
     #[inline]
     fn from(v: I16Vec3) -> Self {
@@ -1337,3 +1905,22 @@
         ))
     }
 }
+
+impl From<BVec3> for I64Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y), i64::from(v.z))
+    }
+}
+
+impl From<BVec3A> for I64Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            i64::from(bool_array[0]),
+            i64::from(bool_array[1]),
+            i64::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/i64/i64vec4.rs b/crates/glam/src/i64/i64vec4.rs
index bd4c0c1..667756a 100644
--- a/crates/glam/src/i64/i64vec4.rs
+++ b/crates/glam/src/i64/i64vec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec4, I64Vec2, I64Vec3, IVec4, U16Vec4, U64Vec4, UVec4};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec2, I64Vec3, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -92,6 +93,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -130,6 +141,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[i64]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -140,10 +152,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [i64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -156,6 +165,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i64) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: i64) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -230,6 +271,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i64 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i64 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -428,6 +487,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -574,6 +647,62 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U64Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+            w: self.w.wrapping_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U64Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+            w: self.w.wrapping_sub_unsigned(rhs.w),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U64Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+            w: self.w.saturating_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U64Vec4) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+            w: self.w.saturating_sub_unsigned(rhs.w),
+        }
+    }
 }
 
 impl Default for I64Vec4 {
@@ -596,6 +725,30 @@
     }
 }
 
+impl Div<&I64Vec4> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<I64Vec4> for I64Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -606,6 +759,13 @@
     }
 }
 
+impl DivAssign<&Self> for I64Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<i64> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +779,30 @@
     }
 }
 
+impl Div<&i64> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &i64) -> I64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: i64) -> I64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<i64> for I64Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: i64) {
@@ -629,6 +813,13 @@
     }
 }
 
+impl DivAssign<&i64> for I64Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<I64Vec4> for i64 {
     type Output = I64Vec4;
     #[inline]
@@ -642,6 +833,30 @@
     }
 }
 
+impl Div<&I64Vec4> for i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn div(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<I64Vec4> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -655,6 +870,30 @@
     }
 }
 
+impl Mul<&I64Vec4> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<I64Vec4> for I64Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -665,6 +904,13 @@
     }
 }
 
+impl MulAssign<&Self> for I64Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<i64> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +924,30 @@
     }
 }
 
+impl Mul<&i64> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &i64) -> I64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: i64) -> I64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<i64> for I64Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: i64) {
@@ -688,6 +958,13 @@
     }
 }
 
+impl MulAssign<&i64> for I64Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<I64Vec4> for i64 {
     type Output = I64Vec4;
     #[inline]
@@ -701,6 +978,30 @@
     }
 }
 
+impl Mul<&I64Vec4> for i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn mul(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<I64Vec4> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -714,6 +1015,30 @@
     }
 }
 
+impl Add<&I64Vec4> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<I64Vec4> for I64Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -724,6 +1049,13 @@
     }
 }
 
+impl AddAssign<&Self> for I64Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<i64> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1069,30 @@
     }
 }
 
+impl Add<&i64> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &i64) -> I64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: i64) -> I64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<i64> for I64Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: i64) {
@@ -747,6 +1103,13 @@
     }
 }
 
+impl AddAssign<&i64> for I64Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<I64Vec4> for i64 {
     type Output = I64Vec4;
     #[inline]
@@ -760,6 +1123,30 @@
     }
 }
 
+impl Add<&I64Vec4> for i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn add(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<I64Vec4> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -773,6 +1160,30 @@
     }
 }
 
+impl Sub<&I64Vec4> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<I64Vec4> for I64Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: I64Vec4) {
@@ -783,6 +1194,13 @@
     }
 }
 
+impl SubAssign<&Self> for I64Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<i64> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -796,6 +1214,30 @@
     }
 }
 
+impl Sub<&i64> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &i64) -> I64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: i64) -> I64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<i64> for I64Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: i64) {
@@ -806,6 +1248,13 @@
     }
 }
 
+impl SubAssign<&i64> for I64Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<I64Vec4> for i64 {
     type Output = I64Vec4;
     #[inline]
@@ -819,6 +1268,30 @@
     }
 }
 
+impl Sub<&I64Vec4> for i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn sub(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<I64Vec4> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -832,6 +1305,30 @@
     }
 }
 
+impl Rem<&I64Vec4> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec4> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<I64Vec4> for I64Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -842,6 +1339,13 @@
     }
 }
 
+impl RemAssign<&Self> for I64Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<i64> for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -855,6 +1359,30 @@
     }
 }
 
+impl Rem<&i64> for I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &i64) -> I64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i64> for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: i64) -> I64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<i64> for I64Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: i64) {
@@ -865,6 +1393,13 @@
     }
 }
 
+impl RemAssign<&i64> for I64Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<I64Vec4> for i64 {
     type Output = I64Vec4;
     #[inline]
@@ -878,6 +1413,30 @@
     }
 }
 
+impl Rem<&I64Vec4> for i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &I64Vec4) -> I64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: &I64Vec4) -> I64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I64Vec4> for &i64 {
+    type Output = I64Vec4;
+    #[inline]
+    fn rem(self, rhs: I64Vec4) -> I64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[i64; 4]> for I64Vec4 {
     #[inline]
@@ -947,6 +1506,14 @@
     }
 }
 
+impl Neg for &I64Vec4 {
+    type Output = I64Vec4;
+    #[inline]
+    fn neg(self) -> I64Vec4 {
+        (*self).neg()
+    }
+}
+
 impl Not for I64Vec4 {
     type Output = Self;
     #[inline]
@@ -1325,14 +1892,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for I64Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for I64Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(I64Vec4))
@@ -1400,6 +1965,30 @@
     }
 }
 
+impl From<I8Vec4> for I64Vec4 {
+    #[inline]
+    fn from(v: I8Vec4) -> Self {
+        Self::new(
+            i64::from(v.x),
+            i64::from(v.y),
+            i64::from(v.z),
+            i64::from(v.w),
+        )
+    }
+}
+
+impl From<U8Vec4> for I64Vec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            i64::from(v.x),
+            i64::from(v.y),
+            i64::from(v.z),
+            i64::from(v.w),
+        )
+    }
+}
+
 impl From<I16Vec4> for I64Vec4 {
     #[inline]
     fn from(v: I16Vec4) -> Self {
@@ -1461,3 +2050,30 @@
         ))
     }
 }
+
+impl From<BVec4> for I64Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            i64::from(v.x),
+            i64::from(v.y),
+            i64::from(v.z),
+            i64::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for I64Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            i64::from(bool_array[0]),
+            i64::from(bool_array[1]),
+            i64::from(bool_array[2]),
+            i64::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/i8.rs b/crates/glam/src/i8.rs
new file mode 100644
index 0000000..a070ecb
--- /dev/null
+++ b/crates/glam/src/i8.rs
@@ -0,0 +1,44 @@
+mod i8vec2;
+mod i8vec3;
+mod i8vec4;
+
+pub use i8vec2::{i8vec2, I8Vec2};
+pub use i8vec3::{i8vec3, I8Vec3};
+pub use i8vec4::{i8vec4, I8Vec4};
+
+#[cfg(not(target_arch = "spirv"))]
+mod test {
+    use super::*;
+
+    mod const_test_i8vec2 {
+        const_assert_eq!(2, core::mem::size_of::<super::I8Vec2>());
+
+        #[cfg(not(feature = "cuda"))]
+        const_assert_eq!(
+            core::mem::align_of::<i8>(),
+            core::mem::align_of::<super::I8Vec2>()
+        );
+        #[cfg(feature = "cuda")]
+        const_assert_eq!(2, core::mem::align_of::<super::I8Vec2>());
+    }
+
+    mod const_test_i8vec3 {
+        const_assert_eq!(
+            core::mem::align_of::<i8>(),
+            core::mem::align_of::<super::I8Vec3>()
+        );
+        const_assert_eq!(3, core::mem::size_of::<super::I8Vec3>());
+    }
+
+    mod const_test_i8vec4 {
+        const_assert_eq!(4, core::mem::size_of::<super::I8Vec4>());
+
+        #[cfg(not(feature = "cuda"))]
+        const_assert_eq!(
+            core::mem::align_of::<i8>(),
+            core::mem::align_of::<super::I8Vec4>()
+        );
+        #[cfg(feature = "cuda")]
+        const_assert_eq!(4, core::mem::align_of::<super::I8Vec4>());
+    }
+}
diff --git a/crates/glam/src/i8/i8vec2.rs b/crates/glam/src/i8/i8vec2.rs
new file mode 100644
index 0000000..ee75627
--- /dev/null
+++ b/crates/glam/src/i8/i8vec2.rs
@@ -0,0 +1,1809 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec3, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec2};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 2-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn i8vec2(x: i8, y: i8) -> I8Vec2 {
+    I8Vec2::new(x, y)
+}
+
+/// A 2-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "cuda", repr(align(2)))]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct I8Vec2 {
+    pub x: i8,
+    pub y: i8,
+}
+
+impl I8Vec2 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All negative ones.
+    pub const NEG_ONE: Self = Self::splat(-1);
+
+    /// All `i8::MIN`.
+    pub const MIN: Self = Self::splat(i8::MIN);
+
+    /// All `i8::MAX`.
+    pub const MAX: Self = Self::splat(i8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1);
+
+    /// A unit vector pointing along the negative X axis.
+    pub const NEG_X: Self = Self::new(-1, 0);
+
+    /// A unit vector pointing along the negative Y axis.
+    pub const NEG_Y: Self = Self::new(0, -1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 2] = [Self::X, Self::Y];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: i8, y: i8) -> Self {
+        Self { x, y }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: i8) -> Self {
+        Self { x: v, y: v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i8) -> i8,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [i8; 2]) -> Self {
+        Self::new(a[0], a[1])
+    }
+
+    /// `[x, y]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [i8; 2] {
+        [self.x, self.y]
+    }
+
+    /// Creates a vector from the first 2 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[i8]) -> Self {
+        assert!(slice.len() >= 2);
+        Self::new(slice[0], slice[1])
+    }
+
+    /// Writes the elements of `self` to the first 2 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [i8]) {
+        slice[..2].copy_from_slice(&self.to_array());
+    }
+
+    /// Creates a 3D vector from `self` and the given `z` value.
+    #[inline]
+    #[must_use]
+    pub const fn extend(self, z: i8) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, z)
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> i8 {
+        (self.x * rhs.x) + (self.y * rhs.y)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`i8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> i8 {
+        self.x.min(self.y)
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> i8 {
+        self.x.max(self.y)
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i8 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i8 {
+        self.x * self.y
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y))
+    }
+
+    /// Returns a vector containing the absolute value of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn abs(self) -> Self {
+        Self {
+            x: self.x.abs(),
+            y: self.y.abs(),
+        }
+    }
+
+    /// Returns a vector with elements representing the sign of `self`.
+    ///
+    ///  - `0` if the number is zero
+    ///  - `1` if the number is positive
+    ///  - `-1` if the number is negative
+    #[inline]
+    #[must_use]
+    pub fn signum(self) -> Self {
+        Self {
+            x: self.x.signum(),
+            y: self.y.signum(),
+        }
+    }
+
+    /// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
+    ///
+    /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn is_negative_bitmask(self) -> u32 {
+        (self.x.is_negative() as u32) | (self.y.is_negative() as u32) << 1
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> i8 {
+        self.dot(self)
+    }
+
+    /// Compute the squared euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance_squared(self, rhs: Self) -> i8 {
+        (self - rhs).length_squared()
+    }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    #[must_use]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.div_euclid(rhs.x), self.y.div_euclid(rhs.y))
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i8::rem_euclid
+    #[inline]
+    #[must_use]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y))
+    }
+
+    /// Returns a vector that is equal to `self` rotated by 90 degrees.
+    #[inline]
+    #[must_use]
+    pub fn perp(self) -> Self {
+        Self {
+            x: -self.y,
+            y: self.x,
+        }
+    }
+
+    /// The perpendicular dot product of `self` and `rhs`.
+    /// Also known as the wedge product, 2D cross product, and determinant.
+    #[doc(alias = "wedge")]
+    #[doc(alias = "cross")]
+    #[doc(alias = "determinant")]
+    #[inline]
+    #[must_use]
+    pub fn perp_dot(self, rhs: Self) -> i8 {
+        (self.x * rhs.y) - (self.y * rhs.x)
+    }
+
+    /// Returns `rhs` rotated by the angle of `self`. If `self` is normalized,
+    /// then this just rotation. This is what you usually want. Otherwise,
+    /// it will be like a rotation with a multiplication by `self`'s length.
+    #[inline]
+    #[must_use]
+    pub fn rotate(self, rhs: Self) -> Self {
+        Self {
+            x: self.x * rhs.x - self.y * rhs.y,
+            y: self.y * rhs.x + self.x * rhs.y,
+        }
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec2(&self) -> crate::Vec2 {
+        crate::Vec2::new(self.x as f32, self.y as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec2(&self) -> crate::DVec2 {
+        crate::DVec2::new(self.x as f64, self.y as f64)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec2(&self) -> crate::I16Vec2 {
+        crate::I16Vec2::new(self.x as i16, self.y as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec2(&self) -> crate::U16Vec2 {
+        crate::U16Vec2::new(self.x as u16, self.y as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec2(&self) -> crate::IVec2 {
+        crate::IVec2::new(self.x as i32, self.y as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec2(&self) -> crate::UVec2 {
+        crate::UVec2::new(self.x as u32, self.y as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec2(&self) -> crate::I64Vec2 {
+        crate::I64Vec2::new(self.x as i64, self.y as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec2(&self) -> crate::U64Vec2 {
+        crate::U64Vec2::new(self.x as u64, self.y as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U8Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U8Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U8Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U8Vec2) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+        }
+    }
+}
+
+impl Default for I8Vec2 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<I8Vec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+        }
+    }
+}
+
+impl Div<&I8Vec2> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<I8Vec2> for I8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+    }
+}
+
+impl DivAssign<&Self> for I8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+        }
+    }
+}
+
+impl Div<&i8> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: i8) -> I8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<i8> for I8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: i8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&i8> for I8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: I8Vec2) -> I8Vec2 {
+        I8Vec2 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+        }
+    }
+}
+
+impl Div<&I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn div(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<I8Vec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+        }
+    }
+}
+
+impl Mul<&I8Vec2> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<I8Vec2> for I8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+    }
+}
+
+impl MulAssign<&Self> for I8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&i8> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: i8) -> I8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<i8> for I8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: i8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&i8> for I8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: I8Vec2) -> I8Vec2 {
+        I8Vec2 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+        }
+    }
+}
+
+impl Mul<&I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn mul(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<I8Vec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+        }
+    }
+}
+
+impl Add<&I8Vec2> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<I8Vec2> for I8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+    }
+}
+
+impl AddAssign<&Self> for I8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+        }
+    }
+}
+
+impl Add<&i8> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: i8) -> I8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<i8> for I8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: i8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&i8> for I8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: I8Vec2) -> I8Vec2 {
+        I8Vec2 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+        }
+    }
+}
+
+impl Add<&I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn add(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<I8Vec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+        }
+    }
+}
+
+impl Sub<&I8Vec2> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<I8Vec2> for I8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: I8Vec2) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+    }
+}
+
+impl SubAssign<&Self> for I8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&i8> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: i8) -> I8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<i8> for I8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: i8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&i8> for I8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: I8Vec2) -> I8Vec2 {
+        I8Vec2 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+        }
+    }
+}
+
+impl Sub<&I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn sub(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<I8Vec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+        }
+    }
+}
+
+impl Rem<&I8Vec2> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec2> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<I8Vec2> for I8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+    }
+}
+
+impl RemAssign<&Self> for I8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&i8> for I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i8> for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: i8) -> I8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<i8> for I8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: i8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&i8> for I8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: I8Vec2) -> I8Vec2 {
+        I8Vec2 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+        }
+    }
+}
+
+impl Rem<&I8Vec2> for i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &I8Vec2) -> I8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: &I8Vec2) -> I8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec2> for &i8 {
+    type Output = I8Vec2;
+    #[inline]
+    fn rem(self, rhs: I8Vec2) -> I8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[i8; 2]> for I8Vec2 {
+    #[inline]
+    fn as_ref(&self) -> &[i8; 2] {
+        unsafe { &*(self as *const I8Vec2 as *const [i8; 2]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[i8; 2]> for I8Vec2 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [i8; 2] {
+        unsafe { &mut *(self as *mut I8Vec2 as *mut [i8; 2]) }
+    }
+}
+
+impl Sum for I8Vec2 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for I8Vec2 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for I8Vec2 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for I8Vec2 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Neg for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self {
+            x: self.x.neg(),
+            y: self.y.neg(),
+        }
+    }
+}
+
+impl Neg for &I8Vec2 {
+    type Output = I8Vec2;
+    #[inline]
+    fn neg(self) -> I8Vec2 {
+        (*self).neg()
+    }
+}
+
+impl Not for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+        }
+    }
+}
+
+impl BitAnd for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+        }
+    }
+}
+
+impl BitOr for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+        }
+    }
+}
+
+impl BitXor for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+        }
+    }
+}
+
+impl BitAnd<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec2) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+        }
+    }
+}
+
+impl Shr<crate::IVec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec2) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+        }
+    }
+}
+
+impl Shl<crate::UVec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec2) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+        }
+    }
+}
+
+impl Shr<crate::UVec2> for I8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec2) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+        }
+    }
+}
+
+impl Index<usize> for I8Vec2 {
+    type Output = i8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for I8Vec2 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for I8Vec2 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}]", self.x, self.y)
+    }
+}
+
+impl fmt::Debug for I8Vec2 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(I8Vec2))
+            .field(&self.x)
+            .field(&self.y)
+            .finish()
+    }
+}
+
+impl From<[i8; 2]> for I8Vec2 {
+    #[inline]
+    fn from(a: [i8; 2]) -> Self {
+        Self::new(a[0], a[1])
+    }
+}
+
+impl From<I8Vec2> for [i8; 2] {
+    #[inline]
+    fn from(v: I8Vec2) -> Self {
+        [v.x, v.y]
+    }
+}
+
+impl From<(i8, i8)> for I8Vec2 {
+    #[inline]
+    fn from(t: (i8, i8)) -> Self {
+        Self::new(t.0, t.1)
+    }
+}
+
+impl From<I8Vec2> for (i8, i8) {
+    #[inline]
+    fn from(v: I8Vec2) -> Self {
+        (v.x, v.y)
+    }
+}
+
+impl TryFrom<U8Vec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U8Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I16Vec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U16Vec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<IVec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<UVec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I64Vec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U64Vec2> for I8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i8::try_from(v.x)?, i8::try_from(v.y)?))
+    }
+}
+
+impl From<BVec2> for I8Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(i8::from(v.x), i8::from(v.y))
+    }
+}
diff --git a/crates/glam/src/i8/i8vec3.rs b/crates/glam/src/i8/i8vec3.rs
new file mode 100644
index 0000000..6609475
--- /dev/null
+++ b/crates/glam/src/i8/i8vec3.rs
@@ -0,0 +1,1962 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec2, I8Vec4, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 3-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn i8vec3(x: i8, y: i8, z: i8) -> I8Vec3 {
+    I8Vec3::new(x, y, z)
+}
+
+/// A 3-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct I8Vec3 {
+    pub x: i8,
+    pub y: i8,
+    pub z: i8,
+}
+
+impl I8Vec3 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All negative ones.
+    pub const NEG_ONE: Self = Self::splat(-1);
+
+    /// All `i8::MIN`.
+    pub const MIN: Self = Self::splat(i8::MIN);
+
+    /// All `i8::MAX`.
+    pub const MAX: Self = Self::splat(i8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1, 0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0, 0, 1);
+
+    /// A unit vector pointing along the negative X axis.
+    pub const NEG_X: Self = Self::new(-1, 0, 0);
+
+    /// A unit vector pointing along the negative Y axis.
+    pub const NEG_Y: Self = Self::new(0, -1, 0);
+
+    /// A unit vector pointing along the negative Z axis.
+    pub const NEG_Z: Self = Self::new(0, 0, -1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: i8, y: i8, z: i8) -> Self {
+        Self { x, y, z }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: i8) -> Self {
+        Self { x: v, y: v, z: v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i8) -> i8,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+            z: if mask.test(2) { if_true.z } else { if_false.z },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [i8; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
+    /// `[x, y, z]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [i8; 3] {
+        [self.x, self.y, self.z]
+    }
+
+    /// Creates a vector from the first 3 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[i8]) -> Self {
+        assert!(slice.len() >= 3);
+        Self::new(slice[0], slice[1], slice[2])
+    }
+
+    /// Writes the elements of `self` to the first 3 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [i8]) {
+        slice[..3].copy_from_slice(&self.to_array());
+    }
+
+    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
+    #[allow(dead_code)]
+    #[inline]
+    #[must_use]
+    pub(crate) fn from_vec4(v: I8Vec4) -> Self {
+        Self {
+            x: v.x,
+            y: v.y,
+            z: v.z,
+        }
+    }
+
+    /// Creates a 4D vector from `self` and the given `w` value.
+    #[inline]
+    #[must_use]
+    pub fn extend(self, w: i8) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, w)
+    }
+
+    /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`.
+    ///
+    /// Truncation may also be performed by using [`self.xy()`][crate::swizzles::Vec3Swizzles::xy()].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> I8Vec2 {
+        use crate::swizzles::Vec3Swizzles;
+        self.xy()
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i8) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> i8 {
+        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Computes the cross product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn cross(self, rhs: Self) -> Self {
+        Self {
+            x: self.y * rhs.z - rhs.y * self.z,
+            y: self.z * rhs.x - rhs.z * self.x,
+            z: self.x * rhs.y - rhs.x * self.y,
+        }
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+            z: self.z.min(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+            z: self.z.max(rhs.z),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`i8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> i8 {
+        self.x.min(self.y.min(self.z))
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> i8 {
+        self.x.max(self.y.max(self.z))
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i8 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i8 {
+        self.x * self.y * self.z
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z))
+    }
+
+    /// Returns a vector containing the absolute value of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn abs(self) -> Self {
+        Self {
+            x: self.x.abs(),
+            y: self.y.abs(),
+            z: self.z.abs(),
+        }
+    }
+
+    /// Returns a vector with elements representing the sign of `self`.
+    ///
+    ///  - `0` if the number is zero
+    ///  - `1` if the number is positive
+    ///  - `-1` if the number is negative
+    #[inline]
+    #[must_use]
+    pub fn signum(self) -> Self {
+        Self {
+            x: self.x.signum(),
+            y: self.y.signum(),
+            z: self.z.signum(),
+        }
+    }
+
+    /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
+    ///
+    /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn is_negative_bitmask(self) -> u32 {
+        (self.x.is_negative() as u32)
+            | (self.y.is_negative() as u32) << 1
+            | (self.z.is_negative() as u32) << 2
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> i8 {
+        self.dot(self)
+    }
+
+    /// Compute the squared euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance_squared(self, rhs: Self) -> i8 {
+        (self - rhs).length_squared()
+    }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    #[must_use]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i8::rem_euclid
+    #[inline]
+    #[must_use]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+        )
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec3(&self) -> crate::Vec3 {
+        crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32)
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec3a(&self) -> crate::Vec3A {
+        crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec3(&self) -> crate::DVec3 {
+        crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec3(&self) -> crate::I16Vec3 {
+        crate::I16Vec3::new(self.x as i16, self.y as i16, self.z as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec3(&self) -> crate::U16Vec3 {
+        crate::U16Vec3::new(self.x as u16, self.y as u16, self.z as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec3(&self) -> crate::IVec3 {
+        crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec3(&self) -> crate::UVec3 {
+        crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec3(&self) -> crate::I64Vec3 {
+        crate::I64Vec3::new(self.x as i64, self.y as i64, self.z as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec3(&self) -> crate::U64Vec3 {
+        crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+            z: self.z.wrapping_add(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+            z: self.z.wrapping_sub(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+            z: self.z.wrapping_mul(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+            z: self.z.wrapping_div(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+            z: self.z.saturating_add(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+            z: self.z.saturating_sub(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+            z: self.z.saturating_mul(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+            z: self.z.saturating_div(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U8Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U8Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U8Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U8Vec3) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+        }
+    }
+}
+
+impl Default for I8Vec3 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<I8Vec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+            z: self.z.div(rhs.z),
+        }
+    }
+}
+
+impl Div<&I8Vec3> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<I8Vec3> for I8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+        self.z.div_assign(rhs.z);
+    }
+}
+
+impl DivAssign<&Self> for I8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+            z: self.z.div(rhs),
+        }
+    }
+}
+
+impl Div<&i8> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: i8) -> I8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<i8> for I8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: i8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+        self.z.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&i8> for I8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: I8Vec3) -> I8Vec3 {
+        I8Vec3 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+            z: self.div(rhs.z),
+        }
+    }
+}
+
+impl Div<&I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn div(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<I8Vec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+            z: self.z.mul(rhs.z),
+        }
+    }
+}
+
+impl Mul<&I8Vec3> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<I8Vec3> for I8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+        self.z.mul_assign(rhs.z);
+    }
+}
+
+impl MulAssign<&Self> for I8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+            z: self.z.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&i8> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: i8) -> I8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<i8> for I8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: i8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+        self.z.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&i8> for I8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: I8Vec3) -> I8Vec3 {
+        I8Vec3 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+            z: self.mul(rhs.z),
+        }
+    }
+}
+
+impl Mul<&I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn mul(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<I8Vec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+            z: self.z.add(rhs.z),
+        }
+    }
+}
+
+impl Add<&I8Vec3> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<I8Vec3> for I8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+        self.z.add_assign(rhs.z);
+    }
+}
+
+impl AddAssign<&Self> for I8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+            z: self.z.add(rhs),
+        }
+    }
+}
+
+impl Add<&i8> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: i8) -> I8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<i8> for I8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: i8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+        self.z.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&i8> for I8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: I8Vec3) -> I8Vec3 {
+        I8Vec3 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+            z: self.add(rhs.z),
+        }
+    }
+}
+
+impl Add<&I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn add(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<I8Vec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+            z: self.z.sub(rhs.z),
+        }
+    }
+}
+
+impl Sub<&I8Vec3> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<I8Vec3> for I8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: I8Vec3) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+        self.z.sub_assign(rhs.z);
+    }
+}
+
+impl SubAssign<&Self> for I8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+            z: self.z.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&i8> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: i8) -> I8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<i8> for I8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: i8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+        self.z.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&i8> for I8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: I8Vec3) -> I8Vec3 {
+        I8Vec3 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+            z: self.sub(rhs.z),
+        }
+    }
+}
+
+impl Sub<&I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn sub(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<I8Vec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+            z: self.z.rem(rhs.z),
+        }
+    }
+}
+
+impl Rem<&I8Vec3> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec3> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<I8Vec3> for I8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+        self.z.rem_assign(rhs.z);
+    }
+}
+
+impl RemAssign<&Self> for I8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+            z: self.z.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&i8> for I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i8> for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: i8) -> I8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<i8> for I8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: i8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+        self.z.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&i8> for I8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: I8Vec3) -> I8Vec3 {
+        I8Vec3 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+            z: self.rem(rhs.z),
+        }
+    }
+}
+
+impl Rem<&I8Vec3> for i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &I8Vec3) -> I8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: &I8Vec3) -> I8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec3> for &i8 {
+    type Output = I8Vec3;
+    #[inline]
+    fn rem(self, rhs: I8Vec3) -> I8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[i8; 3]> for I8Vec3 {
+    #[inline]
+    fn as_ref(&self) -> &[i8; 3] {
+        unsafe { &*(self as *const I8Vec3 as *const [i8; 3]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[i8; 3]> for I8Vec3 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [i8; 3] {
+        unsafe { &mut *(self as *mut I8Vec3 as *mut [i8; 3]) }
+    }
+}
+
+impl Sum for I8Vec3 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for I8Vec3 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for I8Vec3 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for I8Vec3 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Neg for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self {
+            x: self.x.neg(),
+            y: self.y.neg(),
+            z: self.z.neg(),
+        }
+    }
+}
+
+impl Neg for &I8Vec3 {
+    type Output = I8Vec3;
+    #[inline]
+    fn neg(self) -> I8Vec3 {
+        (*self).neg()
+    }
+}
+
+impl Not for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+            z: self.z.not(),
+        }
+    }
+}
+
+impl BitAnd for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+            z: self.z.bitand(rhs.z),
+        }
+    }
+}
+
+impl BitOr for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+            z: self.z.bitor(rhs.z),
+        }
+    }
+}
+
+impl BitXor for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+            z: self.z.bitxor(rhs.z),
+        }
+    }
+}
+
+impl BitAnd<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+            z: self.z.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+            z: self.z.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+            z: self.z.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec3) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+        }
+    }
+}
+
+impl Shr<crate::IVec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec3) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+        }
+    }
+}
+
+impl Shl<crate::UVec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec3) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+        }
+    }
+}
+
+impl Shr<crate::UVec3> for I8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec3) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+        }
+    }
+}
+
+impl Index<usize> for I8Vec3 {
+    type Output = i8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for I8Vec3 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for I8Vec3 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+    }
+}
+
+impl fmt::Debug for I8Vec3 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(I8Vec3))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .finish()
+    }
+}
+
+impl From<[i8; 3]> for I8Vec3 {
+    #[inline]
+    fn from(a: [i8; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+}
+
+impl From<I8Vec3> for [i8; 3] {
+    #[inline]
+    fn from(v: I8Vec3) -> Self {
+        [v.x, v.y, v.z]
+    }
+}
+
+impl From<(i8, i8, i8)> for I8Vec3 {
+    #[inline]
+    fn from(t: (i8, i8, i8)) -> Self {
+        Self::new(t.0, t.1, t.2)
+    }
+}
+
+impl From<I8Vec3> for (i8, i8, i8) {
+    #[inline]
+    fn from(v: I8Vec3) -> Self {
+        (v.x, v.y, v.z)
+    }
+}
+
+impl From<(I8Vec2, i8)> for I8Vec3 {
+    #[inline]
+    fn from((v, z): (I8Vec2, i8)) -> Self {
+        Self::new(v.x, v.y, z)
+    }
+}
+
+impl TryFrom<U8Vec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U8Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I16Vec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U16Vec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<IVec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<UVec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec3> for I8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl From<BVec3> for I8Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(i8::from(v.x), i8::from(v.y), i8::from(v.z))
+    }
+}
+
+impl From<BVec3A> for I8Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            i8::from(bool_array[0]),
+            i8::from(bool_array[1]),
+            i8::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/i8/i8vec4.rs b/crates/glam/src/i8/i8vec4.rs
new file mode 100644
index 0000000..e1e797d
--- /dev/null
+++ b/crates/glam/src/i8/i8vec4.rs
@@ -0,0 +1,2086 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec2, I8Vec3, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec4};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 4-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn i8vec4(x: i8, y: i8, z: i8, w: i8) -> I8Vec4 {
+    I8Vec4::new(x, y, z, w)
+}
+
+/// A 4-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "cuda", repr(align(4)))]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct I8Vec4 {
+    pub x: i8,
+    pub y: i8,
+    pub z: i8,
+    pub w: i8,
+}
+
+impl I8Vec4 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All negative ones.
+    pub const NEG_ONE: Self = Self::splat(-1);
+
+    /// All `i8::MIN`.
+    pub const MIN: Self = Self::splat(i8::MIN);
+
+    /// All `i8::MAX`.
+    pub const MAX: Self = Self::splat(i8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0, 0, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1, 0, 0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0, 0, 1, 0);
+
+    /// A unit vector pointing along the positive W axis.
+    pub const W: Self = Self::new(0, 0, 0, 1);
+
+    /// A unit vector pointing along the negative X axis.
+    pub const NEG_X: Self = Self::new(-1, 0, 0, 0);
+
+    /// A unit vector pointing along the negative Y axis.
+    pub const NEG_Y: Self = Self::new(0, -1, 0, 0);
+
+    /// A unit vector pointing along the negative Z axis.
+    pub const NEG_Z: Self = Self::new(0, 0, -1, 0);
+
+    /// A unit vector pointing along the negative W axis.
+    pub const NEG_W: Self = Self::new(0, 0, 0, -1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: i8, y: i8, z: i8, w: i8) -> Self {
+        Self { x, y, z, w }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: i8) -> Self {
+        Self {
+            x: v,
+
+            y: v,
+
+            z: v,
+
+            w: v,
+        }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i8) -> i8,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+            z: if mask.test(2) { if_true.z } else { if_false.z },
+            w: if mask.test(3) { if_true.w } else { if_false.w },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [i8; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
+    /// `[x, y, z, w]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [i8; 4] {
+        [self.x, self.y, self.z, self.w]
+    }
+
+    /// Creates a vector from the first 4 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[i8]) -> Self {
+        assert!(slice.len() >= 4);
+        Self::new(slice[0], slice[1], slice[2], slice[3])
+    }
+
+    /// Writes the elements of `self` to the first 4 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [i8]) {
+        slice[..4].copy_from_slice(&self.to_array());
+    }
+
+    /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
+    ///
+    /// Truncation to [`I8Vec3`] may also be performed by using [`self.xyz()`][crate::swizzles::Vec4Swizzles::xyz()].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> I8Vec3 {
+        use crate::swizzles::Vec4Swizzles;
+        self.xyz()
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: i8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: i8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: i8) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: i8) -> Self {
+        self.w = w;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> i8 {
+        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+            z: self.z.min(rhs.z),
+            w: self.w.min(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+            z: self.z.max(rhs.z),
+            w: self.w.max(rhs.w),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`i8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> i8 {
+        self.x.min(self.y.min(self.z.min(self.w)))
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> i8 {
+        self.x.max(self.y.max(self.z.max(self.w)))
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> i8 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> i8 {
+        self.x * self.y * self.z * self.w
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.eq(&rhs.x),
+            self.y.eq(&rhs.y),
+            self.z.eq(&rhs.z),
+            self.w.eq(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.ne(&rhs.x),
+            self.y.ne(&rhs.y),
+            self.z.ne(&rhs.z),
+            self.w.ne(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.ge(&rhs.x),
+            self.y.ge(&rhs.y),
+            self.z.ge(&rhs.z),
+            self.w.ge(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.gt(&rhs.x),
+            self.y.gt(&rhs.y),
+            self.z.gt(&rhs.z),
+            self.w.gt(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.le(&rhs.x),
+            self.y.le(&rhs.y),
+            self.z.le(&rhs.z),
+            self.w.le(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.lt(&rhs.x),
+            self.y.lt(&rhs.y),
+            self.z.lt(&rhs.z),
+            self.w.lt(&rhs.w),
+        )
+    }
+
+    /// Returns a vector containing the absolute value of each element of `self`.
+    #[inline]
+    #[must_use]
+    pub fn abs(self) -> Self {
+        Self {
+            x: self.x.abs(),
+            y: self.y.abs(),
+            z: self.z.abs(),
+            w: self.w.abs(),
+        }
+    }
+
+    /// Returns a vector with elements representing the sign of `self`.
+    ///
+    ///  - `0` if the number is zero
+    ///  - `1` if the number is positive
+    ///  - `-1` if the number is negative
+    #[inline]
+    #[must_use]
+    pub fn signum(self) -> Self {
+        Self {
+            x: self.x.signum(),
+            y: self.y.signum(),
+            z: self.z.signum(),
+            w: self.w.signum(),
+        }
+    }
+
+    /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
+    ///
+    /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
+    /// into the first lowest bit, element `y` into the second, etc.
+    #[inline]
+    #[must_use]
+    pub fn is_negative_bitmask(self) -> u32 {
+        (self.x.is_negative() as u32)
+            | (self.y.is_negative() as u32) << 1
+            | (self.z.is_negative() as u32) << 2
+            | (self.w.is_negative() as u32) << 3
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> i8 {
+        self.dot(self)
+    }
+
+    /// Compute the squared euclidean distance between two points in space.
+    #[inline]
+    #[must_use]
+    pub fn distance_squared(self, rhs: Self) -> i8 {
+        (self - rhs).length_squared()
+    }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    #[must_use]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+            self.w.div_euclid(rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i8::rem_euclid
+    #[inline]
+    #[must_use]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+            self.w.rem_euclid(rhs.w),
+        )
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec4(&self) -> crate::Vec4 {
+        crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec4(&self) -> crate::DVec4 {
+        crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec4(&self) -> crate::I16Vec4 {
+        crate::I16Vec4::new(self.x as i16, self.y as i16, self.z as i16, self.w as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec4(&self) -> crate::U16Vec4 {
+        crate::U16Vec4::new(self.x as u16, self.y as u16, self.z as u16, self.w as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec4(&self) -> crate::IVec4 {
+        crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec4(&self) -> crate::UVec4 {
+        crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec4(&self) -> crate::I64Vec4 {
+        crate::I64Vec4::new(self.x as i64, self.y as i64, self.z as i64, self.w as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec4(&self) -> crate::U64Vec4 {
+        crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+            z: self.z.wrapping_add(rhs.z),
+            w: self.w.wrapping_add(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+            z: self.z.wrapping_sub(rhs.z),
+            w: self.w.wrapping_sub(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+            z: self.z.wrapping_mul(rhs.z),
+            w: self.w.wrapping_mul(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+            z: self.z.wrapping_div(rhs.z),
+            w: self.w.wrapping_div(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+            z: self.z.saturating_add(rhs.z),
+            w: self.w.saturating_add(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+            z: self.z.saturating_sub(rhs.z),
+            w: self.w.saturating_sub(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+            z: self.z.saturating_mul(rhs.z),
+            w: self.w.saturating_mul(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+            z: self.z.saturating_div(rhs.z),
+            w: self.w.saturating_div(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_unsigned(self, rhs: U8Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_unsigned(rhs.x),
+            y: self.y.wrapping_add_unsigned(rhs.y),
+            z: self.z.wrapping_add_unsigned(rhs.z),
+            w: self.w.wrapping_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub_unsigned(rhs.x), self.y.wrapping_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub_unsigned(self, rhs: U8Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_sub_unsigned(rhs.x),
+            y: self.y.wrapping_sub_unsigned(rhs.y),
+            z: self.z.wrapping_sub_unsigned(rhs.z),
+            w: self.w.wrapping_sub_unsigned(rhs.w),
+        }
+    }
+
+    // Returns a vector containing the saturating addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_unsigned(rhs.x), self.y.saturating_add_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_unsigned(self, rhs: U8Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_unsigned(rhs.x),
+            y: self.y.saturating_add_unsigned(rhs.y),
+            z: self.z.saturating_add_unsigned(rhs.z),
+            w: self.w.saturating_add_unsigned(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub_unsigned(rhs.x), self.y.saturating_sub_unsigned(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub_unsigned(self, rhs: U8Vec4) -> Self {
+        Self {
+            x: self.x.saturating_sub_unsigned(rhs.x),
+            y: self.y.saturating_sub_unsigned(rhs.y),
+            z: self.z.saturating_sub_unsigned(rhs.z),
+            w: self.w.saturating_sub_unsigned(rhs.w),
+        }
+    }
+}
+
+impl Default for I8Vec4 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<I8Vec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+            z: self.z.div(rhs.z),
+            w: self.w.div(rhs.w),
+        }
+    }
+}
+
+impl Div<&I8Vec4> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<I8Vec4> for I8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+        self.z.div_assign(rhs.z);
+        self.w.div_assign(rhs.w);
+    }
+}
+
+impl DivAssign<&Self> for I8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+            z: self.z.div(rhs),
+            w: self.w.div(rhs),
+        }
+    }
+}
+
+impl Div<&i8> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &i8) -> I8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: i8) -> I8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<i8> for I8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: i8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+        self.z.div_assign(rhs);
+        self.w.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&i8> for I8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &i8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: I8Vec4) -> I8Vec4 {
+        I8Vec4 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+            z: self.div(rhs.z),
+            w: self.div(rhs.w),
+        }
+    }
+}
+
+impl Div<&I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn div(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<I8Vec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+            z: self.z.mul(rhs.z),
+            w: self.w.mul(rhs.w),
+        }
+    }
+}
+
+impl Mul<&I8Vec4> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<I8Vec4> for I8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+        self.z.mul_assign(rhs.z);
+        self.w.mul_assign(rhs.w);
+    }
+}
+
+impl MulAssign<&Self> for I8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+            z: self.z.mul(rhs),
+            w: self.w.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&i8> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &i8) -> I8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: i8) -> I8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<i8> for I8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: i8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+        self.z.mul_assign(rhs);
+        self.w.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&i8> for I8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &i8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: I8Vec4) -> I8Vec4 {
+        I8Vec4 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+            z: self.mul(rhs.z),
+            w: self.mul(rhs.w),
+        }
+    }
+}
+
+impl Mul<&I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn mul(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<I8Vec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+            z: self.z.add(rhs.z),
+            w: self.w.add(rhs.w),
+        }
+    }
+}
+
+impl Add<&I8Vec4> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<I8Vec4> for I8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+        self.z.add_assign(rhs.z);
+        self.w.add_assign(rhs.w);
+    }
+}
+
+impl AddAssign<&Self> for I8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+            z: self.z.add(rhs),
+            w: self.w.add(rhs),
+        }
+    }
+}
+
+impl Add<&i8> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &i8) -> I8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: i8) -> I8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<i8> for I8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: i8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+        self.z.add_assign(rhs);
+        self.w.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&i8> for I8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &i8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: I8Vec4) -> I8Vec4 {
+        I8Vec4 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+            z: self.add(rhs.z),
+            w: self.add(rhs.w),
+        }
+    }
+}
+
+impl Add<&I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn add(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<I8Vec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+            z: self.z.sub(rhs.z),
+            w: self.w.sub(rhs.w),
+        }
+    }
+}
+
+impl Sub<&I8Vec4> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<I8Vec4> for I8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: I8Vec4) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+        self.z.sub_assign(rhs.z);
+        self.w.sub_assign(rhs.w);
+    }
+}
+
+impl SubAssign<&Self> for I8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+            z: self.z.sub(rhs),
+            w: self.w.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&i8> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &i8) -> I8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: i8) -> I8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<i8> for I8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: i8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+        self.z.sub_assign(rhs);
+        self.w.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&i8> for I8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &i8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: I8Vec4) -> I8Vec4 {
+        I8Vec4 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+            z: self.sub(rhs.z),
+            w: self.sub(rhs.w),
+        }
+    }
+}
+
+impl Sub<&I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn sub(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<I8Vec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+            z: self.z.rem(rhs.z),
+            w: self.w.rem(rhs.w),
+        }
+    }
+}
+
+impl Rem<&I8Vec4> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec4> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<I8Vec4> for I8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+        self.z.rem_assign(rhs.z);
+        self.w.rem_assign(rhs.w);
+    }
+}
+
+impl RemAssign<&Self> for I8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: i8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+            z: self.z.rem(rhs),
+            w: self.w.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&i8> for I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &i8) -> I8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<i8> for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: i8) -> I8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<i8> for I8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: i8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+        self.z.rem_assign(rhs);
+        self.w.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&i8> for I8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &i8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: I8Vec4) -> I8Vec4 {
+        I8Vec4 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+            z: self.rem(rhs.z),
+            w: self.rem(rhs.w),
+        }
+    }
+}
+
+impl Rem<&I8Vec4> for i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &I8Vec4) -> I8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: &I8Vec4) -> I8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<I8Vec4> for &i8 {
+    type Output = I8Vec4;
+    #[inline]
+    fn rem(self, rhs: I8Vec4) -> I8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[i8; 4]> for I8Vec4 {
+    #[inline]
+    fn as_ref(&self) -> &[i8; 4] {
+        unsafe { &*(self as *const I8Vec4 as *const [i8; 4]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[i8; 4]> for I8Vec4 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [i8; 4] {
+        unsafe { &mut *(self as *mut I8Vec4 as *mut [i8; 4]) }
+    }
+}
+
+impl Sum for I8Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for I8Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for I8Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for I8Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Neg for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self {
+            x: self.x.neg(),
+            y: self.y.neg(),
+            z: self.z.neg(),
+            w: self.w.neg(),
+        }
+    }
+}
+
+impl Neg for &I8Vec4 {
+    type Output = I8Vec4;
+    #[inline]
+    fn neg(self) -> I8Vec4 {
+        (*self).neg()
+    }
+}
+
+impl Not for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+            z: self.z.not(),
+            w: self.w.not(),
+        }
+    }
+}
+
+impl BitAnd for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+            z: self.z.bitand(rhs.z),
+            w: self.w.bitand(rhs.w),
+        }
+    }
+}
+
+impl BitOr for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+            z: self.z.bitor(rhs.z),
+            w: self.w.bitor(rhs.w),
+        }
+    }
+}
+
+impl BitXor for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+            z: self.z.bitxor(rhs.z),
+            w: self.w.bitxor(rhs.w),
+        }
+    }
+}
+
+impl BitAnd<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+            z: self.z.bitand(rhs),
+            w: self.w.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+            z: self.z.bitor(rhs),
+            w: self.w.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+            z: self.z.bitxor(rhs),
+            w: self.w.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec4) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+            w: self.w.shl(rhs.w),
+        }
+    }
+}
+
+impl Shr<crate::IVec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec4) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+            w: self.w.shr(rhs.w),
+        }
+    }
+}
+
+impl Shl<crate::UVec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec4) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+            w: self.w.shl(rhs.w),
+        }
+    }
+}
+
+impl Shr<crate::UVec4> for I8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec4) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+            w: self.w.shr(rhs.w),
+        }
+    }
+}
+
+impl Index<usize> for I8Vec4 {
+    type Output = i8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            3 => &self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for I8Vec4 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            3 => &mut self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for I8Vec4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    }
+}
+
+impl fmt::Debug for I8Vec4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(I8Vec4))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .field(&self.w)
+            .finish()
+    }
+}
+
+impl From<[i8; 4]> for I8Vec4 {
+    #[inline]
+    fn from(a: [i8; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+}
+
+impl From<I8Vec4> for [i8; 4] {
+    #[inline]
+    fn from(v: I8Vec4) -> Self {
+        [v.x, v.y, v.z, v.w]
+    }
+}
+
+impl From<(i8, i8, i8, i8)> for I8Vec4 {
+    #[inline]
+    fn from(t: (i8, i8, i8, i8)) -> Self {
+        Self::new(t.0, t.1, t.2, t.3)
+    }
+}
+
+impl From<I8Vec4> for (i8, i8, i8, i8) {
+    #[inline]
+    fn from(v: I8Vec4) -> Self {
+        (v.x, v.y, v.z, v.w)
+    }
+}
+
+impl From<(I8Vec3, i8)> for I8Vec4 {
+    #[inline]
+    fn from((v, w): (I8Vec3, i8)) -> Self {
+        Self::new(v.x, v.y, v.z, w)
+    }
+}
+
+impl From<(i8, I8Vec3)> for I8Vec4 {
+    #[inline]
+    fn from((x, v): (i8, I8Vec3)) -> Self {
+        Self::new(x, v.x, v.y, v.z)
+    }
+}
+
+impl From<(I8Vec2, i8, i8)> for I8Vec4 {
+    #[inline]
+    fn from((v, z, w): (I8Vec2, i8, i8)) -> Self {
+        Self::new(v.x, v.y, z, w)
+    }
+}
+
+impl From<(I8Vec2, I8Vec2)> for I8Vec4 {
+    #[inline]
+    fn from((v, u): (I8Vec2, I8Vec2)) -> Self {
+        Self::new(v.x, v.y, u.x, u.y)
+    }
+}
+
+impl TryFrom<U8Vec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U8Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I16Vec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U16Vec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<IVec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<UVec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec4> for I8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i8::try_from(v.x)?,
+            i8::try_from(v.y)?,
+            i8::try_from(v.z)?,
+            i8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl From<BVec4> for I8Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(i8::from(v.x), i8::from(v.y), i8::from(v.z), i8::from(v.w))
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for I8Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            i8::from(bool_array[0]),
+            i8::from(bool_array[1]),
+            i8::from(bool_array[2]),
+            i8::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/lib.rs b/crates/glam/src/lib.rs
index 1c466df..5d9cfb7 100644
--- a/crates/glam/src/lib.rs
+++ b/crates/glam/src/lib.rs
@@ -15,6 +15,10 @@
   * square matrices: [`DMat2`], [`DMat3`] and [`DMat4`]
   * a quaternion type: [`DQuat`]
   * affine transformation types: [`DAffine2`] and [`DAffine3`]
+* [`i8`](mod@i8) types
+  * vectors: [`I8Vec2`], [`I8Vec3`] and [`I8Vec4`]
+* [`u8`](mod@u8) types
+  * vectors: [`U8Vec2`], [`U8Vec3`] and [`U8Vec4`]
 * [`i16`](mod@i16) types
   * vectors: [`I16Vec2`], [`I16Vec3`] and [`I16Vec4`]
 * [`u16`](mod@u16) types
@@ -46,7 +50,7 @@
 math fallback implementations exist when SIMD is not available. It is intended to add support for
 other SIMD architectures once they appear in stable Rust.
 
-Currently only SSE2 on x86/x86_64 is supported as this is what stable Rust supports.
+Currently only SSE2 on x86/x86_64, NEON on Aarch64, and simd128 on WASM are supported.
 
 ## Vec3A and Mat3A
 
@@ -76,7 +80,8 @@
 let v4 = Vec4::new(1.0, 2.0, 3.0, 4.0);
 
 // Convert from `Vec4` to `Vec3A`, this is a no-op if SIMD is supported.
-let v3a = Vec3A::from(v4);
+// We use an explicit method here instead of a From impl as data is lost in the conversion.
+let v3a = Vec3A::from_vec4(v4);
 assert_eq!(Vec3A::new(1.0, 2.0, 3.0), v3a);
 
 // Convert from `Vec3A` to `Vec3`.
@@ -187,7 +192,7 @@
 // To swizzle a `Vec4` into a `Vec3A` swizzle the `Vec4` first then convert to
 // `Vec3A`. If SIMD is supported this will use a vector shuffle. The last
 // element of the shuffled `Vec4` is ignored by the `Vec3A`.
-let yzw = Vec3A::from(v.yzwx());
+let yzw = Vec3A::from_vec4(v.yzwx());
 assert_eq!(Vec3A::new(2.0, 3.0, 4.0), yzw);
 
 // You can swizzle from a `Vec4` to a `Vec2`
@@ -248,10 +253,10 @@
 
 ## Minimum Supported Rust Version (MSRV)
 
-The minimum supported Rust version is `1.58.1`.
+The minimum supported Rust version is `1.68.2`.
 
 */
-#![doc(html_root_url = "https://docs.rs/glam/0.25.0")]
+#![doc(html_root_url = "https://docs.rs/glam/0.29.2")]
 #![cfg_attr(not(feature = "std"), no_std)]
 #![cfg_attr(target_arch = "spirv", feature(repr_simd))]
 #![deny(
@@ -275,6 +280,12 @@
 mod euler;
 mod features;
 
+#[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+mod neon;
+
 #[cfg(target_arch = "spirv")]
 mod spirv;
 
@@ -311,6 +322,14 @@
 pub mod f64;
 pub use self::f64::*;
 
+/** `i8` vector types. */
+pub mod i8;
+pub use self::i8::*;
+
+/** `u8` vector types. */
+pub mod u8;
+pub use self::u8::*;
+
 /** `i16` vector types. */
 pub mod i16;
 pub use self::i16::*;
diff --git a/crates/glam/src/neon.rs b/crates/glam/src/neon.rs
new file mode 100644
index 0000000..55afe43
--- /dev/null
+++ b/crates/glam/src/neon.rs
@@ -0,0 +1,51 @@
+use core::arch::aarch64::*;
+
+union UnionCast {
+    // u32x4: [u32; 4],
+    f32x4: [f32; 4],
+    v: float32x4_t,
+}
+
+#[inline]
+pub const fn f32x4_from_array(f32x4: [f32; 4]) -> float32x4_t {
+    unsafe { UnionCast { f32x4 }.v }
+}
+
+// #[inline]
+// pub(crate) unsafe fn dot3_in_x(lhs: float32x4_t, rhs: float32x4_t) -> float32x4_t {
+//     let x2_y2_z2_w2 = vmulq_f32(lhs, rhs);
+//     let y2 = vdupq_laneq_f32(x2_y2_z2_w2, 1);
+//     let z2 = vdupq_laneq_f32(x2_y2_z2_w2, 2);
+//     let x2y2 = vaddq_f32(x2_y2_z2_w2, y2);
+//     vaddq_f32(x2y2, z2)
+// }
+
+#[inline]
+pub(crate) unsafe fn dot3(lhs: float32x4_t, rhs: float32x4_t) -> f32 {
+    let x2_y2_z2_w2 = vmulq_f32(lhs, rhs);
+    let x2_y2_z2 = vsetq_lane_f32(0.0, x2_y2_z2_w2, 3);
+    vaddvq_f32(x2_y2_z2)
+    // let dot = dot3_in_x(lhs, rhs);
+    // vdups_laneq_f32(dot, 0)
+}
+
+#[inline]
+pub(crate) unsafe fn dot3_into_f32x4(lhs: float32x4_t, rhs: float32x4_t) -> float32x4_t {
+    let dot = dot3(lhs, rhs);
+    vld1q_dup_f32(&dot as *const f32)
+    // let dot = dot3_in_x(lhs, rhs);
+    // vdupq_laneq_f32(dot, 0)
+}
+
+#[inline]
+pub(crate) unsafe fn dot4(lhs: float32x4_t, rhs: float32x4_t) -> f32 {
+    let x2_y2_z2_w2 = vmulq_f32(lhs, rhs);
+    // TODO: horizontal add - might perform bad?
+    vaddvq_f32(x2_y2_z2_w2)
+}
+
+#[inline]
+pub(crate) unsafe fn dot4_into_f32x4(lhs: float32x4_t, rhs: float32x4_t) -> float32x4_t {
+    let dot = dot4(lhs, rhs);
+    vld1q_dup_f32(&dot as *const f32)
+}
diff --git a/crates/glam/src/swizzles.rs b/crates/glam/src/swizzles.rs
index 683a574..f295db7 100644
--- a/crates/glam/src/swizzles.rs
+++ b/crates/glam/src/swizzles.rs
@@ -6,6 +6,14 @@
 mod ivec3_impl;
 mod ivec4_impl;
 
+mod i8vec2_impl;
+mod i8vec3_impl;
+mod i8vec4_impl;
+
+mod u8vec2_impl;
+mod u8vec3_impl;
+mod u8vec4_impl;
+
 mod i16vec2_impl;
 mod i16vec3_impl;
 mod i16vec4_impl;
@@ -32,6 +40,7 @@
 #[cfg(any(
     not(any(
         feature = "core-simd",
+        target_arch = "aarch64",
         target_feature = "sse2",
         target_feature = "simd128"
     )),
@@ -40,6 +49,12 @@
 mod scalar;
 
 #[cfg(all(
+    target_arch = "aarch64",
+    not(any(feature = "core-simd", feature = "scalar-math"))
+))]
+mod neon;
+
+#[cfg(all(
     target_feature = "sse2",
     not(any(feature = "core-simd", feature = "scalar-math"))
 ))]
diff --git a/crates/glam/src/swizzles/coresimd/vec3a_impl.rs b/crates/glam/src/swizzles/coresimd/vec3a_impl.rs
index 36cb9ae..c9cc420 100644
--- a/crates/glam/src/swizzles/coresimd/vec3a_impl.rs
+++ b/crates/glam/src/swizzles/coresimd/vec3a_impl.rs
@@ -124,12 +124,6 @@
 
     #[inline]
     #[must_use]
-    fn xyz(self) -> Vec3A {
-        Vec3A(simd_swizzle!(self.0, [0, 1, 2, 0]).into())
-    }
-
-    #[inline]
-    #[must_use]
     fn xzx(self) -> Vec3A {
         Vec3A(simd_swizzle!(self.0, [0, 2, 0, 0]).into())
     }
diff --git a/crates/glam/src/swizzles/coresimd/vec4_impl.rs b/crates/glam/src/swizzles/coresimd/vec4_impl.rs
index 19eba73..57cd39c 100644
--- a/crates/glam/src/swizzles/coresimd/vec4_impl.rs
+++ b/crates/glam/src/swizzles/coresimd/vec4_impl.rs
@@ -158,641 +158,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -959,12 +703,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> Vec4 {
-        Vec4(simd_swizzle!(self.0, [0, 1, 2, 3]))
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> Vec4 {
         Vec4(simd_swizzle!(self.0, [0, 1, 3, 0]))
     }
diff --git a/crates/glam/src/swizzles/dvec2_impl.rs b/crates/glam/src/swizzles/dvec2_impl.rs
index f8c4748..14bbc4a 100644
--- a/crates/glam/src/swizzles/dvec2_impl.rs
+++ b/crates/glam/src/swizzles/dvec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> DVec2 {
-        DVec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> DVec2 {
         DVec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/dvec3_impl.rs b/crates/glam/src/swizzles/dvec3_impl.rs
index 235ae54..97751a8 100644
--- a/crates/glam/src/swizzles/dvec3_impl.rs
+++ b/crates/glam/src/swizzles/dvec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/dvec4_impl.rs b/crates/glam/src/swizzles/dvec4_impl.rs
index 8e23f97..95406f0 100644
--- a/crates/glam/src/swizzles/dvec4_impl.rs
+++ b/crates/glam/src/swizzles/dvec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        DVec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        DVec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        DVec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        DVec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        DVec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        DVec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> DVec3 {
-        DVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        DVec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        DVec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        DVec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        DVec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        DVec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        DVec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        DVec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> DVec3 {
-        DVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        DVec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        DVec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        DVec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        DVec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        DVec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        DVec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        DVec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> DVec3 {
-        DVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        DVec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        DVec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        DVec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        DVec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        DVec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        DVec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        DVec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        DVec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        DVec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        DVec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        DVec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        DVec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        DVec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        DVec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        DVec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        DVec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> DVec3 {
-        DVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        DVec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> DVec4 {
-        DVec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> DVec4 {
         DVec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/i16vec2_impl.rs b/crates/glam/src/swizzles/i16vec2_impl.rs
index 23445e5..ac1b7ce 100644
--- a/crates/glam/src/swizzles/i16vec2_impl.rs
+++ b/crates/glam/src/swizzles/i16vec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> I16Vec2 {
-        I16Vec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> I16Vec2 {
         I16Vec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/i16vec3_impl.rs b/crates/glam/src/swizzles/i16vec3_impl.rs
index 9d33df0..8435637 100644
--- a/crates/glam/src/swizzles/i16vec3_impl.rs
+++ b/crates/glam/src/swizzles/i16vec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/i16vec4_impl.rs b/crates/glam/src/swizzles/i16vec4_impl.rs
index 6bf4246..8687c94 100644
--- a/crates/glam/src/swizzles/i16vec4_impl.rs
+++ b/crates/glam/src/swizzles/i16vec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        I16Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        I16Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        I16Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        I16Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        I16Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        I16Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        I16Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        I16Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        I16Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        I16Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        I16Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        I16Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        I16Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        I16Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        I16Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        I16Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        I16Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        I16Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        I16Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        I16Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        I16Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        I16Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        I16Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        I16Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        I16Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        I16Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        I16Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        I16Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        I16Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        I16Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        I16Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        I16Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        I16Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        I16Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        I16Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        I16Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> I16Vec3 {
-        I16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        I16Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> I16Vec4 {
-        I16Vec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> I16Vec4 {
         I16Vec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/i64vec2_impl.rs b/crates/glam/src/swizzles/i64vec2_impl.rs
index 99c3e19..12f3822 100644
--- a/crates/glam/src/swizzles/i64vec2_impl.rs
+++ b/crates/glam/src/swizzles/i64vec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> I64Vec2 {
-        I64Vec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> I64Vec2 {
         I64Vec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/i64vec3_impl.rs b/crates/glam/src/swizzles/i64vec3_impl.rs
index 30d8ccc..c4cbc3b 100644
--- a/crates/glam/src/swizzles/i64vec3_impl.rs
+++ b/crates/glam/src/swizzles/i64vec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/i64vec4_impl.rs b/crates/glam/src/swizzles/i64vec4_impl.rs
index 8dcbca9..a2f6141 100644
--- a/crates/glam/src/swizzles/i64vec4_impl.rs
+++ b/crates/glam/src/swizzles/i64vec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        I64Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        I64Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        I64Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        I64Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        I64Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        I64Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        I64Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        I64Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        I64Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        I64Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        I64Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        I64Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        I64Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        I64Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        I64Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        I64Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        I64Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        I64Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        I64Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        I64Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        I64Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        I64Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        I64Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        I64Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        I64Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        I64Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        I64Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        I64Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        I64Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        I64Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        I64Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        I64Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        I64Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        I64Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        I64Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        I64Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> I64Vec3 {
-        I64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        I64Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> I64Vec4 {
-        I64Vec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> I64Vec4 {
         I64Vec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/i8vec2_impl.rs b/crates/glam/src/swizzles/i8vec2_impl.rs
new file mode 100644
index 0000000..8f8013f
--- /dev/null
+++ b/crates/glam/src/swizzles/i8vec2_impl.rs
@@ -0,0 +1,180 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{I8Vec2, I8Vec3, I8Vec4, Vec2Swizzles};
+
+impl Vec2Swizzles for I8Vec2 {
+    type Vec3 = I8Vec3;
+
+    type Vec4 = I8Vec4;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+}
diff --git a/crates/glam/src/swizzles/i8vec3_impl.rs b/crates/glam/src/swizzles/i8vec3_impl.rs
new file mode 100644
index 0000000..40a75a2
--- /dev/null
+++ b/crates/glam/src/swizzles/i8vec3_impl.rs
@@ -0,0 +1,732 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{I8Vec2, I8Vec3, I8Vec4, Vec3Swizzles};
+
+impl Vec3Swizzles for I8Vec3 {
+    type Vec2 = I8Vec2;
+
+    type Vec4 = I8Vec4;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.z)
+    }
+}
diff --git a/crates/glam/src/swizzles/i8vec4_impl.rs b/crates/glam/src/swizzles/i8vec4_impl.rs
new file mode 100644
index 0000000..105a76d
--- /dev/null
+++ b/crates/glam/src/swizzles/i8vec4_impl.rs
@@ -0,0 +1,2067 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{I8Vec2, I8Vec3, I8Vec4, Vec4Swizzles};
+
+impl Vec4Swizzles for I8Vec4 {
+    type Vec2 = I8Vec2;
+
+    type Vec3 = I8Vec3;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xw(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.x,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yw(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.y,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zw(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.z,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wx(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.w,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wy(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.w,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wz(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.w,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn ww(self) -> I8Vec2 {
+        I8Vec2 {
+            x: self.w,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxw(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyw(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzw(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwx(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwy(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwz(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xww(self) -> I8Vec3 {
+        I8Vec3::new(self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxw(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyw(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzw(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywx(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywy(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywz(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yww(self) -> I8Vec3 {
+        I8Vec3::new(self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxw(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyw(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzw(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwx(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwy(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwz(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zww(self) -> I8Vec3 {
+        I8Vec3::new(self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxx(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxy(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxz(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxw(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyx(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyy(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyz(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyw(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzx(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzy(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzz(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzw(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwx(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwy(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwz(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn www(self) -> I8Vec3 {
+        I8Vec3::new(self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxww(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyww(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzww(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzw(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwx(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwy(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwz(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwww(self) -> I8Vec4 {
+        I8Vec4::new(self.x, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxww(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyww(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzww(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzw(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwx(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwy(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwz(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywww(self) -> I8Vec4 {
+        I8Vec4::new(self.y, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxww(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyww(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzww(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzw(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwx(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwy(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwz(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwww(self) -> I8Vec4 {
+        I8Vec4::new(self.z, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxww(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyww(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzww(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzw(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwx(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwy(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwz(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwww(self) -> I8Vec4 {
+        I8Vec4::new(self.w, self.w, self.w, self.w)
+    }
+}
diff --git a/crates/glam/src/swizzles/ivec2_impl.rs b/crates/glam/src/swizzles/ivec2_impl.rs
index 916c132..1764564 100644
--- a/crates/glam/src/swizzles/ivec2_impl.rs
+++ b/crates/glam/src/swizzles/ivec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> IVec2 {
-        IVec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> IVec2 {
         IVec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/ivec3_impl.rs b/crates/glam/src/swizzles/ivec3_impl.rs
index 1ef0a8b..707a44e 100644
--- a/crates/glam/src/swizzles/ivec3_impl.rs
+++ b/crates/glam/src/swizzles/ivec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/ivec4_impl.rs b/crates/glam/src/swizzles/ivec4_impl.rs
index a446486..523a302 100644
--- a/crates/glam/src/swizzles/ivec4_impl.rs
+++ b/crates/glam/src/swizzles/ivec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        IVec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        IVec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        IVec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        IVec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        IVec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        IVec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> IVec3 {
-        IVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        IVec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        IVec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        IVec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        IVec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        IVec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        IVec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        IVec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> IVec3 {
-        IVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        IVec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        IVec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        IVec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        IVec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        IVec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        IVec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        IVec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> IVec3 {
-        IVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        IVec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        IVec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        IVec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        IVec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        IVec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        IVec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        IVec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        IVec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        IVec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        IVec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        IVec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        IVec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        IVec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        IVec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        IVec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        IVec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> IVec3 {
-        IVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        IVec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> IVec4 {
-        IVec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> IVec4 {
         IVec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/neon.rs b/crates/glam/src/swizzles/neon.rs
new file mode 100644
index 0000000..10479c8
--- /dev/null
+++ b/crates/glam/src/swizzles/neon.rs
@@ -0,0 +1,2 @@
+mod vec3a_impl;
+mod vec4_impl;
diff --git a/crates/glam/src/swizzles/neon/vec3a_impl.rs b/crates/glam/src/swizzles/neon/vec3a_impl.rs
new file mode 100644
index 0000000..b5c87fc
--- /dev/null
+++ b/crates/glam/src/swizzles/neon/vec3a_impl.rs
@@ -0,0 +1,732 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{Vec2, Vec3A, Vec3Swizzles, Vec4};
+
+impl Vec3Swizzles for Vec3A {
+    type Vec2 = Vec2;
+
+    type Vec4 = Vec4;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> Vec3A {
+        Vec3A::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> Vec3A {
+        Vec3A::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> Vec3A {
+        Vec3A::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> Vec3A {
+        Vec3A::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> Vec3A {
+        Vec3A::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> Vec3A {
+        Vec3A::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> Vec3A {
+        Vec3A::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> Vec3A {
+        Vec3A::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> Vec3A {
+        Vec3A::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> Vec3A {
+        Vec3A::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> Vec3A {
+        Vec3A::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> Vec3A {
+        Vec3A::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> Vec3A {
+        Vec3A::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> Vec3A {
+        Vec3A::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> Vec3A {
+        Vec3A::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> Vec3A {
+        Vec3A::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> Vec3A {
+        Vec3A::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> Vec3A {
+        Vec3A::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> Vec3A {
+        Vec3A::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> Vec3A {
+        Vec3A::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> Vec3A {
+        Vec3A::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> Vec3A {
+        Vec3A::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> Vec3A {
+        Vec3A::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> Vec3A {
+        Vec3A::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> Vec3A {
+        Vec3A::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> Vec3A {
+        Vec3A::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.z)
+    }
+}
diff --git a/crates/glam/src/swizzles/neon/vec4_impl.rs b/crates/glam/src/swizzles/neon/vec4_impl.rs
new file mode 100644
index 0000000..1186e27
--- /dev/null
+++ b/crates/glam/src/swizzles/neon/vec4_impl.rs
@@ -0,0 +1,2067 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{Vec2, Vec3, Vec4, Vec4Swizzles};
+
+impl Vec4Swizzles for Vec4 {
+    type Vec2 = Vec2;
+
+    type Vec3 = Vec3;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xw(self) -> Vec2 {
+        Vec2 {
+            x: self.x,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yw(self) -> Vec2 {
+        Vec2 {
+            x: self.y,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zw(self) -> Vec2 {
+        Vec2 {
+            x: self.z,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wx(self) -> Vec2 {
+        Vec2 {
+            x: self.w,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wy(self) -> Vec2 {
+        Vec2 {
+            x: self.w,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wz(self) -> Vec2 {
+        Vec2 {
+            x: self.w,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn ww(self) -> Vec2 {
+        Vec2 {
+            x: self.w,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> Vec3 {
+        Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> Vec3 {
+        Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> Vec3 {
+        Vec3::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxw(self) -> Vec3 {
+        Vec3::new(self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> Vec3 {
+        Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> Vec3 {
+        Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyz(self) -> Vec3 {
+        Vec3::new(self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyw(self) -> Vec3 {
+        Vec3::new(self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> Vec3 {
+        Vec3::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> Vec3 {
+        Vec3::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> Vec3 {
+        Vec3::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzw(self) -> Vec3 {
+        Vec3::new(self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwx(self) -> Vec3 {
+        Vec3::new(self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwy(self) -> Vec3 {
+        Vec3::new(self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwz(self) -> Vec3 {
+        Vec3::new(self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xww(self) -> Vec3 {
+        Vec3::new(self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> Vec3 {
+        Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> Vec3 {
+        Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> Vec3 {
+        Vec3::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxw(self) -> Vec3 {
+        Vec3::new(self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> Vec3 {
+        Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> Vec3 {
+        Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> Vec3 {
+        Vec3::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyw(self) -> Vec3 {
+        Vec3::new(self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> Vec3 {
+        Vec3::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> Vec3 {
+        Vec3::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> Vec3 {
+        Vec3::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzw(self) -> Vec3 {
+        Vec3::new(self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywx(self) -> Vec3 {
+        Vec3::new(self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywy(self) -> Vec3 {
+        Vec3::new(self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywz(self) -> Vec3 {
+        Vec3::new(self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yww(self) -> Vec3 {
+        Vec3::new(self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> Vec3 {
+        Vec3::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> Vec3 {
+        Vec3::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> Vec3 {
+        Vec3::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxw(self) -> Vec3 {
+        Vec3::new(self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> Vec3 {
+        Vec3::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> Vec3 {
+        Vec3::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> Vec3 {
+        Vec3::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyw(self) -> Vec3 {
+        Vec3::new(self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> Vec3 {
+        Vec3::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> Vec3 {
+        Vec3::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> Vec3 {
+        Vec3::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzw(self) -> Vec3 {
+        Vec3::new(self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwx(self) -> Vec3 {
+        Vec3::new(self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwy(self) -> Vec3 {
+        Vec3::new(self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwz(self) -> Vec3 {
+        Vec3::new(self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zww(self) -> Vec3 {
+        Vec3::new(self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxx(self) -> Vec3 {
+        Vec3::new(self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxy(self) -> Vec3 {
+        Vec3::new(self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxz(self) -> Vec3 {
+        Vec3::new(self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxw(self) -> Vec3 {
+        Vec3::new(self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyx(self) -> Vec3 {
+        Vec3::new(self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyy(self) -> Vec3 {
+        Vec3::new(self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyz(self) -> Vec3 {
+        Vec3::new(self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyw(self) -> Vec3 {
+        Vec3::new(self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzx(self) -> Vec3 {
+        Vec3::new(self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzy(self) -> Vec3 {
+        Vec3::new(self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzz(self) -> Vec3 {
+        Vec3::new(self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzw(self) -> Vec3 {
+        Vec3::new(self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwx(self) -> Vec3 {
+        Vec3::new(self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwy(self) -> Vec3 {
+        Vec3::new(self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwz(self) -> Vec3 {
+        Vec3::new(self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn www(self) -> Vec3 {
+        Vec3::new(self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxw(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyw(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzw(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwx(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwy(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwz(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxww(self) -> Vec4 {
+        Vec4::new(self.x, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxw(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyw(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywx(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywy(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywz(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyww(self) -> Vec4 {
+        Vec4::new(self.x, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxw(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyw(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzw(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwx(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwy(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwz(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzww(self) -> Vec4 {
+        Vec4::new(self.x, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxx(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxy(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxz(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxw(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyx(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyy(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyz(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyw(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzx(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzy(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzz(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzw(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwx(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwy(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwz(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwww(self) -> Vec4 {
+        Vec4::new(self.x, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxw(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyw(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzw(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwx(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwy(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwz(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxww(self) -> Vec4 {
+        Vec4::new(self.y, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxw(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyw(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzw(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywx(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywy(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywz(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyww(self) -> Vec4 {
+        Vec4::new(self.y, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxw(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyw(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzw(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwx(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwy(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwz(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzww(self) -> Vec4 {
+        Vec4::new(self.y, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxx(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxy(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxz(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxw(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyx(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyy(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyz(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyw(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzx(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzy(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzz(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzw(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwx(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwy(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwz(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywww(self) -> Vec4 {
+        Vec4::new(self.y, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxw(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyw(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzw(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwx(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwy(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwz(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxww(self) -> Vec4 {
+        Vec4::new(self.z, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxw(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyw(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzw(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywx(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywy(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywz(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyww(self) -> Vec4 {
+        Vec4::new(self.z, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxw(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyw(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzw(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwx(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwy(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwz(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzww(self) -> Vec4 {
+        Vec4::new(self.z, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxx(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxy(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxz(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxw(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyx(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyy(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyz(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyw(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzx(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzy(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzz(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzw(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwx(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwy(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwz(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwww(self) -> Vec4 {
+        Vec4::new(self.z, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxx(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxy(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxz(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxw(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyx(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyy(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyz(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyw(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzx(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzy(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzz(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzw(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwx(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwy(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwz(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxww(self) -> Vec4 {
+        Vec4::new(self.w, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxx(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxy(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxz(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxw(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyx(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyy(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyz(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyw(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzx(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzy(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzz(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzw(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywx(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywy(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywz(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyww(self) -> Vec4 {
+        Vec4::new(self.w, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxx(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxy(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxz(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxw(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyx(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyy(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyz(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyw(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzx(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzy(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzz(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzw(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwx(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwy(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwz(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzww(self) -> Vec4 {
+        Vec4::new(self.w, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxx(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxy(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxz(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxw(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyx(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyy(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyz(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyw(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzx(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzy(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzz(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzw(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwx(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwy(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwz(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwww(self) -> Vec4 {
+        Vec4::new(self.w, self.w, self.w, self.w)
+    }
+}
diff --git a/crates/glam/src/swizzles/scalar/vec3a_impl.rs b/crates/glam/src/swizzles/scalar/vec3a_impl.rs
index 9b7d3bd..b5c87fc 100644
--- a/crates/glam/src/swizzles/scalar/vec3a_impl.rs
+++ b/crates/glam/src/swizzles/scalar/vec3a_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3A::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3A::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3A::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3A::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3A::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3A::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3A::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3A {
-        Vec3A {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3A::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3A::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3A::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3A::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3A::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3A::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3A::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3A::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3A::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3A {
-        Vec3A {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3A::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3A::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3A::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3A::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3A::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3A::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3A::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3A::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3A::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3A {
-        Vec3A {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3A::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/scalar/vec4_impl.rs b/crates/glam/src/swizzles/scalar/vec4_impl.rs
index b18862a..1186e27 100644
--- a/crates/glam/src/swizzles/scalar/vec4_impl.rs
+++ b/crates/glam/src/swizzles/scalar/vec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> Vec4 {
-        Vec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> Vec4 {
         Vec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/sse2/vec3a_impl.rs b/crates/glam/src/swizzles/sse2/vec3a_impl.rs
index 7ae6379..eb56569 100644
--- a/crates/glam/src/swizzles/sse2/vec3a_impl.rs
+++ b/crates/glam/src/swizzles/sse2/vec3a_impl.rs
@@ -127,12 +127,6 @@
 
     #[inline]
     #[must_use]
-    fn xyz(self) -> Vec3A {
-        Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_10_01_00) }).into())
-    }
-
-    #[inline]
-    #[must_use]
     fn xzx(self) -> Vec3A {
         Vec3A((unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_00_10_00) }).into())
     }
diff --git a/crates/glam/src/swizzles/sse2/vec4_impl.rs b/crates/glam/src/swizzles/sse2/vec4_impl.rs
index 9220990..c00586b 100644
--- a/crates/glam/src/swizzles/sse2/vec4_impl.rs
+++ b/crates/glam/src/swizzles/sse2/vec4_impl.rs
@@ -161,641 +161,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -962,12 +706,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> Vec4 {
-        Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b11_10_01_00) })
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> Vec4 {
         Vec4(unsafe { _mm_shuffle_ps(self.0, self.0, 0b00_11_01_00) })
     }
diff --git a/crates/glam/src/swizzles/u16vec2_impl.rs b/crates/glam/src/swizzles/u16vec2_impl.rs
index 8d47ef7..13180d1 100644
--- a/crates/glam/src/swizzles/u16vec2_impl.rs
+++ b/crates/glam/src/swizzles/u16vec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> U16Vec2 {
-        U16Vec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> U16Vec2 {
         U16Vec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/u16vec3_impl.rs b/crates/glam/src/swizzles/u16vec3_impl.rs
index ae8cdcc..aa76b5f 100644
--- a/crates/glam/src/swizzles/u16vec3_impl.rs
+++ b/crates/glam/src/swizzles/u16vec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/u16vec4_impl.rs b/crates/glam/src/swizzles/u16vec4_impl.rs
index 15fd834..a3904dc 100644
--- a/crates/glam/src/swizzles/u16vec4_impl.rs
+++ b/crates/glam/src/swizzles/u16vec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        U16Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        U16Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        U16Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        U16Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        U16Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        U16Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        U16Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        U16Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        U16Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        U16Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        U16Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        U16Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        U16Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        U16Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        U16Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        U16Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        U16Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        U16Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        U16Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        U16Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        U16Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        U16Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        U16Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        U16Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        U16Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        U16Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        U16Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        U16Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        U16Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        U16Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        U16Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        U16Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        U16Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        U16Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        U16Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        U16Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> U16Vec3 {
-        U16Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        U16Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> U16Vec4 {
-        U16Vec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> U16Vec4 {
         U16Vec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/u64vec2_impl.rs b/crates/glam/src/swizzles/u64vec2_impl.rs
index ee23afb..0acef19 100644
--- a/crates/glam/src/swizzles/u64vec2_impl.rs
+++ b/crates/glam/src/swizzles/u64vec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> U64Vec2 {
-        U64Vec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> U64Vec2 {
         U64Vec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/u64vec3_impl.rs b/crates/glam/src/swizzles/u64vec3_impl.rs
index 5c0dcc6..ae62b10 100644
--- a/crates/glam/src/swizzles/u64vec3_impl.rs
+++ b/crates/glam/src/swizzles/u64vec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/u64vec4_impl.rs b/crates/glam/src/swizzles/u64vec4_impl.rs
index 111d70f..c6ddd2b 100644
--- a/crates/glam/src/swizzles/u64vec4_impl.rs
+++ b/crates/glam/src/swizzles/u64vec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        U64Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        U64Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        U64Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        U64Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        U64Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        U64Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        U64Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        U64Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        U64Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        U64Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        U64Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        U64Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        U64Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        U64Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        U64Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        U64Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        U64Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        U64Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        U64Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        U64Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        U64Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        U64Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        U64Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        U64Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        U64Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        U64Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        U64Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        U64Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        U64Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        U64Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        U64Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        U64Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        U64Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        U64Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        U64Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        U64Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> U64Vec3 {
-        U64Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        U64Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> U64Vec4 {
-        U64Vec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> U64Vec4 {
         U64Vec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/u8vec2_impl.rs b/crates/glam/src/swizzles/u8vec2_impl.rs
new file mode 100644
index 0000000..2606baf
--- /dev/null
+++ b/crates/glam/src/swizzles/u8vec2_impl.rs
@@ -0,0 +1,180 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{U8Vec2, U8Vec3, U8Vec4, Vec2Swizzles};
+
+impl Vec2Swizzles for U8Vec2 {
+    type Vec3 = U8Vec3;
+
+    type Vec4 = U8Vec4;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+}
diff --git a/crates/glam/src/swizzles/u8vec3_impl.rs b/crates/glam/src/swizzles/u8vec3_impl.rs
new file mode 100644
index 0000000..878b6d9
--- /dev/null
+++ b/crates/glam/src/swizzles/u8vec3_impl.rs
@@ -0,0 +1,732 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{U8Vec2, U8Vec3, U8Vec4, Vec3Swizzles};
+
+impl Vec3Swizzles for U8Vec3 {
+    type Vec2 = U8Vec2;
+
+    type Vec4 = U8Vec4;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.z)
+    }
+}
diff --git a/crates/glam/src/swizzles/u8vec4_impl.rs b/crates/glam/src/swizzles/u8vec4_impl.rs
new file mode 100644
index 0000000..02b95de
--- /dev/null
+++ b/crates/glam/src/swizzles/u8vec4_impl.rs
@@ -0,0 +1,2067 @@
+// Generated from swizzle_impl.rs.tera template. Edit the template, not the generated file.
+
+use crate::{U8Vec2, U8Vec3, U8Vec4, Vec4Swizzles};
+
+impl Vec4Swizzles for U8Vec4 {
+    type Vec2 = U8Vec2;
+
+    type Vec3 = U8Vec3;
+
+    #[inline]
+    #[must_use]
+    fn xx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xw(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.x,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn yw(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.y,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn zw(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.z,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wx(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.w,
+            y: self.x,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wy(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.w,
+            y: self.y,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn wz(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.w,
+            y: self.z,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn ww(self) -> U8Vec2 {
+        U8Vec2 {
+            x: self.w,
+            y: self.w,
+        }
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxw(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyw(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzw(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwx(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwy(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwz(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xww(self) -> U8Vec3 {
+        U8Vec3::new(self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxw(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyw(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzw(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywx(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywy(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywz(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yww(self) -> U8Vec3 {
+        U8Vec3::new(self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxw(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyw(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzw(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwx(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwy(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwz(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zww(self) -> U8Vec3 {
+        U8Vec3::new(self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxx(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxy(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxz(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxw(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyx(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyy(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyz(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyw(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzx(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzy(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzz(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzw(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwx(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwy(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwz(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn www(self) -> U8Vec3 {
+        U8Vec3::new(self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxxw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxyw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxzw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxwz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xxww(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyxw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyyw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xywz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xyww(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzxw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzyw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzzw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzwz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xzww(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwxw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwyw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwzw(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwx(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwy(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwwz(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn xwww(self) -> U8Vec4 {
+        U8Vec4::new(self.x, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxxw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxyw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxzw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxwz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yxww(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyxw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyyw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyzw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yywz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yyww(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzxw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzyw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzzw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzwz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn yzww(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywxw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywyw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywzw(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwx(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwy(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywwz(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn ywww(self) -> U8Vec4 {
+        U8Vec4::new(self.y, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxxw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxyw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxzw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxwz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zxww(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyxw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyyw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyzw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zywz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zyww(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzxw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzyw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzzw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzwz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zzww(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwxw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwyw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwzw(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwx(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwy(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwwz(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn zwww(self) -> U8Vec4 {
+        U8Vec4::new(self.z, self.w, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxxw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxyw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxzw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxwz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wxww(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.x, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyxw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyyw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyzw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wywz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wyww(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.y, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzxw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzyw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzzw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzwz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wzww(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.z, self.w, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.x, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.x, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.x, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwxw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.x, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.y, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.y, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.y, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwyw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.y, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.z, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.z, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.z, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwzw(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.z, self.w)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwx(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.w, self.x)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwy(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.w, self.y)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwwz(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.w, self.z)
+    }
+
+    #[inline]
+    #[must_use]
+    fn wwww(self) -> U8Vec4 {
+        U8Vec4::new(self.w, self.w, self.w, self.w)
+    }
+}
diff --git a/crates/glam/src/swizzles/uvec2_impl.rs b/crates/glam/src/swizzles/uvec2_impl.rs
index 78bb40c..b9b51d9 100644
--- a/crates/glam/src/swizzles/uvec2_impl.rs
+++ b/crates/glam/src/swizzles/uvec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> UVec2 {
-        UVec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> UVec2 {
         UVec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/uvec3_impl.rs b/crates/glam/src/swizzles/uvec3_impl.rs
index 9a91b7c..885a109 100644
--- a/crates/glam/src/swizzles/uvec3_impl.rs
+++ b/crates/glam/src/swizzles/uvec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/uvec4_impl.rs b/crates/glam/src/swizzles/uvec4_impl.rs
index afd3d32..5f4c27e 100644
--- a/crates/glam/src/swizzles/uvec4_impl.rs
+++ b/crates/glam/src/swizzles/uvec4_impl.rs
@@ -154,641 +154,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        UVec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        UVec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        UVec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        UVec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        UVec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        UVec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> UVec3 {
-        UVec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        UVec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        UVec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        UVec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        UVec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        UVec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        UVec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        UVec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> UVec3 {
-        UVec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        UVec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        UVec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        UVec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        UVec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        UVec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        UVec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        UVec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> UVec3 {
-        UVec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        UVec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        UVec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        UVec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        UVec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        UVec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        UVec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        UVec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        UVec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        UVec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        UVec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        UVec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        UVec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        UVec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        UVec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        UVec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        UVec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> UVec3 {
-        UVec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        UVec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -955,12 +699,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> UVec4 {
-        UVec4::new(self.x, self.y, self.z, self.w)
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> UVec4 {
         UVec4::new(self.x, self.y, self.w, self.x)
     }
diff --git a/crates/glam/src/swizzles/vec2_impl.rs b/crates/glam/src/swizzles/vec2_impl.rs
index e4d68aa..d7899d2 100644
--- a/crates/glam/src/swizzles/vec2_impl.rs
+++ b/crates/glam/src/swizzles/vec2_impl.rs
@@ -18,15 +18,6 @@
 
     #[inline]
     #[must_use]
-    fn xy(self) -> Vec2 {
-        Vec2 {
-            x: self.x,
-            y: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
     fn yx(self) -> Vec2 {
         Vec2 {
             x: self.y,
@@ -46,81 +37,49 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/vec3_impl.rs b/crates/glam/src/swizzles/vec3_impl.rs
index db657e2..9a07e4a 100644
--- a/crates/glam/src/swizzles/vec3_impl.rs
+++ b/crates/glam/src/swizzles/vec3_impl.rs
@@ -91,271 +91,157 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
-    }
-
-    #[inline]
-    #[must_use]
-    fn xyz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
diff --git a/crates/glam/src/swizzles/wasm32/vec3a_impl.rs b/crates/glam/src/swizzles/wasm32/vec3a_impl.rs
index 7bfe7cc..85a57e8 100644
--- a/crates/glam/src/swizzles/wasm32/vec3a_impl.rs
+++ b/crates/glam/src/swizzles/wasm32/vec3a_impl.rs
@@ -124,12 +124,6 @@
 
     #[inline]
     #[must_use]
-    fn xyz(self) -> Vec3A {
-        Vec3A(i32x4_shuffle::<0, 1, 6, 4>(self.0, self.0).into())
-    }
-
-    #[inline]
-    #[must_use]
     fn xzx(self) -> Vec3A {
         Vec3A(i32x4_shuffle::<0, 2, 4, 4>(self.0, self.0).into())
     }
diff --git a/crates/glam/src/swizzles/wasm32/vec4_impl.rs b/crates/glam/src/swizzles/wasm32/vec4_impl.rs
index 5b58927..8fd5b2e 100644
--- a/crates/glam/src/swizzles/wasm32/vec4_impl.rs
+++ b/crates/glam/src/swizzles/wasm32/vec4_impl.rs
@@ -158,641 +158,385 @@
     #[inline]
     #[must_use]
     fn xxx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xxy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xxz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xxw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xyx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xyy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xyz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xyw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xzx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xzy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xzz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xzw(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn xwx(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.x, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn xwy(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.x, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn xwz(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.x, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn xww(self) -> Vec3 {
-        Vec3 {
-            x: self.x,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.x, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yxx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yxy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yxz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yxw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yyx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yyy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yyz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yyw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn yzx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn yzy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn yzz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yzw(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn ywx(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.y, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn ywy(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.y, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn ywz(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.y, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn yww(self) -> Vec3 {
-        Vec3 {
-            x: self.y,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.y, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zxx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zxy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zxz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zxw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zyx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zyy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zyz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zyw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zzx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zzy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zzz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zzw(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn zwx(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.z, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn zwy(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.z, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn zwz(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.z, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn zww(self) -> Vec3 {
-        Vec3 {
-            x: self.z,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.z, self.w, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wxx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.x, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wxy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.x, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wxz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.x, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wxw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.x,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.x, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wyx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.y, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wyy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.y, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wyz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.y, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wyw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.y,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.y, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wzx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.z, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wzy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.z, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wzz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.z, self.z)
     }
 
     #[inline]
     #[must_use]
     fn wzw(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.z,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.z, self.w)
     }
 
     #[inline]
     #[must_use]
     fn wwx(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.x,
-        }
+        Vec3::new(self.w, self.w, self.x)
     }
 
     #[inline]
     #[must_use]
     fn wwy(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.y,
-        }
+        Vec3::new(self.w, self.w, self.y)
     }
 
     #[inline]
     #[must_use]
     fn wwz(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.z,
-        }
+        Vec3::new(self.w, self.w, self.z)
     }
 
     #[inline]
     #[must_use]
     fn www(self) -> Vec3 {
-        Vec3 {
-            x: self.w,
-            y: self.w,
-            z: self.w,
-        }
+        Vec3::new(self.w, self.w, self.w)
     }
 
     #[inline]
@@ -959,12 +703,6 @@
 
     #[inline]
     #[must_use]
-    fn xyzw(self) -> Vec4 {
-        Vec4(i32x4_shuffle::<0, 1, 6, 7>(self.0, self.0))
-    }
-
-    #[inline]
-    #[must_use]
     fn xywx(self) -> Vec4 {
         Vec4(i32x4_shuffle::<0, 1, 7, 4>(self.0, self.0))
     }
diff --git a/crates/glam/src/u16/u16vec2.rs b/crates/glam/src/u16/u16vec2.rs
index 3ee390c..907f8a8 100644
--- a/crates/glam/src/u16/u16vec2.rs
+++ b/crates/glam/src/u16/u16vec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec2, I64Vec2, IVec2, U16Vec3, U64Vec2, UVec2};
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec3, U64Vec2, U8Vec2, UVec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -61,6 +60,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -97,6 +106,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u16]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -107,8 +117,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -118,6 +127,22 @@
         U16Vec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u16) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -188,6 +213,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u16 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u16 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -276,6 +319,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -406,6 +463,30 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I16Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I16Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+        }
+    }
 }
 
 impl Default for U16Vec2 {
@@ -426,6 +507,30 @@
     }
 }
 
+impl Div<&U16Vec2> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U16Vec2> for U16Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -434,6 +539,13 @@
     }
 }
 
+impl DivAssign<&Self> for U16Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u16> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -445,6 +557,30 @@
     }
 }
 
+impl Div<&u16> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: u16) -> U16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u16> for U16Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: u16) {
@@ -453,6 +589,13 @@
     }
 }
 
+impl DivAssign<&u16> for U16Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U16Vec2> for u16 {
     type Output = U16Vec2;
     #[inline]
@@ -464,6 +607,30 @@
     }
 }
 
+impl Div<&U16Vec2> for u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn div(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U16Vec2> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -475,6 +642,30 @@
     }
 }
 
+impl Mul<&U16Vec2> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U16Vec2> for U16Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -483,6 +674,13 @@
     }
 }
 
+impl MulAssign<&Self> for U16Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u16> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -494,6 +692,30 @@
     }
 }
 
+impl Mul<&u16> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: u16) -> U16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u16> for U16Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: u16) {
@@ -502,6 +724,13 @@
     }
 }
 
+impl MulAssign<&u16> for U16Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U16Vec2> for u16 {
     type Output = U16Vec2;
     #[inline]
@@ -513,6 +742,30 @@
     }
 }
 
+impl Mul<&U16Vec2> for u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn mul(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U16Vec2> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -524,6 +777,30 @@
     }
 }
 
+impl Add<&U16Vec2> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U16Vec2> for U16Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -532,6 +809,13 @@
     }
 }
 
+impl AddAssign<&Self> for U16Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u16> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -543,6 +827,30 @@
     }
 }
 
+impl Add<&u16> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: u16) -> U16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u16> for U16Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: u16) {
@@ -551,6 +859,13 @@
     }
 }
 
+impl AddAssign<&u16> for U16Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U16Vec2> for u16 {
     type Output = U16Vec2;
     #[inline]
@@ -562,6 +877,30 @@
     }
 }
 
+impl Add<&U16Vec2> for u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn add(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U16Vec2> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -573,6 +912,30 @@
     }
 }
 
+impl Sub<&U16Vec2> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U16Vec2> for U16Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: U16Vec2) {
@@ -581,6 +944,13 @@
     }
 }
 
+impl SubAssign<&Self> for U16Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u16> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -592,6 +962,30 @@
     }
 }
 
+impl Sub<&u16> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: u16) -> U16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u16> for U16Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: u16) {
@@ -600,6 +994,13 @@
     }
 }
 
+impl SubAssign<&u16> for U16Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U16Vec2> for u16 {
     type Output = U16Vec2;
     #[inline]
@@ -611,6 +1012,30 @@
     }
 }
 
+impl Sub<&U16Vec2> for u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn sub(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U16Vec2> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -622,6 +1047,30 @@
     }
 }
 
+impl Rem<&U16Vec2> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec2> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U16Vec2> for U16Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -630,6 +1079,13 @@
     }
 }
 
+impl RemAssign<&Self> for U16Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u16> for U16Vec2 {
     type Output = Self;
     #[inline]
@@ -641,6 +1097,30 @@
     }
 }
 
+impl Rem<&u16> for U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u16> for &U16Vec2 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: u16) -> U16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u16> for U16Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: u16) {
@@ -649,6 +1129,13 @@
     }
 }
 
+impl RemAssign<&u16> for U16Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U16Vec2> for u16 {
     type Output = U16Vec2;
     #[inline]
@@ -660,6 +1147,30 @@
     }
 }
 
+impl Rem<&U16Vec2> for u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &U16Vec2) -> U16Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: &U16Vec2) -> U16Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec2> for &u16 {
+    type Output = U16Vec2;
+    #[inline]
+    fn rem(self, rhs: U16Vec2) -> U16Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u16; 2]> for U16Vec2 {
     #[inline]
@@ -1036,14 +1547,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U16Vec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U16Vec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U16Vec2))
@@ -1081,6 +1590,22 @@
     }
 }
 
+impl From<U8Vec2> for U16Vec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(u16::from(v.x), u16::from(v.y))
+    }
+}
+
+impl TryFrom<I8Vec2> for U16Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u16::try_from(v.x)?, u16::try_from(v.y)?))
+    }
+}
+
 impl TryFrom<I16Vec2> for U16Vec2 {
     type Error = core::num::TryFromIntError;
 
@@ -1125,3 +1650,10 @@
         Ok(Self::new(u16::try_from(v.x)?, u16::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for U16Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(u16::from(v.x), u16::from(v.y))
+    }
+}
diff --git a/crates/glam/src/u16/u16vec3.rs b/crates/glam/src/u16/u16vec3.rs
index e2859a0..14bb406 100644
--- a/crates/glam/src/u16/u16vec3.rs
+++ b/crates/glam/src/u16/u16vec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec3, I64Vec3, IVec3, U16Vec2, U16Vec4, U64Vec3, UVec3};
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec2, U16Vec4, U64Vec3, U8Vec3, UVec3,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -64,6 +65,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -101,6 +112,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u16]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -111,9 +123,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -145,6 +155,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u16) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u16) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -228,6 +262,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u16 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u16 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,6 +375,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -461,6 +527,32 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I16Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I16Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+        }
+    }
 }
 
 impl Default for U16Vec3 {
@@ -482,6 +574,30 @@
     }
 }
 
+impl Div<&U16Vec3> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U16Vec3> for U16Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -491,6 +607,13 @@
     }
 }
 
+impl DivAssign<&Self> for U16Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u16> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -503,6 +626,30 @@
     }
 }
 
+impl Div<&u16> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: u16) -> U16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u16> for U16Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: u16) {
@@ -512,6 +659,13 @@
     }
 }
 
+impl DivAssign<&u16> for U16Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U16Vec3> for u16 {
     type Output = U16Vec3;
     #[inline]
@@ -524,6 +678,30 @@
     }
 }
 
+impl Div<&U16Vec3> for u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn div(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U16Vec3> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -536,6 +714,30 @@
     }
 }
 
+impl Mul<&U16Vec3> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U16Vec3> for U16Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -545,6 +747,13 @@
     }
 }
 
+impl MulAssign<&Self> for U16Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u16> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -557,6 +766,30 @@
     }
 }
 
+impl Mul<&u16> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: u16) -> U16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u16> for U16Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: u16) {
@@ -566,6 +799,13 @@
     }
 }
 
+impl MulAssign<&u16> for U16Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U16Vec3> for u16 {
     type Output = U16Vec3;
     #[inline]
@@ -578,6 +818,30 @@
     }
 }
 
+impl Mul<&U16Vec3> for u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn mul(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U16Vec3> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +854,30 @@
     }
 }
 
+impl Add<&U16Vec3> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U16Vec3> for U16Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -599,6 +887,13 @@
     }
 }
 
+impl AddAssign<&Self> for U16Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u16> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -611,6 +906,30 @@
     }
 }
 
+impl Add<&u16> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: u16) -> U16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u16> for U16Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: u16) {
@@ -620,6 +939,13 @@
     }
 }
 
+impl AddAssign<&u16> for U16Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U16Vec3> for u16 {
     type Output = U16Vec3;
     #[inline]
@@ -632,6 +958,30 @@
     }
 }
 
+impl Add<&U16Vec3> for u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn add(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U16Vec3> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +994,30 @@
     }
 }
 
+impl Sub<&U16Vec3> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U16Vec3> for U16Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: U16Vec3) {
@@ -653,6 +1027,13 @@
     }
 }
 
+impl SubAssign<&Self> for U16Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u16> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -665,6 +1046,30 @@
     }
 }
 
+impl Sub<&u16> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: u16) -> U16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u16> for U16Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: u16) {
@@ -674,6 +1079,13 @@
     }
 }
 
+impl SubAssign<&u16> for U16Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U16Vec3> for u16 {
     type Output = U16Vec3;
     #[inline]
@@ -686,6 +1098,30 @@
     }
 }
 
+impl Sub<&U16Vec3> for u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn sub(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U16Vec3> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1134,30 @@
     }
 }
 
+impl Rem<&U16Vec3> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec3> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U16Vec3> for U16Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -707,6 +1167,13 @@
     }
 }
 
+impl RemAssign<&Self> for U16Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u16> for U16Vec3 {
     type Output = Self;
     #[inline]
@@ -719,6 +1186,30 @@
     }
 }
 
+impl Rem<&u16> for U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u16> for &U16Vec3 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: u16) -> U16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u16> for U16Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: u16) {
@@ -728,6 +1219,13 @@
     }
 }
 
+impl RemAssign<&u16> for U16Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U16Vec3> for u16 {
     type Output = U16Vec3;
     #[inline]
@@ -740,6 +1238,30 @@
     }
 }
 
+impl Rem<&U16Vec3> for u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &U16Vec3) -> U16Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: &U16Vec3) -> U16Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec3> for &u16 {
+    type Output = U16Vec3;
+    #[inline]
+    fn rem(self, rhs: U16Vec3) -> U16Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u16; 3]> for U16Vec3 {
     #[inline]
@@ -1145,14 +1667,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U16Vec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U16Vec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U16Vec3))
@@ -1198,6 +1718,26 @@
     }
 }
 
+impl From<U8Vec3> for U16Vec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(u16::from(v.x), u16::from(v.y), u16::from(v.z))
+    }
+}
+
+impl TryFrom<I8Vec3> for U16Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u16::try_from(v.x)?,
+            u16::try_from(v.y)?,
+            u16::try_from(v.z)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec3> for U16Vec3 {
     type Error = core::num::TryFromIntError;
 
@@ -1262,3 +1802,22 @@
         ))
     }
 }
+
+impl From<BVec3> for U16Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(u16::from(v.x), u16::from(v.y), u16::from(v.z))
+    }
+}
+
+impl From<BVec3A> for U16Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            u16::from(bool_array[0]),
+            u16::from(bool_array[1]),
+            u16::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/u16/u16vec4.rs b/crates/glam/src/u16/u16vec4.rs
index e6b68e5..0ff3b72 100644
--- a/crates/glam/src/u16/u16vec4.rs
+++ b/crates/glam/src/u16/u16vec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec4, I64Vec4, IVec4, U16Vec2, U16Vec3, U64Vec4, UVec4};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec2, U16Vec3, U64Vec4, U8Vec4, UVec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -77,6 +78,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -115,6 +126,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u16]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -125,10 +137,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u16]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -141,6 +150,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u16) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u16) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u16) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: u16) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -215,6 +256,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u16 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u16 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -333,6 +392,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -479,6 +552,34 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I16Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+            w: self.w.wrapping_add_signed(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I16Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+            w: self.w.saturating_add_signed(rhs.w),
+        }
+    }
 }
 
 impl Default for U16Vec4 {
@@ -501,6 +602,30 @@
     }
 }
 
+impl Div<&U16Vec4> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U16Vec4> for U16Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -511,6 +636,13 @@
     }
 }
 
+impl DivAssign<&Self> for U16Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u16> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -524,6 +656,30 @@
     }
 }
 
+impl Div<&u16> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &u16) -> U16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: u16) -> U16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u16> for U16Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: u16) {
@@ -534,6 +690,13 @@
     }
 }
 
+impl DivAssign<&u16> for U16Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u16) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U16Vec4> for u16 {
     type Output = U16Vec4;
     #[inline]
@@ -547,6 +710,30 @@
     }
 }
 
+impl Div<&U16Vec4> for u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn div(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U16Vec4> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -560,6 +747,30 @@
     }
 }
 
+impl Mul<&U16Vec4> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U16Vec4> for U16Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -570,6 +781,13 @@
     }
 }
 
+impl MulAssign<&Self> for U16Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u16> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -583,6 +801,30 @@
     }
 }
 
+impl Mul<&u16> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &u16) -> U16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: u16) -> U16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u16> for U16Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: u16) {
@@ -593,6 +835,13 @@
     }
 }
 
+impl MulAssign<&u16> for U16Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u16) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U16Vec4> for u16 {
     type Output = U16Vec4;
     #[inline]
@@ -606,6 +855,30 @@
     }
 }
 
+impl Mul<&U16Vec4> for u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn mul(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U16Vec4> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +892,30 @@
     }
 }
 
+impl Add<&U16Vec4> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U16Vec4> for U16Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -629,6 +926,13 @@
     }
 }
 
+impl AddAssign<&Self> for U16Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u16> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -642,6 +946,30 @@
     }
 }
 
+impl Add<&u16> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &u16) -> U16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: u16) -> U16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u16> for U16Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: u16) {
@@ -652,6 +980,13 @@
     }
 }
 
+impl AddAssign<&u16> for U16Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u16) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U16Vec4> for u16 {
     type Output = U16Vec4;
     #[inline]
@@ -665,6 +1000,30 @@
     }
 }
 
+impl Add<&U16Vec4> for u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn add(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U16Vec4> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +1037,30 @@
     }
 }
 
+impl Sub<&U16Vec4> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U16Vec4> for U16Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: U16Vec4) {
@@ -688,6 +1071,13 @@
     }
 }
 
+impl SubAssign<&Self> for U16Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u16> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -701,6 +1091,30 @@
     }
 }
 
+impl Sub<&u16> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &u16) -> U16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: u16) -> U16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u16> for U16Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: u16) {
@@ -711,6 +1125,13 @@
     }
 }
 
+impl SubAssign<&u16> for U16Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u16) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U16Vec4> for u16 {
     type Output = U16Vec4;
     #[inline]
@@ -724,6 +1145,30 @@
     }
 }
 
+impl Sub<&U16Vec4> for u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn sub(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U16Vec4> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1182,30 @@
     }
 }
 
+impl Rem<&U16Vec4> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec4> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U16Vec4> for U16Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -747,6 +1216,13 @@
     }
 }
 
+impl RemAssign<&Self> for U16Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u16> for U16Vec4 {
     type Output = Self;
     #[inline]
@@ -760,6 +1236,30 @@
     }
 }
 
+impl Rem<&u16> for U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &u16) -> U16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u16> for &U16Vec4 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: u16) -> U16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u16> for U16Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: u16) {
@@ -770,6 +1270,13 @@
     }
 }
 
+impl RemAssign<&u16> for U16Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u16) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U16Vec4> for u16 {
     type Output = U16Vec4;
     #[inline]
@@ -783,6 +1290,30 @@
     }
 }
 
+impl Rem<&U16Vec4> for u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &U16Vec4) -> U16Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: &U16Vec4) -> U16Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U16Vec4> for &u16 {
+    type Output = U16Vec4;
+    #[inline]
+    fn rem(self, rhs: U16Vec4) -> U16Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u16; 4]> for U16Vec4 {
     #[inline]
@@ -1217,14 +1748,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U16Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U16Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U16Vec4))
@@ -1292,6 +1821,32 @@
     }
 }
 
+impl From<U8Vec4> for U16Vec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            u16::from(v.x),
+            u16::from(v.y),
+            u16::from(v.z),
+            u16::from(v.w),
+        )
+    }
+}
+
+impl TryFrom<I8Vec4> for U16Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u16::try_from(v.x)?,
+            u16::try_from(v.y)?,
+            u16::try_from(v.z)?,
+            u16::try_from(v.w)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec4> for U16Vec4 {
     type Error = core::num::TryFromIntError;
 
@@ -1361,3 +1916,30 @@
         ))
     }
 }
+
+impl From<BVec4> for U16Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            u16::from(v.x),
+            u16::from(v.y),
+            u16::from(v.z),
+            u16::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for U16Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            u16::from(bool_array[0]),
+            u16::from(bool_array[1]),
+            u16::from(bool_array[2]),
+            u16::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/u32/uvec2.rs b/crates/glam/src/u32/uvec2.rs
index 39fbf9a..e81e003 100644
--- a/crates/glam/src/u32/uvec2.rs
+++ b/crates/glam/src/u32/uvec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U64Vec2, UVec3};
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec3};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -61,6 +60,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -97,6 +106,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u32]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -107,8 +117,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -118,6 +127,22 @@
         UVec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u32) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -188,6 +213,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u32 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u32 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -276,6 +319,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -406,6 +463,30 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: IVec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: IVec2) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+        }
+    }
 }
 
 impl Default for UVec2 {
@@ -426,6 +507,30 @@
     }
 }
 
+impl Div<&UVec2> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &UVec2) -> UVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &UVec2) -> UVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: UVec2) -> UVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<UVec2> for UVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -434,6 +539,13 @@
     }
 }
 
+impl DivAssign<&Self> for UVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u32> for UVec2 {
     type Output = Self;
     #[inline]
@@ -445,6 +557,30 @@
     }
 }
 
+impl Div<&u32> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: u32) -> UVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u32> for UVec2 {
     #[inline]
     fn div_assign(&mut self, rhs: u32) {
@@ -453,6 +589,13 @@
     }
 }
 
+impl DivAssign<&u32> for UVec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<UVec2> for u32 {
     type Output = UVec2;
     #[inline]
@@ -464,6 +607,30 @@
     }
 }
 
+impl Div<&UVec2> for u32 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &UVec2) -> UVec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: &UVec2) -> UVec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn div(self, rhs: UVec2) -> UVec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<UVec2> for UVec2 {
     type Output = Self;
     #[inline]
@@ -475,6 +642,30 @@
     }
 }
 
+impl Mul<&UVec2> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &UVec2) -> UVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &UVec2) -> UVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: UVec2) -> UVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<UVec2> for UVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -483,6 +674,13 @@
     }
 }
 
+impl MulAssign<&Self> for UVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u32> for UVec2 {
     type Output = Self;
     #[inline]
@@ -494,6 +692,30 @@
     }
 }
 
+impl Mul<&u32> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: u32) -> UVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u32> for UVec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: u32) {
@@ -502,6 +724,13 @@
     }
 }
 
+impl MulAssign<&u32> for UVec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<UVec2> for u32 {
     type Output = UVec2;
     #[inline]
@@ -513,6 +742,30 @@
     }
 }
 
+impl Mul<&UVec2> for u32 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &UVec2) -> UVec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: &UVec2) -> UVec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn mul(self, rhs: UVec2) -> UVec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<UVec2> for UVec2 {
     type Output = Self;
     #[inline]
@@ -524,6 +777,30 @@
     }
 }
 
+impl Add<&UVec2> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &UVec2) -> UVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &UVec2) -> UVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: UVec2) -> UVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<UVec2> for UVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -532,6 +809,13 @@
     }
 }
 
+impl AddAssign<&Self> for UVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u32> for UVec2 {
     type Output = Self;
     #[inline]
@@ -543,6 +827,30 @@
     }
 }
 
+impl Add<&u32> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: u32) -> UVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u32> for UVec2 {
     #[inline]
     fn add_assign(&mut self, rhs: u32) {
@@ -551,6 +859,13 @@
     }
 }
 
+impl AddAssign<&u32> for UVec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<UVec2> for u32 {
     type Output = UVec2;
     #[inline]
@@ -562,6 +877,30 @@
     }
 }
 
+impl Add<&UVec2> for u32 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &UVec2) -> UVec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: &UVec2) -> UVec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn add(self, rhs: UVec2) -> UVec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<UVec2> for UVec2 {
     type Output = Self;
     #[inline]
@@ -573,6 +912,30 @@
     }
 }
 
+impl Sub<&UVec2> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &UVec2) -> UVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &UVec2) -> UVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: UVec2) -> UVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<UVec2> for UVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: UVec2) {
@@ -581,6 +944,13 @@
     }
 }
 
+impl SubAssign<&Self> for UVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u32> for UVec2 {
     type Output = Self;
     #[inline]
@@ -592,6 +962,30 @@
     }
 }
 
+impl Sub<&u32> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: u32) -> UVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u32> for UVec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: u32) {
@@ -600,6 +994,13 @@
     }
 }
 
+impl SubAssign<&u32> for UVec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<UVec2> for u32 {
     type Output = UVec2;
     #[inline]
@@ -611,6 +1012,30 @@
     }
 }
 
+impl Sub<&UVec2> for u32 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &UVec2) -> UVec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: &UVec2) -> UVec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn sub(self, rhs: UVec2) -> UVec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<UVec2> for UVec2 {
     type Output = Self;
     #[inline]
@@ -622,6 +1047,30 @@
     }
 }
 
+impl Rem<&UVec2> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &UVec2) -> UVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &UVec2) -> UVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec2> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: UVec2) -> UVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<UVec2> for UVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -630,6 +1079,13 @@
     }
 }
 
+impl RemAssign<&Self> for UVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u32> for UVec2 {
     type Output = Self;
     #[inline]
@@ -641,6 +1097,30 @@
     }
 }
 
+impl Rem<&u32> for UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u32> for &UVec2 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: u32) -> UVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u32> for UVec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: u32) {
@@ -649,6 +1129,13 @@
     }
 }
 
+impl RemAssign<&u32> for UVec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<UVec2> for u32 {
     type Output = UVec2;
     #[inline]
@@ -660,6 +1147,30 @@
     }
 }
 
+impl Rem<&UVec2> for u32 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &UVec2) -> UVec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: &UVec2) -> UVec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec2> for &u32 {
+    type Output = UVec2;
+    #[inline]
+    fn rem(self, rhs: UVec2) -> UVec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u32; 2]> for UVec2 {
     #[inline]
@@ -1036,14 +1547,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for UVec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for UVec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(UVec2))
@@ -1081,6 +1590,13 @@
     }
 }
 
+impl From<U8Vec2> for UVec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(u32::from(v.x), u32::from(v.y))
+    }
+}
+
 impl From<U16Vec2> for UVec2 {
     #[inline]
     fn from(v: U16Vec2) -> Self {
@@ -1088,6 +1604,15 @@
     }
 }
 
+impl TryFrom<I8Vec2> for UVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u32::try_from(v.x)?, u32::try_from(v.y)?))
+    }
+}
+
 impl TryFrom<I16Vec2> for UVec2 {
     type Error = core::num::TryFromIntError;
 
@@ -1123,3 +1648,10 @@
         Ok(Self::new(u32::try_from(v.x)?, u32::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for UVec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(u32::from(v.x), u32::from(v.y))
+    }
+}
diff --git a/crates/glam/src/u32/uvec3.rs b/crates/glam/src/u32/uvec3.rs
index ca06d46..5ac4d49 100644
--- a/crates/glam/src/u32/uvec3.rs
+++ b/crates/glam/src/u32/uvec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec2, UVec4};
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec2, UVec4,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -64,6 +65,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -101,6 +112,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u32]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -111,9 +123,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -145,6 +155,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u32) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -228,6 +262,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u32 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u32 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,6 +375,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -461,6 +527,32 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: IVec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: IVec3) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+        }
+    }
 }
 
 impl Default for UVec3 {
@@ -482,6 +574,30 @@
     }
 }
 
+impl Div<&UVec3> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &UVec3) -> UVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &UVec3) -> UVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: UVec3) -> UVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<UVec3> for UVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -491,6 +607,13 @@
     }
 }
 
+impl DivAssign<&Self> for UVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u32> for UVec3 {
     type Output = Self;
     #[inline]
@@ -503,6 +626,30 @@
     }
 }
 
+impl Div<&u32> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: u32) -> UVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u32> for UVec3 {
     #[inline]
     fn div_assign(&mut self, rhs: u32) {
@@ -512,6 +659,13 @@
     }
 }
 
+impl DivAssign<&u32> for UVec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<UVec3> for u32 {
     type Output = UVec3;
     #[inline]
@@ -524,6 +678,30 @@
     }
 }
 
+impl Div<&UVec3> for u32 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &UVec3) -> UVec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: &UVec3) -> UVec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn div(self, rhs: UVec3) -> UVec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<UVec3> for UVec3 {
     type Output = Self;
     #[inline]
@@ -536,6 +714,30 @@
     }
 }
 
+impl Mul<&UVec3> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &UVec3) -> UVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &UVec3) -> UVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: UVec3) -> UVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<UVec3> for UVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -545,6 +747,13 @@
     }
 }
 
+impl MulAssign<&Self> for UVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u32> for UVec3 {
     type Output = Self;
     #[inline]
@@ -557,6 +766,30 @@
     }
 }
 
+impl Mul<&u32> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: u32) -> UVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u32> for UVec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: u32) {
@@ -566,6 +799,13 @@
     }
 }
 
+impl MulAssign<&u32> for UVec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<UVec3> for u32 {
     type Output = UVec3;
     #[inline]
@@ -578,6 +818,30 @@
     }
 }
 
+impl Mul<&UVec3> for u32 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &UVec3) -> UVec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: &UVec3) -> UVec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn mul(self, rhs: UVec3) -> UVec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<UVec3> for UVec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +854,30 @@
     }
 }
 
+impl Add<&UVec3> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &UVec3) -> UVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &UVec3) -> UVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: UVec3) -> UVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<UVec3> for UVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -599,6 +887,13 @@
     }
 }
 
+impl AddAssign<&Self> for UVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u32> for UVec3 {
     type Output = Self;
     #[inline]
@@ -611,6 +906,30 @@
     }
 }
 
+impl Add<&u32> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: u32) -> UVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u32> for UVec3 {
     #[inline]
     fn add_assign(&mut self, rhs: u32) {
@@ -620,6 +939,13 @@
     }
 }
 
+impl AddAssign<&u32> for UVec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<UVec3> for u32 {
     type Output = UVec3;
     #[inline]
@@ -632,6 +958,30 @@
     }
 }
 
+impl Add<&UVec3> for u32 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &UVec3) -> UVec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: &UVec3) -> UVec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn add(self, rhs: UVec3) -> UVec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<UVec3> for UVec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +994,30 @@
     }
 }
 
+impl Sub<&UVec3> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &UVec3) -> UVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &UVec3) -> UVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: UVec3) -> UVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<UVec3> for UVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: UVec3) {
@@ -653,6 +1027,13 @@
     }
 }
 
+impl SubAssign<&Self> for UVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u32> for UVec3 {
     type Output = Self;
     #[inline]
@@ -665,6 +1046,30 @@
     }
 }
 
+impl Sub<&u32> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: u32) -> UVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u32> for UVec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: u32) {
@@ -674,6 +1079,13 @@
     }
 }
 
+impl SubAssign<&u32> for UVec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<UVec3> for u32 {
     type Output = UVec3;
     #[inline]
@@ -686,6 +1098,30 @@
     }
 }
 
+impl Sub<&UVec3> for u32 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &UVec3) -> UVec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: &UVec3) -> UVec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn sub(self, rhs: UVec3) -> UVec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<UVec3> for UVec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1134,30 @@
     }
 }
 
+impl Rem<&UVec3> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &UVec3) -> UVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &UVec3) -> UVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec3> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: UVec3) -> UVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<UVec3> for UVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -707,6 +1167,13 @@
     }
 }
 
+impl RemAssign<&Self> for UVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u32> for UVec3 {
     type Output = Self;
     #[inline]
@@ -719,6 +1186,30 @@
     }
 }
 
+impl Rem<&u32> for UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u32> for &UVec3 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: u32) -> UVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u32> for UVec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: u32) {
@@ -728,6 +1219,13 @@
     }
 }
 
+impl RemAssign<&u32> for UVec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<UVec3> for u32 {
     type Output = UVec3;
     #[inline]
@@ -740,6 +1238,30 @@
     }
 }
 
+impl Rem<&UVec3> for u32 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &UVec3) -> UVec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: &UVec3) -> UVec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec3> for &u32 {
+    type Output = UVec3;
+    #[inline]
+    fn rem(self, rhs: UVec3) -> UVec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u32; 3]> for UVec3 {
     #[inline]
@@ -1145,14 +1667,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for UVec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for UVec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(UVec3))
@@ -1198,6 +1718,13 @@
     }
 }
 
+impl From<U8Vec3> for UVec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(u32::from(v.x), u32::from(v.y), u32::from(v.z))
+    }
+}
+
 impl From<U16Vec3> for UVec3 {
     #[inline]
     fn from(v: U16Vec3) -> Self {
@@ -1205,6 +1732,19 @@
     }
 }
 
+impl TryFrom<I8Vec3> for UVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec3> for UVec3 {
     type Error = core::num::TryFromIntError;
 
@@ -1256,3 +1796,22 @@
         ))
     }
 }
+
+impl From<BVec3> for UVec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(u32::from(v.x), u32::from(v.y), u32::from(v.z))
+    }
+}
+
+impl From<BVec3A> for UVec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            u32::from(bool_array[0]),
+            u32::from(bool_array[1]),
+            u32::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/u32/uvec4.rs b/crates/glam/src/u32/uvec4.rs
index 1e64072..f02182f 100644
--- a/crates/glam/src/u32/uvec4.rs
+++ b/crates/glam/src/u32/uvec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec2, UVec3};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec2, UVec3};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -77,6 +78,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -115,6 +126,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u32]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -125,10 +137,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u32]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -141,6 +150,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u32) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u32) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u32) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: u32) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -215,6 +256,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u32 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u32 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -333,6 +392,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -479,6 +552,34 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: IVec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+            w: self.w.wrapping_add_signed(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: IVec4) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+            w: self.w.saturating_add_signed(rhs.w),
+        }
+    }
 }
 
 impl Default for UVec4 {
@@ -501,6 +602,30 @@
     }
 }
 
+impl Div<&UVec4> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &UVec4) -> UVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &UVec4) -> UVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: UVec4) -> UVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<UVec4> for UVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -511,6 +636,13 @@
     }
 }
 
+impl DivAssign<&Self> for UVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u32> for UVec4 {
     type Output = Self;
     #[inline]
@@ -524,6 +656,30 @@
     }
 }
 
+impl Div<&u32> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &u32) -> UVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: u32) -> UVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u32> for UVec4 {
     #[inline]
     fn div_assign(&mut self, rhs: u32) {
@@ -534,6 +690,13 @@
     }
 }
 
+impl DivAssign<&u32> for UVec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u32) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<UVec4> for u32 {
     type Output = UVec4;
     #[inline]
@@ -547,6 +710,30 @@
     }
 }
 
+impl Div<&UVec4> for u32 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &UVec4) -> UVec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: &UVec4) -> UVec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn div(self, rhs: UVec4) -> UVec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<UVec4> for UVec4 {
     type Output = Self;
     #[inline]
@@ -560,6 +747,30 @@
     }
 }
 
+impl Mul<&UVec4> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &UVec4) -> UVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &UVec4) -> UVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: UVec4) -> UVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<UVec4> for UVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -570,6 +781,13 @@
     }
 }
 
+impl MulAssign<&Self> for UVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u32> for UVec4 {
     type Output = Self;
     #[inline]
@@ -583,6 +801,30 @@
     }
 }
 
+impl Mul<&u32> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &u32) -> UVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: u32) -> UVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u32> for UVec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: u32) {
@@ -593,6 +835,13 @@
     }
 }
 
+impl MulAssign<&u32> for UVec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u32) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<UVec4> for u32 {
     type Output = UVec4;
     #[inline]
@@ -606,6 +855,30 @@
     }
 }
 
+impl Mul<&UVec4> for u32 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &UVec4) -> UVec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: &UVec4) -> UVec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn mul(self, rhs: UVec4) -> UVec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<UVec4> for UVec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +892,30 @@
     }
 }
 
+impl Add<&UVec4> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &UVec4) -> UVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &UVec4) -> UVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: UVec4) -> UVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<UVec4> for UVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -629,6 +926,13 @@
     }
 }
 
+impl AddAssign<&Self> for UVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u32> for UVec4 {
     type Output = Self;
     #[inline]
@@ -642,6 +946,30 @@
     }
 }
 
+impl Add<&u32> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &u32) -> UVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: u32) -> UVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u32> for UVec4 {
     #[inline]
     fn add_assign(&mut self, rhs: u32) {
@@ -652,6 +980,13 @@
     }
 }
 
+impl AddAssign<&u32> for UVec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u32) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<UVec4> for u32 {
     type Output = UVec4;
     #[inline]
@@ -665,6 +1000,30 @@
     }
 }
 
+impl Add<&UVec4> for u32 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &UVec4) -> UVec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: &UVec4) -> UVec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn add(self, rhs: UVec4) -> UVec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<UVec4> for UVec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +1037,30 @@
     }
 }
 
+impl Sub<&UVec4> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &UVec4) -> UVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &UVec4) -> UVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: UVec4) -> UVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<UVec4> for UVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: UVec4) {
@@ -688,6 +1071,13 @@
     }
 }
 
+impl SubAssign<&Self> for UVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u32> for UVec4 {
     type Output = Self;
     #[inline]
@@ -701,6 +1091,30 @@
     }
 }
 
+impl Sub<&u32> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &u32) -> UVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: u32) -> UVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u32> for UVec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: u32) {
@@ -711,6 +1125,13 @@
     }
 }
 
+impl SubAssign<&u32> for UVec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u32) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<UVec4> for u32 {
     type Output = UVec4;
     #[inline]
@@ -724,6 +1145,30 @@
     }
 }
 
+impl Sub<&UVec4> for u32 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &UVec4) -> UVec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: &UVec4) -> UVec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn sub(self, rhs: UVec4) -> UVec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<UVec4> for UVec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1182,30 @@
     }
 }
 
+impl Rem<&UVec4> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &UVec4) -> UVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &UVec4) -> UVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec4> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: UVec4) -> UVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<UVec4> for UVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -747,6 +1216,13 @@
     }
 }
 
+impl RemAssign<&Self> for UVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u32> for UVec4 {
     type Output = Self;
     #[inline]
@@ -760,6 +1236,30 @@
     }
 }
 
+impl Rem<&u32> for UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &u32) -> UVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u32> for &UVec4 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: u32) -> UVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u32> for UVec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: u32) {
@@ -770,6 +1270,13 @@
     }
 }
 
+impl RemAssign<&u32> for UVec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u32) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<UVec4> for u32 {
     type Output = UVec4;
     #[inline]
@@ -783,6 +1290,30 @@
     }
 }
 
+impl Rem<&UVec4> for u32 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &UVec4) -> UVec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: &UVec4) -> UVec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<UVec4> for &u32 {
+    type Output = UVec4;
+    #[inline]
+    fn rem(self, rhs: UVec4) -> UVec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u32; 4]> for UVec4 {
     #[inline]
@@ -1217,14 +1748,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for UVec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for UVec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(UVec4))
@@ -1292,6 +1821,18 @@
     }
 }
 
+impl From<U8Vec4> for UVec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            u32::from(v.x),
+            u32::from(v.y),
+            u32::from(v.z),
+            u32::from(v.w),
+        )
+    }
+}
+
 impl From<U16Vec4> for UVec4 {
     #[inline]
     fn from(v: U16Vec4) -> Self {
@@ -1304,6 +1845,20 @@
     }
 }
 
+impl TryFrom<I8Vec4> for UVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+            u32::try_from(v.w)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec4> for UVec4 {
     type Error = core::num::TryFromIntError;
 
@@ -1359,3 +1914,30 @@
         ))
     }
 }
+
+impl From<BVec4> for UVec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            u32::from(v.x),
+            u32::from(v.y),
+            u32::from(v.z),
+            u32::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for UVec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            u32::from(bool_array[0]),
+            u32::from(bool_array[1]),
+            u32::from(bool_array[2]),
+            u32::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/u64/u64vec2.rs b/crates/glam/src/u64/u64vec2.rs
index 4f74652..83f333b 100644
--- a/crates/glam/src/u64/u64vec2.rs
+++ b/crates/glam/src/u64/u64vec2.rs
@@ -1,8 +1,7 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U64Vec3, UVec2};
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec3, U8Vec2, UVec2};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -61,6 +60,16 @@
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -97,6 +106,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u64]) -> Self {
+        assert!(slice.len() >= 2);
         Self::new(slice[0], slice[1])
     }
 
@@ -107,8 +117,7 @@
     /// Panics if `slice` is less than 2 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
+        slice[..2].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from `self` and the given `z` value.
@@ -118,6 +127,22 @@
         U64Vec3::new(self.x, self.y, z)
     }
 
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u64) -> Self {
+        self.y = y;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -188,6 +213,24 @@
         self.x.max(self.y)
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u64 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u64 {
+        self.x * self.y
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -276,6 +319,20 @@
         crate::DVec2::new(self.x as f64, self.y as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec2(&self) -> crate::U8Vec2 {
+        crate::U8Vec2::new(self.x as u8, self.y as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -406,6 +463,30 @@
             y: self.y.saturating_div(rhs.y),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I64Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I64Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+        }
+    }
 }
 
 impl Default for U64Vec2 {
@@ -426,6 +507,30 @@
     }
 }
 
+impl Div<&U64Vec2> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U64Vec2> for U64Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -434,6 +539,13 @@
     }
 }
 
+impl DivAssign<&Self> for U64Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u64> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -445,6 +557,30 @@
     }
 }
 
+impl Div<&u64> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: u64) -> U64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u64> for U64Vec2 {
     #[inline]
     fn div_assign(&mut self, rhs: u64) {
@@ -453,6 +589,13 @@
     }
 }
 
+impl DivAssign<&u64> for U64Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U64Vec2> for u64 {
     type Output = U64Vec2;
     #[inline]
@@ -464,6 +607,30 @@
     }
 }
 
+impl Div<&U64Vec2> for u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn div(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U64Vec2> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -475,6 +642,30 @@
     }
 }
 
+impl Mul<&U64Vec2> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U64Vec2> for U64Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -483,6 +674,13 @@
     }
 }
 
+impl MulAssign<&Self> for U64Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u64> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -494,6 +692,30 @@
     }
 }
 
+impl Mul<&u64> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: u64) -> U64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u64> for U64Vec2 {
     #[inline]
     fn mul_assign(&mut self, rhs: u64) {
@@ -502,6 +724,13 @@
     }
 }
 
+impl MulAssign<&u64> for U64Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U64Vec2> for u64 {
     type Output = U64Vec2;
     #[inline]
@@ -513,6 +742,30 @@
     }
 }
 
+impl Mul<&U64Vec2> for u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn mul(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U64Vec2> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -524,6 +777,30 @@
     }
 }
 
+impl Add<&U64Vec2> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U64Vec2> for U64Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -532,6 +809,13 @@
     }
 }
 
+impl AddAssign<&Self> for U64Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u64> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -543,6 +827,30 @@
     }
 }
 
+impl Add<&u64> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: u64) -> U64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u64> for U64Vec2 {
     #[inline]
     fn add_assign(&mut self, rhs: u64) {
@@ -551,6 +859,13 @@
     }
 }
 
+impl AddAssign<&u64> for U64Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U64Vec2> for u64 {
     type Output = U64Vec2;
     #[inline]
@@ -562,6 +877,30 @@
     }
 }
 
+impl Add<&U64Vec2> for u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn add(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U64Vec2> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -573,6 +912,30 @@
     }
 }
 
+impl Sub<&U64Vec2> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U64Vec2> for U64Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: U64Vec2) {
@@ -581,6 +944,13 @@
     }
 }
 
+impl SubAssign<&Self> for U64Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u64> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -592,6 +962,30 @@
     }
 }
 
+impl Sub<&u64> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: u64) -> U64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u64> for U64Vec2 {
     #[inline]
     fn sub_assign(&mut self, rhs: u64) {
@@ -600,6 +994,13 @@
     }
 }
 
+impl SubAssign<&u64> for U64Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U64Vec2> for u64 {
     type Output = U64Vec2;
     #[inline]
@@ -611,6 +1012,30 @@
     }
 }
 
+impl Sub<&U64Vec2> for u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn sub(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U64Vec2> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -622,6 +1047,30 @@
     }
 }
 
+impl Rem<&U64Vec2> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec2> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U64Vec2> for U64Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -630,6 +1079,13 @@
     }
 }
 
+impl RemAssign<&Self> for U64Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u64> for U64Vec2 {
     type Output = Self;
     #[inline]
@@ -641,6 +1097,30 @@
     }
 }
 
+impl Rem<&u64> for U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u64> for &U64Vec2 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: u64) -> U64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u64> for U64Vec2 {
     #[inline]
     fn rem_assign(&mut self, rhs: u64) {
@@ -649,6 +1129,13 @@
     }
 }
 
+impl RemAssign<&u64> for U64Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U64Vec2> for u64 {
     type Output = U64Vec2;
     #[inline]
@@ -660,6 +1147,30 @@
     }
 }
 
+impl Rem<&U64Vec2> for u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &U64Vec2) -> U64Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: &U64Vec2) -> U64Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec2> for &u64 {
+    type Output = U64Vec2;
+    #[inline]
+    fn rem(self, rhs: U64Vec2) -> U64Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u64; 2]> for U64Vec2 {
     #[inline]
@@ -1036,14 +1547,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U64Vec2 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}]", self.x, self.y)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U64Vec2 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U64Vec2))
@@ -1081,6 +1590,13 @@
     }
 }
 
+impl From<U8Vec2> for U64Vec2 {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y))
+    }
+}
+
 impl From<U16Vec2> for U64Vec2 {
     #[inline]
     fn from(v: U16Vec2) -> Self {
@@ -1095,6 +1611,15 @@
     }
 }
 
+impl TryFrom<I8Vec2> for U64Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u64::try_from(v.x)?, u64::try_from(v.y)?))
+    }
+}
+
 impl TryFrom<I16Vec2> for U64Vec2 {
     type Error = core::num::TryFromIntError;
 
@@ -1121,3 +1646,10 @@
         Ok(Self::new(u64::try_from(v.x)?, u64::try_from(v.y)?))
     }
 }
+
+impl From<BVec2> for U64Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y))
+    }
+}
diff --git a/crates/glam/src/u64/u64vec3.rs b/crates/glam/src/u64/u64vec3.rs
index 7411bff..585fbb5 100644
--- a/crates/glam/src/u64/u64vec3.rs
+++ b/crates/glam/src/u64/u64vec3.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec2, U64Vec4, UVec3};
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec2, U64Vec4, U8Vec3, UVec3,
+};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -64,6 +65,16 @@
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -101,6 +112,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u64]) -> Self {
+        assert!(slice.len() >= 3);
         Self::new(slice[0], slice[1], slice[2])
     }
 
@@ -111,9 +123,7 @@
     /// Panics if `slice` is less than 3 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
+        slice[..3].copy_from_slice(&self.to_array());
     }
 
     /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
@@ -145,6 +155,30 @@
         self.xy()
     }
 
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u64) -> Self {
+        self.z = z;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -228,6 +262,24 @@
         self.x.max(self.y.max(self.z))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u64 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u64 {
+        self.x * self.y * self.z
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -323,6 +375,20 @@
         crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec3(&self) -> crate::U8Vec3 {
+        crate::U8Vec3::new(self.x as u8, self.y as u8, self.z as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -461,6 +527,32 @@
             z: self.z.saturating_div(rhs.z),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I64Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I64Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+        }
+    }
 }
 
 impl Default for U64Vec3 {
@@ -482,6 +574,30 @@
     }
 }
 
+impl Div<&U64Vec3> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U64Vec3> for U64Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -491,6 +607,13 @@
     }
 }
 
+impl DivAssign<&Self> for U64Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u64> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -503,6 +626,30 @@
     }
 }
 
+impl Div<&u64> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: u64) -> U64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u64> for U64Vec3 {
     #[inline]
     fn div_assign(&mut self, rhs: u64) {
@@ -512,6 +659,13 @@
     }
 }
 
+impl DivAssign<&u64> for U64Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U64Vec3> for u64 {
     type Output = U64Vec3;
     #[inline]
@@ -524,6 +678,30 @@
     }
 }
 
+impl Div<&U64Vec3> for u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn div(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U64Vec3> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -536,6 +714,30 @@
     }
 }
 
+impl Mul<&U64Vec3> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U64Vec3> for U64Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -545,6 +747,13 @@
     }
 }
 
+impl MulAssign<&Self> for U64Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u64> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -557,6 +766,30 @@
     }
 }
 
+impl Mul<&u64> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: u64) -> U64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u64> for U64Vec3 {
     #[inline]
     fn mul_assign(&mut self, rhs: u64) {
@@ -566,6 +799,13 @@
     }
 }
 
+impl MulAssign<&u64> for U64Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U64Vec3> for u64 {
     type Output = U64Vec3;
     #[inline]
@@ -578,6 +818,30 @@
     }
 }
 
+impl Mul<&U64Vec3> for u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn mul(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U64Vec3> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -590,6 +854,30 @@
     }
 }
 
+impl Add<&U64Vec3> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U64Vec3> for U64Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -599,6 +887,13 @@
     }
 }
 
+impl AddAssign<&Self> for U64Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u64> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -611,6 +906,30 @@
     }
 }
 
+impl Add<&u64> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: u64) -> U64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u64> for U64Vec3 {
     #[inline]
     fn add_assign(&mut self, rhs: u64) {
@@ -620,6 +939,13 @@
     }
 }
 
+impl AddAssign<&u64> for U64Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U64Vec3> for u64 {
     type Output = U64Vec3;
     #[inline]
@@ -632,6 +958,30 @@
     }
 }
 
+impl Add<&U64Vec3> for u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn add(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U64Vec3> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -644,6 +994,30 @@
     }
 }
 
+impl Sub<&U64Vec3> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U64Vec3> for U64Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: U64Vec3) {
@@ -653,6 +1027,13 @@
     }
 }
 
+impl SubAssign<&Self> for U64Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u64> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -665,6 +1046,30 @@
     }
 }
 
+impl Sub<&u64> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: u64) -> U64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u64> for U64Vec3 {
     #[inline]
     fn sub_assign(&mut self, rhs: u64) {
@@ -674,6 +1079,13 @@
     }
 }
 
+impl SubAssign<&u64> for U64Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U64Vec3> for u64 {
     type Output = U64Vec3;
     #[inline]
@@ -686,6 +1098,30 @@
     }
 }
 
+impl Sub<&U64Vec3> for u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn sub(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U64Vec3> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -698,6 +1134,30 @@
     }
 }
 
+impl Rem<&U64Vec3> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec3> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U64Vec3> for U64Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -707,6 +1167,13 @@
     }
 }
 
+impl RemAssign<&Self> for U64Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u64> for U64Vec3 {
     type Output = Self;
     #[inline]
@@ -719,6 +1186,30 @@
     }
 }
 
+impl Rem<&u64> for U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u64> for &U64Vec3 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: u64) -> U64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u64> for U64Vec3 {
     #[inline]
     fn rem_assign(&mut self, rhs: u64) {
@@ -728,6 +1219,13 @@
     }
 }
 
+impl RemAssign<&u64> for U64Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U64Vec3> for u64 {
     type Output = U64Vec3;
     #[inline]
@@ -740,6 +1238,30 @@
     }
 }
 
+impl Rem<&U64Vec3> for u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &U64Vec3) -> U64Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: &U64Vec3) -> U64Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec3> for &u64 {
+    type Output = U64Vec3;
+    #[inline]
+    fn rem(self, rhs: U64Vec3) -> U64Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u64; 3]> for U64Vec3 {
     #[inline]
@@ -1145,14 +1667,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U64Vec3 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U64Vec3 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U64Vec3))
@@ -1198,6 +1718,13 @@
     }
 }
 
+impl From<U8Vec3> for U64Vec3 {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y), u64::from(v.z))
+    }
+}
+
 impl From<U16Vec3> for U64Vec3 {
     #[inline]
     fn from(v: U16Vec3) -> Self {
@@ -1212,6 +1739,19 @@
     }
 }
 
+impl TryFrom<I8Vec3> for U64Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u64::try_from(v.x)?,
+            u64::try_from(v.y)?,
+            u64::try_from(v.z)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec3> for U64Vec3 {
     type Error = core::num::TryFromIntError;
 
@@ -1250,3 +1790,22 @@
         ))
     }
 }
+
+impl From<BVec3> for U64Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y), u64::from(v.z))
+    }
+}
+
+impl From<BVec3A> for U64Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            u64::from(bool_array[0]),
+            u64::from(bool_array[1]),
+            u64::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/u64/u64vec4.rs b/crates/glam/src/u64/u64vec4.rs
index 91df699..07ce227 100644
--- a/crates/glam/src/u64/u64vec4.rs
+++ b/crates/glam/src/u64/u64vec4.rs
@@ -1,8 +1,9 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec2, U64Vec3, UVec4};
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec2, U64Vec3, U8Vec4, UVec4};
 
-#[cfg(not(target_arch = "spirv"))]
 use core::fmt;
 use core::iter::{Product, Sum};
 use core::{f32, ops::*};
@@ -77,6 +78,16 @@
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
@@ -115,6 +126,7 @@
     #[inline]
     #[must_use]
     pub const fn from_slice(slice: &[u64]) -> Self {
+        assert!(slice.len() >= 4);
         Self::new(slice[0], slice[1], slice[2], slice[3])
     }
 
@@ -125,10 +137,7 @@
     /// Panics if `slice` is less than 4 elements long.
     #[inline]
     pub fn write_to_slice(self, slice: &mut [u64]) {
-        slice[0] = self.x;
-        slice[1] = self.y;
-        slice[2] = self.z;
-        slice[3] = self.w;
+        slice[..4].copy_from_slice(&self.to_array());
     }
 
     /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
@@ -141,6 +150,38 @@
         self.xyz()
     }
 
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u64) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u64) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u64) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: u64) -> Self {
+        self.w = w;
+        self
+    }
+
     /// Computes the dot product of `self` and `rhs`.
     #[inline]
     #[must_use]
@@ -215,6 +256,24 @@
         self.x.max(self.y.max(self.z.max(self.w)))
     }
 
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u64 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u64 {
+        self.x * self.y * self.z * self.w
+    }
+
     /// Returns a vector mask containing the result of a `==` comparison for each element of
     /// `self` and `rhs`.
     ///
@@ -333,6 +392,20 @@
         crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
     }
 
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `u8`.
+    #[inline]
+    #[must_use]
+    pub fn as_u8vec4(&self) -> crate::U8Vec4 {
+        crate::U8Vec4::new(self.x as u8, self.y as u8, self.z as u8, self.w as u8)
+    }
+
     /// Casts all elements of `self` to `i16`.
     #[inline]
     #[must_use]
@@ -479,6 +552,34 @@
             w: self.w.saturating_div(rhs.w),
         }
     }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I64Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+            w: self.w.wrapping_add_signed(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I64Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+            w: self.w.saturating_add_signed(rhs.w),
+        }
+    }
 }
 
 impl Default for U64Vec4 {
@@ -501,6 +602,30 @@
     }
 }
 
+impl Div<&U64Vec4> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<U64Vec4> for U64Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
@@ -511,6 +636,13 @@
     }
 }
 
+impl DivAssign<&Self> for U64Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<u64> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -524,6 +656,30 @@
     }
 }
 
+impl Div<&u64> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &u64) -> U64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: u64) -> U64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl DivAssign<u64> for U64Vec4 {
     #[inline]
     fn div_assign(&mut self, rhs: u64) {
@@ -534,6 +690,13 @@
     }
 }
 
+impl DivAssign<&u64> for U64Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u64) {
+        self.div_assign(*rhs)
+    }
+}
+
 impl Div<U64Vec4> for u64 {
     type Output = U64Vec4;
     #[inline]
@@ -547,6 +710,30 @@
     }
 }
 
+impl Div<&U64Vec4> for u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn div(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).div(rhs)
+    }
+}
+
 impl Mul<U64Vec4> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -560,6 +747,30 @@
     }
 }
 
+impl Mul<&U64Vec4> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<U64Vec4> for U64Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
@@ -570,6 +781,13 @@
     }
 }
 
+impl MulAssign<&Self> for U64Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<u64> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -583,6 +801,30 @@
     }
 }
 
+impl Mul<&u64> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &u64) -> U64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: u64) -> U64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl MulAssign<u64> for U64Vec4 {
     #[inline]
     fn mul_assign(&mut self, rhs: u64) {
@@ -593,6 +835,13 @@
     }
 }
 
+impl MulAssign<&u64> for U64Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u64) {
+        self.mul_assign(*rhs)
+    }
+}
+
 impl Mul<U64Vec4> for u64 {
     type Output = U64Vec4;
     #[inline]
@@ -606,6 +855,30 @@
     }
 }
 
+impl Mul<&U64Vec4> for u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn mul(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
 impl Add<U64Vec4> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -619,6 +892,30 @@
     }
 }
 
+impl Add<&U64Vec4> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<U64Vec4> for U64Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
@@ -629,6 +926,13 @@
     }
 }
 
+impl AddAssign<&Self> for U64Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<u64> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -642,6 +946,30 @@
     }
 }
 
+impl Add<&u64> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &u64) -> U64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: u64) -> U64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl AddAssign<u64> for U64Vec4 {
     #[inline]
     fn add_assign(&mut self, rhs: u64) {
@@ -652,6 +980,13 @@
     }
 }
 
+impl AddAssign<&u64> for U64Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u64) {
+        self.add_assign(*rhs)
+    }
+}
+
 impl Add<U64Vec4> for u64 {
     type Output = U64Vec4;
     #[inline]
@@ -665,6 +1000,30 @@
     }
 }
 
+impl Add<&U64Vec4> for u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn add(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).add(rhs)
+    }
+}
+
 impl Sub<U64Vec4> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -678,6 +1037,30 @@
     }
 }
 
+impl Sub<&U64Vec4> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<U64Vec4> for U64Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: U64Vec4) {
@@ -688,6 +1071,13 @@
     }
 }
 
+impl SubAssign<&Self> for U64Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<u64> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -701,6 +1091,30 @@
     }
 }
 
+impl Sub<&u64> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &u64) -> U64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: u64) -> U64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl SubAssign<u64> for U64Vec4 {
     #[inline]
     fn sub_assign(&mut self, rhs: u64) {
@@ -711,6 +1125,13 @@
     }
 }
 
+impl SubAssign<&u64> for U64Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u64) {
+        self.sub_assign(*rhs)
+    }
+}
+
 impl Sub<U64Vec4> for u64 {
     type Output = U64Vec4;
     #[inline]
@@ -724,6 +1145,30 @@
     }
 }
 
+impl Sub<&U64Vec4> for u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn sub(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
 impl Rem<U64Vec4> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -737,6 +1182,30 @@
     }
 }
 
+impl Rem<&U64Vec4> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec4> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<U64Vec4> for U64Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
@@ -747,6 +1216,13 @@
     }
 }
 
+impl RemAssign<&Self> for U64Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<u64> for U64Vec4 {
     type Output = Self;
     #[inline]
@@ -760,6 +1236,30 @@
     }
 }
 
+impl Rem<&u64> for U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &u64) -> U64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u64> for &U64Vec4 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: u64) -> U64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 impl RemAssign<u64> for U64Vec4 {
     #[inline]
     fn rem_assign(&mut self, rhs: u64) {
@@ -770,6 +1270,13 @@
     }
 }
 
+impl RemAssign<&u64> for U64Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u64) {
+        self.rem_assign(*rhs)
+    }
+}
+
 impl Rem<U64Vec4> for u64 {
     type Output = U64Vec4;
     #[inline]
@@ -783,6 +1290,30 @@
     }
 }
 
+impl Rem<&U64Vec4> for u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &U64Vec4) -> U64Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: &U64Vec4) -> U64Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U64Vec4> for &u64 {
+    type Output = U64Vec4;
+    #[inline]
+    fn rem(self, rhs: U64Vec4) -> U64Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
 #[cfg(not(target_arch = "spirv"))]
 impl AsRef<[u64; 4]> for U64Vec4 {
     #[inline]
@@ -1217,14 +1748,12 @@
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Display for U64Vec4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
     }
 }
 
-#[cfg(not(target_arch = "spirv"))]
 impl fmt::Debug for U64Vec4 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_tuple(stringify!(U64Vec4))
@@ -1292,6 +1821,18 @@
     }
 }
 
+impl From<U8Vec4> for U64Vec4 {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        Self::new(
+            u64::from(v.x),
+            u64::from(v.y),
+            u64::from(v.z),
+            u64::from(v.w),
+        )
+    }
+}
+
 impl From<U16Vec4> for U64Vec4 {
     #[inline]
     fn from(v: U16Vec4) -> Self {
@@ -1316,6 +1857,20 @@
     }
 }
 
+impl TryFrom<I8Vec4> for U64Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u64::try_from(v.x)?,
+            u64::try_from(v.y)?,
+            u64::try_from(v.z)?,
+            u64::try_from(v.w)?,
+        ))
+    }
+}
+
 impl TryFrom<I16Vec4> for U64Vec4 {
     type Error = core::num::TryFromIntError;
 
@@ -1357,3 +1912,30 @@
         ))
     }
 }
+
+impl From<BVec4> for U64Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(
+            u64::from(v.x),
+            u64::from(v.y),
+            u64::from(v.z),
+            u64::from(v.w),
+        )
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for U64Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            u64::from(bool_array[0]),
+            u64::from(bool_array[1]),
+            u64::from(bool_array[2]),
+            u64::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/src/u8.rs b/crates/glam/src/u8.rs
new file mode 100644
index 0000000..d977e36
--- /dev/null
+++ b/crates/glam/src/u8.rs
@@ -0,0 +1,44 @@
+mod u8vec2;
+mod u8vec3;
+mod u8vec4;
+
+pub use u8vec2::{u8vec2, U8Vec2};
+pub use u8vec3::{u8vec3, U8Vec3};
+pub use u8vec4::{u8vec4, U8Vec4};
+
+#[cfg(not(target_arch = "spirv"))]
+mod test {
+    use super::*;
+
+    mod const_test_u8vec2 {
+        const_assert_eq!(2, core::mem::size_of::<super::U8Vec2>());
+
+        #[cfg(not(feature = "cuda"))]
+        const_assert_eq!(
+            core::mem::align_of::<u8>(),
+            core::mem::align_of::<super::U8Vec2>()
+        );
+        #[cfg(feature = "cuda")]
+        const_assert_eq!(2, core::mem::align_of::<super::U8Vec2>());
+    }
+
+    mod const_test_u8vec3 {
+        const_assert_eq!(
+            core::mem::align_of::<u8>(),
+            core::mem::align_of::<super::U8Vec3>()
+        );
+        const_assert_eq!(3, core::mem::size_of::<super::U8Vec3>());
+    }
+
+    mod const_test_u8vec4 {
+        const_assert_eq!(4, core::mem::size_of::<super::U8Vec4>());
+
+        #[cfg(not(feature = "cuda"))]
+        const_assert_eq!(
+            core::mem::align_of::<u8>(),
+            core::mem::align_of::<super::U8Vec4>()
+        );
+        #[cfg(feature = "cuda")]
+        const_assert_eq!(4, core::mem::align_of::<super::U8Vec4>());
+    }
+}
diff --git a/crates/glam/src/u8/u8vec2.rs b/crates/glam/src/u8/u8vec2.rs
new file mode 100644
index 0000000..cf2c1bb
--- /dev/null
+++ b/crates/glam/src/u8/u8vec2.rs
@@ -0,0 +1,1661 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec3, UVec2};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 2-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn u8vec2(x: u8, y: u8) -> U8Vec2 {
+    U8Vec2::new(x, y)
+}
+
+/// A 2-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "cuda", repr(align(2)))]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct U8Vec2 {
+    pub x: u8,
+    pub y: u8,
+}
+
+impl U8Vec2 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All `u8::MIN`.
+    pub const MIN: Self = Self::splat(u8::MIN);
+
+    /// All `u8::MAX`.
+    pub const MAX: Self = Self::splat(u8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 2] = [Self::X, Self::Y];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: u8, y: u8) -> Self {
+        Self { x, y }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: u8) -> Self {
+        Self { x: v, y: v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u8) -> u8,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [u8; 2]) -> Self {
+        Self::new(a[0], a[1])
+    }
+
+    /// `[x, y]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [u8; 2] {
+        [self.x, self.y]
+    }
+
+    /// Creates a vector from the first 2 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[u8]) -> Self {
+        assert!(slice.len() >= 2);
+        Self::new(slice[0], slice[1])
+    }
+
+    /// Writes the elements of `self` to the first 2 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [u8]) {
+        slice[..2].copy_from_slice(&self.to_array());
+    }
+
+    /// Creates a 3D vector from `self` and the given `z` value.
+    #[inline]
+    #[must_use]
+    pub const fn extend(self, z: u8) -> U8Vec3 {
+        U8Vec3::new(self.x, self.y, z)
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 2D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> u8 {
+        (self.x * rhs.x) + (self.y * rhs.y)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`u8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> u8 {
+        self.x.min(self.y)
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> u8 {
+        self.x.max(self.y)
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u8 {
+        self.x + self.y
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u8 {
+        self.x * self.y
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.le(&rhs.x), self.y.le(&rhs.y))
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec2 {
+        BVec2::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y))
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> u8 {
+        self.dot(self)
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec2(&self) -> crate::Vec2 {
+        crate::Vec2::new(self.x as f32, self.y as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec2(&self) -> crate::DVec2 {
+        crate::DVec2::new(self.x as f64, self.y as f64)
+    }
+
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec2(&self) -> crate::I8Vec2 {
+        crate::I8Vec2::new(self.x as i8, self.y as i8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec2(&self) -> crate::I16Vec2 {
+        crate::I16Vec2::new(self.x as i16, self.y as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec2(&self) -> crate::U16Vec2 {
+        crate::U16Vec2::new(self.x as u16, self.y as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec2(&self) -> crate::IVec2 {
+        crate::IVec2::new(self.x as i32, self.y as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec2(&self) -> crate::UVec2 {
+        crate::UVec2::new(self.x as u32, self.y as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec2(&self) -> crate::I64Vec2 {
+        crate::I64Vec2::new(self.x as i64, self.y as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec2(&self) -> crate::U64Vec2 {
+        crate::U64Vec2::new(self.x as u64, self.y as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I8Vec2) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I8Vec2) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+        }
+    }
+}
+
+impl Default for U8Vec2 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<U8Vec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+        }
+    }
+}
+
+impl Div<&U8Vec2> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<U8Vec2> for U8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+    }
+}
+
+impl DivAssign<&Self> for U8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+        }
+    }
+}
+
+impl Div<&u8> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: u8) -> U8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<u8> for U8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: u8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&u8> for U8Vec2 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: U8Vec2) -> U8Vec2 {
+        U8Vec2 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+        }
+    }
+}
+
+impl Div<&U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn div(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<U8Vec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+        }
+    }
+}
+
+impl Mul<&U8Vec2> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<U8Vec2> for U8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+    }
+}
+
+impl MulAssign<&Self> for U8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&u8> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: u8) -> U8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<u8> for U8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: u8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&u8> for U8Vec2 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: U8Vec2) -> U8Vec2 {
+        U8Vec2 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+        }
+    }
+}
+
+impl Mul<&U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn mul(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<U8Vec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+        }
+    }
+}
+
+impl Add<&U8Vec2> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<U8Vec2> for U8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+    }
+}
+
+impl AddAssign<&Self> for U8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+        }
+    }
+}
+
+impl Add<&u8> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: u8) -> U8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<u8> for U8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: u8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&u8> for U8Vec2 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: U8Vec2) -> U8Vec2 {
+        U8Vec2 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+        }
+    }
+}
+
+impl Add<&U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn add(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<U8Vec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+        }
+    }
+}
+
+impl Sub<&U8Vec2> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<U8Vec2> for U8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: U8Vec2) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+    }
+}
+
+impl SubAssign<&Self> for U8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&u8> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: u8) -> U8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<u8> for U8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: u8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&u8> for U8Vec2 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: U8Vec2) -> U8Vec2 {
+        U8Vec2 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+        }
+    }
+}
+
+impl Sub<&U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn sub(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<U8Vec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+        }
+    }
+}
+
+impl Rem<&U8Vec2> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec2> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<U8Vec2> for U8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+    }
+}
+
+impl RemAssign<&Self> for U8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&u8> for U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u8> for &U8Vec2 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: u8) -> U8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<u8> for U8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: u8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&u8> for U8Vec2 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: U8Vec2) -> U8Vec2 {
+        U8Vec2 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+        }
+    }
+}
+
+impl Rem<&U8Vec2> for u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &U8Vec2) -> U8Vec2 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: &U8Vec2) -> U8Vec2 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec2> for &u8 {
+    type Output = U8Vec2;
+    #[inline]
+    fn rem(self, rhs: U8Vec2) -> U8Vec2 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[u8; 2]> for U8Vec2 {
+    #[inline]
+    fn as_ref(&self) -> &[u8; 2] {
+        unsafe { &*(self as *const U8Vec2 as *const [u8; 2]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[u8; 2]> for U8Vec2 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8; 2] {
+        unsafe { &mut *(self as *mut U8Vec2 as *mut [u8; 2]) }
+    }
+}
+
+impl Sum for U8Vec2 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for U8Vec2 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for U8Vec2 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for U8Vec2 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Not for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+        }
+    }
+}
+
+impl BitAnd for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+        }
+    }
+}
+
+impl BitOr for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+        }
+    }
+}
+
+impl BitXor for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+        }
+    }
+}
+
+impl BitAnd<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec2) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+        }
+    }
+}
+
+impl Shr<crate::IVec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec2) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+        }
+    }
+}
+
+impl Shl<crate::UVec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec2) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+        }
+    }
+}
+
+impl Shr<crate::UVec2> for U8Vec2 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec2) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+        }
+    }
+}
+
+impl Index<usize> for U8Vec2 {
+    type Output = u8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for U8Vec2 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for U8Vec2 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}]", self.x, self.y)
+    }
+}
+
+impl fmt::Debug for U8Vec2 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(U8Vec2))
+            .field(&self.x)
+            .field(&self.y)
+            .finish()
+    }
+}
+
+impl From<[u8; 2]> for U8Vec2 {
+    #[inline]
+    fn from(a: [u8; 2]) -> Self {
+        Self::new(a[0], a[1])
+    }
+}
+
+impl From<U8Vec2> for [u8; 2] {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        [v.x, v.y]
+    }
+}
+
+impl From<(u8, u8)> for U8Vec2 {
+    #[inline]
+    fn from(t: (u8, u8)) -> Self {
+        Self::new(t.0, t.1)
+    }
+}
+
+impl From<U8Vec2> for (u8, u8) {
+    #[inline]
+    fn from(v: U8Vec2) -> Self {
+        (v.x, v.y)
+    }
+}
+
+impl TryFrom<I8Vec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I16Vec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U16Vec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<IVec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<UVec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I64Vec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U64Vec2> for U8Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u8::try_from(v.x)?, u8::try_from(v.y)?))
+    }
+}
+
+impl From<BVec2> for U8Vec2 {
+    #[inline]
+    fn from(v: BVec2) -> Self {
+        Self::new(u8::from(v.x), u8::from(v.y))
+    }
+}
diff --git a/crates/glam/src/u8/u8vec3.rs b/crates/glam/src/u8/u8vec3.rs
new file mode 100644
index 0000000..09ba3f4
--- /dev/null
+++ b/crates/glam/src/u8/u8vec3.rs
@@ -0,0 +1,1829 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+use crate::{
+    BVec3, BVec3A, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec2, U8Vec4, UVec3,
+};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 3-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn u8vec3(x: u8, y: u8, z: u8) -> U8Vec3 {
+    U8Vec3::new(x, y, z)
+}
+
+/// A 3-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct U8Vec3 {
+    pub x: u8,
+    pub y: u8,
+    pub z: u8,
+}
+
+impl U8Vec3 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All `u8::MIN`.
+    pub const MIN: Self = Self::splat(u8::MIN);
+
+    /// All `u8::MAX`.
+    pub const MAX: Self = Self::splat(u8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1, 0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0, 0, 1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: u8, y: u8, z: u8) -> Self {
+        Self { x, y, z }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: u8) -> Self {
+        Self { x: v, y: v, z: v }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u8) -> u8,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec3, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+            z: if mask.test(2) { if_true.z } else { if_false.z },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [u8; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+
+    /// `[x, y, z]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [u8; 3] {
+        [self.x, self.y, self.z]
+    }
+
+    /// Creates a vector from the first 3 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[u8]) -> Self {
+        assert!(slice.len() >= 3);
+        Self::new(slice[0], slice[1], slice[2])
+    }
+
+    /// Writes the elements of `self` to the first 3 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 3 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [u8]) {
+        slice[..3].copy_from_slice(&self.to_array());
+    }
+
+    /// Internal method for creating a 3D vector from a 4D vector, discarding `w`.
+    #[allow(dead_code)]
+    #[inline]
+    #[must_use]
+    pub(crate) fn from_vec4(v: U8Vec4) -> Self {
+        Self {
+            x: v.x,
+            y: v.y,
+            z: v.z,
+        }
+    }
+
+    /// Creates a 4D vector from `self` and the given `w` value.
+    #[inline]
+    #[must_use]
+    pub fn extend(self, w: u8) -> U8Vec4 {
+        U8Vec4::new(self.x, self.y, self.z, w)
+    }
+
+    /// Creates a 2D vector from the `x` and `y` elements of `self`, discarding `z`.
+    ///
+    /// Truncation may also be performed by using [`self.xy()`][crate::swizzles::Vec3Swizzles::xy()].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> U8Vec2 {
+        use crate::swizzles::Vec3Swizzles;
+        self.xy()
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 3D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u8) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> u8 {
+        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Computes the cross product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn cross(self, rhs: Self) -> Self {
+        Self {
+            x: self.y * rhs.z - rhs.y * self.z,
+            y: self.z * rhs.x - rhs.z * self.x,
+            z: self.x * rhs.y - rhs.x * self.y,
+        }
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+            z: self.z.min(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+            z: self.z.max(rhs.z),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`u8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> u8 {
+        self.x.min(self.y.min(self.z))
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> u8 {
+        self.x.max(self.y.max(self.z))
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u8 {
+        self.x + self.y + self.z
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u8 {
+        self.x * self.y * self.z
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.eq(&rhs.x), self.y.eq(&rhs.y), self.z.eq(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.ne(&rhs.x), self.y.ne(&rhs.y), self.z.ne(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.ge(&rhs.x), self.y.ge(&rhs.y), self.z.ge(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.gt(&rhs.x), self.y.gt(&rhs.y), self.z.gt(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.le(&rhs.x), self.y.le(&rhs.y), self.z.le(&rhs.z))
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec3 {
+        BVec3::new(self.x.lt(&rhs.x), self.y.lt(&rhs.y), self.z.lt(&rhs.z))
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> u8 {
+        self.dot(self)
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec3(&self) -> crate::Vec3 {
+        crate::Vec3::new(self.x as f32, self.y as f32, self.z as f32)
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec3a(&self) -> crate::Vec3A {
+        crate::Vec3A::new(self.x as f32, self.y as f32, self.z as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec3(&self) -> crate::DVec3 {
+        crate::DVec3::new(self.x as f64, self.y as f64, self.z as f64)
+    }
+
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec3(&self) -> crate::I8Vec3 {
+        crate::I8Vec3::new(self.x as i8, self.y as i8, self.z as i8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec3(&self) -> crate::I16Vec3 {
+        crate::I16Vec3::new(self.x as i16, self.y as i16, self.z as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec3(&self) -> crate::U16Vec3 {
+        crate::U16Vec3::new(self.x as u16, self.y as u16, self.z as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec3(&self) -> crate::IVec3 {
+        crate::IVec3::new(self.x as i32, self.y as i32, self.z as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec3(&self) -> crate::UVec3 {
+        crate::UVec3::new(self.x as u32, self.y as u32, self.z as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec3(&self) -> crate::I64Vec3 {
+        crate::I64Vec3::new(self.x as i64, self.y as i64, self.z as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec3(&self) -> crate::U64Vec3 {
+        crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+            z: self.z.wrapping_add(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+            z: self.z.wrapping_sub(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+            z: self.z.wrapping_mul(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+            z: self.z.wrapping_div(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+            z: self.z.saturating_add(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+            z: self.z.saturating_sub(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+            z: self.z.saturating_mul(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+            z: self.z.saturating_div(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I8Vec3) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I8Vec3) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+        }
+    }
+}
+
+impl Default for U8Vec3 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<U8Vec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+            z: self.z.div(rhs.z),
+        }
+    }
+}
+
+impl Div<&U8Vec3> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<U8Vec3> for U8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+        self.z.div_assign(rhs.z);
+    }
+}
+
+impl DivAssign<&Self> for U8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+            z: self.z.div(rhs),
+        }
+    }
+}
+
+impl Div<&u8> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: u8) -> U8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<u8> for U8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: u8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+        self.z.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&u8> for U8Vec3 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: U8Vec3) -> U8Vec3 {
+        U8Vec3 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+            z: self.div(rhs.z),
+        }
+    }
+}
+
+impl Div<&U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn div(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<U8Vec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+            z: self.z.mul(rhs.z),
+        }
+    }
+}
+
+impl Mul<&U8Vec3> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<U8Vec3> for U8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+        self.z.mul_assign(rhs.z);
+    }
+}
+
+impl MulAssign<&Self> for U8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+            z: self.z.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&u8> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: u8) -> U8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<u8> for U8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: u8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+        self.z.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&u8> for U8Vec3 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: U8Vec3) -> U8Vec3 {
+        U8Vec3 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+            z: self.mul(rhs.z),
+        }
+    }
+}
+
+impl Mul<&U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn mul(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<U8Vec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+            z: self.z.add(rhs.z),
+        }
+    }
+}
+
+impl Add<&U8Vec3> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<U8Vec3> for U8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+        self.z.add_assign(rhs.z);
+    }
+}
+
+impl AddAssign<&Self> for U8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+            z: self.z.add(rhs),
+        }
+    }
+}
+
+impl Add<&u8> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: u8) -> U8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<u8> for U8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: u8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+        self.z.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&u8> for U8Vec3 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: U8Vec3) -> U8Vec3 {
+        U8Vec3 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+            z: self.add(rhs.z),
+        }
+    }
+}
+
+impl Add<&U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn add(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<U8Vec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+            z: self.z.sub(rhs.z),
+        }
+    }
+}
+
+impl Sub<&U8Vec3> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<U8Vec3> for U8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: U8Vec3) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+        self.z.sub_assign(rhs.z);
+    }
+}
+
+impl SubAssign<&Self> for U8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+            z: self.z.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&u8> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: u8) -> U8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<u8> for U8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: u8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+        self.z.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&u8> for U8Vec3 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: U8Vec3) -> U8Vec3 {
+        U8Vec3 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+            z: self.sub(rhs.z),
+        }
+    }
+}
+
+impl Sub<&U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn sub(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<U8Vec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+            z: self.z.rem(rhs.z),
+        }
+    }
+}
+
+impl Rem<&U8Vec3> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec3> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<U8Vec3> for U8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+        self.z.rem_assign(rhs.z);
+    }
+}
+
+impl RemAssign<&Self> for U8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+            z: self.z.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&u8> for U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u8> for &U8Vec3 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: u8) -> U8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<u8> for U8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: u8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+        self.z.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&u8> for U8Vec3 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: U8Vec3) -> U8Vec3 {
+        U8Vec3 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+            z: self.rem(rhs.z),
+        }
+    }
+}
+
+impl Rem<&U8Vec3> for u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &U8Vec3) -> U8Vec3 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: &U8Vec3) -> U8Vec3 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec3> for &u8 {
+    type Output = U8Vec3;
+    #[inline]
+    fn rem(self, rhs: U8Vec3) -> U8Vec3 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[u8; 3]> for U8Vec3 {
+    #[inline]
+    fn as_ref(&self) -> &[u8; 3] {
+        unsafe { &*(self as *const U8Vec3 as *const [u8; 3]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[u8; 3]> for U8Vec3 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8; 3] {
+        unsafe { &mut *(self as *mut U8Vec3 as *mut [u8; 3]) }
+    }
+}
+
+impl Sum for U8Vec3 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for U8Vec3 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for U8Vec3 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for U8Vec3 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Not for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+            z: self.z.not(),
+        }
+    }
+}
+
+impl BitAnd for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+            z: self.z.bitand(rhs.z),
+        }
+    }
+}
+
+impl BitOr for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+            z: self.z.bitor(rhs.z),
+        }
+    }
+}
+
+impl BitXor for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+            z: self.z.bitxor(rhs.z),
+        }
+    }
+}
+
+impl BitAnd<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+            z: self.z.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+            z: self.z.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+            z: self.z.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec3) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+        }
+    }
+}
+
+impl Shr<crate::IVec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec3) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+        }
+    }
+}
+
+impl Shl<crate::UVec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec3) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+        }
+    }
+}
+
+impl Shr<crate::UVec3> for U8Vec3 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec3) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+        }
+    }
+}
+
+impl Index<usize> for U8Vec3 {
+    type Output = u8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for U8Vec3 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for U8Vec3 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
+    }
+}
+
+impl fmt::Debug for U8Vec3 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(U8Vec3))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .finish()
+    }
+}
+
+impl From<[u8; 3]> for U8Vec3 {
+    #[inline]
+    fn from(a: [u8; 3]) -> Self {
+        Self::new(a[0], a[1], a[2])
+    }
+}
+
+impl From<U8Vec3> for [u8; 3] {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        [v.x, v.y, v.z]
+    }
+}
+
+impl From<(u8, u8, u8)> for U8Vec3 {
+    #[inline]
+    fn from(t: (u8, u8, u8)) -> Self {
+        Self::new(t.0, t.1, t.2)
+    }
+}
+
+impl From<U8Vec3> for (u8, u8, u8) {
+    #[inline]
+    fn from(v: U8Vec3) -> Self {
+        (v.x, v.y, v.z)
+    }
+}
+
+impl From<(U8Vec2, u8)> for U8Vec3 {
+    #[inline]
+    fn from((v, z): (U8Vec2, u8)) -> Self {
+        Self::new(v.x, v.y, z)
+    }
+}
+
+impl TryFrom<I8Vec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I16Vec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U16Vec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<IVec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<UVec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec3> for U8Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+        ))
+    }
+}
+
+impl From<BVec3> for U8Vec3 {
+    #[inline]
+    fn from(v: BVec3) -> Self {
+        Self::new(u8::from(v.x), u8::from(v.y), u8::from(v.z))
+    }
+}
+
+impl From<BVec3A> for U8Vec3 {
+    #[inline]
+    fn from(v: BVec3A) -> Self {
+        let bool_array: [bool; 3] = v.into();
+        Self::new(
+            u8::from(bool_array[0]),
+            u8::from(bool_array[1]),
+            u8::from(bool_array[2]),
+        )
+    }
+}
diff --git a/crates/glam/src/u8/u8vec4.rs b/crates/glam/src/u8/u8vec4.rs
new file mode 100644
index 0000000..1b64aa8
--- /dev/null
+++ b/crates/glam/src/u8/u8vec4.rs
@@ -0,0 +1,1942 @@
+// Generated from vec.rs.tera template. Edit the template, not the generated file.
+
+#[cfg(not(feature = "scalar-math"))]
+use crate::BVec4A;
+use crate::{BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec2, U8Vec3, UVec4};
+
+use core::fmt;
+use core::iter::{Product, Sum};
+use core::{f32, ops::*};
+
+/// Creates a 4-dimensional vector.
+#[inline(always)]
+#[must_use]
+pub const fn u8vec4(x: u8, y: u8, z: u8, w: u8) -> U8Vec4 {
+    U8Vec4::new(x, y, z, w)
+}
+
+/// A 4-dimensional vector.
+#[cfg_attr(not(target_arch = "spirv"), derive(Hash))]
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "cuda", repr(align(4)))]
+#[cfg_attr(not(target_arch = "spirv"), repr(C))]
+#[cfg_attr(target_arch = "spirv", repr(simd))]
+pub struct U8Vec4 {
+    pub x: u8,
+    pub y: u8,
+    pub z: u8,
+    pub w: u8,
+}
+
+impl U8Vec4 {
+    /// All zeroes.
+    pub const ZERO: Self = Self::splat(0);
+
+    /// All ones.
+    pub const ONE: Self = Self::splat(1);
+
+    /// All `u8::MIN`.
+    pub const MIN: Self = Self::splat(u8::MIN);
+
+    /// All `u8::MAX`.
+    pub const MAX: Self = Self::splat(u8::MAX);
+
+    /// A unit vector pointing along the positive X axis.
+    pub const X: Self = Self::new(1, 0, 0, 0);
+
+    /// A unit vector pointing along the positive Y axis.
+    pub const Y: Self = Self::new(0, 1, 0, 0);
+
+    /// A unit vector pointing along the positive Z axis.
+    pub const Z: Self = Self::new(0, 0, 1, 0);
+
+    /// A unit vector pointing along the positive W axis.
+    pub const W: Self = Self::new(0, 0, 0, 1);
+
+    /// The unit axes.
+    pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
+
+    /// Creates a new vector.
+    #[inline(always)]
+    #[must_use]
+    pub const fn new(x: u8, y: u8, z: u8, w: u8) -> Self {
+        Self { x, y, z, w }
+    }
+
+    /// Creates a vector with all elements set to `v`.
+    #[inline]
+    #[must_use]
+    pub const fn splat(v: u8) -> Self {
+        Self {
+            x: v,
+
+            y: v,
+
+            z: v,
+
+            w: v,
+        }
+    }
+
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u8) -> u8,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
+    /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
+    /// for each element of `self`.
+    ///
+    /// A true element in the mask uses the corresponding element from `if_true`, and false
+    /// uses the element from `if_false`.
+    #[inline]
+    #[must_use]
+    pub fn select(mask: BVec4, if_true: Self, if_false: Self) -> Self {
+        Self {
+            x: if mask.test(0) { if_true.x } else { if_false.x },
+            y: if mask.test(1) { if_true.y } else { if_false.y },
+            z: if mask.test(2) { if_true.z } else { if_false.z },
+            w: if mask.test(3) { if_true.w } else { if_false.w },
+        }
+    }
+
+    /// Creates a new vector from an array.
+    #[inline]
+    #[must_use]
+    pub const fn from_array(a: [u8; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+
+    /// `[x, y, z, w]`
+    #[inline]
+    #[must_use]
+    pub const fn to_array(&self) -> [u8; 4] {
+        [self.x, self.y, self.z, self.w]
+    }
+
+    /// Creates a vector from the first 4 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[u8]) -> Self {
+        assert!(slice.len() >= 4);
+        Self::new(slice[0], slice[1], slice[2], slice[3])
+    }
+
+    /// Writes the elements of `self` to the first 4 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 4 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [u8]) {
+        slice[..4].copy_from_slice(&self.to_array());
+    }
+
+    /// Creates a 3D vector from the `x`, `y` and `z` elements of `self`, discarding `w`.
+    ///
+    /// Truncation to [`U8Vec3`] may also be performed by using [`self.xyz()`][crate::swizzles::Vec4Swizzles::xyz()].
+    #[inline]
+    #[must_use]
+    pub fn truncate(self) -> U8Vec3 {
+        use crate::swizzles::Vec4Swizzles;
+        self.xyz()
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `x`.
+    #[inline]
+    #[must_use]
+    pub fn with_x(mut self, x: u8) -> Self {
+        self.x = x;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `y`.
+    #[inline]
+    #[must_use]
+    pub fn with_y(mut self, y: u8) -> Self {
+        self.y = y;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `z`.
+    #[inline]
+    #[must_use]
+    pub fn with_z(mut self, z: u8) -> Self {
+        self.z = z;
+        self
+    }
+
+    /// Creates a 4D vector from `self` with the given value of `w`.
+    #[inline]
+    #[must_use]
+    pub fn with_w(mut self, w: u8) -> Self {
+        self.w = w;
+        self
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot(self, rhs: Self) -> u8 {
+        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w)
+    }
+
+    /// Returns a vector where every component is the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn dot_into_vec(self, rhs: Self) -> Self {
+        Self::splat(self.dot(rhs))
+    }
+
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+            z: self.z.min(rhs.z),
+            w: self.w.min(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+            z: self.z.max(rhs.z),
+            w: self.w.max(rhs.w),
+        }
+    }
+
+    /// Component-wise clamping of values, similar to [`u8::clamp`].
+    ///
+    /// Each element in `min` must be less-or-equal to the corresponding element in `max`.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if `min` is greater than `max` when `glam_assert` is enabled.
+    #[inline]
+    #[must_use]
+    pub fn clamp(self, min: Self, max: Self) -> Self {
+        glam_assert!(min.cmple(max).all(), "clamp: expected min <= max");
+        self.max(min).min(max)
+    }
+
+    /// Returns the horizontal minimum of `self`.
+    ///
+    /// In other words this computes `min(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn min_element(self) -> u8 {
+        self.x.min(self.y.min(self.z.min(self.w)))
+    }
+
+    /// Returns the horizontal maximum of `self`.
+    ///
+    /// In other words this computes `max(x, y, ..)`.
+    #[inline]
+    #[must_use]
+    pub fn max_element(self) -> u8 {
+        self.x.max(self.y.max(self.z.max(self.w)))
+    }
+
+    /// Returns the sum of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x + self.y + ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_sum(self) -> u8 {
+        self.x + self.y + self.z + self.w
+    }
+
+    /// Returns the product of all elements of `self`.
+    ///
+    /// In other words, this computes `self.x * self.y * ..`.
+    #[inline]
+    #[must_use]
+    pub fn element_product(self) -> u8 {
+        self.x * self.y * self.z * self.w
+    }
+
+    /// Returns a vector mask containing the result of a `==` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words, this computes `[self.x == rhs.x, self.y == rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpeq(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.eq(&rhs.x),
+            self.y.eq(&rhs.y),
+            self.z.eq(&rhs.z),
+            self.w.eq(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `!=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x != rhs.x, self.y != rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpne(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.ne(&rhs.x),
+            self.y.ne(&rhs.y),
+            self.z.ne(&rhs.z),
+            self.w.ne(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `>=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x >= rhs.x, self.y >= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpge(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.ge(&rhs.x),
+            self.y.ge(&rhs.y),
+            self.z.ge(&rhs.z),
+            self.w.ge(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `>` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x > rhs.x, self.y > rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmpgt(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.gt(&rhs.x),
+            self.y.gt(&rhs.y),
+            self.z.gt(&rhs.z),
+            self.w.gt(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `<=` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x <= rhs.x, self.y <= rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmple(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.le(&rhs.x),
+            self.y.le(&rhs.y),
+            self.z.le(&rhs.z),
+            self.w.le(&rhs.w),
+        )
+    }
+
+    /// Returns a vector mask containing the result of a `<` comparison for each element of
+    /// `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x < rhs.x, self.y < rhs.y, ..]` for all
+    /// elements.
+    #[inline]
+    #[must_use]
+    pub fn cmplt(self, rhs: Self) -> BVec4 {
+        BVec4::new(
+            self.x.lt(&rhs.x),
+            self.y.lt(&rhs.y),
+            self.z.lt(&rhs.z),
+            self.w.lt(&rhs.w),
+        )
+    }
+
+    /// Computes the squared length of `self`.
+    #[doc(alias = "magnitude2")]
+    #[inline]
+    #[must_use]
+    pub fn length_squared(self) -> u8 {
+        self.dot(self)
+    }
+
+    /// Casts all elements of `self` to `f32`.
+    #[inline]
+    #[must_use]
+    pub fn as_vec4(&self) -> crate::Vec4 {
+        crate::Vec4::new(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
+    }
+
+    /// Casts all elements of `self` to `f64`.
+    #[inline]
+    #[must_use]
+    pub fn as_dvec4(&self) -> crate::DVec4 {
+        crate::DVec4::new(self.x as f64, self.y as f64, self.z as f64, self.w as f64)
+    }
+
+    /// Casts all elements of `self` to `i8`.
+    #[inline]
+    #[must_use]
+    pub fn as_i8vec4(&self) -> crate::I8Vec4 {
+        crate::I8Vec4::new(self.x as i8, self.y as i8, self.z as i8, self.w as i8)
+    }
+
+    /// Casts all elements of `self` to `i16`.
+    #[inline]
+    #[must_use]
+    pub fn as_i16vec4(&self) -> crate::I16Vec4 {
+        crate::I16Vec4::new(self.x as i16, self.y as i16, self.z as i16, self.w as i16)
+    }
+
+    /// Casts all elements of `self` to `u16`.
+    #[inline]
+    #[must_use]
+    pub fn as_u16vec4(&self) -> crate::U16Vec4 {
+        crate::U16Vec4::new(self.x as u16, self.y as u16, self.z as u16, self.w as u16)
+    }
+
+    /// Casts all elements of `self` to `i32`.
+    #[inline]
+    #[must_use]
+    pub fn as_ivec4(&self) -> crate::IVec4 {
+        crate::IVec4::new(self.x as i32, self.y as i32, self.z as i32, self.w as i32)
+    }
+
+    /// Casts all elements of `self` to `u32`.
+    #[inline]
+    #[must_use]
+    pub fn as_uvec4(&self) -> crate::UVec4 {
+        crate::UVec4::new(self.x as u32, self.y as u32, self.z as u32, self.w as u32)
+    }
+
+    /// Casts all elements of `self` to `i64`.
+    #[inline]
+    #[must_use]
+    pub fn as_i64vec4(&self) -> crate::I64Vec4 {
+        crate::I64Vec4::new(self.x as i64, self.y as i64, self.z as i64, self.w as i64)
+    }
+
+    /// Casts all elements of `self` to `u64`.
+    #[inline]
+    #[must_use]
+    pub fn as_u64vec4(&self) -> crate::U64Vec4 {
+        crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_add(rhs.x),
+            y: self.y.wrapping_add(rhs.y),
+            z: self.z.wrapping_add(rhs.z),
+            w: self.w.wrapping_add(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_sub(rhs.x), self.y.wrapping_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_sub(rhs.x),
+            y: self.y.wrapping_sub(rhs.y),
+            z: self.z.wrapping_sub(rhs.z),
+            w: self.w.wrapping_sub(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_mul(rhs.x), self.y.wrapping_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_mul(rhs.x),
+            y: self.y.wrapping_mul(rhs.y),
+            z: self.z.wrapping_mul(rhs.z),
+            w: self.w.wrapping_mul(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_div(rhs.x), self.y.wrapping_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.wrapping_div(rhs.x),
+            y: self.y.wrapping_div(rhs.y),
+            z: self.z.wrapping_div(rhs.z),
+            w: self.w.wrapping_div(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add(rhs.x), self.y.saturating_add(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_add(rhs.x),
+            y: self.y.saturating_add(rhs.y),
+            z: self.z.saturating_add(rhs.z),
+            w: self.w.saturating_add(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_sub(rhs.x), self.y.saturating_sub(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_sub(rhs.x),
+            y: self.y.saturating_sub(rhs.y),
+            z: self.z.saturating_sub(rhs.z),
+            w: self.w.saturating_sub(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_mul(rhs.x), self.y.saturating_mul(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_mul(rhs.x),
+            y: self.y.saturating_mul(rhs.y),
+            z: self.z.saturating_mul(rhs.z),
+            w: self.w.saturating_mul(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating division of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_div(rhs.x), self.y.saturating_div(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.saturating_div(rhs.x),
+            y: self.y.saturating_div(rhs.y),
+            z: self.z.saturating_div(rhs.z),
+            w: self.w.saturating_div(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn wrapping_add_signed(self, rhs: I8Vec4) -> Self {
+        Self {
+            x: self.x.wrapping_add_signed(rhs.x),
+            y: self.y.wrapping_add_signed(rhs.y),
+            z: self.z.wrapping_add_signed(rhs.z),
+            w: self.w.wrapping_add_signed(rhs.w),
+        }
+    }
+
+    /// Returns a vector containing the saturating addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `[self.x.saturating_add_signed(rhs.x), self.y.saturating_add_signed(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub const fn saturating_add_signed(self, rhs: I8Vec4) -> Self {
+        Self {
+            x: self.x.saturating_add_signed(rhs.x),
+            y: self.y.saturating_add_signed(rhs.y),
+            z: self.z.saturating_add_signed(rhs.z),
+            w: self.w.saturating_add_signed(rhs.w),
+        }
+    }
+}
+
+impl Default for U8Vec4 {
+    #[inline(always)]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+impl Div<U8Vec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
+            z: self.z.div(rhs.z),
+            w: self.w.div(rhs.w),
+        }
+    }
+}
+
+impl Div<&U8Vec4> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<U8Vec4> for U8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: Self) {
+        self.x.div_assign(rhs.x);
+        self.y.div_assign(rhs.y);
+        self.z.div_assign(rhs.z);
+        self.w.div_assign(rhs.w);
+    }
+}
+
+impl DivAssign<&Self> for U8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &Self) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn div(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.div(rhs),
+            y: self.y.div(rhs),
+            z: self.z.div(rhs),
+            w: self.w.div(rhs),
+        }
+    }
+}
+
+impl Div<&u8> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &u8) -> U8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: u8) -> U8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl DivAssign<u8> for U8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: u8) {
+        self.x.div_assign(rhs);
+        self.y.div_assign(rhs);
+        self.z.div_assign(rhs);
+        self.w.div_assign(rhs);
+    }
+}
+
+impl DivAssign<&u8> for U8Vec4 {
+    #[inline]
+    fn div_assign(&mut self, rhs: &u8) {
+        self.div_assign(*rhs)
+    }
+}
+
+impl Div<U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: U8Vec4) -> U8Vec4 {
+        U8Vec4 {
+            x: self.div(rhs.x),
+            y: self.div(rhs.y),
+            z: self.div(rhs.z),
+            w: self.div(rhs.w),
+        }
+    }
+}
+
+impl Div<&U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.div(*rhs)
+    }
+}
+
+impl Div<&U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).div(*rhs)
+    }
+}
+
+impl Div<U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn div(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).div(rhs)
+    }
+}
+
+impl Mul<U8Vec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
+            z: self.z.mul(rhs.z),
+            w: self.w.mul(rhs.w),
+        }
+    }
+}
+
+impl Mul<&U8Vec4> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<U8Vec4> for U8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: Self) {
+        self.x.mul_assign(rhs.x);
+        self.y.mul_assign(rhs.y);
+        self.z.mul_assign(rhs.z);
+        self.w.mul_assign(rhs.w);
+    }
+}
+
+impl MulAssign<&Self> for U8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &Self) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn mul(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
+            z: self.z.mul(rhs),
+            w: self.w.mul(rhs),
+        }
+    }
+}
+
+impl Mul<&u8> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &u8) -> U8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: u8) -> U8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl MulAssign<u8> for U8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: u8) {
+        self.x.mul_assign(rhs);
+        self.y.mul_assign(rhs);
+        self.z.mul_assign(rhs);
+        self.w.mul_assign(rhs);
+    }
+}
+
+impl MulAssign<&u8> for U8Vec4 {
+    #[inline]
+    fn mul_assign(&mut self, rhs: &u8) {
+        self.mul_assign(*rhs)
+    }
+}
+
+impl Mul<U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: U8Vec4) -> U8Vec4 {
+        U8Vec4 {
+            x: self.mul(rhs.x),
+            y: self.mul(rhs.y),
+            z: self.mul(rhs.z),
+            w: self.mul(rhs.w),
+        }
+    }
+}
+
+impl Mul<&U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.mul(*rhs)
+    }
+}
+
+impl Mul<&U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).mul(*rhs)
+    }
+}
+
+impl Mul<U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn mul(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).mul(rhs)
+    }
+}
+
+impl Add<U8Vec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.add(rhs.x),
+            y: self.y.add(rhs.y),
+            z: self.z.add(rhs.z),
+            w: self.w.add(rhs.w),
+        }
+    }
+}
+
+impl Add<&U8Vec4> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<U8Vec4> for U8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: Self) {
+        self.x.add_assign(rhs.x);
+        self.y.add_assign(rhs.y);
+        self.z.add_assign(rhs.z);
+        self.w.add_assign(rhs.w);
+    }
+}
+
+impl AddAssign<&Self> for U8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &Self) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn add(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
+            z: self.z.add(rhs),
+            w: self.w.add(rhs),
+        }
+    }
+}
+
+impl Add<&u8> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &u8) -> U8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: u8) -> U8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl AddAssign<u8> for U8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: u8) {
+        self.x.add_assign(rhs);
+        self.y.add_assign(rhs);
+        self.z.add_assign(rhs);
+        self.w.add_assign(rhs);
+    }
+}
+
+impl AddAssign<&u8> for U8Vec4 {
+    #[inline]
+    fn add_assign(&mut self, rhs: &u8) {
+        self.add_assign(*rhs)
+    }
+}
+
+impl Add<U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: U8Vec4) -> U8Vec4 {
+        U8Vec4 {
+            x: self.add(rhs.x),
+            y: self.add(rhs.y),
+            z: self.add(rhs.z),
+            w: self.add(rhs.w),
+        }
+    }
+}
+
+impl Add<&U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.add(*rhs)
+    }
+}
+
+impl Add<&U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).add(*rhs)
+    }
+}
+
+impl Add<U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn add(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).add(rhs)
+    }
+}
+
+impl Sub<U8Vec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.sub(rhs.x),
+            y: self.y.sub(rhs.y),
+            z: self.z.sub(rhs.z),
+            w: self.w.sub(rhs.w),
+        }
+    }
+}
+
+impl Sub<&U8Vec4> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<U8Vec4> for U8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: U8Vec4) {
+        self.x.sub_assign(rhs.x);
+        self.y.sub_assign(rhs.y);
+        self.z.sub_assign(rhs.z);
+        self.w.sub_assign(rhs.w);
+    }
+}
+
+impl SubAssign<&Self> for U8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &Self) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn sub(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
+            z: self.z.sub(rhs),
+            w: self.w.sub(rhs),
+        }
+    }
+}
+
+impl Sub<&u8> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &u8) -> U8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: u8) -> U8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl SubAssign<u8> for U8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: u8) {
+        self.x.sub_assign(rhs);
+        self.y.sub_assign(rhs);
+        self.z.sub_assign(rhs);
+        self.w.sub_assign(rhs);
+    }
+}
+
+impl SubAssign<&u8> for U8Vec4 {
+    #[inline]
+    fn sub_assign(&mut self, rhs: &u8) {
+        self.sub_assign(*rhs)
+    }
+}
+
+impl Sub<U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: U8Vec4) -> U8Vec4 {
+        U8Vec4 {
+            x: self.sub(rhs.x),
+            y: self.sub(rhs.y),
+            z: self.sub(rhs.z),
+            w: self.sub(rhs.w),
+        }
+    }
+}
+
+impl Sub<&U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.sub(*rhs)
+    }
+}
+
+impl Sub<&U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).sub(*rhs)
+    }
+}
+
+impl Sub<U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn sub(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).sub(rhs)
+    }
+}
+
+impl Rem<U8Vec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.rem(rhs.x),
+            y: self.y.rem(rhs.y),
+            z: self.z.rem(rhs.z),
+            w: self.w.rem(rhs.w),
+        }
+    }
+}
+
+impl Rem<&U8Vec4> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec4> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<U8Vec4> for U8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: Self) {
+        self.x.rem_assign(rhs.x);
+        self.y.rem_assign(rhs.y);
+        self.z.rem_assign(rhs.z);
+        self.w.rem_assign(rhs.w);
+    }
+}
+
+impl RemAssign<&Self> for U8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &Self) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn rem(self, rhs: u8) -> Self {
+        Self {
+            x: self.x.rem(rhs),
+            y: self.y.rem(rhs),
+            z: self.z.rem(rhs),
+            w: self.w.rem(rhs),
+        }
+    }
+}
+
+impl Rem<&u8> for U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &u8) -> U8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<u8> for &U8Vec4 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: u8) -> U8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+impl RemAssign<u8> for U8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: u8) {
+        self.x.rem_assign(rhs);
+        self.y.rem_assign(rhs);
+        self.z.rem_assign(rhs);
+        self.w.rem_assign(rhs);
+    }
+}
+
+impl RemAssign<&u8> for U8Vec4 {
+    #[inline]
+    fn rem_assign(&mut self, rhs: &u8) {
+        self.rem_assign(*rhs)
+    }
+}
+
+impl Rem<U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: U8Vec4) -> U8Vec4 {
+        U8Vec4 {
+            x: self.rem(rhs.x),
+            y: self.rem(rhs.y),
+            z: self.rem(rhs.z),
+            w: self.rem(rhs.w),
+        }
+    }
+}
+
+impl Rem<&U8Vec4> for u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &U8Vec4) -> U8Vec4 {
+        self.rem(*rhs)
+    }
+}
+
+impl Rem<&U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: &U8Vec4) -> U8Vec4 {
+        (*self).rem(*rhs)
+    }
+}
+
+impl Rem<U8Vec4> for &u8 {
+    type Output = U8Vec4;
+    #[inline]
+    fn rem(self, rhs: U8Vec4) -> U8Vec4 {
+        (*self).rem(rhs)
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsRef<[u8; 4]> for U8Vec4 {
+    #[inline]
+    fn as_ref(&self) -> &[u8; 4] {
+        unsafe { &*(self as *const U8Vec4 as *const [u8; 4]) }
+    }
+}
+
+#[cfg(not(target_arch = "spirv"))]
+impl AsMut<[u8; 4]> for U8Vec4 {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8; 4] {
+        unsafe { &mut *(self as *mut U8Vec4 as *mut [u8; 4]) }
+    }
+}
+
+impl Sum for U8Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ZERO, Self::add)
+    }
+}
+
+impl<'a> Sum<&'a Self> for U8Vec4 {
+    #[inline]
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
+    }
+}
+
+impl Product for U8Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = Self>,
+    {
+        iter.fold(Self::ONE, Self::mul)
+    }
+}
+
+impl<'a> Product<&'a Self> for U8Vec4 {
+    #[inline]
+    fn product<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = &'a Self>,
+    {
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
+    }
+}
+
+impl Not for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self {
+            x: self.x.not(),
+            y: self.y.not(),
+            z: self.z.not(),
+            w: self.w.not(),
+        }
+    }
+}
+
+impl BitAnd for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+            z: self.z.bitand(rhs.z),
+            w: self.w.bitand(rhs.w),
+        }
+    }
+}
+
+impl BitOr for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+            z: self.z.bitor(rhs.z),
+            w: self.w.bitor(rhs.w),
+        }
+    }
+}
+
+impl BitXor for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+            z: self.z.bitxor(rhs.z),
+            w: self.w.bitxor(rhs.w),
+        }
+    }
+}
+
+impl BitAnd<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+            z: self.z.bitand(rhs),
+            w: self.w.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+            z: self.z.bitor(rhs),
+            w: self.w.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+            z: self.z.bitxor(rhs),
+            w: self.w.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i64> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i64> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u64> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+            z: self.z.shl(rhs),
+            w: self.w.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u64> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u64) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+            z: self.z.shr(rhs),
+            w: self.w.shr(rhs),
+        }
+    }
+}
+
+impl Shl<crate::IVec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::IVec4) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+            w: self.w.shl(rhs.w),
+        }
+    }
+}
+
+impl Shr<crate::IVec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::IVec4) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+            w: self.w.shr(rhs.w),
+        }
+    }
+}
+
+impl Shl<crate::UVec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: crate::UVec4) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+            z: self.z.shl(rhs.z),
+            w: self.w.shl(rhs.w),
+        }
+    }
+}
+
+impl Shr<crate::UVec4> for U8Vec4 {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: crate::UVec4) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs.x),
+            y: self.y.shr(rhs.y),
+            z: self.z.shr(rhs.z),
+            w: self.w.shr(rhs.w),
+        }
+    }
+}
+
+impl Index<usize> for U8Vec4 {
+    type Output = u8;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        match index {
+            0 => &self.x,
+            1 => &self.y,
+            2 => &self.z,
+            3 => &self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl IndexMut<usize> for U8Vec4 {
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match index {
+            0 => &mut self.x,
+            1 => &mut self.y,
+            2 => &mut self.z,
+            3 => &mut self.w,
+            _ => panic!("index out of bounds"),
+        }
+    }
+}
+
+impl fmt::Display for U8Vec4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
+    }
+}
+
+impl fmt::Debug for U8Vec4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple(stringify!(U8Vec4))
+            .field(&self.x)
+            .field(&self.y)
+            .field(&self.z)
+            .field(&self.w)
+            .finish()
+    }
+}
+
+impl From<[u8; 4]> for U8Vec4 {
+    #[inline]
+    fn from(a: [u8; 4]) -> Self {
+        Self::new(a[0], a[1], a[2], a[3])
+    }
+}
+
+impl From<U8Vec4> for [u8; 4] {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        [v.x, v.y, v.z, v.w]
+    }
+}
+
+impl From<(u8, u8, u8, u8)> for U8Vec4 {
+    #[inline]
+    fn from(t: (u8, u8, u8, u8)) -> Self {
+        Self::new(t.0, t.1, t.2, t.3)
+    }
+}
+
+impl From<U8Vec4> for (u8, u8, u8, u8) {
+    #[inline]
+    fn from(v: U8Vec4) -> Self {
+        (v.x, v.y, v.z, v.w)
+    }
+}
+
+impl From<(U8Vec3, u8)> for U8Vec4 {
+    #[inline]
+    fn from((v, w): (U8Vec3, u8)) -> Self {
+        Self::new(v.x, v.y, v.z, w)
+    }
+}
+
+impl From<(u8, U8Vec3)> for U8Vec4 {
+    #[inline]
+    fn from((x, v): (u8, U8Vec3)) -> Self {
+        Self::new(x, v.x, v.y, v.z)
+    }
+}
+
+impl From<(U8Vec2, u8, u8)> for U8Vec4 {
+    #[inline]
+    fn from((v, z, w): (U8Vec2, u8, u8)) -> Self {
+        Self::new(v.x, v.y, z, w)
+    }
+}
+
+impl From<(U8Vec2, U8Vec2)> for U8Vec4 {
+    #[inline]
+    fn from((v, u): (U8Vec2, U8Vec2)) -> Self {
+        Self::new(v.x, v.y, u.x, u.y)
+    }
+}
+
+impl TryFrom<I8Vec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I8Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I16Vec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I16Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U16Vec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U16Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<IVec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<UVec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec4> for U8Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u8::try_from(v.x)?,
+            u8::try_from(v.y)?,
+            u8::try_from(v.z)?,
+            u8::try_from(v.w)?,
+        ))
+    }
+}
+
+impl From<BVec4> for U8Vec4 {
+    #[inline]
+    fn from(v: BVec4) -> Self {
+        Self::new(u8::from(v.x), u8::from(v.y), u8::from(v.z), u8::from(v.w))
+    }
+}
+
+#[cfg(not(feature = "scalar-math"))]
+
+impl From<BVec4A> for U8Vec4 {
+    #[inline]
+    fn from(v: BVec4A) -> Self {
+        let bool_array: [bool; 4] = v.into();
+        Self::new(
+            u8::from(bool_array[0]),
+            u8::from(bool_array[1]),
+            u8::from(bool_array[2]),
+            u8::from(bool_array[3]),
+        )
+    }
+}
diff --git a/crates/glam/tests/affine2.rs b/crates/glam/tests/affine2.rs
index 205caa4..0f56e7e 100644
--- a/crates/glam/tests/affine2.rs
+++ b/crates/glam/tests/affine2.rs
@@ -6,9 +6,6 @@
         const MATRIX1D: [$t; 6] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
         const MATRIX2D: [[$t; 2]; 3] = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
 
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_affine2_identity, {
             assert_eq!($affine2::IDENTITY, $affine2::IDENTITY * $affine2::IDENTITY);
             assert_eq!($affine2::IDENTITY, $affine2::default());
@@ -232,6 +229,7 @@
         glam_test!(test_affine2_fmt, {
             let a = $affine2::from_cols_array_2d(&MATRIX2D);
             assert_eq!(format!("{}", a), "[[1, 2], [3, 4], [5, 6]]");
+            assert_eq!(format!("{:.1}", a), "[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]");
         });
 
         glam_test!(test_affine2_to_from_slice, {
@@ -259,8 +257,8 @@
         glam_test!(test_affine2_is_finite, {
             assert!($affine2::from_scale($vec2::new(1.0, 1.0)).is_finite());
             assert!($affine2::from_scale($vec2::new(0.0, 1.0)).is_finite());
-            assert!(!$affine2::from_scale($vec2::new(1.0, NAN)).is_finite());
-            assert!(!$affine2::from_scale($vec2::new(1.0, NEG_INFINITY)).is_finite());
+            assert!(!$affine2::from_scale($vec2::new(1.0, $t::NAN)).is_finite());
+            assert!(!$affine2::from_scale($vec2::new(1.0, $t::NEG_INFINITY)).is_finite());
         });
     };
 }
diff --git a/crates/glam/tests/affine3.rs b/crates/glam/tests/affine3.rs
index 49c4391..46b704c 100644
--- a/crates/glam/tests/affine3.rs
+++ b/crates/glam/tests/affine3.rs
@@ -13,9 +13,6 @@
             [10.0, 11.0, 12.0],
         ];
 
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_affine3_identity, {
             assert_eq!($affine3::IDENTITY, $affine3::IDENTITY * $affine3::IDENTITY);
             assert_eq!($affine3::IDENTITY, $affine3::default());
@@ -98,7 +95,7 @@
         });
 
         glam_test!(test_from_rotation, {
-            let eps = 2.0 * core::f32::EPSILON;
+            let eps = 2.0 * f32::EPSILON;
             let rot_x1 = $affine3::from_rotation_x(deg(180.0));
             let rot_x2 = $affine3::from_axis_angle($vec3::X, deg(180.0));
             assert_approx_eq!(rot_x1, rot_x2, eps);
@@ -309,6 +306,10 @@
                 format!("{}", a),
                 "[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]"
             );
+            assert_eq!(
+                format!("{:.1}", a),
+                "[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0], [10.0, 11.0, 12.0]]"
+            );
         });
 
         glam_test!(test_affine3_to_from_slice, {
@@ -341,8 +342,8 @@
         glam_test!(test_affine3_is_finite, {
             assert!($affine3::from_scale($vec3::new(1.0, 1.0, 1.0)).is_finite());
             assert!($affine3::from_scale($vec3::new(0.0, 1.0, 1.0)).is_finite());
-            assert!(!$affine3::from_scale($vec3::new(1.0, NAN, 1.0)).is_finite());
-            assert!(!$affine3::from_scale($vec3::new(1.0, 1.0, NEG_INFINITY)).is_finite());
+            assert!(!$affine3::from_scale($vec3::new(1.0, $t::NAN, 1.0)).is_finite());
+            assert!(!$affine3::from_scale($vec3::new(1.0, 1.0, $t::NEG_INFINITY)).is_finite());
         });
     };
 }
diff --git a/crates/glam/tests/euler.rs b/crates/glam/tests/euler.rs
index b2d0726..3890f25 100644
--- a/crates/glam/tests/euler.rs
+++ b/crates/glam/tests/euler.rs
@@ -1,121 +1,287 @@
 #[macro_use]
 mod support;
 
-/// Helper to get the 'canonical' version of a `Quat`. We define the canonical of quat `q` as:
-/// * `q`, if q.w > epsilon
-/// * `-q`, if q.w < -epsilon
-/// * `(0, 0, 0, 1)` otherwise
-/// The rationale is that q and -q represent the same rotation, and any (_, _, _, 0) respresent no rotation at all.
-trait CanonicalQuat: Copy {
-    fn canonical(self) -> Self;
-}
+mod euler {
+    use glam::*;
+    use std::ops::RangeInclusive;
 
-macro_rules! impl_canonical_quat {
-    ($t:ty) => {
-        impl CanonicalQuat for $t {
-            fn canonical(self) -> Self {
-                match self {
-                    _ if self.w >= 1e-5 => self,
-                    _ if self.w <= -1e-5 => -self,
-                    _ => <$t>::from_xyzw(0.0, 0.0, 0.0, 1.0),
+    /// Helper to get the 'canonical' version of a `Quat`. We define the canonical of quat `q` as:
+    ///
+    /// * `q`, if q.w > epsilon
+    /// * `-q`, if q.w < -epsilon
+    /// * `(0, 0, 0, 1)` otherwise
+    ///
+    /// The rationale is that q and -q represent the same rotation, and any (_, _, _, 0) represent no rotation at all.
+    trait CanonicalQuat: Copy {
+        fn canonical(self) -> Self;
+    }
+
+    /// Helper to set some alternative epsilons based on the floating point type used
+    trait EulerEpsilon {
+        /// epsilon for comparing quaternion round-tripped through eulers (quat -> euler -> quat)
+        const E_EPS: f32;
+    }
+
+    impl EulerEpsilon for f32 {
+        const E_EPS: f32 = 2e-6;
+    }
+
+    impl EulerEpsilon for f64 {
+        const E_EPS: f32 = 1e-8;
+    }
+
+    fn axis_order(order: EulerRot) -> (usize, usize, usize) {
+        match order {
+            EulerRot::XYZ => (0, 1, 2),
+            EulerRot::XYX => (0, 1, 0),
+            EulerRot::XZY => (0, 2, 1),
+            EulerRot::XZX => (0, 2, 0),
+            EulerRot::YZX => (1, 2, 0),
+            EulerRot::YZY => (1, 2, 1),
+            EulerRot::YXZ => (1, 0, 2),
+            EulerRot::YXY => (1, 0, 1),
+            EulerRot::ZXY => (2, 0, 1),
+            EulerRot::ZXZ => (2, 0, 2),
+            EulerRot::ZYX => (2, 1, 0),
+            EulerRot::ZYZ => (2, 1, 2),
+            EulerRot::ZYXEx => (2, 1, 0),
+            EulerRot::XYXEx => (0, 1, 0),
+            EulerRot::YZXEx => (1, 2, 0),
+            EulerRot::XZXEx => (0, 2, 0),
+            EulerRot::XZYEx => (0, 2, 1),
+            EulerRot::YZYEx => (1, 2, 1),
+            EulerRot::ZXYEx => (2, 0, 1),
+            EulerRot::YXYEx => (1, 0, 1),
+            EulerRot::YXZEx => (1, 0, 2),
+            EulerRot::ZXZEx => (2, 0, 2),
+            EulerRot::XYZEx => (0, 1, 2),
+            EulerRot::ZYZEx => (2, 1, 2),
+        }
+    }
+
+    fn is_intrinsic(order: EulerRot) -> bool {
+        match order {
+            EulerRot::XYZ
+            | EulerRot::XYX
+            | EulerRot::XZY
+            | EulerRot::XZX
+            | EulerRot::YZX
+            | EulerRot::YZY
+            | EulerRot::YXZ
+            | EulerRot::YXY
+            | EulerRot::ZXY
+            | EulerRot::ZXZ
+            | EulerRot::ZYX
+            | EulerRot::ZYZ => true,
+            EulerRot::ZYXEx
+            | EulerRot::XYXEx
+            | EulerRot::YZXEx
+            | EulerRot::XZXEx
+            | EulerRot::XZYEx
+            | EulerRot::YZYEx
+            | EulerRot::ZXYEx
+            | EulerRot::YXYEx
+            | EulerRot::YXZEx
+            | EulerRot::ZXZEx
+            | EulerRot::XYZEx
+            | EulerRot::ZYZEx => false,
+        }
+    }
+
+    mod f32 {
+        pub fn deg_to_rad(a: i32, b: i32, c: i32) -> (f32, f32, f32) {
+            (
+                (a as f32).to_radians(),
+                (b as f32).to_radians(),
+                (c as f32).to_radians(),
+            )
+        }
+    }
+
+    mod f64 {
+        pub fn deg_to_rad(a: i32, b: i32, c: i32) -> (f64, f64, f64) {
+            (
+                (a as f64).to_radians(),
+                (b as f64).to_radians(),
+                (c as f64).to_radians(),
+            )
+        }
+    }
+
+    fn test_order_angles<F: Fn(EulerRot, i32, i32, i32)>(order: EulerRot, test: &F) {
+        const RANGE: RangeInclusive<i32> = -180..=180;
+        const STEP: usize = 15;
+        for i in RANGE.step_by(STEP) {
+            for j in RANGE.step_by(STEP) {
+                for k in RANGE.step_by(STEP) {
+                    test(order, i, j, k);
                 }
             }
         }
-    };
-}
+    }
 
-impl_canonical_quat!(glam::Quat);
-impl_canonical_quat!(glam::DQuat);
+    fn test_all_orders<F: Fn(EulerRot)>(test: &F) {
+        test(EulerRot::XYZ);
+        test(EulerRot::XZY);
+        test(EulerRot::YZX);
+        test(EulerRot::YXZ);
+        test(EulerRot::ZXY);
+        test(EulerRot::ZYX);
 
-/// Helper to set some alternative epsilons based on the floating point type used
-trait EulerEpsilon {
-    /// epsilon for comparing quaterions built from eulers and axis-angles
-    const Q_EPS: f32;
+        test(EulerRot::XZX);
+        test(EulerRot::XYX);
+        test(EulerRot::YXY);
+        test(EulerRot::YZY);
+        test(EulerRot::ZYZ);
+        test(EulerRot::ZXZ);
 
-    /// epsilon for comparing quaternion round-tripped through eulers (quat -> euler -> quat)
-    const E_EPS: f32;
-}
-impl EulerEpsilon for f32 {
-    const Q_EPS: f32 = 1e-5;
+        test(EulerRot::XYZEx);
+        test(EulerRot::XZYEx);
+        test(EulerRot::YZXEx);
+        test(EulerRot::YXZEx);
+        test(EulerRot::ZXYEx);
+        test(EulerRot::ZYXEx);
 
-    // The scalar-math and wasm paths seems to use a particularly bad implementation of the trig functions
-    #[cfg(any(feature = "scalar-math", target_arch = "wasm32"))]
-    const E_EPS: f32 = 2e-4;
+        test(EulerRot::XZXEx);
+        test(EulerRot::XYXEx);
+        test(EulerRot::YXYEx);
+        test(EulerRot::YZYEx);
+        test(EulerRot::ZYZEx);
+        test(EulerRot::ZXZEx);
+    }
 
-    #[cfg(not(any(feature = "scalar-math", target_arch = "wasm32")))]
-    const E_EPS: f32 = 1e-5;
-}
-impl EulerEpsilon for f64 {
-    const Q_EPS: f32 = 1e-8;
-    const E_EPS: f32 = 1e-8;
-}
+    macro_rules! impl_quat_euler_test {
+        ($quat:ident, $t:ident) => {
+            use super::{
+                axis_order, is_intrinsic, test_all_orders, test_order_angles, $t::deg_to_rad,
+                CanonicalQuat, EulerEpsilon,
+            };
+            use glam::{$quat, EulerRot};
 
-macro_rules! impl_3axis_test {
-    ($name:ident, $t:ty, $quat:ident, $euler:path, $U:path, $V:path, $W:path, $vec:ident) => {
-        glam_test!($name, {
-            let euler = $euler;
-            assert!($U != $W); // First and last axis must be different for three axis
-            for u in (-180..=180).step_by(15) {
-                for v in (-180..=180).step_by(15) {
-                    for w in (-180..=180).step_by(15) {
-                        let u1 = (u as $t).to_radians();
-                        let v1 = (v as $t).to_radians();
-                        let w1 = (w as $t).to_radians();
+            const AXIS_ANGLE: [fn($t) -> $quat; 3] = [
+                $quat::from_rotation_x,
+                $quat::from_rotation_y,
+                $quat::from_rotation_z,
+            ];
 
-                        let q1: $quat = ($quat::from_axis_angle($U, u1)
-                            * $quat::from_axis_angle($V, v1)
-                            * $quat::from_axis_angle($W, w1))
-                        .normalize();
-
-                        // Test if the rotation is the expected
-                        let q2: $quat = $quat::from_euler(euler, u1, v1, w1).normalize();
-                        assert_approx_eq!(q1.canonical(), q2.canonical(), <$t>::Q_EPS);
-
-                        // Test quat reconstruction from angles
-                        let (u2, v2, w2) = q2.to_euler(euler);
-                        let q3 = $quat::from_euler(euler, u2, v2, w2).normalize();
-                        assert_approx_eq!(
-                            q2.canonical(),
-                            q3.canonical(),
-                            <$t>::E_EPS,
-                            format!(
-                                "angles {:?} -> {:?}",
-                                (u, v, w),
-                                (u2.to_degrees(), v2.to_degrees(), w2.to_degrees())
-                            )
-                        );
+            impl CanonicalQuat for $quat {
+                fn canonical(self) -> Self {
+                    match self {
+                        _ if self.w >= 1e-5 => self,
+                        _ if self.w <= -1e-5 => -self,
+                        _ => $quat::from_xyzw(0.0, 0.0, 0.0, 1.0),
                     }
                 }
             }
-        });
-    };
-}
 
-macro_rules! impl_all_quat_tests_three_axis {
-    ($t:ty, $q:ident, $v:ident) => {
-        impl_3axis_test!(test_euler_zyx, $t, $q, ER::ZYX, $v::Z, $v::Y, $v::X, $v);
-        impl_3axis_test!(test_euler_zxy, $t, $q, ER::ZXY, $v::Z, $v::X, $v::Y, $v);
-        impl_3axis_test!(test_euler_yxz, $t, $q, ER::YXZ, $v::Y, $v::X, $v::Z, $v);
-        impl_3axis_test!(test_euler_yzx, $t, $q, ER::YZX, $v::Y, $v::Z, $v::X, $v);
-        impl_3axis_test!(test_euler_xyz, $t, $q, ER::XYZ, $v::X, $v::Y, $v::Z, $v);
-        impl_3axis_test!(test_euler_xzy, $t, $q, ER::XZY, $v::X, $v::Z, $v::Y, $v);
-    };
-}
+            fn test_euler(order: EulerRot, a: i32, b: i32, c: i32) {
+                println!(
+                    "test_euler: {} {order:?} ({a}, {b}, {c})",
+                    stringify!($quat)
+                );
 
-mod euler {
-    use super::{CanonicalQuat, EulerEpsilon};
-    use glam::*;
-    type ER = EulerRot;
+                let (a, b, c) = deg_to_rad(a, b, c);
+                let m = $quat::from_euler(order, a, b, c);
+
+                let n = {
+                    let (i, j, k) = m.to_euler(order);
+                    $quat::from_euler(order, i, j, k)
+                };
+                assert_approx_eq!(m.canonical(), n.canonical(), $t::E_EPS);
+
+                let o = {
+                    let (i, j, k) = axis_order(order);
+                    if is_intrinsic(order) {
+                        AXIS_ANGLE[i](a) * AXIS_ANGLE[j](b) * AXIS_ANGLE[k](c)
+                    } else {
+                        AXIS_ANGLE[k](c) * AXIS_ANGLE[j](b) * AXIS_ANGLE[i](a)
+                    }
+                };
+                assert_approx_eq!(m.canonical(), o.canonical(), $t::E_EPS);
+            }
+
+            #[test]
+            fn test_all_euler_orders() {
+                let test = |order| test_order_angles(order, &test_euler);
+                test_all_orders(&test);
+            }
+        };
+    }
+
+    macro_rules! impl_mat_euler_test {
+        ($mat:ident, $t:ident) => {
+            use super::{
+                axis_order, is_intrinsic, test_all_orders, test_order_angles, $t::deg_to_rad,
+                EulerEpsilon,
+            };
+            use glam::{$mat, EulerRot};
+
+            const AXIS_ANGLE: [fn($t) -> $mat; 3] = [
+                $mat::from_rotation_x,
+                $mat::from_rotation_y,
+                $mat::from_rotation_z,
+            ];
+
+            fn test_euler(order: EulerRot, a: i32, b: i32, c: i32) {
+                println!("test_euler: {} {order:?} ({a}, {b}, {c})", stringify!($mat));
+
+                let (a, b, c) = deg_to_rad(a, b, c);
+                let m = $mat::from_euler(order, a, b, c);
+                let n = {
+                    let (i, j, k) = m.to_euler(order);
+                    $mat::from_euler(order, i, j, k)
+                };
+                assert_approx_eq!(m, n, $t::E_EPS);
+
+                let o = {
+                    let (i, j, k) = axis_order(order);
+                    if is_intrinsic(order) {
+                        AXIS_ANGLE[i](a) * AXIS_ANGLE[j](b) * AXIS_ANGLE[k](c)
+                    } else {
+                        AXIS_ANGLE[k](c) * AXIS_ANGLE[j](b) * AXIS_ANGLE[i](a)
+                    }
+                };
+                assert_approx_eq!(m, o, $t::E_EPS);
+            }
+
+            #[test]
+            fn test_all_euler_orders() {
+                let test = |order| test_order_angles(order, &test_euler);
+                test_all_orders(&test);
+            }
+        };
+    }
+
+    #[test]
+    fn test_euler_default() {
+        assert_eq!(EulerRot::YXZ, EulerRot::default());
+    }
 
     mod quat {
-        use super::*;
+        impl_quat_euler_test!(Quat, f32);
+    }
 
-        impl_all_quat_tests_three_axis!(f32, Quat, Vec3);
+    mod mat3 {
+        impl_mat_euler_test!(Mat3, f32);
+    }
+
+    mod mat3a {
+        impl_mat_euler_test!(Mat3A, f32);
+    }
+
+    mod mat4 {
+        impl_mat_euler_test!(Mat4, f32);
     }
 
     mod dquat {
-        use super::*;
+        impl_quat_euler_test!(DQuat, f64);
+    }
 
-        impl_all_quat_tests_three_axis!(f64, DQuat, DVec3);
+    mod dmat3 {
+        impl_mat_euler_test!(DMat3, f64);
+    }
+
+    mod dmat4 {
+        impl_mat_euler_test!(DMat4, f64);
     }
 }
diff --git a/crates/glam/tests/mat2.rs b/crates/glam/tests/mat2.rs
index 9d579e4..2746e56 100644
--- a/crates/glam/tests/mat2.rs
+++ b/crates/glam/tests/mat2.rs
@@ -4,19 +4,18 @@
 macro_rules! impl_mat2_tests {
     ($t:ident, $newmat2:ident, $mat2:ident, $mat3:ident, $newvec2:ident, $vec2:ident) => {
         const IDENTITY: [[$t; 2]; 2] = [[1.0, 0.0], [0.0, 1.0]];
-
-        const MATRIX: [[$t; 2]; 2] = [[1.0, 2.0], [3.0, 4.0]];
-
-        const MATRIX1D: [$t; 4] = [1.0, 2.0, 3.0, 4.0];
+        const ARRAY2X2: [[$t; 2]; 2] = [[1.0, 2.0], [3.0, 4.0]];
+        const ARRAY1X4: [$t; 4] = [1.0, 2.0, 3.0, 4.0];
+        const ARRAY3X3: [[$t; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
 
         glam_test!(test_const, {
             const M0: $mat2 = $mat2::from_cols($newvec2(1.0, 2.0), $newvec2(3.0, 4.0));
-            const M1: $mat2 = $mat2::from_cols_array(&MATRIX1D);
-            const M2: $mat2 = $mat2::from_cols_array_2d(&MATRIX);
+            const M1: $mat2 = $mat2::from_cols_array(&ARRAY1X4);
+            const M2: $mat2 = $mat2::from_cols_array_2d(&ARRAY2X2);
 
-            assert_eq!(MATRIX1D, M0.to_cols_array());
-            assert_eq!(MATRIX1D, M1.to_cols_array());
-            assert_eq!(MATRIX1D, M2.to_cols_array());
+            assert_eq!(ARRAY1X4, M0.to_cols_array());
+            assert_eq!(ARRAY1X4, M1.to_cols_array());
+            assert_eq!(ARRAY1X4, M2.to_cols_array());
         });
 
         glam_test!(test_mat2_identity, {
@@ -42,7 +41,7 @@
             let mut m = $mat2::ZERO;
             m.x_axis = $vec2::new(1.0, 2.0);
             m.y_axis = $vec2::new(3.0, 4.0);
-            assert_eq!($mat2::from_cols_array_2d(&MATRIX), m);
+            assert_eq!($mat2::from_cols_array_2d(&ARRAY2X2), m);
             assert_eq!($vec2::new(1.0, 2.0), m.x_axis);
             assert_eq!($vec2::new(3.0, 4.0), m.y_axis);
 
@@ -66,8 +65,8 @@
         });
 
         glam_test!(test_mat2_from_axes, {
-            let a = $mat2::from_cols_array_2d(&[[1.0, 2.0], [3.0, 4.0]]);
-            assert_eq!(MATRIX, a.to_cols_array_2d());
+            let a = $mat2::from_cols_array_2d(&ARRAY2X2);
+            assert_eq!(ARRAY2X2, a.to_cols_array_2d());
             let b = $mat2::from_cols($newvec2(1.0, 2.0), $newvec2(3.0, 4.0));
             assert_eq!(a, b);
             let c = $newmat2($newvec2(1.0, 2.0), $newvec2(3.0, 4.0));
@@ -103,12 +102,23 @@
         });
 
         glam_test!(test_from_mat3, {
-            let m3 =
-                $mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
+            let m3 = $mat3::from_cols_array_2d(&ARRAY3X3);
             let m2 = $mat2::from_mat3(m3);
             assert_eq!($mat2::from_cols_array_2d(&[[1.0, 2.0], [4.0, 5.0]]), m2);
         });
 
+        glam_test!(test_from_mat3_minor, {
+            let m3 = $mat3::from_cols_array_2d(&ARRAY3X3);
+            for i in 0..3 {
+                for j in 0..3 {
+                    let m2 = $mat2::from_mat3_minor(m3, i, j);
+                    test_matrix_minor!(3, m2, m3, i, j);
+                }
+            }
+            should_panic!({ $mat2::from_mat3_minor(m3, 3, 0) });
+            should_panic!({ $mat2::from_mat3_minor(m3, 0, 3) });
+        });
+
         glam_test!(test_mat2_transpose, {
             let m = $newmat2($newvec2(1.0, 2.0), $newvec2(3.0, 4.0));
             let mt = m.transpose();
@@ -128,7 +138,7 @@
             );
             assert_eq!(
                 1.0 * 4.0 - 2.0 * 3.0,
-                $mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]).determinant()
+                $mat2::from_cols_array(&ARRAY1X4).determinant()
             );
         });
 
@@ -156,11 +166,13 @@
         });
 
         glam_test!(test_mat2_ops, {
-            let m0 = $mat2::from_cols_array_2d(&MATRIX);
+            let m0 = $mat2::from_cols_array_2d(&ARRAY2X2);
             let m0x2 = $mat2::from_cols_array_2d(&[[2.0, 4.0], [6.0, 8.0]]);
             let m0_neg = $mat2::from_cols_array_2d(&[[-1.0, -2.0], [-3.0, -4.0]]);
             assert_eq!(m0x2, m0 * 2.0);
             assert_eq!(m0x2, 2.0 * m0);
+            assert_eq!(m0, m0x2 / 2.0);
+            assert_eq!(m0, 2.0 / m0x2);
             assert_eq!(m0x2, m0 + m0);
             assert_eq!($mat2::ZERO, m0 - m0);
             assert_eq!(m0_neg, -m0);
@@ -171,6 +183,10 @@
             m1 *= 2.0;
             assert_eq!(m0x2, m1);
 
+            let mut m1 = m0x2;
+            m1 /= 2.0;
+            assert_eq!(m0, m1);
+
             let mut m1 = m0;
             m1 += m0;
             assert_eq!(m0x2, m1);
@@ -185,16 +201,17 @@
         });
 
         glam_test!(test_mat2_fmt, {
-            let a = $mat2::from_cols_array_2d(&MATRIX);
+            let a = $mat2::from_cols_array_2d(&ARRAY2X2);
             assert_eq!(format!("{}", a), "[[1, 2], [3, 4]]");
+            assert_eq!(format!("{:.2}", a), "[[1.00, 2.00], [3.00, 4.00]]");
         });
 
         glam_test!(test_mat2_to_from_slice, {
-            let m = $mat2::from_cols_slice(&MATRIX1D);
-            assert_eq!($mat2::from_cols_array(&MATRIX1D), m);
+            let m = $mat2::from_cols_slice(&ARRAY1X4);
+            assert_eq!($mat2::from_cols_array(&ARRAY1X4), m);
             let mut out: [$t; 4] = Default::default();
             m.write_cols_to_slice(&mut out);
-            assert_eq!(MATRIX1D, out);
+            assert_eq!(ARRAY1X4, out);
 
             should_panic!({ $mat2::from_cols_slice(&[0.0; 3]) });
             should_panic!({ $mat2::IDENTITY.write_cols_to_slice(&mut [0.0; 3]) });
@@ -213,13 +230,10 @@
         });
 
         glam_test!(test_mat2_is_finite, {
-            use std::$t::INFINITY;
-            use std::$t::NAN;
-            use std::$t::NEG_INFINITY;
             assert!($mat2::IDENTITY.is_finite());
-            assert!(!($mat2::IDENTITY * INFINITY).is_finite());
-            assert!(!($mat2::IDENTITY * NEG_INFINITY).is_finite());
-            assert!(!($mat2::IDENTITY * NAN).is_finite());
+            assert!(!($mat2::IDENTITY * $t::INFINITY).is_finite());
+            assert!(!($mat2::IDENTITY * $t::NEG_INFINITY).is_finite());
+            assert!(!($mat2::IDENTITY * $t::NAN).is_finite());
         });
     };
 }
@@ -227,20 +241,20 @@
 macro_rules! impl_as_ref_tests {
     ($mat:ident) => {
         glam_test!(test_as_ref, {
-            let m = $mat::from_cols_array_2d(&MATRIX);
-            assert_eq!(MATRIX1D, *m.as_ref());
+            let m = $mat::from_cols_array_2d(&ARRAY2X2);
+            assert_eq!(ARRAY1X4, *m.as_ref());
         });
         glam_test!(test_as_mut, {
             let mut m = $mat::ZERO;
-            *m.as_mut() = MATRIX1D;
-            assert_eq!($mat::from_cols_array_2d(&MATRIX), m);
+            *m.as_mut() = ARRAY1X4;
+            assert_eq!($mat::from_cols_array_2d(&ARRAY2X2), m);
         });
     };
 }
 
 mod mat2 {
     use super::support::deg;
-    use glam::{mat2, swizzles::*, vec2, Mat2, Mat3, Vec2};
+    use glam::{mat2, swizzles::*, vec2, Mat2, Mat3, Mat3A, Vec2};
 
     glam_test!(test_align, {
         use std::mem;
@@ -253,12 +267,23 @@
     });
 
     glam_test!(test_from_mat3a, {
-        use glam::Mat3A;
-        let m3 = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
+        let m3 = Mat3A::from_cols_array_2d(&ARRAY3X3);
         let m2 = Mat2::from_mat3a(m3);
         assert_eq!(Mat2::from_cols_array_2d(&[[1.0, 2.0], [4.0, 5.0]]), m2);
     });
 
+    glam_test!(test_from_mat3a_minor, {
+        let m3 = Mat3A::from_cols_array_2d(&ARRAY3X3);
+        for i in 0..3 {
+            for j in 0..3 {
+                let m2 = Mat2::from_mat3a_minor(m3, i, j);
+                test_matrix_minor!(3, m2, m3, i, j);
+            }
+        }
+        should_panic!({ Mat2::from_mat3a_minor(m3, 3, 0) });
+        should_panic!({ Mat2::from_mat3a_minor(m3, 0, 3) });
+    });
+
     glam_test!(test_as, {
         use glam::DMat2;
         assert_eq!(
diff --git a/crates/glam/tests/mat3.rs b/crates/glam/tests/mat3.rs
index 36a8d38..ef36606 100644
--- a/crates/glam/tests/mat3.rs
+++ b/crates/glam/tests/mat3.rs
@@ -3,15 +3,15 @@
 
 macro_rules! impl_mat3_tests {
     ($t:ident, $newmat3:ident, $mat3:ident, $mat2:ident, $mat4:ident, $quat:ident, $newvec3:ident, $vec3:ident, $vec2:ident) => {
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         const IDENTITY: [[$t; 3]; 3] = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
-
-        const MATRIX: [[$t; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
-
-        const MATRIX1D: [$t; 9] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
+        const ARRAY3X3: [[$t; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
+        const ARRAY1X9: [$t; 9] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
+        const ARRAY4X4: [[$t; 4]; 4] = [
+            [1.0, 2.0, 3.0, 4.0],
+            [5.0, 6.0, 7.0, 8.0],
+            [9.0, 10.0, 11.0, 12.0],
+            [13.0, 14.0, 15.0, 16.0],
+        ];
 
         glam_test!(test_const, {
             const M0: $mat3 = $mat3::from_cols(
@@ -19,12 +19,12 @@
                 $newvec3(4.0, 5.0, 6.0),
                 $newvec3(7.0, 8.0, 9.0),
             );
-            const M1: $mat3 = $mat3::from_cols_array(&MATRIX1D);
-            const M2: $mat3 = $mat3::from_cols_array_2d(&MATRIX);
+            const M1: $mat3 = $mat3::from_cols_array(&ARRAY1X9);
+            const M2: $mat3 = $mat3::from_cols_array_2d(&ARRAY3X3);
 
-            assert_eq!(MATRIX1D, M0.to_cols_array());
-            assert_eq!(MATRIX1D, M1.to_cols_array());
-            assert_eq!(MATRIX1D, M2.to_cols_array());
+            assert_eq!(ARRAY1X9, M0.to_cols_array());
+            assert_eq!(ARRAY1X9, M1.to_cols_array());
+            assert_eq!(ARRAY1X9, M2.to_cols_array());
         });
 
         glam_test!(test_mat3_identity, {
@@ -61,7 +61,7 @@
             m.x_axis = $newvec3(1.0, 2.0, 3.0);
             m.y_axis = $newvec3(4.0, 5.0, 6.0);
             m.z_axis = $newvec3(7.0, 8.0, 9.0);
-            assert_eq!($mat3::from_cols_array_2d(&MATRIX), m);
+            assert_eq!($mat3::from_cols_array_2d(&ARRAY3X3), m);
             assert_eq!($newvec3(1.0, 2.0, 3.0), m.x_axis);
             assert_eq!($newvec3(4.0, 5.0, 6.0), m.y_axis);
             assert_eq!($newvec3(7.0, 8.0, 9.0), m.z_axis);
@@ -91,7 +91,7 @@
 
         glam_test!(test_mat3_from_axes, {
             let a = $mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
-            assert_eq!(MATRIX, a.to_cols_array_2d());
+            assert_eq!(ARRAY3X3, a.to_cols_array_2d());
             let b = $mat3::from_cols(
                 $newvec3(1.0, 2.0, 3.0),
                 $newvec3(4.0, 5.0, 6.0),
@@ -218,12 +218,7 @@
         });
 
         glam_test!(test_from_mat4, {
-            let m4 = $mat4::from_cols_array_2d(&[
-                [1.0, 2.0, 3.0, 4.0],
-                [5.0, 6.0, 7.0, 8.0],
-                [9.0, 10.0, 11.0, 12.0],
-                [13.0, 14.0, 15.0, 16.0],
-            ]);
+            let m4 = $mat4::from_cols_array_2d(&ARRAY4X4);
             let m3 = $mat3::from_mat4(m4);
             assert_eq!(
                 $mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [5.0, 6.0, 7.0], [9.0, 10.0, 11.0]]),
@@ -231,6 +226,18 @@
             );
         });
 
+        glam_test!(test_from_mat4_minor, {
+            let m4 = $mat4::from_cols_array_2d(&ARRAY4X4);
+            for i in 0..4 {
+                for j in 0..4 {
+                    let m3 = $mat3::from_mat4_minor(m4, i, j);
+                    test_matrix_minor!(4, m3, m4, i, j);
+                }
+            }
+            should_panic!({ $mat3::from_mat4_minor(m4, 4, 0) });
+            should_panic!({ $mat3::from_mat4_minor(m4, 0, 4) });
+        });
+
         glam_test!(test_mat3_transpose, {
             let m = $newmat3(
                 $newvec3(1.0, 2.0, 3.0),
@@ -287,7 +294,7 @@
         });
 
         glam_test!(test_mat3_ops, {
-            let m0 = $mat3::from_cols_array_2d(&MATRIX);
+            let m0 = $mat3::from_cols_array_2d(&ARRAY3X3);
             let m0x2 = $mat3::from_cols_array_2d(&[
                 [2.0, 4.0, 6.0],
                 [8.0, 10.0, 12.0],
@@ -300,6 +307,8 @@
             ]);
             assert_eq!(m0x2, m0 * 2.0);
             assert_eq!(m0x2, 2.0 * m0);
+            assert_eq!(m0, m0x2 / 2.0);
+            assert_eq!(m0, 2.0 / m0x2);
             assert_eq!(m0x2, m0 + m0);
             assert_eq!($mat3::ZERO, m0 - m0);
             assert_eq!(m0_neg, -m0);
@@ -310,6 +319,10 @@
             m1 *= 2.0;
             assert_eq!(m0x2, m1);
 
+            let mut m1 = m0x2;
+            m1 /= 2.0;
+            assert_eq!(m0, m1);
+
             let mut m1 = m0;
             m1 += m0;
             assert_eq!(m0x2, m1);
@@ -324,16 +337,20 @@
         });
 
         glam_test!(test_mat3_fmt, {
-            let a = $mat3::from_cols_array_2d(&MATRIX);
+            let a = $mat3::from_cols_array_2d(&ARRAY3X3);
             assert_eq!(format!("{}", a), "[[1, 2, 3], [4, 5, 6], [7, 8, 9]]");
+            assert_eq!(
+                format!("{:.1}", a),
+                "[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]"
+            );
         });
 
         glam_test!(test_mat3_to_from_slice, {
-            let m = $mat3::from_cols_slice(&MATRIX1D);
-            assert_eq!($mat3::from_cols_array(&MATRIX1D), m);
+            let m = $mat3::from_cols_slice(&ARRAY1X9);
+            assert_eq!($mat3::from_cols_array(&ARRAY1X9), m);
             let mut out: [$t; 9] = Default::default();
             m.write_cols_to_slice(&mut out);
-            assert_eq!(MATRIX1D, out);
+            assert_eq!(ARRAY1X9, out);
 
             should_panic!({ $mat3::from_cols_slice(&[0.0; 8]) });
             should_panic!({ $mat3::IDENTITY.write_cols_to_slice(&mut [0.0; 8]) });
@@ -353,9 +370,9 @@
 
         glam_test!(test_mat3_is_finite, {
             assert!($mat3::IDENTITY.is_finite());
-            assert!(!($mat3::IDENTITY * INFINITY).is_finite());
-            assert!(!($mat3::IDENTITY * NEG_INFINITY).is_finite());
-            assert!(!($mat3::IDENTITY * NAN).is_finite());
+            assert!(!($mat3::IDENTITY * $t::INFINITY).is_finite());
+            assert!(!($mat3::IDENTITY * $t::NEG_INFINITY).is_finite());
+            assert!(!($mat3::IDENTITY * $t::NAN).is_finite());
         });
     };
 }
@@ -363,13 +380,13 @@
 macro_rules! impl_as_ref_tests {
     ($mat:ident) => {
         glam_test!(test_as_ref, {
-            let m = $mat::from_cols_array_2d(&MATRIX);
-            assert_eq!(MATRIX1D, *m.as_ref());
+            let m = $mat::from_cols_array_2d(&ARRAY3X3);
+            assert_eq!(ARRAY1X9, *m.as_ref());
         });
         glam_test!(test_as_mut, {
             let mut m = $mat::ZERO;
-            *m.as_mut() = MATRIX1D;
-            assert_eq!($mat::from_cols_array_2d(&MATRIX), m);
+            *m.as_mut() = ARRAY1X9;
+            assert_eq!($mat::from_cols_array_2d(&ARRAY3X3), m);
         });
     };
 }
diff --git a/crates/glam/tests/mat4.rs b/crates/glam/tests/mat4.rs
index d3b9031..e2a760c 100644
--- a/crates/glam/tests/mat4.rs
+++ b/crates/glam/tests/mat4.rs
@@ -3,26 +3,22 @@
 
 macro_rules! impl_mat4_tests {
     ($t:ident, $newmat4:ident, $newvec4:ident, $newvec3:ident, $mat4:ident, $mat3:ident, $quat:ident, $vec4:ident, $vec3:ident) => {
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         const IDENTITY: [[$t; 4]; 4] = [
             [1.0, 0.0, 0.0, 0.0],
             [0.0, 1.0, 0.0, 0.0],
             [0.0, 0.0, 1.0, 0.0],
             [0.0, 0.0, 0.0, 1.0],
         ];
-        const MATRIX: [[$t; 4]; 4] = [
+        const ARRAY4X4: [[$t; 4]; 4] = [
             [1.0, 2.0, 3.0, 4.0],
             [5.0, 6.0, 7.0, 8.0],
             [9.0, 10.0, 11.0, 12.0],
             [13.0, 14.0, 15.0, 16.0],
         ];
-
-        const MATRIX1D: [$t; 16] = [
+        const ARRAY1X16: [$t; 16] = [
             1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
         ];
+        const ARRAY3X3: [[$t; 3]; 3] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
 
         glam_test!(test_const, {
             const M0: $mat4 = $mat4::from_cols(
@@ -31,12 +27,12 @@
                 $newvec4(9.0, 10.0, 11.0, 12.0),
                 $newvec4(13.0, 14.0, 15.0, 16.0),
             );
-            const M1: $mat4 = $mat4::from_cols_array(&MATRIX1D);
-            const M2: $mat4 = $mat4::from_cols_array_2d(&MATRIX);
+            const M1: $mat4 = $mat4::from_cols_array(&ARRAY1X16);
+            const M2: $mat4 = $mat4::from_cols_array_2d(&ARRAY4X4);
 
-            assert_eq!(MATRIX1D, M0.to_cols_array());
-            assert_eq!(MATRIX1D, M1.to_cols_array());
-            assert_eq!(MATRIX1D, M2.to_cols_array());
+            assert_eq!(ARRAY1X16, M0.to_cols_array());
+            assert_eq!(ARRAY1X16, M1.to_cols_array());
+            assert_eq!(ARRAY1X16, M2.to_cols_array());
         });
 
         glam_test!(test_mat4_identity, {
@@ -80,7 +76,7 @@
             m.y_axis = $vec4::new(5.0, 6.0, 7.0, 8.0);
             m.z_axis = $vec4::new(9.0, 10.0, 11.0, 12.0);
             m.w_axis = $vec4::new(13.0, 14.0, 15.0, 16.0);
-            assert_eq!($mat4::from_cols_array_2d(&MATRIX), m);
+            assert_eq!($mat4::from_cols_array_2d(&ARRAY4X4), m);
             assert_eq!($vec4::new(1.0, 2.0, 3.0, 4.0), m.x_axis);
             assert_eq!($vec4::new(5.0, 6.0, 7.0, 8.0), m.y_axis);
             assert_eq!($vec4::new(9.0, 10.0, 11.0, 12.0), m.z_axis);
@@ -120,7 +116,7 @@
                 [9.0, 10.0, 11.0, 12.0],
                 [13.0, 14.0, 15.0, 16.0],
             ]);
-            assert_eq!(MATRIX, a.to_cols_array_2d());
+            assert_eq!(ARRAY4X4, a.to_cols_array_2d());
             let b = $mat4::from_cols(
                 $newvec4(1.0, 2.0, 3.0, 4.0),
                 $newvec4(5.0, 6.0, 7.0, 8.0),
@@ -172,7 +168,7 @@
 
         glam_test!(test_from_mat3, {
             let m3 =
-                $mat3::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
+                $mat3::from_cols_array_2d(&ARRAY3X3);
             let m4 = $mat4::from_mat3(m3);
             assert_eq!(
                 $mat4::from_cols_array_2d(&[
@@ -588,7 +584,7 @@
         });
 
         glam_test!(test_mat4_ops, {
-            let m0 = $mat4::from_cols_array_2d(&MATRIX);
+            let m0 = $mat4::from_cols_array_2d(&ARRAY4X4);
             let m0x2 = $mat4::from_cols_array_2d(&[
                 [2.0, 4.0, 6.0, 8.0],
                 [10.0, 12.0, 14.0, 16.0],
@@ -603,6 +599,8 @@
             ]);
             assert_eq!(m0x2, m0 * 2.0);
             assert_eq!(m0x2, 2.0 * m0);
+            assert_eq!(m0, m0x2 / 2.0);
+            assert_eq!(m0, 2.0 / m0x2);
             assert_eq!(m0x2, m0 + m0);
             assert_eq!($mat4::ZERO, m0 - m0);
             assert_eq!(m0_neg, -m0);
@@ -613,6 +611,10 @@
             m1 *= 2.0;
             assert_eq!(m0x2, m1);
 
+            let mut m1 = m0x2;
+            m1 /= 2.0;
+            assert_eq!(m0, m1);
+
             let mut m1 = m0;
             m1 += m0;
             assert_eq!(m0x2, m1);
@@ -627,19 +629,23 @@
         });
 
         glam_test!(test_mat4_fmt, {
-            let a = $mat4::from_cols_array_2d(&MATRIX);
+            let a = $mat4::from_cols_array_2d(&ARRAY4X4);
             assert_eq!(
                 format!("{}", a),
                 "[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]"
             );
+            assert_eq!(
+                format!("{:.1}", a),
+                "[[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, 10.0, 11.0, 12.0], [13.0, 14.0, 15.0, 16.0]]"
+            );
         });
 
         glam_test!(test_mat4_to_from_slice, {
-            let m = $mat4::from_cols_slice(&MATRIX1D);
-            assert_eq!($mat4::from_cols_array(&MATRIX1D), m);
+            let m = $mat4::from_cols_slice(&ARRAY1X16);
+            assert_eq!($mat4::from_cols_array(&ARRAY1X16), m);
             let mut out: [$t; 16] = Default::default();
             m.write_cols_to_slice(&mut out);
-            assert_eq!(MATRIX1D, out);
+            assert_eq!(ARRAY1X16, out);
 
             should_panic!({ $mat4::from_cols_slice(&[0.0; 15]) });
             should_panic!({ $mat4::IDENTITY.write_cols_to_slice(&mut [0.0; 15]) });
@@ -659,9 +665,31 @@
 
         glam_test!(test_mat4_is_finite, {
             assert!($mat4::IDENTITY.is_finite());
-            assert!(!($mat4::IDENTITY * INFINITY).is_finite());
-            assert!(!($mat4::IDENTITY * NEG_INFINITY).is_finite());
-            assert!(!($mat4::IDENTITY * NAN).is_finite());
+            assert!(!($mat4::IDENTITY * $t::INFINITY).is_finite());
+            assert!(!($mat4::IDENTITY * $t::NEG_INFINITY).is_finite());
+            assert!(!($mat4::IDENTITY * $t::NAN).is_finite());
+        });
+
+        glam_test!(test_mat4_abs, {
+            let neg = $mat4::IDENTITY * -1.0;
+            assert_eq!(neg.abs(), $mat4::IDENTITY);
+
+            let partial_neg = $mat4::from_cols_array_2d(&[
+                [1.0, -2.0, 3.0, -4.0],
+                [-5.0, 6.0, -7.0, 8.0],
+                [-9.0, 10.0, 11.0, -12.0],
+                [13.0, -14.0, -15.0, 16.0],
+            ]);
+
+            assert_eq!(
+                partial_neg.abs(),
+                $mat4::from_cols_array_2d(&[
+                    [1.0, 2.0, 3.0, 4.0],
+                    [5.0, 6.0, 7.0, 8.0],
+                    [9.0, 10.0, 11.0, 12.0],
+                    [13.0, 14.0, 15.0, 16.0],
+                ])
+            );
         });
     };
 }
@@ -669,13 +697,13 @@
 macro_rules! impl_as_ref_tests {
     ($mat:ident) => {
         glam_test!(test_as_ref, {
-            let m = $mat::from_cols_array_2d(&MATRIX);
-            assert_eq!(MATRIX1D, *m.as_ref());
+            let m = $mat::from_cols_array_2d(&ARRAY4X4);
+            assert_eq!(ARRAY1X16, *m.as_ref());
         });
         glam_test!(test_as_mut, {
             let mut m = $mat::ZERO;
-            *m.as_mut() = MATRIX1D;
-            assert_eq!($mat::from_cols_array_2d(&MATRIX), m);
+            *m.as_mut() = ARRAY1X16;
+            assert_eq!($mat::from_cols_array_2d(&ARRAY4X4), m);
         });
     };
 }
@@ -692,7 +720,7 @@
 
     glam_test!(test_from_mat3a, {
         use glam::Mat3A;
-        let m3 = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
+        let m3 = Mat3A::from_cols_array_2d(&ARRAY3X3);
         let m4 = Mat4::from_mat3a(m3);
         assert_eq!(
             Mat4::from_cols_array_2d(&[
@@ -705,6 +733,35 @@
         );
     });
 
+    glam_test!(test_transform_vec3a, {
+        use glam::Vec3A;
+        let m = Mat4::from_axis_angle(Vec3::Z, deg(90.0));
+        let result3 = m.transform_vector3a(Vec3A::Y);
+        assert_approx_eq!(Vec3A::new(-1.0, 0.0, 0.0), result3);
+
+        let m = Mat4::from_scale_rotation_translation(
+            Vec3::new(0.5, 1.5, 2.0),
+            Quat::from_rotation_x(deg(90.0)),
+            Vec3::new(1.0, 2.0, 3.0),
+        );
+        let result3 = m.transform_vector3a(Vec3A::Y);
+        assert_approx_eq!(Vec3A::new(0.0, 0.0, 1.5), result3, 1.0e-6);
+
+        let result3 = m.transform_point3a(Vec3A::Y);
+        assert_approx_eq!(Vec3A::new(1.0, 2.0, 4.5), result3, 1.0e-6);
+
+        let m = Mat4::from_cols(
+            vec4(8.0, 0.0, 0.0, 0.0),
+            vec4(0.0, 4.0, 0.0, 0.0),
+            vec4(0.0, 0.0, 2.0, 2.0),
+            vec4(0.0, 0.0, 0.0, 0.0),
+        );
+        assert_approx_eq!(
+            Vec3A::new(4.0, 2.0, 1.0),
+            m.project_point3a(Vec3A::new(2.0, 2.0, 2.0))
+        );
+    });
+
     glam_test!(test_as, {
         use glam::DMat4;
         assert_eq!(
diff --git a/crates/glam/tests/quat.rs b/crates/glam/tests/quat.rs
index dfa7afa..3c8a090 100644
--- a/crates/glam/tests/quat.rs
+++ b/crates/glam/tests/quat.rs
@@ -5,10 +5,6 @@
 
 macro_rules! impl_quat_tests {
     ($t:ident, $new:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => {
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_const, {
             const Q0: $quat = $quat::from_xyzw(1.0, 2.0, 3.0, 4.0);
             const Q1: $quat = $quat::from_array([1.0, 2.0, 3.0, 4.0]);
@@ -230,13 +226,11 @@
 
             should_glam_assert!({ ($quat::IDENTITY * 0.5).mul_vec3($vec3::X) });
             should_glam_assert!({ ($quat::IDENTITY * 0.5) * $vec3::X });
-            should_glam_assert!({ ($quat::IDENTITY * 0.5).mul_quat($quat::IDENTITY) });
-            should_glam_assert!({ ($quat::IDENTITY * 0.5) * $quat::IDENTITY });
         });
 
         glam_test!(test_angle_between, {
             const TAU: $t = 2.0 * core::$t::consts::PI;
-            let eps = 10.0 * core::$t::EPSILON as f32;
+            let eps = 10.0 * $t::EPSILON as f32;
             let q1 = $quat::from_euler(EulerRot::YXZ, 0.0, 0.0, 0.0);
             let q2 = $quat::from_euler(EulerRot::YXZ, TAU * 0.25, 0.0, 0.0);
             let q3 = $quat::from_euler(EulerRot::YXZ, TAU * 0.5, 0.0, 0.0);
@@ -264,6 +258,9 @@
 
         glam_test!(test_lerp, {
             let q0 = $quat::from_rotation_y(deg(0.0));
+            assert_approx_eq!(q0, q0.slerp(q0, 0.0));
+            assert_approx_eq!(q0, q0.slerp(q0, 1.0));
+
             let q1 = $quat::from_rotation_y(deg(90.0));
             assert_approx_eq!(q0, q0.lerp(q1, 0.0));
             assert_approx_eq!(q1, q0.lerp(q1, 1.0));
@@ -275,13 +272,16 @@
 
         glam_test!(test_slerp, {
             let q0 = $quat::from_rotation_y(deg(0.0));
+            assert_approx_eq!(q0, q0.slerp(q0, 0.0));
+            assert_approx_eq!(q0, q0.slerp(q0, 1.0));
+
             let q1 = $quat::from_rotation_y(deg(90.0));
             assert_approx_eq!(q0, q0.slerp(q1, 0.0), 1.0e-3);
             assert_approx_eq!(q1, q0.slerp(q1, 1.0), 1.0e-3);
             assert_approx_eq!($quat::from_rotation_y(deg(45.0)), q0.slerp(q1, 0.5), 1.0e-3);
 
-            should_glam_assert!({ $quat::lerp($quat::IDENTITY * 2.0, $quat::IDENTITY, 1.0) });
-            should_glam_assert!({ $quat::lerp($quat::IDENTITY, $quat::IDENTITY * 0.5, 1.0) });
+            should_glam_assert!({ $quat::slerp($quat::IDENTITY * 2.0, $quat::IDENTITY, 1.0) });
+            should_glam_assert!({ $quat::slerp($quat::IDENTITY, $quat::IDENTITY * 0.5, 1.0) });
         });
 
         glam_test!(test_slerp_constant_speed, {
@@ -329,6 +329,35 @@
             assert!(s.is_normalized());
         });
 
+        glam_test!(test_rotate_towards, {
+            use core::$t::consts::{FRAC_PI_2, FRAC_PI_4};
+            let eps = 10.0 * $t::EPSILON as f32;
+
+            // Setup such that `q0` is `PI/2` and `-PI/2` radians away from `q1` and `q2` respectively.
+            let q0 = $quat::from_euler(EulerRot::YXZ, 0.0, 0.0, 0.0);
+            let q1 = $quat::from_euler(EulerRot::YXZ, FRAC_PI_2, 0.0, 0.0);
+            let q2 = $quat::from_euler(EulerRot::YXZ, -FRAC_PI_2, 0.0, 0.0);
+
+            // Positive delta
+            assert_approx_eq!(q0, q0.rotate_towards(q1, 0.0), eps);
+            assert_approx_eq!(
+                $quat::from_euler(EulerRot::YXZ, FRAC_PI_4, 0.0, 0.0),
+                q0.rotate_towards(q1, FRAC_PI_4),
+                eps
+            );
+            assert_approx_eq!(q1, q0.rotate_towards(q1, FRAC_PI_2), eps);
+            assert_approx_eq!(q1, q0.rotate_towards(q1, FRAC_PI_2 * 1.5), eps);
+
+            // Negative delta
+            assert_approx_eq!(
+                $quat::from_euler(EulerRot::YXZ, -FRAC_PI_4, 0.0, 0.0),
+                q0.rotate_towards(q1, -FRAC_PI_4),
+                eps
+            );
+            assert_approx_eq!(q2, q0.rotate_towards(q1, -FRAC_PI_2), eps);
+            assert_approx_eq!(q2, q0.rotate_towards(q1, -FRAC_PI_2 * 1.5), eps);
+        });
+
         glam_test!(test_fmt, {
             let a = $quat::IDENTITY;
             assert_eq!(
@@ -340,6 +369,7 @@
             //     "$quat(\n    1.0,\n    2.0,\n    3.0,\n    4.0\n)"
             // );
             assert_eq!(format!("{}", a), "[0, 0, 0, 1]");
+            assert_eq!(format!("{:.2}", a), "[0.00, 0.00, 0.00, 1.00]");
         });
 
         glam_test!(test_identity, {
@@ -420,14 +450,14 @@
         glam_test!(test_is_finite, {
             assert!($quat::from_xyzw(0.0, 0.0, 0.0, 0.0).is_finite());
             assert!($quat::from_xyzw(-1e-10, 1.0, 1e10, 42.0).is_finite());
-            assert!(!$quat::from_xyzw(INFINITY, 0.0, 0.0, 0.0).is_finite());
-            assert!(!$quat::from_xyzw(0.0, NAN, 0.0, 0.0).is_finite());
-            assert!(!$quat::from_xyzw(0.0, 0.0, NEG_INFINITY, 0.0).is_finite());
-            assert!(!$quat::from_xyzw(0.0, 0.0, 0.0, NAN).is_finite());
+            assert!(!$quat::from_xyzw($t::INFINITY, 0.0, 0.0, 0.0).is_finite());
+            assert!(!$quat::from_xyzw(0.0, $t::NAN, 0.0, 0.0).is_finite());
+            assert!(!$quat::from_xyzw(0.0, 0.0, $t::NEG_INFINITY, 0.0).is_finite());
+            assert!(!$quat::from_xyzw(0.0, 0.0, 0.0, $t::NAN).is_finite());
         });
 
         glam_test!(test_rotation_arc, {
-            let eps = 2.0 * core::$t::EPSILON.sqrt();
+            let eps = 2.0 * $t::EPSILON.sqrt();
 
             for &from in &vec3_float_test_vectors!($vec3) {
                 let from = from.normalize();
diff --git a/crates/glam/tests/support.rs b/crates/glam/tests/support.rs
index 08000e9..063a882 100644
--- a/crates/glam/tests/support.rs
+++ b/crates/glam/tests/support.rs
@@ -1,3 +1,4 @@
+#![allow(dead_code)]
 #[path = "support/macros.rs"]
 #[macro_use]
 mod macros;
diff --git a/crates/glam/tests/support/macros.rs b/crates/glam/tests/support/macros.rs
index e7fadd1..4babd87 100644
--- a/crates/glam/tests/support/macros.rs
+++ b/crates/glam/tests/support/macros.rs
@@ -12,7 +12,7 @@
 #[macro_export]
 macro_rules! should_panic {
     ($block:block) => {{
-        #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
+        #[cfg(all(feature = "std", panic = "unwind"))]
         assert!(std::panic::catch_unwind(|| $block).is_err());
     }};
 }
@@ -30,7 +30,7 @@
     ($a:expr, $b:expr) => {{
         #[allow(unused_imports)]
         use $crate::support::FloatCompare;
-        let eps = core::f32::EPSILON;
+        let eps = f32::EPSILON;
         let (a, b) = (&$a, &$b);
         assert!(
             a.approx_eq(b, eps),
@@ -78,9 +78,6 @@
 #[macro_export]
 macro_rules! impl_vec_float_normalize_tests {
     ($t:ident, $vec:ident) => {
-        use core::$t::MAX;
-        use core::$t::MIN_POSITIVE;
-
         /// Works for vec2, vec3, vec4
         fn from_x_y(x: $t, y: $t) -> $vec {
             let mut v = $vec::ZERO;
@@ -91,27 +88,30 @@
 
         glam_test!(test_normalize, {
             assert_eq!(from_x_y(-42.0, 0.0).normalize(), from_x_y(-1.0, 0.0));
-            assert_eq!(from_x_y(MAX.sqrt(), 0.0).normalize(), from_x_y(1.0, 0.0));
-            // assert_eq!(from_x_y(MAX, 0.0).normalize(), from_x_y(1.0, 0.0)); // normalize fails for huge vectors and returns zero
+            assert_eq!(
+                from_x_y($t::MAX.sqrt(), 0.0).normalize(),
+                from_x_y(1.0, 0.0)
+            );
+            // assert_eq!(from_x_y($t::MAX, 0.0).normalize(), from_x_y(1.0, 0.0)); // normalize fails for huge vectors and returns zero
 
             // We expect not to be able to normalize small numbers:
             should_glam_assert!({ from_x_y(0.0, 0.0).normalize() });
-            should_glam_assert!({ from_x_y(MIN_POSITIVE, 0.0).normalize() });
+            should_glam_assert!({ from_x_y($t::MIN_POSITIVE, 0.0).normalize() });
 
             // We expect not to be able to normalize non-finite vectors:
-            should_glam_assert!({ from_x_y(INFINITY, 0.0).normalize() });
-            should_glam_assert!({ from_x_y(NAN, 0.0).normalize() });
+            should_glam_assert!({ from_x_y($t::INFINITY, 0.0).normalize() });
+            should_glam_assert!({ from_x_y($t::NAN, 0.0).normalize() });
         });
 
         #[cfg(not(any(feature = "debug-glam-assert", feature = "glam-assert")))]
         glam_test!(test_normalize_no_glam_assert, {
             // We expect not to be able to normalize small numbers:
             assert!(!from_x_y(0.0, 0.0).normalize().is_finite());
-            assert!(!from_x_y(MIN_POSITIVE, 0.0).normalize().is_finite());
+            assert!(!from_x_y($t::MIN_POSITIVE, 0.0).normalize().is_finite());
 
             // We expect not to be able to normalize non-finite vectors:
-            assert!(!from_x_y(INFINITY, 0.0).normalize().is_finite());
-            assert!(!from_x_y(NAN, 0.0).normalize().is_finite());
+            assert!(!from_x_y($t::INFINITY, 0.0).normalize().is_finite());
+            assert!(!from_x_y($t::NAN, 0.0).normalize().is_finite());
         });
 
         glam_test!(test_try_normalize, {
@@ -120,21 +120,47 @@
                 Some(from_x_y(-1.0, 0.0))
             );
             assert_eq!(
-                from_x_y(MAX.sqrt(), 0.0).try_normalize(),
+                from_x_y($t::MAX.sqrt(), 0.0).try_normalize(),
                 Some(from_x_y(1.0, 0.0))
             );
 
             // We expect `try_normalize` to return None when inputs are very small:
             assert_eq!(from_x_y(0.0, 0.0).try_normalize(), None);
-            assert_eq!(from_x_y(MIN_POSITIVE, 0.0).try_normalize(), None);
+            assert_eq!(from_x_y($t::MIN_POSITIVE, 0.0).try_normalize(), None);
 
             // We expect `try_normalize` to return None when inputs are non-finite:
-            assert_eq!(from_x_y(INFINITY, 0.0).try_normalize(), None);
-            assert_eq!(from_x_y(NAN, 0.0).try_normalize(), None);
+            assert_eq!(from_x_y($t::INFINITY, 0.0).try_normalize(), None);
+            assert_eq!(from_x_y($t::NAN, 0.0).try_normalize(), None);
 
             // We expect `try_normalize` to return None when inputs are very large:
-            assert_eq!(from_x_y(MAX, 0.0).try_normalize(), None);
-            assert_eq!(from_x_y(MAX, MAX).try_normalize(), None);
+            assert_eq!(from_x_y($t::MAX, 0.0).try_normalize(), None);
+            assert_eq!(from_x_y($t::MAX, $t::MAX).try_normalize(), None);
+        });
+
+        glam_test!(test_normalize_or, {
+            assert_eq!(
+                from_x_y(-42.0, 0.0).normalize_or($vec::Y),
+                from_x_y(-1.0, 0.0)
+            );
+            assert_eq!(
+                from_x_y($t::MAX.sqrt(), 0.0).normalize_or($vec::Y),
+                from_x_y(1.0, 0.0)
+            );
+
+            // We expect `normalize_or` to return the fallback value when inputs are very small:
+            assert_eq!(from_x_y(0.0, 0.0).normalize_or($vec::Y), $vec::Y);
+            assert_eq!(
+                from_x_y($t::MIN_POSITIVE, 0.0).normalize_or($vec::Y),
+                $vec::Y
+            );
+
+            // We expect `normalize` to return zero when inputs are non-finite:
+            assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or($vec::Y), $vec::Y);
+            assert_eq!(from_x_y($t::NAN, 0.0).normalize_or($vec::Y), $vec::Y);
+
+            // We expect `normalize` to return zero when inputs are very large:
+            assert_eq!(from_x_y($t::MAX, 0.0).normalize_or($vec::Y), $vec::Y);
+            assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or($vec::Y), $vec::Y);
         });
 
         glam_test!(test_normalize_or_zero, {
@@ -143,21 +169,24 @@
                 from_x_y(-1.0, 0.0)
             );
             assert_eq!(
-                from_x_y(MAX.sqrt(), 0.0).normalize_or_zero(),
+                from_x_y($t::MAX.sqrt(), 0.0).normalize_or_zero(),
                 from_x_y(1.0, 0.0)
             );
 
             // We expect `normalize_or_zero` to return zero when inputs are very small:
             assert_eq!(from_x_y(0.0, 0.0).normalize_or_zero(), $vec::ZERO);
-            assert_eq!(from_x_y(MIN_POSITIVE, 0.0).normalize_or_zero(), $vec::ZERO);
+            assert_eq!(
+                from_x_y($t::MIN_POSITIVE, 0.0).normalize_or_zero(),
+                $vec::ZERO
+            );
 
             // We expect `normalize_or_zero` to return zero when inputs are non-finite:
-            assert_eq!(from_x_y(INFINITY, 0.0).normalize_or_zero(), $vec::ZERO);
-            assert_eq!(from_x_y(NAN, 0.0).normalize_or_zero(), $vec::ZERO);
+            assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or_zero(), $vec::ZERO);
+            assert_eq!(from_x_y($t::NAN, 0.0).normalize_or_zero(), $vec::ZERO);
 
             // We expect `normalize_or_zero` to return zero when inputs are very large:
-            assert_eq!(from_x_y(MAX, 0.0).normalize_or_zero(), $vec::ZERO);
-            assert_eq!(from_x_y(MAX, MAX).normalize_or_zero(), $vec::ZERO);
+            assert_eq!(from_x_y($t::MAX, 0.0).normalize_or_zero(), $vec::ZERO);
+            assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or_zero(), $vec::ZERO);
         });
     };
 }
@@ -185,7 +214,7 @@
             $vec3::new(0.2, 0.3, 0.4),
             $vec3::new(4.0, -5.0, 6.0),
             $vec3::new(-2.0, 0.5, -1.0),
-            // Pathalogical cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>:
+            // Pathological cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>:
             $vec3::new(0.00038527316, 0.00038460016, -0.99999988079),
             $vec3::new(-0.00019813581, -0.00008946839, -0.99999988079),
         ]
@@ -212,9 +241,28 @@
             $vec2::new(0.2, 0.3),
             $vec2::new(4.0, -5.0),
             $vec2::new(-2.0, 0.5),
-            // Pathalogical cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>:
+            // Pathological cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>:
             $vec2::new(0.00038527316, 0.00038460016),
             $vec2::new(-0.00019813581, -0.00008946839),
         ]
     };
 }
+
+#[macro_export]
+macro_rules! test_matrix_minor {
+    ($n:expr, $minor:expr, $input:expr, $i:expr, $j:expr) => {
+        let mut yy = 0;
+        for y in 0..$n {
+            if y != $j {
+                let mut xx = 0;
+                for x in 0..$n {
+                    if x != $i {
+                        assert_eq!($minor.col(xx)[yy], $input.col(x)[y]);
+                        xx += 1;
+                    }
+                }
+                yy += 1;
+            }
+        }
+    };
+}
diff --git a/crates/glam/tests/swizzles_i8.rs b/crates/glam/tests/swizzles_i8.rs
new file mode 100644
index 0000000..854461b
--- /dev/null
+++ b/crates/glam/tests/swizzles_i8.rs
@@ -0,0 +1,497 @@
+// Generated by swizzlegen. Do not edit.
+#[macro_use]
+mod support;
+use glam::*;
+
+glam_test!(test_i8vec4_swizzles, {
+    let v = i8vec4(1_i8, 2_i8, 3_i8, 4_i8);
+    assert_eq!(v, v.xyzw());
+    assert_eq!(v.xxxx(), i8vec4(1_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxxy(), i8vec4(1_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xxxz(), i8vec4(1_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.xxxw(), i8vec4(1_i8, 1_i8, 1_i8, 4_i8));
+    assert_eq!(v.xxyx(), i8vec4(1_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xxyy(), i8vec4(1_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.xxyz(), i8vec4(1_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.xxyw(), i8vec4(1_i8, 1_i8, 2_i8, 4_i8));
+    assert_eq!(v.xxzx(), i8vec4(1_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.xxzy(), i8vec4(1_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.xxzz(), i8vec4(1_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.xxzw(), i8vec4(1_i8, 1_i8, 3_i8, 4_i8));
+    assert_eq!(v.xxwx(), i8vec4(1_i8, 1_i8, 4_i8, 1_i8));
+    assert_eq!(v.xxwy(), i8vec4(1_i8, 1_i8, 4_i8, 2_i8));
+    assert_eq!(v.xxwz(), i8vec4(1_i8, 1_i8, 4_i8, 3_i8));
+    assert_eq!(v.xxww(), i8vec4(1_i8, 1_i8, 4_i8, 4_i8));
+    assert_eq!(v.xyxx(), i8vec4(1_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.xyxy(), i8vec4(1_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.xyxz(), i8vec4(1_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.xyxw(), i8vec4(1_i8, 2_i8, 1_i8, 4_i8));
+    assert_eq!(v.xyyx(), i8vec4(1_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyyy(), i8vec4(1_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.xyyz(), i8vec4(1_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.xyyw(), i8vec4(1_i8, 2_i8, 2_i8, 4_i8));
+    assert_eq!(v.xyzx(), i8vec4(1_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.xyzy(), i8vec4(1_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.xyzz(), i8vec4(1_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.xywx(), i8vec4(1_i8, 2_i8, 4_i8, 1_i8));
+    assert_eq!(v.xywy(), i8vec4(1_i8, 2_i8, 4_i8, 2_i8));
+    assert_eq!(v.xywz(), i8vec4(1_i8, 2_i8, 4_i8, 3_i8));
+    assert_eq!(v.xyww(), i8vec4(1_i8, 2_i8, 4_i8, 4_i8));
+    assert_eq!(v.xzxx(), i8vec4(1_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.xzxy(), i8vec4(1_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.xzxz(), i8vec4(1_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.xzxw(), i8vec4(1_i8, 3_i8, 1_i8, 4_i8));
+    assert_eq!(v.xzyx(), i8vec4(1_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.xzyy(), i8vec4(1_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.xzyz(), i8vec4(1_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.xzyw(), i8vec4(1_i8, 3_i8, 2_i8, 4_i8));
+    assert_eq!(v.xzzx(), i8vec4(1_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.xzzy(), i8vec4(1_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.xzzz(), i8vec4(1_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.xzzw(), i8vec4(1_i8, 3_i8, 3_i8, 4_i8));
+    assert_eq!(v.xzwx(), i8vec4(1_i8, 3_i8, 4_i8, 1_i8));
+    assert_eq!(v.xzwy(), i8vec4(1_i8, 3_i8, 4_i8, 2_i8));
+    assert_eq!(v.xzwz(), i8vec4(1_i8, 3_i8, 4_i8, 3_i8));
+    assert_eq!(v.xzww(), i8vec4(1_i8, 3_i8, 4_i8, 4_i8));
+    assert_eq!(v.xwxx(), i8vec4(1_i8, 4_i8, 1_i8, 1_i8));
+    assert_eq!(v.xwxy(), i8vec4(1_i8, 4_i8, 1_i8, 2_i8));
+    assert_eq!(v.xwxz(), i8vec4(1_i8, 4_i8, 1_i8, 3_i8));
+    assert_eq!(v.xwxw(), i8vec4(1_i8, 4_i8, 1_i8, 4_i8));
+    assert_eq!(v.xwyx(), i8vec4(1_i8, 4_i8, 2_i8, 1_i8));
+    assert_eq!(v.xwyy(), i8vec4(1_i8, 4_i8, 2_i8, 2_i8));
+    assert_eq!(v.xwyz(), i8vec4(1_i8, 4_i8, 2_i8, 3_i8));
+    assert_eq!(v.xwyw(), i8vec4(1_i8, 4_i8, 2_i8, 4_i8));
+    assert_eq!(v.xwzx(), i8vec4(1_i8, 4_i8, 3_i8, 1_i8));
+    assert_eq!(v.xwzy(), i8vec4(1_i8, 4_i8, 3_i8, 2_i8));
+    assert_eq!(v.xwzz(), i8vec4(1_i8, 4_i8, 3_i8, 3_i8));
+    assert_eq!(v.xwzw(), i8vec4(1_i8, 4_i8, 3_i8, 4_i8));
+    assert_eq!(v.xwwx(), i8vec4(1_i8, 4_i8, 4_i8, 1_i8));
+    assert_eq!(v.xwwy(), i8vec4(1_i8, 4_i8, 4_i8, 2_i8));
+    assert_eq!(v.xwwz(), i8vec4(1_i8, 4_i8, 4_i8, 3_i8));
+    assert_eq!(v.xwww(), i8vec4(1_i8, 4_i8, 4_i8, 4_i8));
+    assert_eq!(v.yxxx(), i8vec4(2_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxxy(), i8vec4(2_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.yxxz(), i8vec4(2_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.yxxw(), i8vec4(2_i8, 1_i8, 1_i8, 4_i8));
+    assert_eq!(v.yxyx(), i8vec4(2_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.yxyy(), i8vec4(2_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.yxyz(), i8vec4(2_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.yxyw(), i8vec4(2_i8, 1_i8, 2_i8, 4_i8));
+    assert_eq!(v.yxzx(), i8vec4(2_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.yxzy(), i8vec4(2_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.yxzz(), i8vec4(2_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.yxzw(), i8vec4(2_i8, 1_i8, 3_i8, 4_i8));
+    assert_eq!(v.yxwx(), i8vec4(2_i8, 1_i8, 4_i8, 1_i8));
+    assert_eq!(v.yxwy(), i8vec4(2_i8, 1_i8, 4_i8, 2_i8));
+    assert_eq!(v.yxwz(), i8vec4(2_i8, 1_i8, 4_i8, 3_i8));
+    assert_eq!(v.yxww(), i8vec4(2_i8, 1_i8, 4_i8, 4_i8));
+    assert_eq!(v.yyxx(), i8vec4(2_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yyxy(), i8vec4(2_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yyxz(), i8vec4(2_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.yyxw(), i8vec4(2_i8, 2_i8, 1_i8, 4_i8));
+    assert_eq!(v.yyyx(), i8vec4(2_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyyy(), i8vec4(2_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.yyyz(), i8vec4(2_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.yyyw(), i8vec4(2_i8, 2_i8, 2_i8, 4_i8));
+    assert_eq!(v.yyzx(), i8vec4(2_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.yyzy(), i8vec4(2_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.yyzz(), i8vec4(2_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.yyzw(), i8vec4(2_i8, 2_i8, 3_i8, 4_i8));
+    assert_eq!(v.yywx(), i8vec4(2_i8, 2_i8, 4_i8, 1_i8));
+    assert_eq!(v.yywy(), i8vec4(2_i8, 2_i8, 4_i8, 2_i8));
+    assert_eq!(v.yywz(), i8vec4(2_i8, 2_i8, 4_i8, 3_i8));
+    assert_eq!(v.yyww(), i8vec4(2_i8, 2_i8, 4_i8, 4_i8));
+    assert_eq!(v.yzxx(), i8vec4(2_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.yzxy(), i8vec4(2_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.yzxz(), i8vec4(2_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.yzxw(), i8vec4(2_i8, 3_i8, 1_i8, 4_i8));
+    assert_eq!(v.yzyx(), i8vec4(2_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.yzyy(), i8vec4(2_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.yzyz(), i8vec4(2_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.yzyw(), i8vec4(2_i8, 3_i8, 2_i8, 4_i8));
+    assert_eq!(v.yzzx(), i8vec4(2_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.yzzy(), i8vec4(2_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.yzzz(), i8vec4(2_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.yzzw(), i8vec4(2_i8, 3_i8, 3_i8, 4_i8));
+    assert_eq!(v.yzwx(), i8vec4(2_i8, 3_i8, 4_i8, 1_i8));
+    assert_eq!(v.yzwy(), i8vec4(2_i8, 3_i8, 4_i8, 2_i8));
+    assert_eq!(v.yzwz(), i8vec4(2_i8, 3_i8, 4_i8, 3_i8));
+    assert_eq!(v.yzww(), i8vec4(2_i8, 3_i8, 4_i8, 4_i8));
+    assert_eq!(v.ywxx(), i8vec4(2_i8, 4_i8, 1_i8, 1_i8));
+    assert_eq!(v.ywxy(), i8vec4(2_i8, 4_i8, 1_i8, 2_i8));
+    assert_eq!(v.ywxz(), i8vec4(2_i8, 4_i8, 1_i8, 3_i8));
+    assert_eq!(v.ywxw(), i8vec4(2_i8, 4_i8, 1_i8, 4_i8));
+    assert_eq!(v.ywyx(), i8vec4(2_i8, 4_i8, 2_i8, 1_i8));
+    assert_eq!(v.ywyy(), i8vec4(2_i8, 4_i8, 2_i8, 2_i8));
+    assert_eq!(v.ywyz(), i8vec4(2_i8, 4_i8, 2_i8, 3_i8));
+    assert_eq!(v.ywyw(), i8vec4(2_i8, 4_i8, 2_i8, 4_i8));
+    assert_eq!(v.ywzx(), i8vec4(2_i8, 4_i8, 3_i8, 1_i8));
+    assert_eq!(v.ywzy(), i8vec4(2_i8, 4_i8, 3_i8, 2_i8));
+    assert_eq!(v.ywzz(), i8vec4(2_i8, 4_i8, 3_i8, 3_i8));
+    assert_eq!(v.ywzw(), i8vec4(2_i8, 4_i8, 3_i8, 4_i8));
+    assert_eq!(v.ywwx(), i8vec4(2_i8, 4_i8, 4_i8, 1_i8));
+    assert_eq!(v.ywwy(), i8vec4(2_i8, 4_i8, 4_i8, 2_i8));
+    assert_eq!(v.ywwz(), i8vec4(2_i8, 4_i8, 4_i8, 3_i8));
+    assert_eq!(v.ywww(), i8vec4(2_i8, 4_i8, 4_i8, 4_i8));
+    assert_eq!(v.zxxx(), i8vec4(3_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.zxxy(), i8vec4(3_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.zxxz(), i8vec4(3_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.zxxw(), i8vec4(3_i8, 1_i8, 1_i8, 4_i8));
+    assert_eq!(v.zxyx(), i8vec4(3_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.zxyy(), i8vec4(3_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.zxyz(), i8vec4(3_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.zxyw(), i8vec4(3_i8, 1_i8, 2_i8, 4_i8));
+    assert_eq!(v.zxzx(), i8vec4(3_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.zxzy(), i8vec4(3_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.zxzz(), i8vec4(3_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.zxzw(), i8vec4(3_i8, 1_i8, 3_i8, 4_i8));
+    assert_eq!(v.zxwx(), i8vec4(3_i8, 1_i8, 4_i8, 1_i8));
+    assert_eq!(v.zxwy(), i8vec4(3_i8, 1_i8, 4_i8, 2_i8));
+    assert_eq!(v.zxwz(), i8vec4(3_i8, 1_i8, 4_i8, 3_i8));
+    assert_eq!(v.zxww(), i8vec4(3_i8, 1_i8, 4_i8, 4_i8));
+    assert_eq!(v.zyxx(), i8vec4(3_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.zyxy(), i8vec4(3_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.zyxz(), i8vec4(3_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.zyxw(), i8vec4(3_i8, 2_i8, 1_i8, 4_i8));
+    assert_eq!(v.zyyx(), i8vec4(3_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.zyyy(), i8vec4(3_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.zyyz(), i8vec4(3_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.zyyw(), i8vec4(3_i8, 2_i8, 2_i8, 4_i8));
+    assert_eq!(v.zyzx(), i8vec4(3_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.zyzy(), i8vec4(3_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.zyzz(), i8vec4(3_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.zyzw(), i8vec4(3_i8, 2_i8, 3_i8, 4_i8));
+    assert_eq!(v.zywx(), i8vec4(3_i8, 2_i8, 4_i8, 1_i8));
+    assert_eq!(v.zywy(), i8vec4(3_i8, 2_i8, 4_i8, 2_i8));
+    assert_eq!(v.zywz(), i8vec4(3_i8, 2_i8, 4_i8, 3_i8));
+    assert_eq!(v.zyww(), i8vec4(3_i8, 2_i8, 4_i8, 4_i8));
+    assert_eq!(v.zzxx(), i8vec4(3_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.zzxy(), i8vec4(3_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.zzxz(), i8vec4(3_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.zzxw(), i8vec4(3_i8, 3_i8, 1_i8, 4_i8));
+    assert_eq!(v.zzyx(), i8vec4(3_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.zzyy(), i8vec4(3_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.zzyz(), i8vec4(3_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.zzyw(), i8vec4(3_i8, 3_i8, 2_i8, 4_i8));
+    assert_eq!(v.zzzx(), i8vec4(3_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.zzzy(), i8vec4(3_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.zzzz(), i8vec4(3_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.zzzw(), i8vec4(3_i8, 3_i8, 3_i8, 4_i8));
+    assert_eq!(v.zzwx(), i8vec4(3_i8, 3_i8, 4_i8, 1_i8));
+    assert_eq!(v.zzwy(), i8vec4(3_i8, 3_i8, 4_i8, 2_i8));
+    assert_eq!(v.zzwz(), i8vec4(3_i8, 3_i8, 4_i8, 3_i8));
+    assert_eq!(v.zzww(), i8vec4(3_i8, 3_i8, 4_i8, 4_i8));
+    assert_eq!(v.zwxx(), i8vec4(3_i8, 4_i8, 1_i8, 1_i8));
+    assert_eq!(v.zwxy(), i8vec4(3_i8, 4_i8, 1_i8, 2_i8));
+    assert_eq!(v.zwxz(), i8vec4(3_i8, 4_i8, 1_i8, 3_i8));
+    assert_eq!(v.zwxw(), i8vec4(3_i8, 4_i8, 1_i8, 4_i8));
+    assert_eq!(v.zwyx(), i8vec4(3_i8, 4_i8, 2_i8, 1_i8));
+    assert_eq!(v.zwyy(), i8vec4(3_i8, 4_i8, 2_i8, 2_i8));
+    assert_eq!(v.zwyz(), i8vec4(3_i8, 4_i8, 2_i8, 3_i8));
+    assert_eq!(v.zwyw(), i8vec4(3_i8, 4_i8, 2_i8, 4_i8));
+    assert_eq!(v.zwzx(), i8vec4(3_i8, 4_i8, 3_i8, 1_i8));
+    assert_eq!(v.zwzy(), i8vec4(3_i8, 4_i8, 3_i8, 2_i8));
+    assert_eq!(v.zwzz(), i8vec4(3_i8, 4_i8, 3_i8, 3_i8));
+    assert_eq!(v.zwzw(), i8vec4(3_i8, 4_i8, 3_i8, 4_i8));
+    assert_eq!(v.zwwx(), i8vec4(3_i8, 4_i8, 4_i8, 1_i8));
+    assert_eq!(v.zwwy(), i8vec4(3_i8, 4_i8, 4_i8, 2_i8));
+    assert_eq!(v.zwwz(), i8vec4(3_i8, 4_i8, 4_i8, 3_i8));
+    assert_eq!(v.zwww(), i8vec4(3_i8, 4_i8, 4_i8, 4_i8));
+    assert_eq!(v.wxxx(), i8vec4(4_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.wxxy(), i8vec4(4_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.wxxz(), i8vec4(4_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.wxxw(), i8vec4(4_i8, 1_i8, 1_i8, 4_i8));
+    assert_eq!(v.wxyx(), i8vec4(4_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.wxyy(), i8vec4(4_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.wxyz(), i8vec4(4_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.wxyw(), i8vec4(4_i8, 1_i8, 2_i8, 4_i8));
+    assert_eq!(v.wxzx(), i8vec4(4_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.wxzy(), i8vec4(4_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.wxzz(), i8vec4(4_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.wxzw(), i8vec4(4_i8, 1_i8, 3_i8, 4_i8));
+    assert_eq!(v.wxwx(), i8vec4(4_i8, 1_i8, 4_i8, 1_i8));
+    assert_eq!(v.wxwy(), i8vec4(4_i8, 1_i8, 4_i8, 2_i8));
+    assert_eq!(v.wxwz(), i8vec4(4_i8, 1_i8, 4_i8, 3_i8));
+    assert_eq!(v.wxww(), i8vec4(4_i8, 1_i8, 4_i8, 4_i8));
+    assert_eq!(v.wyxx(), i8vec4(4_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.wyxy(), i8vec4(4_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.wyxz(), i8vec4(4_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.wyxw(), i8vec4(4_i8, 2_i8, 1_i8, 4_i8));
+    assert_eq!(v.wyyx(), i8vec4(4_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.wyyy(), i8vec4(4_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.wyyz(), i8vec4(4_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.wyyw(), i8vec4(4_i8, 2_i8, 2_i8, 4_i8));
+    assert_eq!(v.wyzx(), i8vec4(4_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.wyzy(), i8vec4(4_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.wyzz(), i8vec4(4_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.wyzw(), i8vec4(4_i8, 2_i8, 3_i8, 4_i8));
+    assert_eq!(v.wywx(), i8vec4(4_i8, 2_i8, 4_i8, 1_i8));
+    assert_eq!(v.wywy(), i8vec4(4_i8, 2_i8, 4_i8, 2_i8));
+    assert_eq!(v.wywz(), i8vec4(4_i8, 2_i8, 4_i8, 3_i8));
+    assert_eq!(v.wyww(), i8vec4(4_i8, 2_i8, 4_i8, 4_i8));
+    assert_eq!(v.wzxx(), i8vec4(4_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.wzxy(), i8vec4(4_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.wzxz(), i8vec4(4_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.wzxw(), i8vec4(4_i8, 3_i8, 1_i8, 4_i8));
+    assert_eq!(v.wzyx(), i8vec4(4_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.wzyy(), i8vec4(4_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.wzyz(), i8vec4(4_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.wzyw(), i8vec4(4_i8, 3_i8, 2_i8, 4_i8));
+    assert_eq!(v.wzzx(), i8vec4(4_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.wzzy(), i8vec4(4_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.wzzz(), i8vec4(4_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.wzzw(), i8vec4(4_i8, 3_i8, 3_i8, 4_i8));
+    assert_eq!(v.wzwx(), i8vec4(4_i8, 3_i8, 4_i8, 1_i8));
+    assert_eq!(v.wzwy(), i8vec4(4_i8, 3_i8, 4_i8, 2_i8));
+    assert_eq!(v.wzwz(), i8vec4(4_i8, 3_i8, 4_i8, 3_i8));
+    assert_eq!(v.wzww(), i8vec4(4_i8, 3_i8, 4_i8, 4_i8));
+    assert_eq!(v.wwxx(), i8vec4(4_i8, 4_i8, 1_i8, 1_i8));
+    assert_eq!(v.wwxy(), i8vec4(4_i8, 4_i8, 1_i8, 2_i8));
+    assert_eq!(v.wwxz(), i8vec4(4_i8, 4_i8, 1_i8, 3_i8));
+    assert_eq!(v.wwxw(), i8vec4(4_i8, 4_i8, 1_i8, 4_i8));
+    assert_eq!(v.wwyx(), i8vec4(4_i8, 4_i8, 2_i8, 1_i8));
+    assert_eq!(v.wwyy(), i8vec4(4_i8, 4_i8, 2_i8, 2_i8));
+    assert_eq!(v.wwyz(), i8vec4(4_i8, 4_i8, 2_i8, 3_i8));
+    assert_eq!(v.wwyw(), i8vec4(4_i8, 4_i8, 2_i8, 4_i8));
+    assert_eq!(v.wwzx(), i8vec4(4_i8, 4_i8, 3_i8, 1_i8));
+    assert_eq!(v.wwzy(), i8vec4(4_i8, 4_i8, 3_i8, 2_i8));
+    assert_eq!(v.wwzz(), i8vec4(4_i8, 4_i8, 3_i8, 3_i8));
+    assert_eq!(v.wwzw(), i8vec4(4_i8, 4_i8, 3_i8, 4_i8));
+    assert_eq!(v.wwwx(), i8vec4(4_i8, 4_i8, 4_i8, 1_i8));
+    assert_eq!(v.wwwy(), i8vec4(4_i8, 4_i8, 4_i8, 2_i8));
+    assert_eq!(v.wwwz(), i8vec4(4_i8, 4_i8, 4_i8, 3_i8));
+    assert_eq!(v.wwww(), i8vec4(4_i8, 4_i8, 4_i8, 4_i8));
+    assert_eq!(v.xxx(), i8vec3(1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxy(), i8vec3(1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xxz(), i8vec3(1_i8, 1_i8, 3_i8));
+    assert_eq!(v.xxw(), i8vec3(1_i8, 1_i8, 4_i8));
+    assert_eq!(v.xyx(), i8vec3(1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyy(), i8vec3(1_i8, 2_i8, 2_i8));
+    assert_eq!(v.xyz(), i8vec3(1_i8, 2_i8, 3_i8));
+    assert_eq!(v.xyw(), i8vec3(1_i8, 2_i8, 4_i8));
+    assert_eq!(v.xzx(), i8vec3(1_i8, 3_i8, 1_i8));
+    assert_eq!(v.xzy(), i8vec3(1_i8, 3_i8, 2_i8));
+    assert_eq!(v.xzz(), i8vec3(1_i8, 3_i8, 3_i8));
+    assert_eq!(v.xzw(), i8vec3(1_i8, 3_i8, 4_i8));
+    assert_eq!(v.xwx(), i8vec3(1_i8, 4_i8, 1_i8));
+    assert_eq!(v.xwy(), i8vec3(1_i8, 4_i8, 2_i8));
+    assert_eq!(v.xwz(), i8vec3(1_i8, 4_i8, 3_i8));
+    assert_eq!(v.xww(), i8vec3(1_i8, 4_i8, 4_i8));
+    assert_eq!(v.yxx(), i8vec3(2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxy(), i8vec3(2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yxz(), i8vec3(2_i8, 1_i8, 3_i8));
+    assert_eq!(v.yxw(), i8vec3(2_i8, 1_i8, 4_i8));
+    assert_eq!(v.yyx(), i8vec3(2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyy(), i8vec3(2_i8, 2_i8, 2_i8));
+    assert_eq!(v.yyz(), i8vec3(2_i8, 2_i8, 3_i8));
+    assert_eq!(v.yyw(), i8vec3(2_i8, 2_i8, 4_i8));
+    assert_eq!(v.yzx(), i8vec3(2_i8, 3_i8, 1_i8));
+    assert_eq!(v.yzy(), i8vec3(2_i8, 3_i8, 2_i8));
+    assert_eq!(v.yzz(), i8vec3(2_i8, 3_i8, 3_i8));
+    assert_eq!(v.yzw(), i8vec3(2_i8, 3_i8, 4_i8));
+    assert_eq!(v.ywx(), i8vec3(2_i8, 4_i8, 1_i8));
+    assert_eq!(v.ywy(), i8vec3(2_i8, 4_i8, 2_i8));
+    assert_eq!(v.ywz(), i8vec3(2_i8, 4_i8, 3_i8));
+    assert_eq!(v.yww(), i8vec3(2_i8, 4_i8, 4_i8));
+    assert_eq!(v.zxx(), i8vec3(3_i8, 1_i8, 1_i8));
+    assert_eq!(v.zxy(), i8vec3(3_i8, 1_i8, 2_i8));
+    assert_eq!(v.zxz(), i8vec3(3_i8, 1_i8, 3_i8));
+    assert_eq!(v.zxw(), i8vec3(3_i8, 1_i8, 4_i8));
+    assert_eq!(v.zyx(), i8vec3(3_i8, 2_i8, 1_i8));
+    assert_eq!(v.zyy(), i8vec3(3_i8, 2_i8, 2_i8));
+    assert_eq!(v.zyz(), i8vec3(3_i8, 2_i8, 3_i8));
+    assert_eq!(v.zyw(), i8vec3(3_i8, 2_i8, 4_i8));
+    assert_eq!(v.zzx(), i8vec3(3_i8, 3_i8, 1_i8));
+    assert_eq!(v.zzy(), i8vec3(3_i8, 3_i8, 2_i8));
+    assert_eq!(v.zzz(), i8vec3(3_i8, 3_i8, 3_i8));
+    assert_eq!(v.zzw(), i8vec3(3_i8, 3_i8, 4_i8));
+    assert_eq!(v.zwx(), i8vec3(3_i8, 4_i8, 1_i8));
+    assert_eq!(v.zwy(), i8vec3(3_i8, 4_i8, 2_i8));
+    assert_eq!(v.zwz(), i8vec3(3_i8, 4_i8, 3_i8));
+    assert_eq!(v.zww(), i8vec3(3_i8, 4_i8, 4_i8));
+    assert_eq!(v.wxx(), i8vec3(4_i8, 1_i8, 1_i8));
+    assert_eq!(v.wxy(), i8vec3(4_i8, 1_i8, 2_i8));
+    assert_eq!(v.wxz(), i8vec3(4_i8, 1_i8, 3_i8));
+    assert_eq!(v.wxw(), i8vec3(4_i8, 1_i8, 4_i8));
+    assert_eq!(v.wyx(), i8vec3(4_i8, 2_i8, 1_i8));
+    assert_eq!(v.wyy(), i8vec3(4_i8, 2_i8, 2_i8));
+    assert_eq!(v.wyz(), i8vec3(4_i8, 2_i8, 3_i8));
+    assert_eq!(v.wyw(), i8vec3(4_i8, 2_i8, 4_i8));
+    assert_eq!(v.wzx(), i8vec3(4_i8, 3_i8, 1_i8));
+    assert_eq!(v.wzy(), i8vec3(4_i8, 3_i8, 2_i8));
+    assert_eq!(v.wzz(), i8vec3(4_i8, 3_i8, 3_i8));
+    assert_eq!(v.wzw(), i8vec3(4_i8, 3_i8, 4_i8));
+    assert_eq!(v.wwx(), i8vec3(4_i8, 4_i8, 1_i8));
+    assert_eq!(v.wwy(), i8vec3(4_i8, 4_i8, 2_i8));
+    assert_eq!(v.wwz(), i8vec3(4_i8, 4_i8, 3_i8));
+    assert_eq!(v.www(), i8vec3(4_i8, 4_i8, 4_i8));
+    assert_eq!(v.xx(), i8vec2(1_i8, 1_i8));
+    assert_eq!(v.xy(), i8vec2(1_i8, 2_i8));
+    assert_eq!(v.xz(), i8vec2(1_i8, 3_i8));
+    assert_eq!(v.xw(), i8vec2(1_i8, 4_i8));
+    assert_eq!(v.yx(), i8vec2(2_i8, 1_i8));
+    assert_eq!(v.yy(), i8vec2(2_i8, 2_i8));
+    assert_eq!(v.yz(), i8vec2(2_i8, 3_i8));
+    assert_eq!(v.yw(), i8vec2(2_i8, 4_i8));
+    assert_eq!(v.zx(), i8vec2(3_i8, 1_i8));
+    assert_eq!(v.zy(), i8vec2(3_i8, 2_i8));
+    assert_eq!(v.zz(), i8vec2(3_i8, 3_i8));
+    assert_eq!(v.zw(), i8vec2(3_i8, 4_i8));
+    assert_eq!(v.wx(), i8vec2(4_i8, 1_i8));
+    assert_eq!(v.wy(), i8vec2(4_i8, 2_i8));
+    assert_eq!(v.wz(), i8vec2(4_i8, 3_i8));
+    assert_eq!(v.ww(), i8vec2(4_i8, 4_i8));
+});
+
+glam_test!(test_i8vec3_swizzles, {
+    let v = i8vec3(1_i8, 2_i8, 3_i8);
+    assert_eq!(v, v.xyz());
+    assert_eq!(v.xxxx(), i8vec4(1_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxxy(), i8vec4(1_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xxxz(), i8vec4(1_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.xxyx(), i8vec4(1_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xxyy(), i8vec4(1_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.xxyz(), i8vec4(1_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.xxzx(), i8vec4(1_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.xxzy(), i8vec4(1_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.xxzz(), i8vec4(1_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.xyxx(), i8vec4(1_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.xyxy(), i8vec4(1_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.xyxz(), i8vec4(1_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.xyyx(), i8vec4(1_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyyy(), i8vec4(1_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.xyyz(), i8vec4(1_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.xyzx(), i8vec4(1_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.xyzy(), i8vec4(1_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.xyzz(), i8vec4(1_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.xzxx(), i8vec4(1_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.xzxy(), i8vec4(1_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.xzxz(), i8vec4(1_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.xzyx(), i8vec4(1_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.xzyy(), i8vec4(1_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.xzyz(), i8vec4(1_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.xzzx(), i8vec4(1_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.xzzy(), i8vec4(1_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.xzzz(), i8vec4(1_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.yxxx(), i8vec4(2_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxxy(), i8vec4(2_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.yxxz(), i8vec4(2_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.yxyx(), i8vec4(2_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.yxyy(), i8vec4(2_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.yxyz(), i8vec4(2_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.yxzx(), i8vec4(2_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.yxzy(), i8vec4(2_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.yxzz(), i8vec4(2_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.yyxx(), i8vec4(2_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yyxy(), i8vec4(2_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yyxz(), i8vec4(2_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.yyyx(), i8vec4(2_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyyy(), i8vec4(2_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.yyyz(), i8vec4(2_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.yyzx(), i8vec4(2_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.yyzy(), i8vec4(2_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.yyzz(), i8vec4(2_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.yzxx(), i8vec4(2_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.yzxy(), i8vec4(2_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.yzxz(), i8vec4(2_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.yzyx(), i8vec4(2_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.yzyy(), i8vec4(2_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.yzyz(), i8vec4(2_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.yzzx(), i8vec4(2_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.yzzy(), i8vec4(2_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.yzzz(), i8vec4(2_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.zxxx(), i8vec4(3_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.zxxy(), i8vec4(3_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.zxxz(), i8vec4(3_i8, 1_i8, 1_i8, 3_i8));
+    assert_eq!(v.zxyx(), i8vec4(3_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.zxyy(), i8vec4(3_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.zxyz(), i8vec4(3_i8, 1_i8, 2_i8, 3_i8));
+    assert_eq!(v.zxzx(), i8vec4(3_i8, 1_i8, 3_i8, 1_i8));
+    assert_eq!(v.zxzy(), i8vec4(3_i8, 1_i8, 3_i8, 2_i8));
+    assert_eq!(v.zxzz(), i8vec4(3_i8, 1_i8, 3_i8, 3_i8));
+    assert_eq!(v.zyxx(), i8vec4(3_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.zyxy(), i8vec4(3_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.zyxz(), i8vec4(3_i8, 2_i8, 1_i8, 3_i8));
+    assert_eq!(v.zyyx(), i8vec4(3_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.zyyy(), i8vec4(3_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.zyyz(), i8vec4(3_i8, 2_i8, 2_i8, 3_i8));
+    assert_eq!(v.zyzx(), i8vec4(3_i8, 2_i8, 3_i8, 1_i8));
+    assert_eq!(v.zyzy(), i8vec4(3_i8, 2_i8, 3_i8, 2_i8));
+    assert_eq!(v.zyzz(), i8vec4(3_i8, 2_i8, 3_i8, 3_i8));
+    assert_eq!(v.zzxx(), i8vec4(3_i8, 3_i8, 1_i8, 1_i8));
+    assert_eq!(v.zzxy(), i8vec4(3_i8, 3_i8, 1_i8, 2_i8));
+    assert_eq!(v.zzxz(), i8vec4(3_i8, 3_i8, 1_i8, 3_i8));
+    assert_eq!(v.zzyx(), i8vec4(3_i8, 3_i8, 2_i8, 1_i8));
+    assert_eq!(v.zzyy(), i8vec4(3_i8, 3_i8, 2_i8, 2_i8));
+    assert_eq!(v.zzyz(), i8vec4(3_i8, 3_i8, 2_i8, 3_i8));
+    assert_eq!(v.zzzx(), i8vec4(3_i8, 3_i8, 3_i8, 1_i8));
+    assert_eq!(v.zzzy(), i8vec4(3_i8, 3_i8, 3_i8, 2_i8));
+    assert_eq!(v.zzzz(), i8vec4(3_i8, 3_i8, 3_i8, 3_i8));
+    assert_eq!(v.xxx(), i8vec3(1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxy(), i8vec3(1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xxz(), i8vec3(1_i8, 1_i8, 3_i8));
+    assert_eq!(v.xyx(), i8vec3(1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyy(), i8vec3(1_i8, 2_i8, 2_i8));
+    assert_eq!(v.xzx(), i8vec3(1_i8, 3_i8, 1_i8));
+    assert_eq!(v.xzy(), i8vec3(1_i8, 3_i8, 2_i8));
+    assert_eq!(v.xzz(), i8vec3(1_i8, 3_i8, 3_i8));
+    assert_eq!(v.yxx(), i8vec3(2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxy(), i8vec3(2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yxz(), i8vec3(2_i8, 1_i8, 3_i8));
+    assert_eq!(v.yyx(), i8vec3(2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyy(), i8vec3(2_i8, 2_i8, 2_i8));
+    assert_eq!(v.yyz(), i8vec3(2_i8, 2_i8, 3_i8));
+    assert_eq!(v.yzx(), i8vec3(2_i8, 3_i8, 1_i8));
+    assert_eq!(v.yzy(), i8vec3(2_i8, 3_i8, 2_i8));
+    assert_eq!(v.yzz(), i8vec3(2_i8, 3_i8, 3_i8));
+    assert_eq!(v.zxx(), i8vec3(3_i8, 1_i8, 1_i8));
+    assert_eq!(v.zxy(), i8vec3(3_i8, 1_i8, 2_i8));
+    assert_eq!(v.zxz(), i8vec3(3_i8, 1_i8, 3_i8));
+    assert_eq!(v.zyx(), i8vec3(3_i8, 2_i8, 1_i8));
+    assert_eq!(v.zyy(), i8vec3(3_i8, 2_i8, 2_i8));
+    assert_eq!(v.zyz(), i8vec3(3_i8, 2_i8, 3_i8));
+    assert_eq!(v.zzx(), i8vec3(3_i8, 3_i8, 1_i8));
+    assert_eq!(v.zzy(), i8vec3(3_i8, 3_i8, 2_i8));
+    assert_eq!(v.zzz(), i8vec3(3_i8, 3_i8, 3_i8));
+    assert_eq!(v.xx(), i8vec2(1_i8, 1_i8));
+    assert_eq!(v.xy(), i8vec2(1_i8, 2_i8));
+    assert_eq!(v.xz(), i8vec2(1_i8, 3_i8));
+    assert_eq!(v.yx(), i8vec2(2_i8, 1_i8));
+    assert_eq!(v.yy(), i8vec2(2_i8, 2_i8));
+    assert_eq!(v.yz(), i8vec2(2_i8, 3_i8));
+    assert_eq!(v.zx(), i8vec2(3_i8, 1_i8));
+    assert_eq!(v.zy(), i8vec2(3_i8, 2_i8));
+    assert_eq!(v.zz(), i8vec2(3_i8, 3_i8));
+});
+
+glam_test!(test_i8vec2_swizzles, {
+    let v = i8vec2(1_i8, 2_i8);
+    assert_eq!(v, v.xy());
+    assert_eq!(v.xxxx(), i8vec4(1_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxxy(), i8vec4(1_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xxyx(), i8vec4(1_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xxyy(), i8vec4(1_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.xyxx(), i8vec4(1_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.xyxy(), i8vec4(1_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.xyyx(), i8vec4(1_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyyy(), i8vec4(1_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.yxxx(), i8vec4(2_i8, 1_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxxy(), i8vec4(2_i8, 1_i8, 1_i8, 2_i8));
+    assert_eq!(v.yxyx(), i8vec4(2_i8, 1_i8, 2_i8, 1_i8));
+    assert_eq!(v.yxyy(), i8vec4(2_i8, 1_i8, 2_i8, 2_i8));
+    assert_eq!(v.yyxx(), i8vec4(2_i8, 2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yyxy(), i8vec4(2_i8, 2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yyyx(), i8vec4(2_i8, 2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyyy(), i8vec4(2_i8, 2_i8, 2_i8, 2_i8));
+    assert_eq!(v.xxx(), i8vec3(1_i8, 1_i8, 1_i8));
+    assert_eq!(v.xxy(), i8vec3(1_i8, 1_i8, 2_i8));
+    assert_eq!(v.xyx(), i8vec3(1_i8, 2_i8, 1_i8));
+    assert_eq!(v.xyy(), i8vec3(1_i8, 2_i8, 2_i8));
+    assert_eq!(v.yxx(), i8vec3(2_i8, 1_i8, 1_i8));
+    assert_eq!(v.yxy(), i8vec3(2_i8, 1_i8, 2_i8));
+    assert_eq!(v.yyx(), i8vec3(2_i8, 2_i8, 1_i8));
+    assert_eq!(v.yyy(), i8vec3(2_i8, 2_i8, 2_i8));
+    assert_eq!(v.xx(), i8vec2(1_i8, 1_i8));
+    assert_eq!(v.yx(), i8vec2(2_i8, 1_i8));
+    assert_eq!(v.yy(), i8vec2(2_i8, 2_i8));
+});
diff --git a/crates/glam/tests/swizzles_u8.rs b/crates/glam/tests/swizzles_u8.rs
new file mode 100644
index 0000000..542812a
--- /dev/null
+++ b/crates/glam/tests/swizzles_u8.rs
@@ -0,0 +1,497 @@
+// Generated by swizzlegen. Do not edit.
+#[macro_use]
+mod support;
+use glam::*;
+
+glam_test!(test_u8vec4_swizzles, {
+    let v = u8vec4(1_u8, 2_u8, 3_u8, 4_u8);
+    assert_eq!(v, v.xyzw());
+    assert_eq!(v.xxxx(), u8vec4(1_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxxy(), u8vec4(1_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xxxz(), u8vec4(1_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.xxxw(), u8vec4(1_u8, 1_u8, 1_u8, 4_u8));
+    assert_eq!(v.xxyx(), u8vec4(1_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xxyy(), u8vec4(1_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.xxyz(), u8vec4(1_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.xxyw(), u8vec4(1_u8, 1_u8, 2_u8, 4_u8));
+    assert_eq!(v.xxzx(), u8vec4(1_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.xxzy(), u8vec4(1_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.xxzz(), u8vec4(1_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.xxzw(), u8vec4(1_u8, 1_u8, 3_u8, 4_u8));
+    assert_eq!(v.xxwx(), u8vec4(1_u8, 1_u8, 4_u8, 1_u8));
+    assert_eq!(v.xxwy(), u8vec4(1_u8, 1_u8, 4_u8, 2_u8));
+    assert_eq!(v.xxwz(), u8vec4(1_u8, 1_u8, 4_u8, 3_u8));
+    assert_eq!(v.xxww(), u8vec4(1_u8, 1_u8, 4_u8, 4_u8));
+    assert_eq!(v.xyxx(), u8vec4(1_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.xyxy(), u8vec4(1_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.xyxz(), u8vec4(1_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.xyxw(), u8vec4(1_u8, 2_u8, 1_u8, 4_u8));
+    assert_eq!(v.xyyx(), u8vec4(1_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyyy(), u8vec4(1_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.xyyz(), u8vec4(1_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.xyyw(), u8vec4(1_u8, 2_u8, 2_u8, 4_u8));
+    assert_eq!(v.xyzx(), u8vec4(1_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.xyzy(), u8vec4(1_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.xyzz(), u8vec4(1_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.xywx(), u8vec4(1_u8, 2_u8, 4_u8, 1_u8));
+    assert_eq!(v.xywy(), u8vec4(1_u8, 2_u8, 4_u8, 2_u8));
+    assert_eq!(v.xywz(), u8vec4(1_u8, 2_u8, 4_u8, 3_u8));
+    assert_eq!(v.xyww(), u8vec4(1_u8, 2_u8, 4_u8, 4_u8));
+    assert_eq!(v.xzxx(), u8vec4(1_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.xzxy(), u8vec4(1_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.xzxz(), u8vec4(1_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.xzxw(), u8vec4(1_u8, 3_u8, 1_u8, 4_u8));
+    assert_eq!(v.xzyx(), u8vec4(1_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.xzyy(), u8vec4(1_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.xzyz(), u8vec4(1_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.xzyw(), u8vec4(1_u8, 3_u8, 2_u8, 4_u8));
+    assert_eq!(v.xzzx(), u8vec4(1_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.xzzy(), u8vec4(1_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.xzzz(), u8vec4(1_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.xzzw(), u8vec4(1_u8, 3_u8, 3_u8, 4_u8));
+    assert_eq!(v.xzwx(), u8vec4(1_u8, 3_u8, 4_u8, 1_u8));
+    assert_eq!(v.xzwy(), u8vec4(1_u8, 3_u8, 4_u8, 2_u8));
+    assert_eq!(v.xzwz(), u8vec4(1_u8, 3_u8, 4_u8, 3_u8));
+    assert_eq!(v.xzww(), u8vec4(1_u8, 3_u8, 4_u8, 4_u8));
+    assert_eq!(v.xwxx(), u8vec4(1_u8, 4_u8, 1_u8, 1_u8));
+    assert_eq!(v.xwxy(), u8vec4(1_u8, 4_u8, 1_u8, 2_u8));
+    assert_eq!(v.xwxz(), u8vec4(1_u8, 4_u8, 1_u8, 3_u8));
+    assert_eq!(v.xwxw(), u8vec4(1_u8, 4_u8, 1_u8, 4_u8));
+    assert_eq!(v.xwyx(), u8vec4(1_u8, 4_u8, 2_u8, 1_u8));
+    assert_eq!(v.xwyy(), u8vec4(1_u8, 4_u8, 2_u8, 2_u8));
+    assert_eq!(v.xwyz(), u8vec4(1_u8, 4_u8, 2_u8, 3_u8));
+    assert_eq!(v.xwyw(), u8vec4(1_u8, 4_u8, 2_u8, 4_u8));
+    assert_eq!(v.xwzx(), u8vec4(1_u8, 4_u8, 3_u8, 1_u8));
+    assert_eq!(v.xwzy(), u8vec4(1_u8, 4_u8, 3_u8, 2_u8));
+    assert_eq!(v.xwzz(), u8vec4(1_u8, 4_u8, 3_u8, 3_u8));
+    assert_eq!(v.xwzw(), u8vec4(1_u8, 4_u8, 3_u8, 4_u8));
+    assert_eq!(v.xwwx(), u8vec4(1_u8, 4_u8, 4_u8, 1_u8));
+    assert_eq!(v.xwwy(), u8vec4(1_u8, 4_u8, 4_u8, 2_u8));
+    assert_eq!(v.xwwz(), u8vec4(1_u8, 4_u8, 4_u8, 3_u8));
+    assert_eq!(v.xwww(), u8vec4(1_u8, 4_u8, 4_u8, 4_u8));
+    assert_eq!(v.yxxx(), u8vec4(2_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxxy(), u8vec4(2_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.yxxz(), u8vec4(2_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.yxxw(), u8vec4(2_u8, 1_u8, 1_u8, 4_u8));
+    assert_eq!(v.yxyx(), u8vec4(2_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.yxyy(), u8vec4(2_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.yxyz(), u8vec4(2_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.yxyw(), u8vec4(2_u8, 1_u8, 2_u8, 4_u8));
+    assert_eq!(v.yxzx(), u8vec4(2_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.yxzy(), u8vec4(2_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.yxzz(), u8vec4(2_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.yxzw(), u8vec4(2_u8, 1_u8, 3_u8, 4_u8));
+    assert_eq!(v.yxwx(), u8vec4(2_u8, 1_u8, 4_u8, 1_u8));
+    assert_eq!(v.yxwy(), u8vec4(2_u8, 1_u8, 4_u8, 2_u8));
+    assert_eq!(v.yxwz(), u8vec4(2_u8, 1_u8, 4_u8, 3_u8));
+    assert_eq!(v.yxww(), u8vec4(2_u8, 1_u8, 4_u8, 4_u8));
+    assert_eq!(v.yyxx(), u8vec4(2_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yyxy(), u8vec4(2_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yyxz(), u8vec4(2_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.yyxw(), u8vec4(2_u8, 2_u8, 1_u8, 4_u8));
+    assert_eq!(v.yyyx(), u8vec4(2_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyyy(), u8vec4(2_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.yyyz(), u8vec4(2_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.yyyw(), u8vec4(2_u8, 2_u8, 2_u8, 4_u8));
+    assert_eq!(v.yyzx(), u8vec4(2_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.yyzy(), u8vec4(2_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.yyzz(), u8vec4(2_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.yyzw(), u8vec4(2_u8, 2_u8, 3_u8, 4_u8));
+    assert_eq!(v.yywx(), u8vec4(2_u8, 2_u8, 4_u8, 1_u8));
+    assert_eq!(v.yywy(), u8vec4(2_u8, 2_u8, 4_u8, 2_u8));
+    assert_eq!(v.yywz(), u8vec4(2_u8, 2_u8, 4_u8, 3_u8));
+    assert_eq!(v.yyww(), u8vec4(2_u8, 2_u8, 4_u8, 4_u8));
+    assert_eq!(v.yzxx(), u8vec4(2_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.yzxy(), u8vec4(2_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.yzxz(), u8vec4(2_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.yzxw(), u8vec4(2_u8, 3_u8, 1_u8, 4_u8));
+    assert_eq!(v.yzyx(), u8vec4(2_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.yzyy(), u8vec4(2_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.yzyz(), u8vec4(2_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.yzyw(), u8vec4(2_u8, 3_u8, 2_u8, 4_u8));
+    assert_eq!(v.yzzx(), u8vec4(2_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.yzzy(), u8vec4(2_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.yzzz(), u8vec4(2_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.yzzw(), u8vec4(2_u8, 3_u8, 3_u8, 4_u8));
+    assert_eq!(v.yzwx(), u8vec4(2_u8, 3_u8, 4_u8, 1_u8));
+    assert_eq!(v.yzwy(), u8vec4(2_u8, 3_u8, 4_u8, 2_u8));
+    assert_eq!(v.yzwz(), u8vec4(2_u8, 3_u8, 4_u8, 3_u8));
+    assert_eq!(v.yzww(), u8vec4(2_u8, 3_u8, 4_u8, 4_u8));
+    assert_eq!(v.ywxx(), u8vec4(2_u8, 4_u8, 1_u8, 1_u8));
+    assert_eq!(v.ywxy(), u8vec4(2_u8, 4_u8, 1_u8, 2_u8));
+    assert_eq!(v.ywxz(), u8vec4(2_u8, 4_u8, 1_u8, 3_u8));
+    assert_eq!(v.ywxw(), u8vec4(2_u8, 4_u8, 1_u8, 4_u8));
+    assert_eq!(v.ywyx(), u8vec4(2_u8, 4_u8, 2_u8, 1_u8));
+    assert_eq!(v.ywyy(), u8vec4(2_u8, 4_u8, 2_u8, 2_u8));
+    assert_eq!(v.ywyz(), u8vec4(2_u8, 4_u8, 2_u8, 3_u8));
+    assert_eq!(v.ywyw(), u8vec4(2_u8, 4_u8, 2_u8, 4_u8));
+    assert_eq!(v.ywzx(), u8vec4(2_u8, 4_u8, 3_u8, 1_u8));
+    assert_eq!(v.ywzy(), u8vec4(2_u8, 4_u8, 3_u8, 2_u8));
+    assert_eq!(v.ywzz(), u8vec4(2_u8, 4_u8, 3_u8, 3_u8));
+    assert_eq!(v.ywzw(), u8vec4(2_u8, 4_u8, 3_u8, 4_u8));
+    assert_eq!(v.ywwx(), u8vec4(2_u8, 4_u8, 4_u8, 1_u8));
+    assert_eq!(v.ywwy(), u8vec4(2_u8, 4_u8, 4_u8, 2_u8));
+    assert_eq!(v.ywwz(), u8vec4(2_u8, 4_u8, 4_u8, 3_u8));
+    assert_eq!(v.ywww(), u8vec4(2_u8, 4_u8, 4_u8, 4_u8));
+    assert_eq!(v.zxxx(), u8vec4(3_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.zxxy(), u8vec4(3_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.zxxz(), u8vec4(3_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.zxxw(), u8vec4(3_u8, 1_u8, 1_u8, 4_u8));
+    assert_eq!(v.zxyx(), u8vec4(3_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.zxyy(), u8vec4(3_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.zxyz(), u8vec4(3_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.zxyw(), u8vec4(3_u8, 1_u8, 2_u8, 4_u8));
+    assert_eq!(v.zxzx(), u8vec4(3_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.zxzy(), u8vec4(3_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.zxzz(), u8vec4(3_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.zxzw(), u8vec4(3_u8, 1_u8, 3_u8, 4_u8));
+    assert_eq!(v.zxwx(), u8vec4(3_u8, 1_u8, 4_u8, 1_u8));
+    assert_eq!(v.zxwy(), u8vec4(3_u8, 1_u8, 4_u8, 2_u8));
+    assert_eq!(v.zxwz(), u8vec4(3_u8, 1_u8, 4_u8, 3_u8));
+    assert_eq!(v.zxww(), u8vec4(3_u8, 1_u8, 4_u8, 4_u8));
+    assert_eq!(v.zyxx(), u8vec4(3_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.zyxy(), u8vec4(3_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.zyxz(), u8vec4(3_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.zyxw(), u8vec4(3_u8, 2_u8, 1_u8, 4_u8));
+    assert_eq!(v.zyyx(), u8vec4(3_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.zyyy(), u8vec4(3_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.zyyz(), u8vec4(3_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.zyyw(), u8vec4(3_u8, 2_u8, 2_u8, 4_u8));
+    assert_eq!(v.zyzx(), u8vec4(3_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.zyzy(), u8vec4(3_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.zyzz(), u8vec4(3_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.zyzw(), u8vec4(3_u8, 2_u8, 3_u8, 4_u8));
+    assert_eq!(v.zywx(), u8vec4(3_u8, 2_u8, 4_u8, 1_u8));
+    assert_eq!(v.zywy(), u8vec4(3_u8, 2_u8, 4_u8, 2_u8));
+    assert_eq!(v.zywz(), u8vec4(3_u8, 2_u8, 4_u8, 3_u8));
+    assert_eq!(v.zyww(), u8vec4(3_u8, 2_u8, 4_u8, 4_u8));
+    assert_eq!(v.zzxx(), u8vec4(3_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.zzxy(), u8vec4(3_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.zzxz(), u8vec4(3_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.zzxw(), u8vec4(3_u8, 3_u8, 1_u8, 4_u8));
+    assert_eq!(v.zzyx(), u8vec4(3_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.zzyy(), u8vec4(3_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.zzyz(), u8vec4(3_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.zzyw(), u8vec4(3_u8, 3_u8, 2_u8, 4_u8));
+    assert_eq!(v.zzzx(), u8vec4(3_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.zzzy(), u8vec4(3_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.zzzz(), u8vec4(3_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.zzzw(), u8vec4(3_u8, 3_u8, 3_u8, 4_u8));
+    assert_eq!(v.zzwx(), u8vec4(3_u8, 3_u8, 4_u8, 1_u8));
+    assert_eq!(v.zzwy(), u8vec4(3_u8, 3_u8, 4_u8, 2_u8));
+    assert_eq!(v.zzwz(), u8vec4(3_u8, 3_u8, 4_u8, 3_u8));
+    assert_eq!(v.zzww(), u8vec4(3_u8, 3_u8, 4_u8, 4_u8));
+    assert_eq!(v.zwxx(), u8vec4(3_u8, 4_u8, 1_u8, 1_u8));
+    assert_eq!(v.zwxy(), u8vec4(3_u8, 4_u8, 1_u8, 2_u8));
+    assert_eq!(v.zwxz(), u8vec4(3_u8, 4_u8, 1_u8, 3_u8));
+    assert_eq!(v.zwxw(), u8vec4(3_u8, 4_u8, 1_u8, 4_u8));
+    assert_eq!(v.zwyx(), u8vec4(3_u8, 4_u8, 2_u8, 1_u8));
+    assert_eq!(v.zwyy(), u8vec4(3_u8, 4_u8, 2_u8, 2_u8));
+    assert_eq!(v.zwyz(), u8vec4(3_u8, 4_u8, 2_u8, 3_u8));
+    assert_eq!(v.zwyw(), u8vec4(3_u8, 4_u8, 2_u8, 4_u8));
+    assert_eq!(v.zwzx(), u8vec4(3_u8, 4_u8, 3_u8, 1_u8));
+    assert_eq!(v.zwzy(), u8vec4(3_u8, 4_u8, 3_u8, 2_u8));
+    assert_eq!(v.zwzz(), u8vec4(3_u8, 4_u8, 3_u8, 3_u8));
+    assert_eq!(v.zwzw(), u8vec4(3_u8, 4_u8, 3_u8, 4_u8));
+    assert_eq!(v.zwwx(), u8vec4(3_u8, 4_u8, 4_u8, 1_u8));
+    assert_eq!(v.zwwy(), u8vec4(3_u8, 4_u8, 4_u8, 2_u8));
+    assert_eq!(v.zwwz(), u8vec4(3_u8, 4_u8, 4_u8, 3_u8));
+    assert_eq!(v.zwww(), u8vec4(3_u8, 4_u8, 4_u8, 4_u8));
+    assert_eq!(v.wxxx(), u8vec4(4_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.wxxy(), u8vec4(4_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.wxxz(), u8vec4(4_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.wxxw(), u8vec4(4_u8, 1_u8, 1_u8, 4_u8));
+    assert_eq!(v.wxyx(), u8vec4(4_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.wxyy(), u8vec4(4_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.wxyz(), u8vec4(4_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.wxyw(), u8vec4(4_u8, 1_u8, 2_u8, 4_u8));
+    assert_eq!(v.wxzx(), u8vec4(4_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.wxzy(), u8vec4(4_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.wxzz(), u8vec4(4_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.wxzw(), u8vec4(4_u8, 1_u8, 3_u8, 4_u8));
+    assert_eq!(v.wxwx(), u8vec4(4_u8, 1_u8, 4_u8, 1_u8));
+    assert_eq!(v.wxwy(), u8vec4(4_u8, 1_u8, 4_u8, 2_u8));
+    assert_eq!(v.wxwz(), u8vec4(4_u8, 1_u8, 4_u8, 3_u8));
+    assert_eq!(v.wxww(), u8vec4(4_u8, 1_u8, 4_u8, 4_u8));
+    assert_eq!(v.wyxx(), u8vec4(4_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.wyxy(), u8vec4(4_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.wyxz(), u8vec4(4_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.wyxw(), u8vec4(4_u8, 2_u8, 1_u8, 4_u8));
+    assert_eq!(v.wyyx(), u8vec4(4_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.wyyy(), u8vec4(4_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.wyyz(), u8vec4(4_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.wyyw(), u8vec4(4_u8, 2_u8, 2_u8, 4_u8));
+    assert_eq!(v.wyzx(), u8vec4(4_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.wyzy(), u8vec4(4_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.wyzz(), u8vec4(4_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.wyzw(), u8vec4(4_u8, 2_u8, 3_u8, 4_u8));
+    assert_eq!(v.wywx(), u8vec4(4_u8, 2_u8, 4_u8, 1_u8));
+    assert_eq!(v.wywy(), u8vec4(4_u8, 2_u8, 4_u8, 2_u8));
+    assert_eq!(v.wywz(), u8vec4(4_u8, 2_u8, 4_u8, 3_u8));
+    assert_eq!(v.wyww(), u8vec4(4_u8, 2_u8, 4_u8, 4_u8));
+    assert_eq!(v.wzxx(), u8vec4(4_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.wzxy(), u8vec4(4_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.wzxz(), u8vec4(4_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.wzxw(), u8vec4(4_u8, 3_u8, 1_u8, 4_u8));
+    assert_eq!(v.wzyx(), u8vec4(4_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.wzyy(), u8vec4(4_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.wzyz(), u8vec4(4_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.wzyw(), u8vec4(4_u8, 3_u8, 2_u8, 4_u8));
+    assert_eq!(v.wzzx(), u8vec4(4_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.wzzy(), u8vec4(4_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.wzzz(), u8vec4(4_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.wzzw(), u8vec4(4_u8, 3_u8, 3_u8, 4_u8));
+    assert_eq!(v.wzwx(), u8vec4(4_u8, 3_u8, 4_u8, 1_u8));
+    assert_eq!(v.wzwy(), u8vec4(4_u8, 3_u8, 4_u8, 2_u8));
+    assert_eq!(v.wzwz(), u8vec4(4_u8, 3_u8, 4_u8, 3_u8));
+    assert_eq!(v.wzww(), u8vec4(4_u8, 3_u8, 4_u8, 4_u8));
+    assert_eq!(v.wwxx(), u8vec4(4_u8, 4_u8, 1_u8, 1_u8));
+    assert_eq!(v.wwxy(), u8vec4(4_u8, 4_u8, 1_u8, 2_u8));
+    assert_eq!(v.wwxz(), u8vec4(4_u8, 4_u8, 1_u8, 3_u8));
+    assert_eq!(v.wwxw(), u8vec4(4_u8, 4_u8, 1_u8, 4_u8));
+    assert_eq!(v.wwyx(), u8vec4(4_u8, 4_u8, 2_u8, 1_u8));
+    assert_eq!(v.wwyy(), u8vec4(4_u8, 4_u8, 2_u8, 2_u8));
+    assert_eq!(v.wwyz(), u8vec4(4_u8, 4_u8, 2_u8, 3_u8));
+    assert_eq!(v.wwyw(), u8vec4(4_u8, 4_u8, 2_u8, 4_u8));
+    assert_eq!(v.wwzx(), u8vec4(4_u8, 4_u8, 3_u8, 1_u8));
+    assert_eq!(v.wwzy(), u8vec4(4_u8, 4_u8, 3_u8, 2_u8));
+    assert_eq!(v.wwzz(), u8vec4(4_u8, 4_u8, 3_u8, 3_u8));
+    assert_eq!(v.wwzw(), u8vec4(4_u8, 4_u8, 3_u8, 4_u8));
+    assert_eq!(v.wwwx(), u8vec4(4_u8, 4_u8, 4_u8, 1_u8));
+    assert_eq!(v.wwwy(), u8vec4(4_u8, 4_u8, 4_u8, 2_u8));
+    assert_eq!(v.wwwz(), u8vec4(4_u8, 4_u8, 4_u8, 3_u8));
+    assert_eq!(v.wwww(), u8vec4(4_u8, 4_u8, 4_u8, 4_u8));
+    assert_eq!(v.xxx(), u8vec3(1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxy(), u8vec3(1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xxz(), u8vec3(1_u8, 1_u8, 3_u8));
+    assert_eq!(v.xxw(), u8vec3(1_u8, 1_u8, 4_u8));
+    assert_eq!(v.xyx(), u8vec3(1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyy(), u8vec3(1_u8, 2_u8, 2_u8));
+    assert_eq!(v.xyz(), u8vec3(1_u8, 2_u8, 3_u8));
+    assert_eq!(v.xyw(), u8vec3(1_u8, 2_u8, 4_u8));
+    assert_eq!(v.xzx(), u8vec3(1_u8, 3_u8, 1_u8));
+    assert_eq!(v.xzy(), u8vec3(1_u8, 3_u8, 2_u8));
+    assert_eq!(v.xzz(), u8vec3(1_u8, 3_u8, 3_u8));
+    assert_eq!(v.xzw(), u8vec3(1_u8, 3_u8, 4_u8));
+    assert_eq!(v.xwx(), u8vec3(1_u8, 4_u8, 1_u8));
+    assert_eq!(v.xwy(), u8vec3(1_u8, 4_u8, 2_u8));
+    assert_eq!(v.xwz(), u8vec3(1_u8, 4_u8, 3_u8));
+    assert_eq!(v.xww(), u8vec3(1_u8, 4_u8, 4_u8));
+    assert_eq!(v.yxx(), u8vec3(2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxy(), u8vec3(2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yxz(), u8vec3(2_u8, 1_u8, 3_u8));
+    assert_eq!(v.yxw(), u8vec3(2_u8, 1_u8, 4_u8));
+    assert_eq!(v.yyx(), u8vec3(2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyy(), u8vec3(2_u8, 2_u8, 2_u8));
+    assert_eq!(v.yyz(), u8vec3(2_u8, 2_u8, 3_u8));
+    assert_eq!(v.yyw(), u8vec3(2_u8, 2_u8, 4_u8));
+    assert_eq!(v.yzx(), u8vec3(2_u8, 3_u8, 1_u8));
+    assert_eq!(v.yzy(), u8vec3(2_u8, 3_u8, 2_u8));
+    assert_eq!(v.yzz(), u8vec3(2_u8, 3_u8, 3_u8));
+    assert_eq!(v.yzw(), u8vec3(2_u8, 3_u8, 4_u8));
+    assert_eq!(v.ywx(), u8vec3(2_u8, 4_u8, 1_u8));
+    assert_eq!(v.ywy(), u8vec3(2_u8, 4_u8, 2_u8));
+    assert_eq!(v.ywz(), u8vec3(2_u8, 4_u8, 3_u8));
+    assert_eq!(v.yww(), u8vec3(2_u8, 4_u8, 4_u8));
+    assert_eq!(v.zxx(), u8vec3(3_u8, 1_u8, 1_u8));
+    assert_eq!(v.zxy(), u8vec3(3_u8, 1_u8, 2_u8));
+    assert_eq!(v.zxz(), u8vec3(3_u8, 1_u8, 3_u8));
+    assert_eq!(v.zxw(), u8vec3(3_u8, 1_u8, 4_u8));
+    assert_eq!(v.zyx(), u8vec3(3_u8, 2_u8, 1_u8));
+    assert_eq!(v.zyy(), u8vec3(3_u8, 2_u8, 2_u8));
+    assert_eq!(v.zyz(), u8vec3(3_u8, 2_u8, 3_u8));
+    assert_eq!(v.zyw(), u8vec3(3_u8, 2_u8, 4_u8));
+    assert_eq!(v.zzx(), u8vec3(3_u8, 3_u8, 1_u8));
+    assert_eq!(v.zzy(), u8vec3(3_u8, 3_u8, 2_u8));
+    assert_eq!(v.zzz(), u8vec3(3_u8, 3_u8, 3_u8));
+    assert_eq!(v.zzw(), u8vec3(3_u8, 3_u8, 4_u8));
+    assert_eq!(v.zwx(), u8vec3(3_u8, 4_u8, 1_u8));
+    assert_eq!(v.zwy(), u8vec3(3_u8, 4_u8, 2_u8));
+    assert_eq!(v.zwz(), u8vec3(3_u8, 4_u8, 3_u8));
+    assert_eq!(v.zww(), u8vec3(3_u8, 4_u8, 4_u8));
+    assert_eq!(v.wxx(), u8vec3(4_u8, 1_u8, 1_u8));
+    assert_eq!(v.wxy(), u8vec3(4_u8, 1_u8, 2_u8));
+    assert_eq!(v.wxz(), u8vec3(4_u8, 1_u8, 3_u8));
+    assert_eq!(v.wxw(), u8vec3(4_u8, 1_u8, 4_u8));
+    assert_eq!(v.wyx(), u8vec3(4_u8, 2_u8, 1_u8));
+    assert_eq!(v.wyy(), u8vec3(4_u8, 2_u8, 2_u8));
+    assert_eq!(v.wyz(), u8vec3(4_u8, 2_u8, 3_u8));
+    assert_eq!(v.wyw(), u8vec3(4_u8, 2_u8, 4_u8));
+    assert_eq!(v.wzx(), u8vec3(4_u8, 3_u8, 1_u8));
+    assert_eq!(v.wzy(), u8vec3(4_u8, 3_u8, 2_u8));
+    assert_eq!(v.wzz(), u8vec3(4_u8, 3_u8, 3_u8));
+    assert_eq!(v.wzw(), u8vec3(4_u8, 3_u8, 4_u8));
+    assert_eq!(v.wwx(), u8vec3(4_u8, 4_u8, 1_u8));
+    assert_eq!(v.wwy(), u8vec3(4_u8, 4_u8, 2_u8));
+    assert_eq!(v.wwz(), u8vec3(4_u8, 4_u8, 3_u8));
+    assert_eq!(v.www(), u8vec3(4_u8, 4_u8, 4_u8));
+    assert_eq!(v.xx(), u8vec2(1_u8, 1_u8));
+    assert_eq!(v.xy(), u8vec2(1_u8, 2_u8));
+    assert_eq!(v.xz(), u8vec2(1_u8, 3_u8));
+    assert_eq!(v.xw(), u8vec2(1_u8, 4_u8));
+    assert_eq!(v.yx(), u8vec2(2_u8, 1_u8));
+    assert_eq!(v.yy(), u8vec2(2_u8, 2_u8));
+    assert_eq!(v.yz(), u8vec2(2_u8, 3_u8));
+    assert_eq!(v.yw(), u8vec2(2_u8, 4_u8));
+    assert_eq!(v.zx(), u8vec2(3_u8, 1_u8));
+    assert_eq!(v.zy(), u8vec2(3_u8, 2_u8));
+    assert_eq!(v.zz(), u8vec2(3_u8, 3_u8));
+    assert_eq!(v.zw(), u8vec2(3_u8, 4_u8));
+    assert_eq!(v.wx(), u8vec2(4_u8, 1_u8));
+    assert_eq!(v.wy(), u8vec2(4_u8, 2_u8));
+    assert_eq!(v.wz(), u8vec2(4_u8, 3_u8));
+    assert_eq!(v.ww(), u8vec2(4_u8, 4_u8));
+});
+
+glam_test!(test_u8vec3_swizzles, {
+    let v = u8vec3(1_u8, 2_u8, 3_u8);
+    assert_eq!(v, v.xyz());
+    assert_eq!(v.xxxx(), u8vec4(1_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxxy(), u8vec4(1_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xxxz(), u8vec4(1_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.xxyx(), u8vec4(1_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xxyy(), u8vec4(1_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.xxyz(), u8vec4(1_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.xxzx(), u8vec4(1_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.xxzy(), u8vec4(1_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.xxzz(), u8vec4(1_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.xyxx(), u8vec4(1_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.xyxy(), u8vec4(1_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.xyxz(), u8vec4(1_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.xyyx(), u8vec4(1_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyyy(), u8vec4(1_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.xyyz(), u8vec4(1_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.xyzx(), u8vec4(1_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.xyzy(), u8vec4(1_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.xyzz(), u8vec4(1_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.xzxx(), u8vec4(1_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.xzxy(), u8vec4(1_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.xzxz(), u8vec4(1_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.xzyx(), u8vec4(1_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.xzyy(), u8vec4(1_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.xzyz(), u8vec4(1_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.xzzx(), u8vec4(1_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.xzzy(), u8vec4(1_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.xzzz(), u8vec4(1_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.yxxx(), u8vec4(2_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxxy(), u8vec4(2_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.yxxz(), u8vec4(2_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.yxyx(), u8vec4(2_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.yxyy(), u8vec4(2_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.yxyz(), u8vec4(2_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.yxzx(), u8vec4(2_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.yxzy(), u8vec4(2_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.yxzz(), u8vec4(2_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.yyxx(), u8vec4(2_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yyxy(), u8vec4(2_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yyxz(), u8vec4(2_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.yyyx(), u8vec4(2_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyyy(), u8vec4(2_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.yyyz(), u8vec4(2_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.yyzx(), u8vec4(2_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.yyzy(), u8vec4(2_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.yyzz(), u8vec4(2_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.yzxx(), u8vec4(2_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.yzxy(), u8vec4(2_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.yzxz(), u8vec4(2_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.yzyx(), u8vec4(2_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.yzyy(), u8vec4(2_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.yzyz(), u8vec4(2_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.yzzx(), u8vec4(2_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.yzzy(), u8vec4(2_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.yzzz(), u8vec4(2_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.zxxx(), u8vec4(3_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.zxxy(), u8vec4(3_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.zxxz(), u8vec4(3_u8, 1_u8, 1_u8, 3_u8));
+    assert_eq!(v.zxyx(), u8vec4(3_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.zxyy(), u8vec4(3_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.zxyz(), u8vec4(3_u8, 1_u8, 2_u8, 3_u8));
+    assert_eq!(v.zxzx(), u8vec4(3_u8, 1_u8, 3_u8, 1_u8));
+    assert_eq!(v.zxzy(), u8vec4(3_u8, 1_u8, 3_u8, 2_u8));
+    assert_eq!(v.zxzz(), u8vec4(3_u8, 1_u8, 3_u8, 3_u8));
+    assert_eq!(v.zyxx(), u8vec4(3_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.zyxy(), u8vec4(3_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.zyxz(), u8vec4(3_u8, 2_u8, 1_u8, 3_u8));
+    assert_eq!(v.zyyx(), u8vec4(3_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.zyyy(), u8vec4(3_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.zyyz(), u8vec4(3_u8, 2_u8, 2_u8, 3_u8));
+    assert_eq!(v.zyzx(), u8vec4(3_u8, 2_u8, 3_u8, 1_u8));
+    assert_eq!(v.zyzy(), u8vec4(3_u8, 2_u8, 3_u8, 2_u8));
+    assert_eq!(v.zyzz(), u8vec4(3_u8, 2_u8, 3_u8, 3_u8));
+    assert_eq!(v.zzxx(), u8vec4(3_u8, 3_u8, 1_u8, 1_u8));
+    assert_eq!(v.zzxy(), u8vec4(3_u8, 3_u8, 1_u8, 2_u8));
+    assert_eq!(v.zzxz(), u8vec4(3_u8, 3_u8, 1_u8, 3_u8));
+    assert_eq!(v.zzyx(), u8vec4(3_u8, 3_u8, 2_u8, 1_u8));
+    assert_eq!(v.zzyy(), u8vec4(3_u8, 3_u8, 2_u8, 2_u8));
+    assert_eq!(v.zzyz(), u8vec4(3_u8, 3_u8, 2_u8, 3_u8));
+    assert_eq!(v.zzzx(), u8vec4(3_u8, 3_u8, 3_u8, 1_u8));
+    assert_eq!(v.zzzy(), u8vec4(3_u8, 3_u8, 3_u8, 2_u8));
+    assert_eq!(v.zzzz(), u8vec4(3_u8, 3_u8, 3_u8, 3_u8));
+    assert_eq!(v.xxx(), u8vec3(1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxy(), u8vec3(1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xxz(), u8vec3(1_u8, 1_u8, 3_u8));
+    assert_eq!(v.xyx(), u8vec3(1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyy(), u8vec3(1_u8, 2_u8, 2_u8));
+    assert_eq!(v.xzx(), u8vec3(1_u8, 3_u8, 1_u8));
+    assert_eq!(v.xzy(), u8vec3(1_u8, 3_u8, 2_u8));
+    assert_eq!(v.xzz(), u8vec3(1_u8, 3_u8, 3_u8));
+    assert_eq!(v.yxx(), u8vec3(2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxy(), u8vec3(2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yxz(), u8vec3(2_u8, 1_u8, 3_u8));
+    assert_eq!(v.yyx(), u8vec3(2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyy(), u8vec3(2_u8, 2_u8, 2_u8));
+    assert_eq!(v.yyz(), u8vec3(2_u8, 2_u8, 3_u8));
+    assert_eq!(v.yzx(), u8vec3(2_u8, 3_u8, 1_u8));
+    assert_eq!(v.yzy(), u8vec3(2_u8, 3_u8, 2_u8));
+    assert_eq!(v.yzz(), u8vec3(2_u8, 3_u8, 3_u8));
+    assert_eq!(v.zxx(), u8vec3(3_u8, 1_u8, 1_u8));
+    assert_eq!(v.zxy(), u8vec3(3_u8, 1_u8, 2_u8));
+    assert_eq!(v.zxz(), u8vec3(3_u8, 1_u8, 3_u8));
+    assert_eq!(v.zyx(), u8vec3(3_u8, 2_u8, 1_u8));
+    assert_eq!(v.zyy(), u8vec3(3_u8, 2_u8, 2_u8));
+    assert_eq!(v.zyz(), u8vec3(3_u8, 2_u8, 3_u8));
+    assert_eq!(v.zzx(), u8vec3(3_u8, 3_u8, 1_u8));
+    assert_eq!(v.zzy(), u8vec3(3_u8, 3_u8, 2_u8));
+    assert_eq!(v.zzz(), u8vec3(3_u8, 3_u8, 3_u8));
+    assert_eq!(v.xx(), u8vec2(1_u8, 1_u8));
+    assert_eq!(v.xy(), u8vec2(1_u8, 2_u8));
+    assert_eq!(v.xz(), u8vec2(1_u8, 3_u8));
+    assert_eq!(v.yx(), u8vec2(2_u8, 1_u8));
+    assert_eq!(v.yy(), u8vec2(2_u8, 2_u8));
+    assert_eq!(v.yz(), u8vec2(2_u8, 3_u8));
+    assert_eq!(v.zx(), u8vec2(3_u8, 1_u8));
+    assert_eq!(v.zy(), u8vec2(3_u8, 2_u8));
+    assert_eq!(v.zz(), u8vec2(3_u8, 3_u8));
+});
+
+glam_test!(test_u8vec2_swizzles, {
+    let v = u8vec2(1_u8, 2_u8);
+    assert_eq!(v, v.xy());
+    assert_eq!(v.xxxx(), u8vec4(1_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxxy(), u8vec4(1_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xxyx(), u8vec4(1_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xxyy(), u8vec4(1_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.xyxx(), u8vec4(1_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.xyxy(), u8vec4(1_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.xyyx(), u8vec4(1_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyyy(), u8vec4(1_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.yxxx(), u8vec4(2_u8, 1_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxxy(), u8vec4(2_u8, 1_u8, 1_u8, 2_u8));
+    assert_eq!(v.yxyx(), u8vec4(2_u8, 1_u8, 2_u8, 1_u8));
+    assert_eq!(v.yxyy(), u8vec4(2_u8, 1_u8, 2_u8, 2_u8));
+    assert_eq!(v.yyxx(), u8vec4(2_u8, 2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yyxy(), u8vec4(2_u8, 2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yyyx(), u8vec4(2_u8, 2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyyy(), u8vec4(2_u8, 2_u8, 2_u8, 2_u8));
+    assert_eq!(v.xxx(), u8vec3(1_u8, 1_u8, 1_u8));
+    assert_eq!(v.xxy(), u8vec3(1_u8, 1_u8, 2_u8));
+    assert_eq!(v.xyx(), u8vec3(1_u8, 2_u8, 1_u8));
+    assert_eq!(v.xyy(), u8vec3(1_u8, 2_u8, 2_u8));
+    assert_eq!(v.yxx(), u8vec3(2_u8, 1_u8, 1_u8));
+    assert_eq!(v.yxy(), u8vec3(2_u8, 1_u8, 2_u8));
+    assert_eq!(v.yyx(), u8vec3(2_u8, 2_u8, 1_u8));
+    assert_eq!(v.yyy(), u8vec3(2_u8, 2_u8, 2_u8));
+    assert_eq!(v.xx(), u8vec2(1_u8, 1_u8));
+    assert_eq!(v.yx(), u8vec2(2_u8, 1_u8));
+    assert_eq!(v.yy(), u8vec2(2_u8, 2_u8));
+});
diff --git a/crates/glam/tests/vec2.rs b/crates/glam/tests/vec2.rs
index fd6df74..e97e308 100644
--- a/crates/glam/tests/vec2.rs
+++ b/crates/glam/tests/vec2.rs
@@ -4,7 +4,7 @@
 mod support;
 
 macro_rules! impl_vec2_tests {
-    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
+    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
         glam_test!(test_const, {
             const V0: $vec2 = $vec2::splat(1 as $t);
             const V1: $vec2 = $vec2::new(1 as $t, 2 as $t);
@@ -48,6 +48,9 @@
             let v = $vec2::new(t.0, t.1);
             assert_eq!(t, v.into());
 
+            assert_eq!($vec2::new(1 as $t, 0 as $t), BVec2::new(true, false).into());
+            assert_eq!($vec2::new(0 as $t, 1 as $t), BVec2::new(false, true).into());
+
             assert_eq!($vec2::new(1 as $t, 0 as $t), $vec2::X);
             assert_eq!($vec2::new(0 as $t, 1 as $t), $vec2::Y);
         });
@@ -81,6 +84,17 @@
             assert_eq!($vec2::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec2::new(1 as $t, 2 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec2::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec2::ZERO);
+        });
+
+        glam_test!(test_with, {
+            assert_eq!($vec2::X, $vec2::ZERO.with_x(1 as $t));
+            assert_eq!($vec2::Y, $vec2::ZERO.with_y(1 as $t));
+        });
+
         glam_test!(test_accessors, {
             let mut a = $vec2::ZERO;
             a.x = 1 as $t;
@@ -138,6 +152,62 @@
             assert_eq!($new(2 as $t, 4 as $t), a % 8 as $t);
         });
 
+        glam_test!(test_ops_propagated, {
+            let vec = $new(2 as $t, 4 as $t);
+            let scalar = 2 as $t;
+            let g_scalar = 16 as $t;
+
+            assert_eq!((vec + vec), (vec + &vec));
+            assert_eq!((vec + vec), (&vec + vec));
+            assert_eq!((vec + vec), (&vec + &vec));
+            assert_eq!((vec + scalar), (vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + scalar));
+            assert_eq!((scalar + vec), (&scalar + vec));
+            assert_eq!((scalar + vec), (&scalar + &vec));
+            assert_eq!((scalar + vec), (scalar + &vec));
+
+            assert_eq!((vec - vec), (vec - &vec));
+            assert_eq!((vec - vec), (&vec - vec));
+            assert_eq!((vec - vec), (&vec - &vec));
+            assert_eq!((vec - scalar), (vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - scalar));
+            assert_eq!((g_scalar - vec), (&g_scalar - vec));
+            assert_eq!((g_scalar - vec), (&g_scalar - &vec));
+            assert_eq!((g_scalar - vec), (g_scalar - &vec));
+
+            assert_eq!((vec * vec), (vec * &vec));
+            assert_eq!((vec * vec), (&vec * vec));
+            assert_eq!((vec * vec), (&vec * &vec));
+            assert_eq!((vec * scalar), (vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * scalar));
+            assert_eq!((scalar * vec), (&scalar * vec));
+            assert_eq!((scalar * vec), (&scalar * &vec));
+            assert_eq!((scalar * vec), (scalar * &vec));
+
+            assert_eq!((vec / vec), (vec / &vec));
+            assert_eq!((vec / vec), (&vec / vec));
+            assert_eq!((vec / vec), (&vec / &vec));
+            assert_eq!((vec / scalar), (vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / scalar));
+            assert_eq!((scalar / vec), (&scalar / vec));
+            assert_eq!((scalar / vec), (&scalar / &vec));
+            assert_eq!((scalar / vec), (scalar / &vec));
+
+            assert_eq!((vec % vec), (vec % &vec));
+            assert_eq!((vec % vec), (&vec % vec));
+            assert_eq!((vec % vec), (&vec % &vec));
+            assert_eq!((vec % scalar), (vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % scalar));
+            assert_eq!((scalar % vec), (&scalar % vec));
+            assert_eq!((scalar % vec), (&scalar % &vec));
+            assert_eq!((scalar % vec), (scalar % &vec));
+        });
+
         glam_test!(test_assign_ops, {
             let a = $new(1 as $t, 2 as $t);
             let mut b = a;
@@ -172,6 +242,47 @@
             assert_eq!($new(0 as $t, 0 as $t), b);
         });
 
+        glam_test!(test_assign_ops_propagation, {
+            let vec = $new(1 as $t, 2 as $t);
+            let mut a = vec;
+            let mut b = vec;
+            let scalar = 2 as $t;
+
+            a += &scalar;
+            b += scalar;
+            assert_eq!(b, a, "AddAssign<Scalar>");
+            a -= &scalar;
+            b -= scalar;
+            assert_eq!(b, a, "SubAssign<Scalar>");
+            a *= &scalar;
+            b *= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+            a /= &scalar;
+            b /= scalar;
+            assert_eq!(b, a, "DivAssign<Scalar>");
+            a %= &scalar;
+            b %= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+
+            a = vec;
+            b = vec;
+            a += &vec;
+            b += vec;
+            assert_eq!(b, a, "AddAssign<Vec>");
+            a -= &vec;
+            b -= vec;
+            assert_eq!(b, a, "SubAssign<Vec>");
+            a *= &vec;
+            b *= vec;
+            assert_eq!(b, a, "MulAssign<Vec>");
+            a /= &vec;
+            b /= vec;
+            assert_eq!(b, a, "DivAssign<Vec>");
+            a %= &vec;
+            b %= vec;
+            assert_eq!(b, a, "RemAssign<Vec>");
+        });
+
         glam_test!(test_min_max, {
             let a = $new(0 as $t, 2 as $t);
             let b = $new(1 as $t, 1 as $t);
@@ -181,6 +292,12 @@
             assert_eq!($new(1 as $t, 2 as $t), b.max(a));
         });
 
+        glam_test!(test_sum_product, {
+            let a = $new(2 as $t, 3 as $t);
+            assert_eq!(a.element_sum(), 5 as $t);
+            assert_eq!(a.element_product(), 6 as $t);
+        });
+
         glam_test!(test_clamp, {
             fn vec(x: i32, y: i32) -> $vec2 {
                 $vec2::new(x as $t, y as $t)
@@ -255,6 +372,20 @@
             assert!(b.cmpeq($vec2::splat(1 as $t)).all());
         });
 
+        glam_test!(test_mask_new, {
+            assert_eq!($mask::new(false, false), $masknew(false, false));
+            assert_eq!($mask::new(true, false), $masknew(true, false));
+            assert_eq!($mask::new(false, true), $masknew(false, true));
+            assert_eq!($mask::new(true, true), $masknew(true, true));
+        });
+
+        glam_test!(test_mask_from_array_bool, {
+            assert_eq!($mask::new(false, false), $mask::from([false, false]));
+            assert_eq!($mask::new(true, false), $mask::from([true, false]));
+            assert_eq!($mask::new(false, true), $mask::from([false, true]));
+            assert_eq!($mask::new(true, true), $mask::from([true, true]));
+        });
+
         glam_test!(test_mask_into_array_u32, {
             assert_eq!(Into::<[u32; 2]>::into($mask::new(false, false)), [0, 0]);
             assert_eq!(Into::<[u32; 2]>::into($mask::new(true, false)), [!0, 0]);
@@ -482,6 +613,11 @@
             v.write_to_slice(&mut a);
             assert_eq!(v, $vec2::from_slice(&a));
 
+            let mut a = [0 as $t; 17];
+            v.write_to_slice(&mut a);
+            assert_eq!(v, $vec2::from_slice(&a[..2]));
+            assert_eq!([0 as $t; 15], a[2..]);
+
             should_panic!({ $vec2::ONE.write_to_slice(&mut [0 as $t]) });
             should_panic!({ $vec2::from_slice(&[0 as $t]) });
         });
@@ -501,8 +637,8 @@
 }
 
 macro_rules! impl_vec2_signed_tests {
-    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
-        impl_vec2_tests!($t, $new, $vec2, $vec3, $mask);
+    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec2_tests!($t, $new, $vec2, $vec3, $mask, $masknew);
 
         glam_test!(test_is_negative_bitmask, {
             assert_eq!($vec2::ZERO.is_negative_bitmask(), 0b00);
@@ -543,6 +679,11 @@
             assert_eq!($new(0.0 as $t, -0.0 as $t), -$new(-0.0 as $t, 0.0 as $t));
         });
 
+        glam_test!(test_neg_propagation, {
+            let a = $new(1 as $t, 2 as $t);
+            assert_eq!(-a, -(&a));
+        });
+
         glam_test!(test_perp, {
             let v1 = $vec2::new(1 as $t, 2 as $t);
             let v2 = $vec2::new(1 as $t, 1 as $t);
@@ -585,8 +726,8 @@
 }
 
 macro_rules! impl_vec2_signed_integer_tests {
-    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
-        impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask);
+    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask, $masknew);
 
         glam_test!(test_signum, {
             assert_eq!($vec3::ZERO.signum(), $vec3::ZERO);
@@ -628,14 +769,10 @@
 }
 
 macro_rules! impl_vec2_float_tests {
-    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
-        impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask);
+    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask, $masknew);
         impl_vec_float_normalize_tests!($t, $vec2);
 
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_vec2_nan, {
             assert!($vec2::NAN.is_nan());
             assert!(!$vec2::NAN.is_finite());
@@ -742,30 +879,39 @@
             assert_eq!($vec2::new(0.0, 11.123).round().y, 11.0);
             assert_eq!($vec2::new(0.0, 11.499).round().y, 11.0);
             assert_eq!(
-                $vec2::new(NEG_INFINITY, INFINITY).round(),
-                $vec2::new(NEG_INFINITY, INFINITY)
+                $vec2::new($t::NEG_INFINITY, $t::INFINITY).round(),
+                $vec2::new($t::NEG_INFINITY, $t::INFINITY)
             );
-            assert!($vec2::new(NAN, 0.0).round().x.is_nan());
+            assert!($vec2::new($t::NAN, 0.0).round().x.is_nan());
         });
 
         glam_test!(test_floor, {
             assert_eq!($vec2::new(1.35, -1.5).floor(), $vec2::new(1.0, -2.0));
             assert_eq!(
-                $vec2::new(INFINITY, NEG_INFINITY).floor(),
-                $vec2::new(INFINITY, NEG_INFINITY)
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY).floor(),
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY)
             );
-            assert!($vec2::new(NAN, 0.0).floor().x.is_nan());
+            assert!($vec2::new($t::NAN, 0.0).floor().x.is_nan());
             assert_eq!(
                 $vec2::new(-2000000.123, 10000000.123).floor(),
                 $vec2::new(-2000001.0, 10000000.0)
             );
         });
 
+        glam_test!(test_fract_gl, {
+            assert_approx_eq!($vec2::new(1.35, -1.5).fract_gl(), $vec2::new(0.35, 0.5));
+            assert_approx_eq!(
+                $vec2::new(-2000000.123, 1000000.123).fract_gl(),
+                $vec2::new(0.877, 0.123),
+                0.002
+            );
+        });
+
         glam_test!(test_fract, {
-            assert_approx_eq!($vec2::new(1.35, -1.5).fract(), $vec2::new(0.35, 0.5));
+            assert_approx_eq!($vec2::new(1.35, -1.5).fract(), $vec2::new(0.35, -0.5));
             assert_approx_eq!(
                 $vec2::new(-2000000.123, 1000000.123).fract(),
-                $vec2::new(0.877, 0.123),
+                $vec2::new(-0.123, 0.123),
                 0.002
             );
         });
@@ -773,10 +919,10 @@
         glam_test!(test_ceil, {
             assert_eq!($vec2::new(1.35, -1.5).ceil(), $vec2::new(2.0, -1.0));
             assert_eq!(
-                $vec2::new(INFINITY, NEG_INFINITY).ceil(),
-                $vec2::new(INFINITY, NEG_INFINITY)
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY).ceil(),
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY)
             );
-            assert!($vec2::new(NAN, 0.0).ceil().x.is_nan());
+            assert!($vec2::new($t::NAN, 0.0).ceil().x.is_nan());
             assert_eq!(
                 $vec2::new(-2000000.123, 1000000.123).ceil(),
                 $vec2::new(-2000000.0, 1000001.0)
@@ -786,10 +932,10 @@
         glam_test!(test_trunc, {
             assert_eq!($vec2::new(1.35, -1.5).trunc(), $vec2::new(1.0, -1.0));
             assert_eq!(
-                $vec2::new(INFINITY, NEG_INFINITY).trunc(),
-                $vec2::new(INFINITY, NEG_INFINITY)
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY).trunc(),
+                $vec2::new($t::INFINITY, $t::NEG_INFINITY)
             );
-            assert!($vec2::new(0.0, NAN).trunc().y.is_nan());
+            assert!($vec2::new(0.0, $t::NAN).trunc().y.is_nan());
             assert_eq!(
                 $vec2::new(-0.0, -2000000.123).trunc(),
                 $vec2::new(-0.0, -2000000.0)
@@ -804,13 +950,65 @@
             assert_approx_eq!($vec2::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_lerp_big_difference, {
+            let v0 = $vec2::new(-1e30, -1e30);
+            let v1 = $vec2::new(16.0, 16.0);
+            assert_approx_eq!(v0, v0.lerp(v1, 0.0));
+            assert_approx_eq!(v1, v0.lerp(v1, 1.0));
+        });
+
+        glam_test!(test_move_towards, {
+            let v0 = $vec2::new(-1.0, -1.0);
+            let v1 = $vec2::new(1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
+        glam_test!(test_rotate_towards, {
+            use core::$t::consts::{FRAC_PI_2, FRAC_PI_4};
+            let eps = 10.0 * $t::EPSILON as f32;
+
+            // Setup such that `v0` is `PI/2` and `-PI/2` radians away from `v1` and `v2` respectively.
+            let v0 = $vec2::new(1.0, 0.0);
+            let v1 = $vec2::new(0.0, -1.0);
+            let v2 = $vec2::new(0.0, 1.0);
+
+            // Positive delta
+            assert_approx_eq!(v0, v0.rotate_towards(v1, 0.0), eps);
+            assert_approx_eq!(
+                $vec2::new($t::sqrt(2.0) / 2.0, -$t::sqrt(2.0) / 2.0),
+                v0.rotate_towards(v1, FRAC_PI_4),
+                eps
+            );
+            assert_approx_eq!(v1, v0.rotate_towards(v1, FRAC_PI_2), eps);
+            assert_approx_eq!(v1, v0.rotate_towards(v1, FRAC_PI_2 * 1.5), eps);
+
+            // Negative delta
+            assert_approx_eq!(
+                $vec2::new($t::sqrt(2.0) / 2.0, $t::sqrt(2.0) / 2.0),
+                v0.rotate_towards(v1, -FRAC_PI_4),
+                eps
+            );
+            assert_approx_eq!(v2, v0.rotate_towards(v1, -FRAC_PI_2), eps);
+            assert_approx_eq!(v2, v0.rotate_towards(v1, -FRAC_PI_2 * 1.5), eps);
+        });
+
+        glam_test!(test_midpoint, {
+            let v0 = $vec2::new(-1.0, -1.0);
+            let v1 = $vec2::new(1.0, 1.0);
+            let v2 = $vec2::new(-1.5, 0.0);
+            assert_approx_eq!($vec2::ZERO, v0.midpoint(v1));
+            assert_approx_eq!($vec2::new(-0.25, 0.5), v1.midpoint(v2));
+        });
+
         glam_test!(test_is_finite, {
             assert!($vec2::new(0.0, 0.0).is_finite());
             assert!($vec2::new(-1e-10, 1e10).is_finite());
-            assert!(!$vec2::new(INFINITY, 0.0).is_finite());
-            assert!(!$vec2::new(0.0, NAN).is_finite());
-            assert!(!$vec2::new(0.0, NEG_INFINITY).is_finite());
-            assert!(!$vec2::new(INFINITY, NEG_INFINITY).is_finite());
+            assert!(!$vec2::new($t::INFINITY, 0.0).is_finite());
+            assert!(!$vec2::new(0.0, $t::NAN).is_finite());
+            assert!(!$vec2::new(0.0, $t::NEG_INFINITY).is_finite());
+            assert!(!$vec2::new($t::INFINITY, $t::NEG_INFINITY).is_finite());
             assert!(!$vec2::INFINITY.is_finite());
             assert!(!$vec2::NEG_INFINITY.is_finite());
         });
@@ -826,15 +1024,22 @@
             );
         });
 
-        glam_test!(test_angle_between, {
-            let angle = $vec2::new(1.0, 0.0).angle_between($vec2::new(0.0, 1.0));
+        glam_test!(test_angle_to, {
+            let angle = $vec2::new(1.0, 0.0).angle_to($vec2::new(0.0, 1.0));
             assert_approx_eq!(core::$t::consts::FRAC_PI_2, angle, 1e-6);
 
-            let angle = $vec2::new(10.0, 0.0).angle_between($vec2::new(0.0, 5.0));
+            let angle = $vec2::new(10.0, 0.0).angle_to($vec2::new(0.0, 5.0));
             assert_approx_eq!(core::$t::consts::FRAC_PI_2, angle, 1e-6);
 
-            let angle = $vec2::new(-1.0, 0.0).angle_between($vec2::new(0.0, 1.0));
+            let angle = $vec2::new(-1.0, 0.0).angle_to($vec2::new(0.0, 1.0));
             assert_approx_eq!(-core::$t::consts::FRAC_PI_2, angle, 1e-6);
+
+            // the angle returned by angle_to should rotate the input vector to the
+            // destination vector
+            assert_approx_eq!(
+                $vec2::from_angle($vec2::X.angle_to($vec2::Y)).rotate($vec2::X),
+                $vec2::Y
+            );
         });
 
         glam_test!(test_clamp_length, {
@@ -896,6 +1101,11 @@
             );
         });
 
+        glam_test!(test_fmt_float, {
+            let a = $vec2::new(1.0, 2.0);
+            assert_eq!(format!("{:.2}", a), "[1.00, 2.00]");
+        });
+
         glam_test!(test_angle_conversion, {
             let angle = 0.;
             let vec = $vec2::from_angle(angle);
@@ -918,6 +1128,22 @@
             assert_approx_eq!(vec, $vec2::new(0.0, -1.0));
             assert_approx_eq!(vec.to_angle(), angle);
         });
+
+        glam_test!(test_reflect, {
+            let incident = $vec2::new(1.0, -1.0);
+            let normal = $vec2::Y;
+            assert_approx_eq!(incident.reflect(normal), $vec2::ONE);
+        });
+
+        glam_test!(test_refract, {
+            let incident = $vec2::NEG_ONE.normalize();
+            let normal = $vec2::ONE.normalize();
+            assert_approx_eq!(incident.refract(normal, 0.5), incident);
+
+            let incident = $vec2::new(1.0, -1.0).normalize();
+            let normal = $vec2::Y;
+            assert_approx_eq!(incident.refract(normal, 1.5), $vec2::ZERO);
+        });
     };
 }
 
@@ -1055,7 +1281,7 @@
 }
 
 mod vec2 {
-    use glam::{vec2, BVec2, Vec2, Vec3};
+    use glam::{bvec2, vec2, BVec2, Vec2, Vec3};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1069,8 +1295,10 @@
     });
 
     glam_test!(test_as, {
-        use glam::{DVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U64Vec2, UVec2};
+        use glam::{DVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec2};
         assert_eq!(DVec2::new(-1.0, -2.0), Vec2::new(-1.0, -2.0).as_dvec2());
+        assert_eq!(I8Vec2::new(-1, -2), Vec2::new(-1.0, -2.0).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), Vec2::new(1.0, 2.0).as_u8vec2());
         assert_eq!(I16Vec2::new(-1, -2), Vec2::new(-1.0, -2.0).as_i16vec2());
         assert_eq!(U16Vec2::new(1, 2), Vec2::new(1.0, 2.0).as_u16vec2());
         assert_eq!(IVec2::new(-1, -2), Vec2::new(-1.0, -2.0).as_ivec2());
@@ -1079,6 +1307,8 @@
         assert_eq!(U64Vec2::new(1, 2), Vec2::new(1.0, 2.0).as_u64vec2());
 
         assert_eq!(Vec2::new(-1.0, -2.0), DVec2::new(-1.0, -2.0).as_vec2());
+        assert_eq!(I8Vec2::new(-1, -2), DVec2::new(-1.0, -2.0).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), DVec2::new(1.0, 2.0).as_u8vec2());
         assert_eq!(I16Vec2::new(-1, -2), DVec2::new(-1.0, -2.0).as_i16vec2());
         assert_eq!(U16Vec2::new(1, 2), DVec2::new(1.0, 2.0).as_u16vec2());
         assert_eq!(IVec2::new(-1, -2), DVec2::new(-1.0, -2.0).as_ivec2());
@@ -1086,8 +1316,30 @@
         assert_eq!(I64Vec2::new(-1, -2), DVec2::new(-1.0, -2.0).as_i64vec2());
         assert_eq!(U64Vec2::new(1, 2), DVec2::new(1.0, 2.0).as_u64vec2());
 
+        assert_eq!(Vec2::new(-1.0, -2.0), I8Vec2::new(-1, -2).as_vec2());
+        assert_eq!(DVec2::new(-1.0, -2.0), I8Vec2::new(-1, -2).as_dvec2());
+        assert_eq!(U8Vec2::new(1, 2), I8Vec2::new(1, 2).as_u8vec2());
+        assert_eq!(I16Vec2::new(-1, -2), I8Vec2::new(-1, -2).as_i16vec2());
+        assert_eq!(U16Vec2::new(1, 2), I8Vec2::new(1, 2).as_u16vec2());
+        assert_eq!(IVec2::new(-1, -2), I8Vec2::new(-1, -2).as_ivec2());
+        assert_eq!(UVec2::new(1, 2), I8Vec2::new(1, 2).as_uvec2());
+        assert_eq!(I64Vec2::new(-1, -2), I8Vec2::new(-1, -2).as_i64vec2());
+        assert_eq!(U64Vec2::new(1, 2), I8Vec2::new(1, 2).as_u64vec2());
+
+        assert_eq!(Vec2::new(1.0, 2.0), U8Vec2::new(1, 2).as_vec2());
+        assert_eq!(DVec2::new(1.0, 2.0), U8Vec2::new(1, 2).as_dvec2());
+        assert_eq!(I8Vec2::new(1, 2), U8Vec2::new(1, 2).as_i8vec2());
+        assert_eq!(I16Vec2::new(1, 2), U8Vec2::new(1, 2).as_i16vec2());
+        assert_eq!(U16Vec2::new(1, 2), U8Vec2::new(1, 2).as_u16vec2());
+        assert_eq!(IVec2::new(1, 2), U8Vec2::new(1, 2).as_ivec2());
+        assert_eq!(UVec2::new(1, 2), U8Vec2::new(1, 2).as_uvec2());
+        assert_eq!(I64Vec2::new(1, 2), U8Vec2::new(1, 2).as_i64vec2());
+        assert_eq!(U64Vec2::new(1, 2), U8Vec2::new(1, 2).as_u64vec2());
+
         assert_eq!(Vec2::new(-1.0, -2.0), I16Vec2::new(-1, -2).as_vec2());
         assert_eq!(DVec2::new(-1.0, -2.0), I16Vec2::new(-1, -2).as_dvec2());
+        assert_eq!(I8Vec2::new(-1, -2), I16Vec2::new(-1, -2).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), I16Vec2::new(1, 2).as_u8vec2());
         assert_eq!(U16Vec2::new(1, 2), I16Vec2::new(1, 2).as_u16vec2());
         assert_eq!(IVec2::new(-1, -2), I16Vec2::new(-1, -2).as_ivec2());
         assert_eq!(UVec2::new(1, 2), I16Vec2::new(1, 2).as_uvec2());
@@ -1096,6 +1348,8 @@
 
         assert_eq!(Vec2::new(1.0, 2.0), U16Vec2::new(1, 2).as_vec2());
         assert_eq!(DVec2::new(1.0, 2.0), U16Vec2::new(1, 2).as_dvec2());
+        assert_eq!(I8Vec2::new(1, 2), U16Vec2::new(1, 2).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), U16Vec2::new(1, 2).as_u8vec2());
         assert_eq!(I16Vec2::new(1, 2), U16Vec2::new(1, 2).as_i16vec2());
         assert_eq!(IVec2::new(1, 2), U16Vec2::new(1, 2).as_ivec2());
         assert_eq!(UVec2::new(1, 2), U16Vec2::new(1, 2).as_uvec2());
@@ -1105,6 +1359,8 @@
         assert_eq!(Vec2::new(-1.0, -2.0), IVec2::new(-1, -2).as_vec2());
         assert_eq!(DVec2::new(-1.0, -2.0), IVec2::new(-1, -2).as_dvec2());
         assert_eq!(UVec2::new(1, 2), IVec2::new(1, 2).as_uvec2());
+        assert_eq!(I8Vec2::new(-1, -2), IVec2::new(-1, -2).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), IVec2::new(1, 2).as_u8vec2());
         assert_eq!(I16Vec2::new(-1, -2), IVec2::new(-1, -2).as_i16vec2());
         assert_eq!(U16Vec2::new(1, 2), IVec2::new(1, 2).as_u16vec2());
         assert_eq!(I64Vec2::new(-1, -2), IVec2::new(-1, -2).as_i64vec2());
@@ -1112,6 +1368,8 @@
 
         assert_eq!(Vec2::new(1.0, 2.0), UVec2::new(1, 2).as_vec2());
         assert_eq!(DVec2::new(1.0, 2.0), UVec2::new(1, 2).as_dvec2());
+        assert_eq!(I8Vec2::new(1, 2), UVec2::new(1, 2).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), UVec2::new(1, 2).as_u8vec2());
         assert_eq!(I16Vec2::new(1, 2), UVec2::new(1, 2).as_i16vec2());
         assert_eq!(U16Vec2::new(1, 2), UVec2::new(1, 2).as_u16vec2());
         assert_eq!(IVec2::new(1, 2), UVec2::new(1, 2).as_ivec2());
@@ -1120,6 +1378,8 @@
 
         assert_eq!(Vec2::new(-1.0, -2.0), I64Vec2::new(-1, -2).as_vec2());
         assert_eq!(DVec2::new(-1.0, -2.0), I64Vec2::new(-1, -2).as_dvec2());
+        assert_eq!(U8Vec2::new(1, 2), I64Vec2::new(1, 2).as_u8vec2());
+        assert_eq!(I8Vec2::new(-1, -2), I64Vec2::new(-1, -2).as_i8vec2());
         assert_eq!(U16Vec2::new(1, 2), I64Vec2::new(1, 2).as_u16vec2());
         assert_eq!(I16Vec2::new(-1, -2), I64Vec2::new(-1, -2).as_i16vec2());
         assert_eq!(UVec2::new(1, 2), I64Vec2::new(1, 2).as_uvec2());
@@ -1128,6 +1388,8 @@
 
         assert_eq!(Vec2::new(1.0, 2.0), U64Vec2::new(1, 2).as_vec2());
         assert_eq!(DVec2::new(1.0, 2.0), U64Vec2::new(1, 2).as_dvec2());
+        assert_eq!(I8Vec2::new(1, 2), U64Vec2::new(1, 2).as_i8vec2());
+        assert_eq!(U8Vec2::new(1, 2), U64Vec2::new(1, 2).as_u8vec2());
         assert_eq!(I16Vec2::new(1, 2), U64Vec2::new(1, 2).as_i16vec2());
         assert_eq!(U16Vec2::new(1, 2), U64Vec2::new(1, 2).as_u16vec2());
         assert_eq!(IVec2::new(1, 2), U64Vec2::new(1, 2).as_ivec2());
@@ -1135,11 +1397,11 @@
         assert_eq!(I64Vec2::new(1, 2), U64Vec2::new(1, 2).as_i64vec2());
     });
 
-    impl_vec2_float_tests!(f32, vec2, Vec2, Vec3, BVec2);
+    impl_vec2_float_tests!(f32, vec2, Vec2, Vec3, BVec2, bvec2);
 }
 
 mod dvec2 {
-    use glam::{dvec2, BVec2, DVec2, DVec3, IVec2, UVec2, Vec2};
+    use glam::{bvec2, dvec2, BVec2, DVec2, DVec3, IVec2, UVec2, Vec2};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1158,11 +1420,328 @@
         assert_eq!(DVec2::new(1.0, 2.0), DVec2::from(UVec2::new(1, 2)));
     });
 
-    impl_vec2_float_tests!(f64, dvec2, DVec2, DVec3, BVec2);
+    impl_vec2_float_tests!(f64, dvec2, DVec2, DVec3, BVec2, bvec2);
+}
+
+mod i8vec2 {
+    use glam::{
+        bvec2, i8vec2, BVec2, I16Vec2, I64Vec2, I8Vec2, I8Vec3, IVec2, U16Vec2, U64Vec2, U8Vec2,
+        UVec2,
+    };
+
+    glam_test!(test_align, {
+        use core::mem;
+        assert_eq!(2, mem::size_of::<I8Vec2>());
+        #[cfg(not(feature = "cuda"))]
+        assert_eq!(1, mem::align_of::<I8Vec2>());
+        #[cfg(feature = "cuda")]
+        assert_eq!(2, mem::align_of::<I8Vec2>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(U8Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(U8Vec2::new(u8::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(U8Vec2::new(1, u8::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(I16Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(I16Vec2::new(i16::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(I16Vec2::new(1, i16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(U16Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(U16Vec2::new(u16::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(U16Vec2::new(1, u16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(IVec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(IVec2::new(i32::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(IVec2::new(1, i32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(UVec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(UVec2::new(u32::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(UVec2::new(1, u32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(I64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(I64Vec2::new(i64::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(I64Vec2::new(1, i64::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec2::new(1, 2),
+            I8Vec2::try_from(U64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I8Vec2::try_from(U64Vec2::new(u64::MAX, 2)).is_err());
+        assert!(I8Vec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, 5).wrapping_add(I8Vec2::new(1, 3)),
+            I8Vec2::new(i8::MIN, 8),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, 5).wrapping_sub(I8Vec2::new(1, 3)),
+            I8Vec2::new(126, 2)
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, 5).wrapping_mul(I8Vec2::new(3, 3)),
+            I8Vec2::new(125, 15)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, 5).wrapping_div(I8Vec2::new(3, 3)),
+            I8Vec2::new(42, 1)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, i8::MIN,).saturating_add(I8Vec2::new(1, -1)),
+            I8Vec2::new(i8::MAX, i8::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            I8Vec2::new(i8::MIN, i8::MAX).saturating_sub(I8Vec2::new(1, -1)),
+            I8Vec2::new(i8::MIN, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, i8::MIN).saturating_mul(I8Vec2::new(2, 2)),
+            I8Vec2::new(i8::MAX, i8::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, i8::MIN).saturating_div(I8Vec2::new(2, 2)),
+            I8Vec2::new(63, -64)
+        );
+    });
+
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, i8::MAX).wrapping_add_unsigned(U8Vec2::new(1, 1)),
+            I8Vec2::new(i8::MIN, i8::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I8Vec2::new(i8::MIN, i8::MIN).wrapping_sub_unsigned(U8Vec2::new(1, 1)),
+            I8Vec2::new(i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I8Vec2::new(i8::MAX, i8::MAX).saturating_add_unsigned(U8Vec2::new(1, 1)),
+            I8Vec2::new(i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I8Vec2::new(i8::MIN, i8::MIN).saturating_sub_unsigned(U8Vec2::new(1, 1)),
+            I8Vec2::new(i8::MIN, i8::MIN)
+        );
+    });
+
+    impl_vec2_signed_integer_tests!(i8, i8vec2, I8Vec2, I8Vec3, BVec2, bvec2);
+    impl_vec2_eq_hash_tests!(i8, i8vec2);
+
+    impl_vec2_scalar_shift_op_tests!(I8Vec2, -2, 2);
+    impl_vec2_shift_op_tests!(I8Vec2);
+
+    impl_vec2_scalar_bit_op_tests!(I8Vec2, -2, 2);
+    impl_vec2_bit_op_tests!(I8Vec2, -2, 2);
+}
+
+mod u8vec2 {
+    use glam::{
+        bvec2, u8vec2, BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, U8Vec3,
+        UVec2,
+    };
+
+    glam_test!(test_align, {
+        use core::mem;
+        assert_eq!(2, mem::size_of::<U8Vec2>());
+        #[cfg(not(feature = "cuda"))]
+        assert_eq!(1, mem::align_of::<U8Vec2>());
+        #[cfg(feature = "cuda")]
+        assert_eq!(2, mem::align_of::<U8Vec2>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(I8Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(I8Vec2::new(-1, 2)).is_err());
+        assert!(U8Vec2::try_from(I8Vec2::new(1, -2)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(I16Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(I16Vec2::new(-1, 2)).is_err());
+        assert!(U8Vec2::try_from(I16Vec2::new(1, -2)).is_err());
+        assert!(U8Vec2::try_from(I16Vec2::new(i16::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(I16Vec2::new(1, i16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(U16Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(U16Vec2::new(u16::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(U16Vec2::new(1, u16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(IVec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(IVec2::new(-1, 2)).is_err());
+        assert!(U8Vec2::try_from(IVec2::new(1, -2)).is_err());
+
+        assert!(U8Vec2::try_from(IVec2::new(i32::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(IVec2::new(1, i32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(UVec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(UVec2::new(u32::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(UVec2::new(1, u32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(I64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(I64Vec2::new(-1, 2)).is_err());
+        assert!(U8Vec2::try_from(I64Vec2::new(1, -2)).is_err());
+
+        assert!(U8Vec2::try_from(I64Vec2::new(i64::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(I64Vec2::new(1, i64::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec2::new(1, 2),
+            U8Vec2::try_from(U64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U8Vec2::try_from(U64Vec2::new(u64::MAX, 2)).is_err());
+        assert!(U8Vec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, 5).wrapping_add(U8Vec2::new(1, 3)),
+            U8Vec2::new(0, 8),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, 5).wrapping_sub(U8Vec2::new(1, 3)),
+            U8Vec2::new(254, 2)
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, 5).wrapping_mul(U8Vec2::new(3, 3)),
+            U8Vec2::new(253, 15)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, 5).wrapping_div(U8Vec2::new(3, 3)),
+            U8Vec2::new(85, 1)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, u8::MAX).saturating_add(U8Vec2::new(1, u8::MAX)),
+            U8Vec2::new(u8::MAX, u8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            U8Vec2::new(0, u8::MAX).saturating_sub(U8Vec2::new(1, 1)),
+            U8Vec2::new(0, 254)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, u8::MAX).saturating_mul(U8Vec2::new(2, u8::MAX)),
+            U8Vec2::new(u8::MAX, u8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, u8::MAX).saturating_div(U8Vec2::new(2, u8::MAX)),
+            U8Vec2::new(127, 1)
+        );
+    });
+
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, u8::MAX).wrapping_add_signed(I8Vec2::new(1, 1)),
+            U8Vec2::new(u8::MIN, u8::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U8Vec2::new(u8::MAX, u8::MAX).saturating_add_signed(I8Vec2::new(1, 1)),
+            U8Vec2::new(u8::MAX, u8::MAX)
+        );
+    });
+
+    impl_vec2_tests!(u8, u8vec2, U8Vec2, U8Vec3, BVec2, bvec2);
+    impl_vec2_eq_hash_tests!(u8, u8vec2);
+
+    impl_vec2_scalar_shift_op_tests!(U8Vec2, 0, 2);
+    impl_vec2_shift_op_tests!(U8Vec2);
+
+    impl_vec2_scalar_bit_op_tests!(U8Vec2, 0, 2);
+    impl_vec2_bit_op_tests!(U8Vec2, 0, 2);
 }
 
 mod i16vec2 {
-    use glam::{i16vec2, BVec2, I16Vec2, I16Vec3, I64Vec2, IVec2, U16Vec2, U64Vec2, UVec2};
+    use glam::{
+        bvec2, i16vec2, BVec2, I16Vec2, I16Vec3, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2,
+        UVec2,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1174,6 +1753,9 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(I16Vec2::new(1, 2), I16Vec2::from(U8Vec2::new(1, 2)));
+        assert_eq!(I16Vec2::new(1, 2), I16Vec2::from(I8Vec2::new(1, 2)));
+
         assert_eq!(
             I16Vec2::new(1, 2),
             I16Vec2::try_from(U16Vec2::new(1, 2)).unwrap()
@@ -1266,7 +1848,35 @@
         );
     });
 
-    impl_vec2_signed_integer_tests!(i16, i16vec2, I16Vec2, I16Vec3, BVec2);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I16Vec2::new(i16::MAX, i16::MAX).wrapping_add_unsigned(U16Vec2::new(1, 1)),
+            I16Vec2::new(i16::MIN, i16::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I16Vec2::new(i16::MIN, i16::MIN).wrapping_sub_unsigned(U16Vec2::new(1, 1)),
+            I16Vec2::new(i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I16Vec2::new(i16::MAX, i16::MAX).saturating_add_unsigned(U16Vec2::new(1, 1)),
+            I16Vec2::new(i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I16Vec2::new(i16::MIN, i16::MIN).saturating_sub_unsigned(U16Vec2::new(1, 1)),
+            I16Vec2::new(i16::MIN, i16::MIN)
+        );
+    });
+
+    impl_vec2_signed_integer_tests!(i16, i16vec2, I16Vec2, I16Vec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(i16, i16vec2);
 
     impl_vec2_scalar_shift_op_tests!(I16Vec2, -2, 2);
@@ -1277,7 +1887,9 @@
 }
 
 mod u16vec2 {
-    use glam::{u16vec2, BVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U16Vec3, U64Vec2, UVec2};
+    use glam::{
+        bvec2, u16vec2, BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U16Vec3, U64Vec2, UVec2,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1291,6 +1903,13 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U16Vec2::new(1, 2),
+            U16Vec2::try_from(I8Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U16Vec2::try_from(I8Vec2::new(-1, 2)).is_err());
+        assert!(U16Vec2::try_from(I8Vec2::new(1, -2)).is_err());
+
+        assert_eq!(
+            U16Vec2::new(1, 2),
             U16Vec2::try_from(I16Vec2::new(1, 2)).unwrap()
         );
         assert!(U16Vec2::try_from(I16Vec2::new(-1, 2)).is_err());
@@ -1387,7 +2006,21 @@
         );
     });
 
-    impl_vec2_tests!(u16, u16vec2, U16Vec2, U16Vec3, BVec2);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U16Vec2::new(u16::MAX, u16::MAX).wrapping_add_signed(I16Vec2::new(1, 1)),
+            U16Vec2::new(u16::MIN, u16::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U16Vec2::new(u16::MAX, u16::MAX).saturating_add_signed(I16Vec2::new(1, 1)),
+            U16Vec2::new(u16::MAX, u16::MAX)
+        );
+    });
+
+    impl_vec2_tests!(u16, u16vec2, U16Vec2, U16Vec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(u16, u16vec2);
 
     impl_vec2_scalar_shift_op_tests!(U16Vec2, 0, 2);
@@ -1398,7 +2031,10 @@
 }
 
 mod ivec2 {
-    use glam::{ivec2, BVec2, I16Vec2, I64Vec2, IVec2, IVec3, U16Vec2, U64Vec2, UVec2};
+    use glam::{
+        bvec2, ivec2, BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, IVec3, U16Vec2, U64Vec2, U8Vec2,
+        UVec2,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1412,6 +2048,9 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(IVec2::new(1, 2), IVec2::from(U8Vec2::new(1, 2)));
+        assert_eq!(IVec2::new(1, 2), IVec2::from(I8Vec2::new(1, 2)));
+
         assert_eq!(IVec2::new(1, 2), IVec2::from(U16Vec2::new(1, 2)));
         assert_eq!(IVec2::new(1, 2), IVec2::from(I16Vec2::new(1, 2)));
 
@@ -1490,7 +2129,35 @@
         );
     });
 
-    impl_vec2_signed_integer_tests!(i32, ivec2, IVec2, IVec3, BVec2);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            IVec2::new(i32::MAX, i32::MAX).wrapping_add_unsigned(UVec2::new(1, 1)),
+            IVec2::new(i32::MIN, i32::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            IVec2::new(i32::MIN, i32::MIN).wrapping_sub_unsigned(UVec2::new(1, 1)),
+            IVec2::new(i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            IVec2::new(i32::MAX, i32::MAX).saturating_add_unsigned(UVec2::new(1, 1)),
+            IVec2::new(i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            IVec2::new(i32::MIN, i32::MIN).saturating_sub_unsigned(UVec2::new(1, 1)),
+            IVec2::new(i32::MIN, i32::MIN)
+        );
+    });
+
+    impl_vec2_signed_integer_tests!(i32, ivec2, IVec2, IVec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(i32, ivec2);
 
     impl_vec2_scalar_shift_op_tests!(IVec2, -2, 2);
@@ -1501,7 +2168,10 @@
 }
 
 mod uvec2 {
-    use glam::{uvec2, BVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U64Vec2, UVec2, UVec3};
+    use glam::{
+        bvec2, uvec2, BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2, UVec2,
+        UVec3,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1517,6 +2187,15 @@
     glam_test!(test_try_from, {
         assert_eq!(
             UVec2::new(1, 2),
+            UVec2::try_from(I8Vec2::new(1, 2)).unwrap()
+        );
+        assert!(UVec2::try_from(I8Vec2::new(-1, 2)).is_err());
+        assert!(UVec2::try_from(I8Vec2::new(1, -2)).is_err());
+
+        assert_eq!(UVec2::new(1, 2), UVec2::from(U8Vec2::new(1, 2)));
+
+        assert_eq!(
+            UVec2::new(1, 2),
             UVec2::try_from(I16Vec2::new(1, 2)).unwrap()
         );
         assert!(UVec2::try_from(I16Vec2::new(-1, 2)).is_err());
@@ -1602,7 +2281,21 @@
         );
     });
 
-    impl_vec2_tests!(u32, uvec2, UVec2, UVec3, BVec2);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            UVec2::new(u32::MAX, u32::MAX).wrapping_add_signed(IVec2::new(1, 1)),
+            UVec2::new(u32::MIN, u32::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            UVec2::new(u32::MAX, u32::MAX).saturating_add_signed(IVec2::new(1, 1)),
+            UVec2::new(u32::MAX, u32::MAX)
+        );
+    });
+
+    impl_vec2_tests!(u32, uvec2, UVec2, UVec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(u32, uvec2);
 
     impl_vec2_scalar_shift_op_tests!(UVec2, 0, 2);
@@ -1613,7 +2306,10 @@
 }
 
 mod i64vec2 {
-    use glam::{i64vec2, BVec2, I16Vec2, I64Vec2, I64Vec3, IVec2, U16Vec2, U64Vec2, UVec2};
+    use glam::{
+        bvec2, i64vec2, BVec2, I16Vec2, I64Vec2, I64Vec3, I8Vec2, IVec2, U16Vec2, U64Vec2, U8Vec2,
+        UVec2,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1627,6 +2323,8 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(I64Vec2::new(1, 2), I64Vec2::from(I8Vec2::new(1, 2)));
+        assert_eq!(I64Vec2::new(1, 2), I64Vec2::from(U8Vec2::new(1, 2)));
         assert_eq!(I64Vec2::new(1, 2), I64Vec2::from(I16Vec2::new(1, 2)));
         assert_eq!(I64Vec2::new(1, 2), I64Vec2::from(U16Vec2::new(1, 2)));
         assert_eq!(I64Vec2::new(1, 2), I64Vec2::from(IVec2::new(1, 2)));
@@ -1640,7 +2338,35 @@
         assert!(I64Vec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
     });
 
-    impl_vec2_signed_integer_tests!(i64, i64vec2, I64Vec2, I64Vec3, BVec2);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I64Vec2::new(i64::MAX, i64::MAX).wrapping_add_unsigned(U64Vec2::new(1, 1)),
+            I64Vec2::new(i64::MIN, i64::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I64Vec2::new(i64::MIN, i64::MIN).wrapping_sub_unsigned(U64Vec2::new(1, 1)),
+            I64Vec2::new(i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I64Vec2::new(i64::MAX, i64::MAX).saturating_add_unsigned(U64Vec2::new(1, 1)),
+            I64Vec2::new(i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I64Vec2::new(i64::MIN, i64::MIN).saturating_sub_unsigned(U64Vec2::new(1, 1)),
+            I64Vec2::new(i64::MIN, i64::MIN)
+        );
+    });
+
+    impl_vec2_signed_integer_tests!(i64, i64vec2, I64Vec2, I64Vec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(i64, i64vec2);
 
     impl_vec2_scalar_shift_op_tests!(I64Vec2, -2, 2);
@@ -1651,7 +2377,10 @@
 }
 
 mod u64vec2 {
-    use glam::{u64vec2, BVec2, I16Vec2, I64Vec2, IVec2, U16Vec2, U64Vec2, U64Vec3, UVec2};
+    use glam::{
+        bvec2, u64vec2, BVec2, I16Vec2, I64Vec2, I8Vec2, IVec2, U16Vec2, U64Vec2, U64Vec3, U8Vec2,
+        UVec2,
+    };
 
     glam_test!(test_align, {
         use core::mem;
@@ -1667,6 +2396,15 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U64Vec2::new(1, 2),
+            U64Vec2::try_from(I8Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U64Vec2::try_from(I8Vec2::new(-1, 2)).is_err());
+        assert!(U64Vec2::try_from(I8Vec2::new(1, -2)).is_err());
+
+        assert_eq!(U64Vec2::new(1, 2), U64Vec2::from(U8Vec2::new(1, 2)));
+
+        assert_eq!(
+            U64Vec2::new(1, 2),
             U64Vec2::try_from(I16Vec2::new(1, 2)).unwrap()
         );
         assert!(U64Vec2::try_from(I16Vec2::new(-1, 2)).is_err());
@@ -1691,7 +2429,21 @@
         assert!(U64Vec2::try_from(I64Vec2::new(1, -2)).is_err());
     });
 
-    impl_vec2_tests!(u64, u64vec2, U64Vec2, U64Vec3, BVec2);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U64Vec2::new(u64::MAX, u64::MAX).wrapping_add_signed(I64Vec2::new(1, 1)),
+            U64Vec2::new(u64::MIN, u64::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U64Vec2::new(u64::MAX, u64::MAX).saturating_add_signed(I64Vec2::new(1, 1)),
+            U64Vec2::new(u64::MAX, u64::MAX)
+        );
+    });
+
+    impl_vec2_tests!(u64, u64vec2, U64Vec2, U64Vec3, BVec2, bvec2);
     impl_vec2_eq_hash_tests!(u64, u64vec2);
 
     impl_vec2_scalar_shift_op_tests!(U64Vec2, 0, 2);
diff --git a/crates/glam/tests/vec3.rs b/crates/glam/tests/vec3.rs
index 0997826..4f4ad05 100644
--- a/crates/glam/tests/vec3.rs
+++ b/crates/glam/tests/vec3.rs
@@ -4,7 +4,7 @@
 mod support;
 
 macro_rules! impl_vec3_tests {
-    ($t:ident, $new:ident, $vec3:ident, $mask:ident) => {
+    ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
         glam_test!(test_const, {
             const V0: $vec3 = $vec3::splat(1 as $t);
             const V1: $vec3 = $vec3::new(1 as $t, 2 as $t, 3 as $t);
@@ -50,6 +50,31 @@
             let v = $vec3::new(t.0, t.1, t.2);
             assert_eq!(t, v.into());
 
+            assert_eq!(
+                $vec3::new(1 as $t, 0 as $t, 0 as $t),
+                glam::BVec3::new(true, false, false).into()
+            );
+            assert_eq!(
+                $vec3::new(0 as $t, 1 as $t, 0 as $t),
+                glam::BVec3::new(false, true, false).into()
+            );
+            assert_eq!(
+                $vec3::new(0 as $t, 0 as $t, 1 as $t),
+                glam::BVec3::new(false, false, true).into()
+            );
+            assert_eq!(
+                $vec3::new(1 as $t, 0 as $t, 0 as $t),
+                glam::BVec3A::new(true, false, false).into()
+            );
+            assert_eq!(
+                $vec3::new(0 as $t, 1 as $t, 0 as $t),
+                glam::BVec3A::new(false, true, false).into()
+            );
+            assert_eq!(
+                $vec3::new(0 as $t, 0 as $t, 1 as $t),
+                glam::BVec3A::new(false, false, true).into()
+            );
+
             assert_eq!($vec3::new(1 as $t, 0 as $t, 0 as $t), $vec3::X);
             assert_eq!($vec3::new(0 as $t, 1 as $t, 0 as $t), $vec3::Y);
             assert_eq!($vec3::new(0 as $t, 0 as $t, 1 as $t), $vec3::Z);
@@ -85,6 +110,18 @@
             assert_eq!($vec3::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec3::new(1 as $t, 2 as $t, 3 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec3::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec3::ZERO);
+        });
+
+        glam_test!(test_with, {
+            assert_eq!($vec3::X, $vec3::ZERO.with_x(1 as $t));
+            assert_eq!($vec3::Y, $vec3::ZERO.with_y(1 as $t));
+            assert_eq!($vec3::Z, $vec3::ZERO.with_z(1 as $t));
+        });
+
         glam_test!(test_accessors, {
             let mut a = $vec3::ZERO;
             a.x = 1 as $t;
@@ -152,6 +189,62 @@
             assert_eq!($new(2 as $t, 4 as $t, 0 as $t), a % 8 as $t);
         });
 
+        glam_test!(test_ops_propagated, {
+            let vec = $new(2 as $t, 4 as $t, 8 as $t);
+            let scalar = 2 as $t;
+            let g_scalar = 16 as $t;
+
+            assert_eq!((vec + vec), (vec + &vec));
+            assert_eq!((vec + vec), (&vec + vec));
+            assert_eq!((vec + vec), (&vec + &vec));
+            assert_eq!((vec + scalar), (vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + scalar));
+            assert_eq!((scalar + vec), (&scalar + vec));
+            assert_eq!((scalar + vec), (&scalar + &vec));
+            assert_eq!((scalar + vec), (scalar + &vec));
+
+            assert_eq!((vec - vec), (vec - &vec));
+            assert_eq!((vec - vec), (&vec - vec));
+            assert_eq!((vec - vec), (&vec - &vec));
+            assert_eq!((vec - scalar), (vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - scalar));
+            assert_eq!((g_scalar - vec), (&g_scalar - vec));
+            assert_eq!((g_scalar - vec), (&g_scalar - &vec));
+            assert_eq!((g_scalar - vec), (g_scalar - &vec));
+
+            assert_eq!((vec * vec), (vec * &vec));
+            assert_eq!((vec * vec), (&vec * vec));
+            assert_eq!((vec * vec), (&vec * &vec));
+            assert_eq!((vec * scalar), (vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * scalar));
+            assert_eq!((scalar * vec), (&scalar * vec));
+            assert_eq!((scalar * vec), (&scalar * &vec));
+            assert_eq!((scalar * vec), (scalar * &vec));
+
+            assert_eq!((vec / vec), (vec / &vec));
+            assert_eq!((vec / vec), (&vec / vec));
+            assert_eq!((vec / vec), (&vec / &vec));
+            assert_eq!((vec / scalar), (vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / scalar));
+            assert_eq!((scalar / vec), (&scalar / vec));
+            assert_eq!((scalar / vec), (&scalar / &vec));
+            assert_eq!((scalar / vec), (scalar / &vec));
+
+            assert_eq!((vec % vec), (vec % &vec));
+            assert_eq!((vec % vec), (&vec % vec));
+            assert_eq!((vec % vec), (&vec % &vec));
+            assert_eq!((vec % scalar), (vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % scalar));
+            assert_eq!((scalar % vec), (&scalar % vec));
+            assert_eq!((scalar % vec), (&scalar % &vec));
+            assert_eq!((scalar % vec), (scalar % &vec));
+        });
+
         glam_test!(test_assign_ops, {
             let a = $new(1 as $t, 2 as $t, 3 as $t);
             let mut b = a;
@@ -186,6 +279,47 @@
             assert_eq!($new(0 as $t, 0 as $t, 0 as $t), b);
         });
 
+        glam_test!(test_assign_ops_propagation, {
+            let vec = $new(1 as $t, 2 as $t, 3 as $t);
+            let mut a = vec;
+            let mut b = vec;
+            let scalar = 2 as $t;
+
+            a += &scalar;
+            b += scalar;
+            assert_eq!(b, a, "AddAssign<Scalar>");
+            a -= &scalar;
+            b -= scalar;
+            assert_eq!(b, a, "SubAssign<Scalar>");
+            a *= &scalar;
+            b *= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+            a /= &scalar;
+            b /= scalar;
+            assert_eq!(b, a, "DivAssign<Scalar>");
+            a %= &scalar;
+            b %= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+
+            a = vec;
+            b = vec;
+            a += &vec;
+            b += vec;
+            assert_eq!(b, a, "AddAssign<Vec>");
+            a -= &vec;
+            b -= vec;
+            assert_eq!(b, a, "SubAssign<Vec>");
+            a *= &vec;
+            b *= vec;
+            assert_eq!(b, a, "MulAssign<Vec>");
+            a /= &vec;
+            b /= vec;
+            assert_eq!(b, a, "DivAssign<Vec>");
+            a %= &vec;
+            b %= vec;
+            assert_eq!(b, a, "RemAssign<Vec>");
+        });
+
         glam_test!(test_min_max, {
             let a = $new(3 as $t, 5 as $t, 1 as $t);
             let b = $new(4 as $t, 2 as $t, 6 as $t);
@@ -220,6 +354,12 @@
             assert_eq!(3 as $t, $new(2 as $t, 3 as $t, 1 as $t).max_element());
         });
 
+        glam_test!(test_sum_product, {
+            let a = $new(2 as $t, 3 as $t, 5 as $t);
+            assert_eq!(a.element_sum(), 10 as $t);
+            assert_eq!(a.element_product(), 30 as $t);
+        });
+
         glam_test!(test_eq, {
             let a = $new(1 as $t, 1 as $t, 1 as $t);
             let b = $new(1 as $t, 2 as $t, 3 as $t);
@@ -273,6 +413,45 @@
             assert!(a.cmpeq($vec3::ONE).all());
         });
 
+        glam_test!(test_mask_new, {
+            assert_eq!(
+                $mask::new(false, false, false),
+                $masknew(false, false, false)
+            );
+            assert_eq!($mask::new(true, false, false), $masknew(true, false, false));
+            assert_eq!($mask::new(false, true, true), $masknew(false, true, true));
+            assert_eq!($mask::new(false, true, false), $masknew(false, true, false));
+            assert_eq!($mask::new(true, false, true), $masknew(true, false, true));
+            assert_eq!($mask::new(true, true, true), $masknew(true, true, true));
+        });
+
+        glam_test!(test_mask_from_array_bool, {
+            assert_eq!(
+                $mask::new(false, false, false),
+                $mask::from([false, false, false])
+            );
+            assert_eq!(
+                $mask::new(true, false, false),
+                $mask::from([true, false, false])
+            );
+            assert_eq!(
+                $mask::new(false, true, true),
+                $mask::from([false, true, true])
+            );
+            assert_eq!(
+                $mask::new(false, true, false),
+                $mask::from([false, true, false])
+            );
+            assert_eq!(
+                $mask::new(true, false, true),
+                $mask::from([true, false, true])
+            );
+            assert_eq!(
+                $mask::new(true, true, true),
+                $mask::from([true, true, true])
+            );
+        });
+
         glam_test!(test_mask_into_array_u32, {
             assert_eq!(
                 Into::<[u32; 3]>::into($mask::new(false, false, false)),
@@ -322,8 +501,8 @@
                 [true, false, true]
             );
             assert_eq!(
-                Into::<[u32; 3]>::into($mask::new(true, true, true)),
-                [!0, !0, !0]
+                Into::<[bool; 3]>::into($mask::new(true, true, true)),
+                [true, true, true]
             );
         });
 
@@ -539,6 +718,11 @@
             v.write_to_slice(&mut a);
             assert_eq!(v, $vec3::from_slice(&a));
 
+            let mut a = [0 as $t; 17];
+            v.write_to_slice(&mut a);
+            assert_eq!(v, $vec3::from_slice(&a[..3]));
+            assert_eq!([0 as $t; 14], a[3..]);
+
             should_panic!({ $vec3::ONE.write_to_slice(&mut [0 as $t; 2]) });
             should_panic!({ $vec3::from_slice(&[0 as $t; 2]) });
         });
@@ -558,8 +742,8 @@
 }
 
 macro_rules! impl_vec3_signed_tests {
-    ($t:ident, $new:ident, $vec3:ident, $mask:ident) => {
-        impl_vec3_tests!($t, $new, $vec3, $mask);
+    ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec3_tests!($t, $new, $vec3, $mask, $masknew);
 
         glam_test!(test_neg, {
             let a = $new(1 as $t, 2 as $t, 3 as $t);
@@ -574,6 +758,11 @@
             );
         });
 
+        glam_test!(test_neg_propagation, {
+            let a = $new(1 as $t, 2 as $t, 3 as $t);
+            assert_eq!(-a, -(&a));
+        });
+
         glam_test!(test_is_negative_bitmask, {
             assert_eq!($vec3::ZERO.is_negative_bitmask(), 0b000);
             assert_eq!($vec3::ONE.is_negative_bitmask(), 0b000);
@@ -652,8 +841,8 @@
 }
 
 macro_rules! impl_vec3_signed_integer_tests {
-    ($t:ident, $new:ident, $vec3:ident, $mask:ident) => {
-        impl_vec3_signed_tests!($t, $new, $vec3, $mask);
+    ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec3_signed_tests!($t, $new, $vec3, $mask, $masknew);
 
         glam_test!(test_signum, {
             assert_eq!($vec3::ZERO.signum(), $vec3::ZERO);
@@ -695,14 +884,10 @@
 }
 
 macro_rules! impl_vec3_float_tests {
-    ($t:ident, $new:ident, $vec3:ident, $mask:ident) => {
-        impl_vec3_signed_tests!($t, $new, $vec3, $mask);
+    ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
+        impl_vec3_signed_tests!($t, $new, $vec3, $mask, $masknew);
         impl_vec_float_normalize_tests!($t, $vec3);
 
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_nan, {
             assert!($vec3::NAN.is_nan());
             assert!(!$vec3::NAN.is_finite());
@@ -823,10 +1008,10 @@
             assert_eq!($vec3::new(0.0, 11.123, 0.0).round().y, 11.0);
             assert_eq!($vec3::new(0.0, 11.499, 0.0).round().y, 11.0);
             assert_eq!(
-                $vec3::new(NEG_INFINITY, INFINITY, 0.0).round(),
-                $vec3::new(NEG_INFINITY, INFINITY, 0.0)
+                $vec3::new($t::NEG_INFINITY, $t::INFINITY, 0.0).round(),
+                $vec3::new($t::NEG_INFINITY, $t::INFINITY, 0.0)
             );
-            assert!($vec3::new(NAN, 0.0, 0.0).round().x.is_nan());
+            assert!($vec3::new($t::NAN, 0.0, 0.0).round().x.is_nan());
         });
 
         glam_test!(test_floor, {
@@ -835,38 +1020,50 @@
                 $vec3::new(1.0, 1.0, -2.0)
             );
             assert_eq!(
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0).floor(),
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0)
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0).floor(),
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0)
             );
-            assert!($vec3::new(NAN, 0.0, 0.0).floor().x.is_nan());
+            assert!($vec3::new($t::NAN, 0.0, 0.0).floor().x.is_nan());
             assert_eq!(
                 $vec3::new(-2000000.123, 10000000.123, 1000.9).floor(),
                 $vec3::new(-2000001.0, 10000000.0, 1000.0)
             );
         });
 
-        glam_test!(test_fract, {
+        glam_test!(test_fract_gl, {
             assert_approx_eq!(
-                $vec3::new(1.35, 1.5, -1.5).fract(),
+                $vec3::new(1.35, 1.5, -1.5).fract_gl(),
                 $vec3::new(0.35, 0.5, 0.5)
             );
             assert_approx_eq!(
-                $vec3::new(-200000.123, 1000000.123, 1000.9).fract(),
+                $vec3::new(-200000.123, 1000000.123, 1000.9).fract_gl(),
                 $vec3::new(0.877, 0.123, 0.9),
                 0.002
             );
         });
 
+        glam_test!(test_fract, {
+            assert_approx_eq!(
+                $vec3::new(1.35, 1.5, -1.5).fract(),
+                $vec3::new(0.35, 0.5, -0.5)
+            );
+            assert_approx_eq!(
+                $vec3::new(-200000.123, 1000000.123, 1000.9).fract(),
+                $vec3::new(-0.123, 0.123, 0.9),
+                0.002
+            );
+        });
+
         glam_test!(test_ceil, {
             assert_eq!(
                 $vec3::new(1.35, 1.5, -1.5).ceil(),
                 $vec3::new(2.0, 2.0, -1.0)
             );
             assert_eq!(
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0).ceil(),
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0)
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0).ceil(),
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0)
             );
-            assert!($vec3::new(NAN, 0.0, 0.0).ceil().x.is_nan());
+            assert!($vec3::new($t::NAN, 0.0, 0.0).ceil().x.is_nan());
             assert_eq!(
                 $vec3::new(-2000000.123, 1000000.123, 1000.9).ceil(),
                 $vec3::new(-2000000.0, 1000001.0, 1001.0)
@@ -879,10 +1076,10 @@
                 $vec3::new(1.0, 1.0, -1.0)
             );
             assert_eq!(
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0).trunc(),
-                $vec3::new(INFINITY, NEG_INFINITY, 0.0)
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0).trunc(),
+                $vec3::new($t::INFINITY, $t::NEG_INFINITY, 0.0)
             );
-            assert!($vec3::new(0.0, NAN, 0.0).trunc().y.is_nan());
+            assert!($vec3::new(0.0, $t::NAN, 0.0).trunc().y.is_nan());
             assert_eq!(
                 $vec3::new(-0.0, -2000000.123, 10000000.123).trunc(),
                 $vec3::new(-0.0, -2000000.0, 10000000.0)
@@ -897,12 +1094,35 @@
             assert_approx_eq!($vec3::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_lerp_big_difference, {
+            let v0 = $vec3::new(-1e30, -1e30, -1e30);
+            let v1 = $vec3::new(16.0, 16.0, 16.0);
+            assert_approx_eq!(v0, v0.lerp(v1, 0.0));
+            assert_approx_eq!(v1, v0.lerp(v1, 1.0));
+        });
+
+        glam_test!(test_move_towards, {
+            let v0 = $vec3::new(-1.0, -1.0, -1.0);
+            let v1 = $vec3::new(1.0, 1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
+        glam_test!(test_midpoint, {
+            let v0 = $vec3::new(-1.0, -1.0, -1.0);
+            let v1 = $vec3::new(1.0, 1.0, 1.0);
+            let v2 = $vec3::new(-1.5, 0.0, 1.0);
+            assert_approx_eq!($vec3::ZERO, v0.midpoint(v1));
+            assert_approx_eq!($vec3::new(-0.25, 0.5, 1.0), v1.midpoint(v2));
+        });
+
         glam_test!(test_is_finite, {
             assert!($vec3::new(0.0, 0.0, 0.0).is_finite());
             assert!($vec3::new(-1e-10, 1.0, 1e10).is_finite());
-            assert!(!$vec3::new(INFINITY, 0.0, 0.0).is_finite());
-            assert!(!$vec3::new(0.0, NAN, 0.0).is_finite());
-            assert!(!$vec3::new(0.0, 0.0, NEG_INFINITY).is_finite());
+            assert!(!$vec3::new($t::INFINITY, 0.0, 0.0).is_finite());
+            assert!(!$vec3::new(0.0, $t::NAN, 0.0).is_finite());
+            assert!(!$vec3::new(0.0, 0.0, $t::NEG_INFINITY).is_finite());
             assert!(!$vec3::NAN.is_finite());
             assert!(!$vec3::INFINITY.is_finite());
             assert!(!$vec3::NEG_INFINITY.is_finite());
@@ -979,7 +1199,7 @@
         });
 
         glam_test!(test_any_ortho, {
-            let eps = 2.0 * core::$t::EPSILON;
+            let eps = 2.0 * $t::EPSILON;
 
             for &v in &vec3_float_test_vectors!($vec3) {
                 let orthogonal = v.any_orthogonal_vector();
@@ -1005,6 +1225,27 @@
                 $vec3::new(-0.5, 1.0, -5.0)
             );
         });
+
+        glam_test!(test_fmt_float, {
+            let a = $vec3::new(1.0, 2.0, 3.0);
+            assert_eq!(format!("{:.2}", a), "[1.00, 2.00, 3.00]");
+        });
+
+        glam_test!(test_reflect, {
+            let incident = $vec3::new(1.0, -1.0, 1.0);
+            let normal = $vec3::Y;
+            assert_approx_eq!(incident.reflect(normal), $vec3::ONE);
+        });
+
+        glam_test!(test_refract, {
+            let incident = $vec3::NEG_ONE.normalize();
+            let normal = $vec3::ONE.normalize();
+            assert_approx_eq!(incident.refract(normal, 0.5), incident);
+
+            let incident = $vec3::new(1.0, -1.0, 0.0).normalize();
+            let normal = $vec3::Y;
+            assert_approx_eq!(incident.refract(normal, 1.5), $vec3::ZERO);
+        });
     };
 }
 
@@ -1169,7 +1410,7 @@
 }
 
 mod vec3 {
-    use glam::{vec3, BVec3, Vec3};
+    use glam::{bvec3, vec3, BVec3, Vec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1180,12 +1421,19 @@
     });
 
     glam_test!(test_as, {
-        use glam::{DVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3, Vec3A};
+        use glam::{
+            DVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3, Vec3A,
+        };
         assert_eq!(
             DVec3::new(-1.0, -2.0, -3.0),
             Vec3::new(-1.0, -2.0, -3.0).as_dvec3()
         );
         assert_eq!(
+            I8Vec3::new(-1, -2, -3),
+            Vec3::new(-1.0, -2.0, -3.0).as_i8vec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), Vec3::new(1.0, 2.0, 3.0).as_u8vec3());
+        assert_eq!(
             I16Vec3::new(-1, -2, -3),
             Vec3::new(-1.0, -2.0, -3.0).as_i16vec3()
         );
@@ -1206,6 +1454,11 @@
             Vec3A::new(-1.0, -2.0, -3.0).as_dvec3()
         );
         assert_eq!(
+            I8Vec3::new(-1, -2, -3),
+            Vec3A::new(-1.0, -2.0, -3.0).as_i8vec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), Vec3A::new(1.0, 2.0, 3.0).as_u8vec3());
+        assert_eq!(
             I16Vec3::new(-1, -2, -3),
             Vec3A::new(-1.0, -2.0, -3.0).as_i16vec3()
         );
@@ -1228,6 +1481,11 @@
         );
 
         assert_eq!(
+            I8Vec3::new(-1, -2, -3),
+            DVec3::new(-1.0, -2.0, -3.0).as_i8vec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), DVec3::new(1.0, 2.0, 3.0).as_u8vec3());
+        assert_eq!(
             I16Vec3::new(-1, -2, -3),
             DVec3::new(-1.0, -2.0, -3.0).as_i16vec3()
         );
@@ -1259,8 +1517,50 @@
 
         assert_eq!(
             DVec3::new(-1.0, -2.0, -3.0),
+            I8Vec3::new(-1, -2, -3).as_dvec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), I8Vec3::new(1, 2, 3).as_u8vec3());
+        assert_eq!(
+            I16Vec3::new(-1, -2, -3),
+            I8Vec3::new(-1, -2, -3).as_i16vec3()
+        );
+        assert_eq!(U16Vec3::new(1, 2, 3), I8Vec3::new(1, 2, 3).as_u16vec3());
+        assert_eq!(IVec3::new(-1, -2, -3), I8Vec3::new(-1, -2, -3).as_ivec3());
+        assert_eq!(UVec3::new(1, 2, 3), I8Vec3::new(1, 2, 3).as_uvec3());
+        assert_eq!(
+            I64Vec3::new(-1, -2, -3),
+            I8Vec3::new(-1, -2, -3).as_i64vec3()
+        );
+        assert_eq!(U64Vec3::new(1, 2, 3), I8Vec3::new(1, 2, 3).as_u64vec3());
+        assert_eq!(
+            Vec3::new(-1.0, -2.0, -3.0),
+            I8Vec3::new(-1, -2, -3).as_vec3()
+        );
+        assert_eq!(
+            Vec3A::new(-1.0, -2.0, -3.0),
+            I8Vec3::new(-1, -2, -3).as_vec3a()
+        );
+
+        assert_eq!(DVec3::new(1.0, 2.0, 3.0), U8Vec3::new(1, 2, 3).as_dvec3());
+        assert_eq!(I8Vec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_i8vec3());
+        assert_eq!(I16Vec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_i16vec3());
+        assert_eq!(U16Vec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_u16vec3());
+        assert_eq!(IVec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_ivec3());
+        assert_eq!(UVec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_uvec3());
+        assert_eq!(I64Vec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_i64vec3());
+        assert_eq!(U64Vec3::new(1, 2, 3), U8Vec3::new(1, 2, 3).as_u64vec3());
+        assert_eq!(Vec3::new(1.0, 2.0, 3.0), U8Vec3::new(1, 2, 3).as_vec3());
+        assert_eq!(Vec3A::new(1.0, 2.0, 3.0), U8Vec3::new(1, 2, 3).as_vec3a());
+
+        assert_eq!(
+            DVec3::new(-1.0, -2.0, -3.0),
             I16Vec3::new(-1, -2, -3).as_dvec3()
         );
+        assert_eq!(
+            I8Vec3::new(-1, -2, -3),
+            I16Vec3::new(-1, -2, -3).as_i8vec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), I16Vec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(U16Vec3::new(1, 2, 3), I16Vec3::new(1, 2, 3).as_u16vec3());
         assert_eq!(IVec3::new(-1, -2, -3), I16Vec3::new(-1, -2, -3).as_ivec3());
         assert_eq!(UVec3::new(1, 2, 3), I16Vec3::new(1, 2, 3).as_uvec3());
@@ -1279,6 +1579,8 @@
         );
 
         assert_eq!(DVec3::new(1.0, 2.0, 3.0), U16Vec3::new(1, 2, 3).as_dvec3());
+        assert_eq!(I8Vec3::new(1, 2, 3), U16Vec3::new(1, 2, 3).as_i8vec3());
+        assert_eq!(U8Vec3::new(1, 2, 3), U16Vec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(I16Vec3::new(1, 2, 3), U16Vec3::new(1, 2, 3).as_i16vec3());
         assert_eq!(IVec3::new(1, 2, 3), U16Vec3::new(1, 2, 3).as_ivec3());
         assert_eq!(UVec3::new(1, 2, 3), U16Vec3::new(1, 2, 3).as_uvec3());
@@ -1291,6 +1593,8 @@
             DVec3::new(-1.0, -2.0, -3.0),
             IVec3::new(-1, -2, -3).as_dvec3()
         );
+        assert_eq!(I8Vec3::new(-1, -2, -3), IVec3::new(-1, -2, -3).as_i8vec3());
+        assert_eq!(U8Vec3::new(1, 2, 3), IVec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(
             I16Vec3::new(-1, -2, -3),
             IVec3::new(-1, -2, -3).as_i16vec3()
@@ -1312,6 +1616,8 @@
         );
 
         assert_eq!(DVec3::new(1.0, 2.0, 3.0), UVec3::new(1, 2, 3).as_dvec3());
+        assert_eq!(I8Vec3::new(1, 2, 3), UVec3::new(1, 2, 3).as_i8vec3());
+        assert_eq!(U8Vec3::new(1, 2, 3), UVec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(I16Vec3::new(1, 2, 3), UVec3::new(1, 2, 3).as_i16vec3());
         assert_eq!(U16Vec3::new(1, 2, 3), UVec3::new(1, 2, 3).as_u16vec3());
         assert_eq!(IVec3::new(1, 2, 3), UVec3::new(1, 2, 3).as_ivec3());
@@ -1324,6 +1630,11 @@
             DVec3::new(-1.0, -2.0, -3.0),
             I64Vec3::new(-1, -2, -3).as_dvec3()
         );
+        assert_eq!(
+            I8Vec3::new(-1, -2, -3),
+            I64Vec3::new(-1, -2, -3).as_i8vec3()
+        );
+        assert_eq!(U8Vec3::new(1, 2, 3), I64Vec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(U16Vec3::new(1, 2, 3), I64Vec3::new(1, 2, 3).as_u16vec3());
         assert_eq!(
             I16Vec3::new(-1, -2, -3),
@@ -1342,6 +1653,8 @@
         );
 
         assert_eq!(DVec3::new(1.0, 2.0, 3.0), U64Vec3::new(1, 2, 3).as_dvec3());
+        assert_eq!(I8Vec3::new(1, 2, 3), U64Vec3::new(1, 2, 3).as_i8vec3());
+        assert_eq!(U8Vec3::new(1, 2, 3), U64Vec3::new(1, 2, 3).as_u8vec3());
         assert_eq!(I16Vec3::new(1, 2, 3), U64Vec3::new(1, 2, 3).as_i16vec3());
         assert_eq!(U16Vec3::new(1, 2, 3), U64Vec3::new(1, 2, 3).as_u16vec3());
         assert_eq!(IVec3::new(1, 2, 3), U64Vec3::new(1, 2, 3).as_ivec3());
@@ -1351,12 +1664,11 @@
         assert_eq!(Vec3A::new(1.0, 2.0, 3.0), U64Vec3::new(1, 2, 3).as_vec3a());
     });
 
-    impl_vec3_float_tests!(f32, vec3, Vec3, BVec3);
+    impl_vec3_float_tests!(f32, vec3, Vec3, BVec3, bvec3);
 }
 
 mod vec3a {
-    use glam::BVec3A;
-    use glam::{vec3a, Vec3A, Vec4};
+    use glam::{bvec3a, vec3a, BVec3A, Vec3A, Vec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1369,7 +1681,7 @@
     glam_test!(test_mask_align16, {
         // make sure the unused 'w' value doesn't break Vec3Ab behaviour
         let a = Vec4::ZERO;
-        let mut b = Vec3A::from(a);
+        let mut b = Vec3A::from_vec4(a);
         b.x = 1.0;
         b.y = 1.0;
         b.z = 1.0;
@@ -1415,17 +1727,17 @@
 
     glam_test!(test_min_max_from_vec4, {
         // checks that the 4th element is unused.
-        let v1 = Vec3A::from(Vec4::new(1.0, 2.0, 3.0, 4.0));
+        let v1 = Vec3A::from_vec4(Vec4::new(1.0, 2.0, 3.0, 4.0));
         assert_eq!(v1.max_element(), 3.0);
-        let v2 = Vec3A::from(Vec4::new(4.0, 3.0, 2.0, 1.0));
+        let v2 = Vec3A::from_vec4(Vec4::new(4.0, 3.0, 2.0, 1.0));
         assert_eq!(v2.min_element(), 2.0);
     });
 
-    impl_vec3_float_tests!(f32, vec3a, Vec3A, BVec3A);
+    impl_vec3_float_tests!(f32, vec3a, Vec3A, BVec3A, bvec3a);
 }
 
 mod dvec3 {
-    use glam::{dvec3, BVec3, DVec3, IVec3, UVec3, Vec3};
+    use glam::{bvec3, dvec3, BVec3, DVec3, IVec3, UVec3, Vec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1444,11 +1756,337 @@
         assert_eq!(DVec3::new(1.0, 2.0, 3.0), DVec3::from(UVec3::new(1, 2, 3)));
     });
 
-    impl_vec3_float_tests!(f64, dvec3, DVec3, BVec3);
+    impl_vec3_float_tests!(f64, dvec3, DVec3, BVec3, bvec3);
+}
+
+mod i8vec3 {
+    use glam::{
+        bvec3, i8vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
+
+    glam_test!(test_align, {
+        use std::mem;
+        assert_eq!(3, mem::size_of::<I8Vec3>());
+        assert_eq!(1, mem::align_of::<I8Vec3>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(U8Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(U8Vec3::new(u8::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(U8Vec3::new(1, u8::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(U8Vec3::new(1, 2, u8::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(I16Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(I16Vec3::new(i16::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(I16Vec3::new(1, i16::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(I16Vec3::new(1, 2, i16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(U16Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(U16Vec3::new(u16::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(U16Vec3::new(1, u16::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(U16Vec3::new(1, 2, u16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(IVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(IVec3::new(i32::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(IVec3::new(1, i32::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(IVec3::new(1, 2, i32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(UVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(UVec3::new(u32::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(UVec3::new(1, u32::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(UVec3::new(1, 2, u32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(I64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(I64Vec3::new(i64::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(I64Vec3::new(1, i64::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(I64Vec3::new(1, 2, i64::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec3::new(1, 2, 3),
+            I8Vec3::try_from(U64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I8Vec3::try_from(U64Vec3::new(u64::MAX, 2, 3)).is_err());
+        assert!(I8Vec3::try_from(U64Vec3::new(1, u64::MAX, 3)).is_err());
+        assert!(I8Vec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, 5, i8::MIN).wrapping_add(I8Vec3::new(1, 3, i8::MAX)),
+            I8Vec3::new(i8::MIN, 8, -1),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, 5, i8::MIN).wrapping_sub(I8Vec3::new(1, 3, i8::MAX)),
+            I8Vec3::new(126, 2, 1),
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, 5, i8::MIN).wrapping_mul(I8Vec3::new(3, 3, 5)),
+            I8Vec3::new(125, 15, -128)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, 5, i8::MIN).wrapping_div(I8Vec3::new(3, 3, 5)),
+            I8Vec3::new(42, 1, -25)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, i8::MIN, 0).saturating_add(I8Vec3::new(1, -1, 2)),
+            I8Vec3::new(i8::MAX, i8::MIN, 2)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            I8Vec3::new(i8::MIN, i8::MAX, 0).saturating_sub(I8Vec3::new(1, -1, 2)),
+            I8Vec3::new(i8::MIN, i8::MAX, -2)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, i8::MIN, 0).saturating_mul(I8Vec3::new(2, 2, 0)),
+            I8Vec3::new(i8::MAX, i8::MIN, 0)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, i8::MIN, 0).saturating_div(I8Vec3::new(2, 2, 3)),
+            I8Vec3::new(63, -64, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, i8::MAX, i8::MAX).wrapping_add_unsigned(U8Vec3::new(1, 1, 1)),
+            I8Vec3::new(i8::MIN, i8::MIN, i8::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I8Vec3::new(i8::MIN, i8::MIN, i8::MIN).wrapping_sub_unsigned(U8Vec3::new(1, 1, 1)),
+            I8Vec3::new(i8::MAX, i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I8Vec3::new(i8::MAX, i8::MAX, i8::MAX).saturating_add_unsigned(U8Vec3::new(1, 1, 1)),
+            I8Vec3::new(i8::MAX, i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I8Vec3::new(i8::MIN, i8::MIN, i8::MIN).saturating_sub_unsigned(U8Vec3::new(1, 1, 1)),
+            I8Vec3::new(i8::MIN, i8::MIN, i8::MIN)
+        );
+    });
+
+    impl_vec3_signed_integer_tests!(i8, i8vec3, I8Vec3, BVec3, bvec3);
+    impl_vec3_eq_hash_tests!(i8, i8vec3);
+
+    impl_vec3_scalar_shift_op_tests!(I8Vec3, -2, 2);
+    impl_vec3_shift_op_tests!(I8Vec3);
+
+    impl_vec3_scalar_bit_op_tests!(I8Vec3, -2, 2);
+    impl_vec3_bit_op_tests!(I8Vec3, -2, 2);
+}
+
+mod u8vec3 {
+    use glam::{
+        bvec3, u8vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
+
+    glam_test!(test_align, {
+        use std::mem;
+        assert_eq!(3, mem::size_of::<U8Vec3>());
+        assert_eq!(1, mem::align_of::<U8Vec3>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(I8Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(I8Vec3::new(-1, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(I8Vec3::new(1, -2, 3)).is_err());
+        assert!(U8Vec3::try_from(I8Vec3::new(1, 2, -3)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(I16Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(I16Vec3::new(-1, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(I16Vec3::new(1, -2, 3)).is_err());
+        assert!(U8Vec3::try_from(I16Vec3::new(1, 2, -3)).is_err());
+
+        assert!(U8Vec3::try_from(I16Vec3::new(i16::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(I16Vec3::new(1, i16::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(I16Vec3::new(1, 2, i16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(U16Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(U16Vec3::new(u16::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(U16Vec3::new(1, u16::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(U16Vec3::new(1, 2, u16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(IVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(IVec3::new(-1, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(IVec3::new(1, -2, 3)).is_err());
+        assert!(U8Vec3::try_from(IVec3::new(1, 2, -3)).is_err());
+
+        assert!(U8Vec3::try_from(IVec3::new(i32::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(IVec3::new(1, i32::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(IVec3::new(1, 2, i32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(UVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(UVec3::new(u32::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(UVec3::new(1, u32::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(UVec3::new(1, 2, u32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(I64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(I64Vec3::new(-1, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(I64Vec3::new(1, -2, 3)).is_err());
+        assert!(U8Vec3::try_from(I64Vec3::new(1, 2, -3)).is_err());
+
+        assert!(U8Vec3::try_from(I64Vec3::new(i64::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(I64Vec3::new(1, i64::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(I64Vec3::new(1, 2, i64::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec3::new(1, 2, 3),
+            U8Vec3::try_from(U64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U8Vec3::try_from(U64Vec3::new(u64::MAX, 2, 3)).is_err());
+        assert!(U8Vec3::try_from(U64Vec3::new(1, u64::MAX, 3)).is_err());
+        assert!(U8Vec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, 5, u8::MAX).wrapping_add(U8Vec3::new(1, 3, u8::MAX)),
+            U8Vec3::new(0, 8, 254),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, 5, u8::MAX - 1).wrapping_sub(U8Vec3::new(1, 3, u8::MAX)),
+            U8Vec3::new(254, 2, 255)
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, 5, u8::MAX).wrapping_mul(U8Vec3::new(3, 3, 5)),
+            U8Vec3::new(253, 15, 251)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, 5, u8::MAX).wrapping_div(U8Vec3::new(3, 3, 5)),
+            U8Vec3::new(85, 1, 51)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, u8::MAX, 0).saturating_add(U8Vec3::new(1, u8::MAX, 2)),
+            U8Vec3::new(u8::MAX, u8::MAX, 2)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            U8Vec3::new(0, u8::MAX, 0).saturating_sub(U8Vec3::new(1, 1, 2)),
+            U8Vec3::new(0, 254, 0)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, u8::MAX, 0).saturating_mul(U8Vec3::new(2, u8::MAX, 0)),
+            U8Vec3::new(u8::MAX, u8::MAX, 0)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, u8::MAX, 0).saturating_div(U8Vec3::new(2, u8::MAX, 3)),
+            U8Vec3::new(127, 1, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, u8::MAX, u8::MAX).wrapping_add_signed(I8Vec3::new(1, 1, 1)),
+            U8Vec3::new(u8::MIN, u8::MIN, u8::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U8Vec3::new(u8::MAX, u8::MAX, u8::MAX).saturating_add_signed(I8Vec3::new(1, 1, 1)),
+            U8Vec3::new(u8::MAX, u8::MAX, u8::MAX)
+        );
+    });
+
+    impl_vec3_tests!(u8, u8vec3, U8Vec3, BVec3, bvec3);
+    impl_vec3_eq_hash_tests!(u8, u8vec3);
+
+    impl_vec3_scalar_shift_op_tests!(U8Vec3, 0, 2);
+    impl_vec3_shift_op_tests!(U8Vec3);
+
+    impl_vec3_scalar_bit_op_tests!(U8Vec3, 0, 2);
+    impl_vec3_bit_op_tests!(U8Vec3, 0, 2);
 }
 
 mod i16vec3 {
-    use glam::{i16vec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, i16vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1457,6 +2095,9 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(I16Vec3::new(1, 2, 3), I16Vec3::from(U8Vec3::new(1, 2, 3)));
+        assert_eq!(I16Vec3::new(1, 2, 3), I16Vec3::from(I8Vec3::new(1, 2, 3)));
+
         assert_eq!(
             I16Vec3::new(1, 2, 3),
             I16Vec3::try_from(U16Vec3::new(1, 2, 3)).unwrap()
@@ -1554,7 +2195,37 @@
         );
     });
 
-    impl_vec3_signed_integer_tests!(i16, i16vec3, I16Vec3, BVec3);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I16Vec3::new(i16::MAX, i16::MAX, i16::MAX).wrapping_add_unsigned(U16Vec3::new(1, 1, 1)),
+            I16Vec3::new(i16::MIN, i16::MIN, i16::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I16Vec3::new(i16::MIN, i16::MIN, i16::MIN).wrapping_sub_unsigned(U16Vec3::new(1, 1, 1)),
+            I16Vec3::new(i16::MAX, i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I16Vec3::new(i16::MAX, i16::MAX, i16::MAX)
+                .saturating_add_unsigned(U16Vec3::new(1, 1, 1)),
+            I16Vec3::new(i16::MAX, i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I16Vec3::new(i16::MIN, i16::MIN, i16::MIN)
+                .saturating_sub_unsigned(U16Vec3::new(1, 1, 1)),
+            I16Vec3::new(i16::MIN, i16::MIN, i16::MIN)
+        );
+    });
+
+    impl_vec3_signed_integer_tests!(i16, i16vec3, I16Vec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(i16, i16vec3);
 
     impl_vec3_scalar_shift_op_tests!(I16Vec3, -2, 2);
@@ -1565,7 +2236,9 @@
 }
 
 mod u16vec3 {
-    use glam::{u16vec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, u16vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1576,6 +2249,16 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U16Vec3::new(1, 2, 3),
+            U16Vec3::try_from(I8Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U16Vec3::try_from(I8Vec3::new(-1, 2, 3)).is_err());
+        assert!(U16Vec3::try_from(I8Vec3::new(1, -2, 3)).is_err());
+        assert!(U16Vec3::try_from(I8Vec3::new(1, 2, -3)).is_err());
+
+        assert_eq!(U16Vec3::new(1, 2, 3), U16Vec3::from(U8Vec3::new(1, 2, 3)));
+
+        assert_eq!(
+            U16Vec3::new(1, 2, 3),
             U16Vec3::try_from(I16Vec3::new(1, 2, 3)).unwrap()
         );
         assert!(U16Vec3::try_from(I16Vec3::new(-1, 2, 3)).is_err());
@@ -1679,7 +2362,21 @@
         );
     });
 
-    impl_vec3_tests!(u16, u16vec3, U16Vec3, BVec3);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U16Vec3::new(u16::MAX, u16::MAX, u16::MAX).wrapping_add_signed(I16Vec3::new(1, 1, 1)),
+            U16Vec3::new(u16::MIN, u16::MIN, u16::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U16Vec3::new(u16::MAX, u16::MAX, u16::MAX).saturating_add_signed(I16Vec3::new(1, 1, 1)),
+            U16Vec3::new(u16::MAX, u16::MAX, u16::MAX)
+        );
+    });
+
+    impl_vec3_tests!(u16, u16vec3, U16Vec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(u16, u16vec3);
 
     impl_vec3_scalar_shift_op_tests!(U16Vec3, 0, 2);
@@ -1690,7 +2387,9 @@
 }
 
 mod ivec3 {
-    use glam::{ivec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, ivec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1701,6 +2400,9 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(IVec3::new(1, 2, 3), IVec3::from(U8Vec3::new(1, 2, 3)));
+        assert_eq!(IVec3::new(1, 2, 3), IVec3::from(I8Vec3::new(1, 2, 3)));
+
         assert_eq!(IVec3::new(1, 2, 3), IVec3::from(U16Vec3::new(1, 2, 3)));
         assert_eq!(IVec3::new(1, 2, 3), IVec3::from(I16Vec3::new(1, 2, 3)));
 
@@ -1785,7 +2487,35 @@
         );
     });
 
-    impl_vec3_signed_integer_tests!(i32, ivec3, IVec3, BVec3);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            IVec3::new(i32::MAX, i32::MAX, i32::MAX).wrapping_add_unsigned(UVec3::new(1, 1, 1)),
+            IVec3::new(i32::MIN, i32::MIN, i32::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            IVec3::new(i32::MIN, i32::MIN, i32::MIN).wrapping_sub_unsigned(UVec3::new(1, 1, 1)),
+            IVec3::new(i32::MAX, i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            IVec3::new(i32::MAX, i32::MAX, i32::MAX).saturating_add_unsigned(UVec3::new(1, 1, 1)),
+            IVec3::new(i32::MAX, i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            IVec3::new(i32::MIN, i32::MIN, i32::MIN).saturating_sub_unsigned(UVec3::new(1, 1, 1)),
+            IVec3::new(i32::MIN, i32::MIN, i32::MIN)
+        );
+    });
+
+    impl_vec3_signed_integer_tests!(i32, ivec3, IVec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(i32, ivec3);
 
     impl_vec3_scalar_shift_op_tests!(IVec3, -2, 2);
@@ -1796,7 +2526,9 @@
 }
 
 mod uvec3 {
-    use glam::{uvec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, uvec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1809,6 +2541,16 @@
     glam_test!(test_try_from, {
         assert_eq!(
             UVec3::new(1, 2, 3),
+            UVec3::try_from(I8Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(UVec3::try_from(I8Vec3::new(-1, 2, 3)).is_err());
+        assert!(UVec3::try_from(I8Vec3::new(1, -2, 3)).is_err());
+        assert!(UVec3::try_from(I8Vec3::new(1, 2, -3)).is_err());
+
+        assert_eq!(UVec3::new(1, 2, 3), UVec3::from(U8Vec3::new(1, 2, 3)));
+
+        assert_eq!(
+            UVec3::new(1, 2, 3),
             UVec3::try_from(I16Vec3::new(1, 2, 3)).unwrap()
         );
         assert!(UVec3::try_from(I16Vec3::new(-1, 2, 3)).is_err());
@@ -1902,7 +2644,21 @@
         );
     });
 
-    impl_vec3_tests!(u32, uvec3, UVec3, BVec3);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            UVec3::new(u32::MAX, u32::MAX, u32::MAX).wrapping_add_signed(IVec3::new(1, 1, 1)),
+            UVec3::new(u32::MIN, u32::MIN, u32::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            UVec3::new(u32::MAX, u32::MAX, u32::MAX).saturating_add_signed(IVec3::new(1, 1, 1)),
+            UVec3::new(u32::MAX, u32::MAX, u32::MAX)
+        );
+    });
+
+    impl_vec3_tests!(u32, uvec3, UVec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(u32, uvec3);
 
     impl_vec3_scalar_shift_op_tests!(UVec3, 0, 2);
@@ -1913,7 +2669,9 @@
 }
 
 mod i64vec3 {
-    use glam::{i64vec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, i64vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1924,6 +2682,8 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(I64Vec3::new(1, 2, 3), I64Vec3::from(I8Vec3::new(1, 2, 3)));
+        assert_eq!(I64Vec3::new(1, 2, 3), I64Vec3::from(U8Vec3::new(1, 2, 3)));
         assert_eq!(I64Vec3::new(1, 2, 3), I64Vec3::from(I16Vec3::new(1, 2, 3)));
         assert_eq!(I64Vec3::new(1, 2, 3), I64Vec3::from(U16Vec3::new(1, 2, 3)));
         assert_eq!(I64Vec3::new(1, 2, 3), I64Vec3::from(IVec3::new(1, 2, 3)));
@@ -1938,7 +2698,37 @@
         assert!(I64Vec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
     });
 
-    impl_vec3_signed_integer_tests!(i64, i64vec3, I64Vec3, BVec3);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I64Vec3::new(i64::MAX, i64::MAX, i64::MAX).wrapping_add_unsigned(U64Vec3::new(1, 1, 1)),
+            I64Vec3::new(i64::MIN, i64::MIN, i64::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I64Vec3::new(i64::MIN, i64::MIN, i64::MIN).wrapping_sub_unsigned(U64Vec3::new(1, 1, 1)),
+            I64Vec3::new(i64::MAX, i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I64Vec3::new(i64::MAX, i64::MAX, i64::MAX)
+                .saturating_add_unsigned(U64Vec3::new(1, 1, 1)),
+            I64Vec3::new(i64::MAX, i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I64Vec3::new(i64::MIN, i64::MIN, i64::MIN)
+                .saturating_sub_unsigned(U64Vec3::new(1, 1, 1)),
+            I64Vec3::new(i64::MIN, i64::MIN, i64::MIN)
+        );
+    });
+
+    impl_vec3_signed_integer_tests!(i64, i64vec3, I64Vec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(i64, i64vec3);
 
     impl_vec3_scalar_shift_op_tests!(I64Vec3, -2, 2);
@@ -1949,7 +2739,9 @@
 }
 
 mod u64vec3 {
-    use glam::{u64vec3, BVec3, I16Vec3, I64Vec3, IVec3, U16Vec3, U64Vec3, UVec3};
+    use glam::{
+        bvec3, u64vec3, BVec3, I16Vec3, I64Vec3, I8Vec3, IVec3, U16Vec3, U64Vec3, U8Vec3, UVec3,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1962,6 +2754,16 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U64Vec3::new(1, 2, 3),
+            U64Vec3::try_from(I8Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U64Vec3::try_from(I8Vec3::new(-1, 2, 3)).is_err());
+        assert!(U64Vec3::try_from(I8Vec3::new(1, -2, 3)).is_err());
+        assert!(U64Vec3::try_from(I8Vec3::new(1, 2, -3)).is_err());
+
+        assert_eq!(U64Vec3::new(1, 2, 3), U64Vec3::from(U8Vec3::new(1, 2, 3)));
+
+        assert_eq!(
+            U64Vec3::new(1, 2, 3),
             U64Vec3::try_from(I16Vec3::new(1, 2, 3)).unwrap()
         );
         assert!(U64Vec3::try_from(I16Vec3::new(-1, 2, 3)).is_err());
@@ -1989,7 +2791,21 @@
         assert!(U64Vec3::try_from(I64Vec3::new(1, 2, -3)).is_err());
     });
 
-    impl_vec3_tests!(u64, u64vec3, U64Vec3, BVec3);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U64Vec3::new(u64::MAX, u64::MAX, u64::MAX).wrapping_add_signed(I64Vec3::new(1, 1, 1)),
+            U64Vec3::new(u64::MIN, u64::MIN, u64::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U64Vec3::new(u64::MAX, u64::MAX, u64::MAX).saturating_add_signed(I64Vec3::new(1, 1, 1)),
+            U64Vec3::new(u64::MAX, u64::MAX, u64::MAX)
+        );
+    });
+
+    impl_vec3_tests!(u64, u64vec3, U64Vec3, BVec3, bvec3);
     impl_vec3_eq_hash_tests!(u64, u64vec3);
 
     impl_vec3_scalar_shift_op_tests!(U64Vec3, 0, 2);
diff --git a/crates/glam/tests/vec4.rs b/crates/glam/tests/vec4.rs
index 499c7b8..1abdaf2 100644
--- a/crates/glam/tests/vec4.rs
+++ b/crates/glam/tests/vec4.rs
@@ -4,7 +4,7 @@
 mod support;
 
 macro_rules! impl_vec4_tests {
-    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => {
+    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => {
         glam_test!(test_const, {
             const V0: $vec4 = $vec4::splat(1 as $t);
             const V1: $vec4 = $vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
@@ -52,6 +52,43 @@
             let v = $vec4::new(t.0, t.1, t.2, t.3);
             assert_eq!(t, v.into());
 
+            assert_eq!(
+                $vec4::new(1 as $t, 0 as $t, 0 as $t, 0 as $t),
+                glam::BVec4::new(true, false, false, false).into()
+            );
+            assert_eq!(
+                $vec4::new(0 as $t, 1 as $t, 0 as $t, 0 as $t),
+                glam::BVec4::new(false, true, false, false).into()
+            );
+            assert_eq!(
+                $vec4::new(0 as $t, 0 as $t, 1 as $t, 0 as $t),
+                glam::BVec4::new(false, false, true, false).into()
+            );
+
+            #[cfg(not(feature = "scalar-math"))]
+            {
+                assert_eq!(
+                    $vec4::new(0 as $t, 0 as $t, 0 as $t, 1 as $t),
+                    glam::BVec4::new(false, false, false, true).into()
+                );
+                assert_eq!(
+                    $vec4::new(1 as $t, 0 as $t, 0 as $t, 0 as $t),
+                    glam::BVec4A::new(true, false, false, false).into()
+                );
+                assert_eq!(
+                    $vec4::new(0 as $t, 1 as $t, 0 as $t, 0 as $t),
+                    glam::BVec4A::new(false, true, false, false).into()
+                );
+                assert_eq!(
+                    $vec4::new(0 as $t, 0 as $t, 1 as $t, 0 as $t),
+                    glam::BVec4A::new(false, false, true, false).into()
+                );
+                assert_eq!(
+                    $vec4::new(0 as $t, 0 as $t, 0 as $t, 1 as $t),
+                    glam::BVec4A::new(false, false, false, true).into()
+                );
+            }
+
             assert_eq!($vec4::new(1 as $t, 0 as $t, 0 as $t, 0 as $t), $vec4::X);
             assert_eq!($vec4::new(0 as $t, 1 as $t, 0 as $t, 0 as $t), $vec4::Y);
             assert_eq!($vec4::new(0 as $t, 0 as $t, 1 as $t, 0 as $t), $vec4::Z);
@@ -115,6 +152,19 @@
             assert_eq!($vec4::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec4::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec4::ZERO);
+        });
+
+        glam_test!(test_with, {
+            assert_eq!($vec4::X, $vec4::ZERO.with_x(1 as $t));
+            assert_eq!($vec4::Y, $vec4::ZERO.with_y(1 as $t));
+            assert_eq!($vec4::Z, $vec4::ZERO.with_z(1 as $t));
+            assert_eq!($vec4::W, $vec4::ZERO.with_w(1 as $t));
+        });
+
         glam_test!(test_accessors, {
             let mut a = $vec4::ZERO;
             a.x = 1 as $t;
@@ -170,23 +220,79 @@
         });
 
         glam_test!(test_ops, {
-            let a = $new(2 as $t, 4 as $t, 8 as $t, 16 as $t);
-            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), a + a);
-            assert_eq!($new(2 as $t, 4 as $t, 8 as $t, 16 as $t), 0 as $t + a);
+            let a = $new(2 as $t, 4 as $t, 8 as $t, 10 as $t);
+            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 20 as $t), a + a);
+            assert_eq!($new(2 as $t, 4 as $t, 8 as $t, 10 as $t), 0 as $t + a);
             assert_eq!($new(0 as $t, 0 as $t, 0 as $t, 0 as $t), a - a);
-            assert_eq!($new(14 as $t, 12 as $t, 8 as $t, 0 as $t), 16 as $t - a);
-            assert_eq!($new(4 as $t, 16 as $t, 64 as $t, 256 as $t), a * a);
-            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), a * 2 as $t);
-            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 32 as $t), 2 as $t * a);
+            assert_eq!($new(8 as $t, 6 as $t, 2 as $t, 0 as $t), 10 as $t - a);
+            assert_eq!($new(4 as $t, 16 as $t, 64 as $t, 100 as $t), a * a);
+            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 20 as $t), a * 2 as $t);
+            assert_eq!($new(4 as $t, 8 as $t, 16 as $t, 20 as $t), 2 as $t * a);
             assert_eq!($new(1 as $t, 1 as $t, 1 as $t, 1 as $t), a / a);
-            assert_eq!($new(1 as $t, 2 as $t, 4 as $t, 8 as $t), a / 2 as $t);
-            assert_eq!($new(8 as $t, 4 as $t, 2 as $t, 1 as $t), 16 as $t / a);
+            assert_eq!($new(1 as $t, 2 as $t, 4 as $t, 5 as $t), a / 2 as $t);
+            assert_eq!($new(8 as $t, 4 as $t, 2 as $t, 1.6 as $t), 16 as $t / a);
             assert_eq!($new(0 as $t, 0 as $t, 0 as $t, 0 as $t), a % a);
             assert_eq!($new(0 as $t, 1 as $t, 1 as $t, 1 as $t), a % (a - 1 as $t));
             assert_eq!($new(0 as $t, 0 as $t, 0 as $t, 0 as $t), a % 1 as $t);
             assert_eq!($new(2 as $t, 1 as $t, 2 as $t, 1 as $t), a % 3 as $t);
-            assert_eq!($new(1 as $t, 1 as $t, 1 as $t, 1 as $t), 17 as $t % a);
-            assert_eq!($new(2 as $t, 4 as $t, 0 as $t, 0 as $t), a % 8 as $t);
+            assert_eq!($new(1 as $t, 1 as $t, 1 as $t, 7 as $t), 17 as $t % a);
+            assert_eq!($new(2 as $t, 4 as $t, 0 as $t, 2 as $t), a % 8 as $t);
+        });
+
+        glam_test!(test_ops_propagated, {
+            let vec = $new(2 as $t, 4 as $t, 8 as $t, 10 as $t);
+            let scalar = 2 as $t;
+            let g_scalar = 10 as $t;
+
+            assert_eq!((vec + vec), (vec + &vec));
+            assert_eq!((vec + vec), (&vec + vec));
+            assert_eq!((vec + vec), (&vec + &vec));
+            assert_eq!((vec + scalar), (vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + &scalar));
+            assert_eq!((vec + scalar), (&vec + scalar));
+            assert_eq!((scalar + vec), (&scalar + vec));
+            assert_eq!((scalar + vec), (&scalar + &vec));
+            assert_eq!((scalar + vec), (scalar + &vec));
+
+            assert_eq!((vec - vec), (vec - &vec));
+            assert_eq!((vec - vec), (&vec - vec));
+            assert_eq!((vec - vec), (&vec - &vec));
+            assert_eq!((vec - scalar), (vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - &scalar));
+            assert_eq!((vec - scalar), (&vec - scalar));
+            assert_eq!((g_scalar - vec), (&g_scalar - vec));
+            assert_eq!((g_scalar - vec), (&g_scalar - &vec));
+            assert_eq!((g_scalar - vec), (g_scalar - &vec));
+
+            assert_eq!((vec * vec), (vec * &vec));
+            assert_eq!((vec * vec), (&vec * vec));
+            assert_eq!((vec * vec), (&vec * &vec));
+            assert_eq!((vec * scalar), (vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * &scalar));
+            assert_eq!((vec * scalar), (&vec * scalar));
+            assert_eq!((scalar * vec), (&scalar * vec));
+            assert_eq!((scalar * vec), (&scalar * &vec));
+            assert_eq!((scalar * vec), (scalar * &vec));
+
+            assert_eq!((vec / vec), (vec / &vec));
+            assert_eq!((vec / vec), (&vec / vec));
+            assert_eq!((vec / vec), (&vec / &vec));
+            assert_eq!((vec / scalar), (vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / &scalar));
+            assert_eq!((vec / scalar), (&vec / scalar));
+            assert_eq!((scalar / vec), (&scalar / vec));
+            assert_eq!((scalar / vec), (&scalar / &vec));
+            assert_eq!((scalar / vec), (scalar / &vec));
+
+            assert_eq!((vec % vec), (vec % &vec));
+            assert_eq!((vec % vec), (&vec % vec));
+            assert_eq!((vec % vec), (&vec % &vec));
+            assert_eq!((vec % scalar), (vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % &scalar));
+            assert_eq!((vec % scalar), (&vec % scalar));
+            assert_eq!((scalar % vec), (&scalar % vec));
+            assert_eq!((scalar % vec), (&scalar % &vec));
+            assert_eq!((scalar % vec), (scalar % &vec));
         });
 
         glam_test!(test_assign_ops, {
@@ -223,6 +329,47 @@
             assert_eq!($new(0 as $t, 0 as $t, 0 as $t, 0 as $t), b);
         });
 
+        glam_test!(test_assign_ops_propagation, {
+            let vec = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            let mut a = vec;
+            let mut b = vec;
+            let scalar = 2 as $t;
+
+            a += &scalar;
+            b += scalar;
+            assert_eq!(b, a, "AddAssign<Scalar>");
+            a -= &scalar;
+            b -= scalar;
+            assert_eq!(b, a, "SubAssign<Scalar>");
+            a *= &scalar;
+            b *= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+            a /= &scalar;
+            b /= scalar;
+            assert_eq!(b, a, "DivAssign<Scalar>");
+            a %= &scalar;
+            b %= scalar;
+            assert_eq!(b, a, "MulAssign<Scalar>");
+
+            a = vec;
+            b = vec;
+            a += &vec;
+            b += vec;
+            assert_eq!(b, a, "AddAssign<Vec>");
+            a -= &vec;
+            b -= vec;
+            assert_eq!(b, a, "SubAssign<Vec>");
+            a *= &vec;
+            b *= vec;
+            assert_eq!(b, a, "MulAssign<Vec>");
+            a /= &vec;
+            b /= vec;
+            assert_eq!(b, a, "DivAssign<Vec>");
+            a %= &vec;
+            b %= vec;
+            assert_eq!(b, a, "RemAssign<Vec>");
+        });
+
         glam_test!(test_min_max, {
             let a = $new(4 as $t, 6 as $t, 2 as $t, 8 as $t);
             let b = $new(5 as $t, 3 as $t, 7 as $t, 1 as $t);
@@ -295,6 +442,12 @@
             );
         });
 
+        glam_test!(test_sum_product, {
+            let a = $new(2 as $t, 3 as $t, 4 as $t, 5 as $t);
+            assert_eq!(a.element_sum(), 14 as $t);
+            assert_eq!(a.element_product(), 120 as $t);
+        });
+
         glam_test!(test_eq, {
             let a = $new(1 as $t, 1 as $t, 1 as $t, 1 as $t);
             let b = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
@@ -350,6 +503,60 @@
             should_panic!({ $vec4::from_slice(&[0 as $t; 3]) });
         });
 
+        glam_test!(test_mask_new, {
+            assert_eq!(
+                $mask::new(false, false, false, false),
+                $masknew(false, false, false, false)
+            );
+            assert_eq!(
+                $mask::new(false, false, true, true),
+                $masknew(false, false, true, true)
+            );
+            assert_eq!(
+                $mask::new(true, true, false, false),
+                $masknew(true, true, false, false)
+            );
+            assert_eq!(
+                $mask::new(false, true, false, true),
+                $masknew(false, true, false, true)
+            );
+            assert_eq!(
+                $mask::new(true, false, true, false),
+                $masknew(true, false, true, false)
+            );
+            assert_eq!(
+                $mask::new(true, true, true, true),
+                $masknew(true, true, true, true)
+            );
+        });
+
+        glam_test!(test_mask_from_array_bool, {
+            assert_eq!(
+                $mask::new(false, false, false, false),
+                $mask::from([false, false, false, false])
+            );
+            assert_eq!(
+                $mask::new(false, false, true, true),
+                $mask::from([false, false, true, true])
+            );
+            assert_eq!(
+                $mask::new(true, true, false, false),
+                $mask::from([true, true, false, false])
+            );
+            assert_eq!(
+                $mask::new(false, true, false, true),
+                $mask::from([false, true, false, true])
+            );
+            assert_eq!(
+                $mask::new(true, false, true, false),
+                $mask::from([true, false, true, false])
+            );
+            assert_eq!(
+                $mask::new(true, true, true, true),
+                $mask::from([true, true, true, true])
+            );
+        });
+
         glam_test!(test_mask_into_array_u32, {
             assert_eq!(
                 Into::<[u32; 4]>::into($mask::new(false, false, false, false)),
@@ -629,6 +836,11 @@
             let mut a = [0 as $t, 0 as $t, 0 as $t, 0 as $t];
             v.write_to_slice(&mut a);
             assert_eq!(v, $vec4::from_slice(&a));
+
+            let mut a = [0 as $t; 17];
+            v.write_to_slice(&mut a);
+            assert_eq!(v, $vec4::from_slice(&a[..4]));
+            assert_eq!([0 as $t; 13], a[4..]);
         });
 
         glam_test!(test_sum, {
@@ -646,8 +858,8 @@
 }
 
 macro_rules! impl_vec4_signed_tests {
-    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => {
-        impl_vec4_tests!($t, $new, $vec4, $vec3, $vec2, $mask);
+    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => {
+        impl_vec4_tests!($t, $new, $vec4, $vec3, $vec2, $mask, $masknew);
 
         glam_test!(test_neg, {
             let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
@@ -662,6 +874,11 @@
             );
         });
 
+        glam_test!(test_neg_propagation, {
+            let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            assert_eq!(-a, -(&a));
+        });
+
         glam_test!(test_is_negative_bitmask, {
             assert_eq!($vec4::ZERO.is_negative_bitmask(), 0b0000);
             assert_eq!($vec4::ONE.is_negative_bitmask(), 0b0000);
@@ -742,8 +959,8 @@
 }
 
 macro_rules! impl_vec4_signed_integer_tests {
-    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => {
-        impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask);
+    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => {
+        impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask, $masknew);
 
         glam_test!(test_signum, {
             assert_eq!($vec4::ZERO.signum(), $vec4::ZERO);
@@ -785,14 +1002,10 @@
 }
 
 macro_rules! impl_vec4_float_tests {
-    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => {
-        impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask);
+    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => {
+        impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask, $masknew);
         impl_vec_float_normalize_tests!($t, $vec4);
 
-        use core::$t::INFINITY;
-        use core::$t::NAN;
-        use core::$t::NEG_INFINITY;
-
         glam_test!(test_vec4_nan, {
             assert!($vec4::NAN.is_nan());
             assert!(!$vec4::NAN.is_finite());
@@ -932,10 +1145,10 @@
             assert_eq!($vec4::new(0.0, 0.0, 0.0, 11.123).round().w, 11.0);
             assert_eq!($vec4::new(0.0, 0.0, 11.501, 0.0).round().z, 12.0);
             assert_eq!(
-                $vec4::new(NEG_INFINITY, INFINITY, 1.0, -1.0).round(),
-                $vec4::new(NEG_INFINITY, INFINITY, 1.0, -1.0)
+                $vec4::new($t::NEG_INFINITY, $t::INFINITY, 1.0, -1.0).round(),
+                $vec4::new($t::NEG_INFINITY, $t::INFINITY, 1.0, -1.0)
             );
-            assert!($vec4::new(NAN, 0.0, 0.0, 1.0).round().x.is_nan());
+            assert!($vec4::new($t::NAN, 0.0, 0.0, 1.0).round().x.is_nan());
         });
 
         glam_test!(test_floor, {
@@ -944,38 +1157,50 @@
                 $vec4::new(1.0, 1.0, -2.0, 1.0)
             );
             assert_eq!(
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0).floor(),
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0)
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0).floor(),
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0)
             );
-            assert!($vec4::new(0.0, NAN, 0.0, 0.0).floor().y.is_nan());
+            assert!($vec4::new(0.0, $t::NAN, 0.0, 0.0).floor().y.is_nan());
             assert_eq!(
                 $vec4::new(-0.0, -2000000.123, 10000000.123, 1000.9).floor(),
                 $vec4::new(-0.0, -2000001.0, 10000000.0, 1000.0)
             );
         });
 
-        glam_test!(test_fract, {
+        glam_test!(test_fract_gl, {
             assert_approx_eq!(
-                $vec4::new(1.35, 1.5, -1.5, 1.999).fract(),
+                $vec4::new(1.35, 1.5, -1.5, 1.999).fract_gl(),
                 $vec4::new(0.35, 0.5, 0.5, 0.999)
             );
             assert_approx_eq!(
-                $vec4::new(-0.0, -200000.123, 1000000.123, 1000.9).fract(),
+                $vec4::new(-0.0, -200000.123, 1000000.123, 1000.9).fract_gl(),
                 $vec4::new(0.0, 0.877, 0.123, 0.9),
                 0.002
             );
         });
 
+        glam_test!(test_fract, {
+            assert_approx_eq!(
+                $vec4::new(1.35, 1.5, -1.5, 1.999).fract(),
+                $vec4::new(0.35, 0.5, -0.5, 0.999)
+            );
+            assert_approx_eq!(
+                $vec4::new(-0.0, -200000.123, 1000000.123, 1000.9).fract(),
+                $vec4::new(0.0, -0.123, 0.123, 0.9),
+                0.002
+            );
+        });
+
         glam_test!(test_ceil, {
             assert_eq!(
                 $vec4::new(1.35, 1.5, -1.5, 1234.1234).ceil(),
                 $vec4::new(2.0, 2.0, -1.0, 1235.0)
             );
             assert_eq!(
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0).ceil(),
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0)
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0).ceil(),
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0)
             );
-            assert!($vec4::new(0.0, 0.0, NAN, 0.0).ceil().z.is_nan());
+            assert!($vec4::new(0.0, 0.0, $t::NAN, 0.0).ceil().z.is_nan());
             assert_eq!(
                 $vec4::new(-1234.1234, -2000000.123, 1000000.123, 1000.9).ceil(),
                 $vec4::new(-1234.0, -2000000.0, 1000001.0, 1001.0)
@@ -988,10 +1213,10 @@
                 $vec4::new(1.0, 1.0, -1.0, 1.0)
             );
             assert_eq!(
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0).trunc(),
-                $vec4::new(INFINITY, NEG_INFINITY, 0.0, 0.0)
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0).trunc(),
+                $vec4::new($t::INFINITY, $t::NEG_INFINITY, 0.0, 0.0)
             );
-            assert!($vec4::new(0.0, NAN, 0.0, 0.0).trunc().y.is_nan());
+            assert!($vec4::new(0.0, $t::NAN, 0.0, 0.0).trunc().y.is_nan());
             assert_eq!(
                 $vec4::new(-0.0, -2000000.123, 10000000.123, 1000.9).trunc(),
                 $vec4::new(-0.0, -2000000.0, 10000000.0, 1000.0)
@@ -1006,13 +1231,36 @@
             assert_approx_eq!($vec4::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_lerp_big_difference, {
+            let v0 = $vec4::new(-1e30, -1e30, -1e30, -1e30);
+            let v1 = $vec4::new(16.0, 16.0, 16.0, 16.0);
+            assert_approx_eq!(v0, v0.lerp(v1, 0.0));
+            assert_approx_eq!(v1, v0.lerp(v1, 1.0));
+        });
+
+        glam_test!(test_move_towards, {
+            let v0 = $vec4::new(-1.0, -1.0, -1.0, -1.0);
+            let v1 = $vec4::new(1.0, 1.0, 1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
+        glam_test!(test_midpoint, {
+            let v0 = $vec4::new(-1.0, -1.0, -1.0, -1.0);
+            let v1 = $vec4::new(1.0, 1.0, 1.0, 1.0);
+            let v2 = $vec4::new(-1.5, 0.0, 1.0, 0.5);
+            assert_approx_eq!($vec4::ZERO, v0.midpoint(v1));
+            assert_approx_eq!($vec4::new(-0.25, 0.5, 1.0, 0.75), v1.midpoint(v2));
+        });
+
         glam_test!(test_is_finite, {
             assert!($vec4::new(0.0, 0.0, 0.0, 0.0).is_finite());
             assert!($vec4::new(-1e-10, 1.0, 1e10, 42.0).is_finite());
-            assert!(!$vec4::new(INFINITY, 0.0, 0.0, 0.0).is_finite());
-            assert!(!$vec4::new(0.0, NAN, 0.0, 0.0).is_finite());
-            assert!(!$vec4::new(0.0, 0.0, NEG_INFINITY, 0.0).is_finite());
-            assert!(!$vec4::new(0.0, 0.0, 0.0, NAN).is_finite());
+            assert!(!$vec4::new($t::INFINITY, 0.0, 0.0, 0.0).is_finite());
+            assert!(!$vec4::new(0.0, $t::NAN, 0.0, 0.0).is_finite());
+            assert!(!$vec4::new(0.0, 0.0, $t::NEG_INFINITY, 0.0).is_finite());
+            assert!(!$vec4::new(0.0, 0.0, 0.0, $t::NAN).is_finite());
             assert!(!$vec4::INFINITY.is_finite());
             assert!(!$vec4::NEG_INFINITY.is_finite());
         });
@@ -1091,6 +1339,27 @@
                 $vec4::new(-0.5, 1.0, -5.0, -1.0)
             );
         });
+
+        glam_test!(test_fmt_float, {
+            let a = $vec4::new(1.0, 2.0, 3.0, 4.0);
+            assert_eq!(format!("{:.2}", a), "[1.00, 2.00, 3.00, 4.00]");
+        });
+
+        glam_test!(test_reflect, {
+            let incident = $vec4::new(1.0, -1.0, 1.0, 1.0);
+            let normal = $vec4::Y;
+            assert_approx_eq!(incident.reflect(normal), $vec4::ONE);
+        });
+
+        glam_test!(test_refract, {
+            let incident = $vec4::NEG_ONE.normalize();
+            let normal = $vec4::ONE.normalize();
+            assert_approx_eq!(incident.refract(normal, 0.5), incident);
+
+            let incident = $vec4::new(1.0, -1.0, 0.0, 0.0).normalize();
+            let normal = $vec4::Y;
+            assert_approx_eq!(incident.refract(normal, 1.5), $vec4::ZERO);
+        });
     };
 }
 
@@ -1272,13 +1541,10 @@
 }
 
 mod vec4 {
-    #[cfg(any(
-        not(any(target_feature = "sse2", target_feature = "simd128")),
-        feature = "scalar-math"
-    ))]
-    use glam::BVec4;
+    #[cfg(feature = "scalar-math")]
+    use glam::{bvec4, BVec4};
     #[cfg(not(feature = "scalar-math"))]
-    use glam::BVec4A;
+    use glam::{bvec4a, BVec4A};
     use glam::{vec4, Vec2, Vec3, Vec4};
 
     glam_test!(test_align, {
@@ -1338,12 +1604,20 @@
     }
 
     glam_test!(test_as, {
-        use glam::{DVec4, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec4, Vec4};
+        use glam::{DVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec4, Vec4};
         assert_eq!(
             DVec4::new(-1.0, -2.0, -3.0, -4.0),
             Vec4::new(-1.0, -2.0, -3.0, -4.0).as_dvec4()
         );
         assert_eq!(
+            I8Vec4::new(-1, -2, -3, -4),
+            Vec4::new(-1.0, -2.0, -3.0, -4.0).as_i8vec4()
+        );
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            Vec4::new(1.0, 2.0, 3.0, 4.0).as_u8vec4()
+        );
+        assert_eq!(
             I16Vec4::new(-1, -2, -3, -4),
             Vec4::new(-1.0, -2.0, -3.0, -4.0).as_i16vec4()
         );
@@ -1373,6 +1647,14 @@
             DVec4::new(-1.0, -2.0, -3.0, -4.0).as_vec4()
         );
         assert_eq!(
+            I8Vec4::new(-1, -2, -3, -4),
+            DVec4::new(-1.0, -2.0, -3.0, -4.0).as_i8vec4()
+        );
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            DVec4::new(1.0, 2.0, 3.0, 4.0).as_u8vec4()
+        );
+        assert_eq!(
             I16Vec4::new(-1, -2, -3, -4),
             DVec4::new(-1.0, -2.0, -3.0, -4.0).as_i16vec4()
         );
@@ -1399,6 +1681,65 @@
 
         assert_eq!(
             Vec4::new(-1.0, -2.0, -3.0, -4.0),
+            I8Vec4::new(-1, -2, -3, -4).as_vec4()
+        );
+        assert_eq!(
+            DVec4::new(-1.0, -2.0, -3.0, -4.0),
+            I8Vec4::new(-1, -2, -3, -4).as_dvec4()
+        );
+        assert_eq!(U8Vec4::new(1, 2, 3, 4), I8Vec4::new(1, 2, 3, 4).as_u8vec4());
+        assert_eq!(
+            I16Vec4::new(-1, -2, -3, -4),
+            I8Vec4::new(-1, -2, -3, -4).as_i16vec4()
+        );
+        assert_eq!(
+            U16Vec4::new(1, 2, 3, 4),
+            I8Vec4::new(1, 2, 3, 4).as_u16vec4()
+        );
+        assert_eq!(
+            IVec4::new(-1, -2, -3, -4),
+            I8Vec4::new(-1, -2, -3, -4).as_ivec4()
+        );
+        assert_eq!(UVec4::new(1, 2, 3, 4), I8Vec4::new(1, 2, 3, 4).as_uvec4());
+        assert_eq!(
+            I64Vec4::new(-1, -2, -3, -4),
+            I8Vec4::new(-1, -2, -3, -4).as_i64vec4()
+        );
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
+            I8Vec4::new(1, 2, 3, 4).as_u64vec4()
+        );
+
+        assert_eq!(
+            Vec4::new(1.0, 2.0, 3.0, 4.0),
+            U8Vec4::new(1, 2, 3, 4).as_vec4()
+        );
+        assert_eq!(
+            DVec4::new(1.0, 2.0, 3.0, 4.0),
+            U8Vec4::new(1, 2, 3, 4).as_dvec4()
+        );
+        assert_eq!(I8Vec4::new(1, 2, 3, 4), U8Vec4::new(1, 2, 3, 4).as_i8vec4());
+        assert_eq!(
+            I16Vec4::new(1, 2, 3, 4),
+            U8Vec4::new(1, 2, 3, 4).as_i16vec4()
+        );
+        assert_eq!(
+            U16Vec4::new(1, 2, 3, 4),
+            U8Vec4::new(1, 2, 3, 4).as_u16vec4()
+        );
+        assert_eq!(IVec4::new(1, 2, 3, 4), U8Vec4::new(1, 2, 3, 4).as_ivec4());
+        assert_eq!(UVec4::new(1, 2, 3, 4), U8Vec4::new(1, 2, 3, 4).as_uvec4());
+        assert_eq!(
+            I64Vec4::new(1, 2, 3, 4),
+            U8Vec4::new(1, 2, 3, 4).as_i64vec4()
+        );
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
+            U8Vec4::new(1, 2, 3, 4).as_u64vec4()
+        );
+
+        assert_eq!(
+            Vec4::new(-1.0, -2.0, -3.0, -4.0),
             I16Vec4::new(-1, -2, -3, -4).as_vec4()
         );
         assert_eq!(
@@ -1406,6 +1747,14 @@
             I16Vec4::new(-1, -2, -3, -4).as_dvec4()
         );
         assert_eq!(
+            I8Vec4::new(-1, -2, -3, -4),
+            I16Vec4::new(-1, -2, -3, -4).as_i8vec4()
+        );
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            I16Vec4::new(1, 2, 3, 4).as_u8vec4()
+        );
+        assert_eq!(
             U16Vec4::new(1, 2, 3, 4),
             I16Vec4::new(1, 2, 3, 4).as_u16vec4()
         );
@@ -1432,6 +1781,14 @@
             U16Vec4::new(1, 2, 3, 4).as_dvec4()
         );
         assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            U16Vec4::new(1, 2, 3, 4).as_i8vec4()
+        );
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U16Vec4::new(1, 2, 3, 4).as_u8vec4()
+        );
+        assert_eq!(
             I16Vec4::new(1, 2, 3, 4),
             U16Vec4::new(1, 2, 3, 4).as_i16vec4()
         );
@@ -1454,6 +1811,11 @@
             DVec4::new(-1.0, -2.0, -3.0, -4.0),
             IVec4::new(-1, -2, -3, -4).as_dvec4()
         );
+        assert_eq!(
+            I8Vec4::new(-1, -2, -3, -4),
+            IVec4::new(-1, -2, -3, -4).as_i8vec4()
+        );
+        assert_eq!(U8Vec4::new(1, 2, 3, 4), IVec4::new(1, 2, 3, 4).as_u8vec4());
         assert_eq!(UVec4::new(1, 2, 3, 4), IVec4::new(1, 2, 3, 4).as_uvec4());
         assert_eq!(
             I16Vec4::new(-1, -2, -3, -4),
@@ -1480,6 +1842,8 @@
             DVec4::new(1.0, 2.0, 3.0, 4.0),
             UVec4::new(1, 2, 3, 4).as_dvec4()
         );
+        assert_eq!(I8Vec4::new(1, 2, 3, 4), UVec4::new(1, 2, 3, 4).as_i8vec4());
+        assert_eq!(U8Vec4::new(1, 2, 3, 4), UVec4::new(1, 2, 3, 4).as_u8vec4());
         assert_eq!(
             I16Vec4::new(1, 2, 3, 4),
             UVec4::new(1, 2, 3, 4).as_i16vec4()
@@ -1507,6 +1871,14 @@
             I64Vec4::new(-1, -2, -3, -4).as_dvec4()
         );
         assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            I64Vec4::new(1, 2, 3, 4).as_u8vec4()
+        );
+        assert_eq!(
+            I8Vec4::new(-1, -2, -3, -4),
+            I64Vec4::new(-1, -2, -3, -4).as_i8vec4()
+        );
+        assert_eq!(
             U16Vec4::new(1, 2, 3, 4),
             I64Vec4::new(1, 2, 3, 4).as_u16vec4()
         );
@@ -1533,6 +1905,14 @@
             U64Vec4::new(1, 2, 3, 4).as_dvec4()
         );
         assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            U64Vec4::new(1, 2, 3, 4).as_i8vec4()
+        );
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U64Vec4::new(1, 2, 3, 4).as_u8vec4()
+        );
+        assert_eq!(
             I16Vec4::new(1, 2, 3, 4),
             U64Vec4::new(1, 2, 3, 4).as_i16vec4()
         );
@@ -1561,14 +1941,14 @@
     });
 
     #[cfg(not(feature = "scalar-math"))]
-    impl_vec4_float_tests!(f32, vec4, Vec4, Vec3, Vec2, BVec4A);
+    impl_vec4_float_tests!(f32, vec4, Vec4, Vec3, Vec2, BVec4A, bvec4a);
 
     #[cfg(feature = "scalar-math")]
-    impl_vec4_float_tests!(f32, vec4, Vec4, Vec3, Vec2, BVec4);
+    impl_vec4_float_tests!(f32, vec4, Vec4, Vec3, Vec2, BVec4, bvec4);
 }
 
 mod dvec4 {
-    use glam::{dvec4, BVec4, DVec2, DVec3, DVec4, IVec4, UVec4, Vec4};
+    use glam::{bvec4, dvec4, BVec4, DVec2, DVec3, DVec4, IVec4, UVec4, Vec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1596,12 +1976,368 @@
         );
     });
 
-    impl_vec4_float_tests!(f64, dvec4, DVec4, DVec3, DVec2, BVec4);
+    impl_vec4_float_tests!(f64, dvec4, DVec4, DVec3, DVec2, BVec4, bvec4);
+}
+
+mod i8vec4 {
+    use glam::{
+        bvec4, i8vec4, BVec4, I16Vec4, I64Vec4, I8Vec2, I8Vec3, I8Vec4, IVec4, U16Vec4, U64Vec4,
+        U8Vec4, UVec4,
+    };
+
+    glam_test!(test_align, {
+        use std::mem;
+        assert_eq!(4, mem::size_of::<I8Vec4>());
+        #[cfg(not(feature = "cuda"))]
+        assert_eq!(1, mem::align_of::<I8Vec4>());
+        #[cfg(feature = "cuda")]
+        assert_eq!(4, mem::align_of::<I8Vec4>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(U8Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(U8Vec4::new(u8::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U8Vec4::new(1, u8::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U8Vec4::new(1, 2, u8::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(U8Vec4::new(1, 2, 3, u8::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(I16Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(I16Vec4::new(i16::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(I16Vec4::new(1, i16::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(I16Vec4::new(1, 2, i16::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(I16Vec4::new(1, 2, 3, i16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(U16Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(U16Vec4::new(u16::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U16Vec4::new(1, u16::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U16Vec4::new(1, 2, u16::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(U16Vec4::new(1, 2, 3, u16::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(IVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(IVec4::new(i32::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(IVec4::new(1, i32::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(IVec4::new(1, 2, i32::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(IVec4::new(1, 2, 3, i32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(UVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(UVec4::new(u32::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(UVec4::new(1, u32::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(UVec4::new(1, 2, u32::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(UVec4::new(1, 2, 3, u32::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(I64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(I64Vec4::new(i64::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(I64Vec4::new(1, i64::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(I64Vec4::new(1, 2, i64::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(I64Vec4::new(1, 2, 3, i64::MAX)).is_err());
+
+        assert_eq!(
+            I8Vec4::new(1, 2, 3, 4),
+            I8Vec4::try_from(U64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I8Vec4::try_from(U64Vec4::new(u64::MAX, 2, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U64Vec4::new(1, u64::MAX, 3, 4)).is_err());
+        assert!(I8Vec4::try_from(U64Vec4::new(1, 2, u64::MAX, 4)).is_err());
+        assert!(I8Vec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, 5, i8::MIN, 0).wrapping_add(I8Vec4::new(1, 3, i8::MAX, 0)),
+            I8Vec4::new(i8::MIN, 8, -1, 0),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, 5, i8::MIN, 0).wrapping_sub(I8Vec4::new(1, 3, i8::MAX, 0)),
+            I8Vec4::new(126, 2, 1, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, 5, i8::MIN, 0).wrapping_mul(I8Vec4::new(3, 3, 5, 1)),
+            I8Vec4::new(125, 15, -128, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, 5, i8::MIN, 0).wrapping_div(I8Vec4::new(3, 3, 5, 1)),
+            I8Vec4::new(42, 1, -25, 0)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, i8::MIN, 0, 0).saturating_add(I8Vec4::new(1, -1, 2, 3)),
+            I8Vec4::new(i8::MAX, i8::MIN, 2, 3)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            I8Vec4::new(i8::MIN, i8::MAX, 0, 0).saturating_sub(I8Vec4::new(1, -1, 2, 3)),
+            I8Vec4::new(i8::MIN, i8::MAX, -2, -3)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, i8::MIN, 0, 0).saturating_mul(I8Vec4::new(2, 2, 0, 0)),
+            I8Vec4::new(i8::MAX, i8::MIN, 0, 0)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, i8::MIN, 0, 0).saturating_div(I8Vec4::new(2, 2, 3, 4)),
+            I8Vec4::new(63, -64, 0, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, i8::MAX, i8::MAX, i8::MAX)
+                .wrapping_add_unsigned(U8Vec4::new(1, 1, 1, 1)),
+            I8Vec4::new(i8::MIN, i8::MIN, i8::MIN, i8::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I8Vec4::new(i8::MIN, i8::MIN, i8::MIN, i8::MIN)
+                .wrapping_sub_unsigned(U8Vec4::new(1, 1, 1, 1)),
+            I8Vec4::new(i8::MAX, i8::MAX, i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I8Vec4::new(i8::MAX, i8::MAX, i8::MAX, i8::MAX)
+                .saturating_add_unsigned(U8Vec4::new(1, 1, 1, 1)),
+            I8Vec4::new(i8::MAX, i8::MAX, i8::MAX, i8::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I8Vec4::new(i8::MIN, i8::MIN, i8::MIN, i8::MIN)
+                .saturating_sub_unsigned(U8Vec4::new(1, 1, 1, 1)),
+            I8Vec4::new(i8::MIN, i8::MIN, i8::MIN, i8::MIN)
+        );
+    });
+
+    impl_vec4_signed_integer_tests!(i8, i8vec4, I8Vec4, I8Vec3, I8Vec2, BVec4, bvec4);
+    impl_vec4_eq_hash_tests!(i8, i8vec4);
+
+    impl_vec4_scalar_shift_op_tests!(I8Vec4, -2, 2);
+    impl_vec4_shift_op_tests!(I8Vec4);
+
+    impl_vec4_scalar_bit_op_tests!(I8Vec4, -2, 2);
+    impl_vec4_bit_op_tests!(I8Vec4, -2, 2);
+}
+
+mod u8vec4 {
+    use glam::{
+        bvec4, u8vec4, BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec2, U8Vec3,
+        U8Vec4, UVec4,
+    };
+
+    glam_test!(test_align, {
+        use std::mem;
+        assert_eq!(4, mem::size_of::<U8Vec4>());
+        #[cfg(not(feature = "cuda"))]
+        assert_eq!(1, mem::align_of::<U8Vec4>());
+        #[cfg(feature = "cuda")]
+        assert_eq!(4, mem::align_of::<U8Vec4>());
+    });
+
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(I8Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(I8Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I8Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I8Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U8Vec4::try_from(I8Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(I16Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(I16Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert!(U8Vec4::try_from(I16Vec4::new(i16::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, i16::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, 2, i16::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(I16Vec4::new(1, 2, 3, i16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(U16Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(U16Vec4::new(u16::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(U16Vec4::new(1, u16::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(U16Vec4::new(1, 2, u16::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(U16Vec4::new(1, 2, 3, u16::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(IVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(IVec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, -2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, 2, -3, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, 2, 3, -4)).is_err());
+
+        assert!(U8Vec4::try_from(IVec4::new(i32::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, i32::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, 2, i32::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(IVec4::new(1, 2, 3, i32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(UVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(UVec4::new(u32::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(UVec4::new(1, u32::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(UVec4::new(1, 2, u32::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(UVec4::new(1, 2, 3, u32::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(I64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(I64Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert!(U8Vec4::try_from(I64Vec4::new(i64::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, i64::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, 2, i64::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(I64Vec4::new(1, 2, 3, i64::MAX)).is_err());
+
+        assert_eq!(
+            U8Vec4::new(1, 2, 3, 4),
+            U8Vec4::try_from(U64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U8Vec4::try_from(U64Vec4::new(u64::MAX, 2, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(U64Vec4::new(1, u64::MAX, 3, 4)).is_err());
+        assert!(U8Vec4::try_from(U64Vec4::new(1, 2, u64::MAX, 4)).is_err());
+        assert!(U8Vec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
+    });
+
+    glam_test!(test_wrapping_add, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, 5, u8::MAX, 0).wrapping_add(U8Vec4::new(1, 3, u8::MAX, 0)),
+            U8Vec4::new(0, 8, 254, 0),
+        );
+    });
+
+    glam_test!(test_wrapping_sub, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, 5, u8::MAX - 1, 0).wrapping_sub(U8Vec4::new(1, 3, u8::MAX, 0)),
+            U8Vec4::new(254, 2, 255, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_mul, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, 5, u8::MAX, 0).wrapping_mul(U8Vec4::new(3, 3, 5, 1)),
+            U8Vec4::new(253, 15, 251, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_div, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, 5, u8::MAX, 0).wrapping_div(U8Vec4::new(3, 3, 5, 1)),
+            U8Vec4::new(85, 1, 51, 0)
+        );
+    });
+
+    glam_test!(test_saturating_add, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, u8::MAX, 0, 0).saturating_add(U8Vec4::new(1, u8::MAX, 2, 3)),
+            U8Vec4::new(u8::MAX, u8::MAX, 2, 3)
+        );
+    });
+
+    glam_test!(test_saturating_sub, {
+        assert_eq!(
+            U8Vec4::new(0, u8::MAX, 0, 0).saturating_sub(U8Vec4::new(1, 1, 2, 3)),
+            U8Vec4::new(0, 254, 0, 0)
+        );
+    });
+
+    glam_test!(test_saturating_mul, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, u8::MAX, 0, 0).saturating_mul(U8Vec4::new(2, u8::MAX, 0, 0)),
+            U8Vec4::new(u8::MAX, u8::MAX, 0, 0)
+        );
+    });
+
+    glam_test!(test_saturating_div, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, u8::MAX, 0, 0).saturating_div(U8Vec4::new(2, u8::MAX, 3, 4)),
+            U8Vec4::new(127, 1, 0, 0)
+        );
+    });
+
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, u8::MAX, u8::MAX, u8::MAX)
+                .wrapping_add_signed(I8Vec4::new(1, 1, 1, 1)),
+            U8Vec4::new(u8::MIN, u8::MIN, u8::MIN, u8::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U8Vec4::new(u8::MAX, u8::MAX, u8::MAX, u8::MAX)
+                .saturating_add_signed(I8Vec4::new(1, 1, 1, 1)),
+            U8Vec4::new(u8::MAX, u8::MAX, u8::MAX, u8::MAX)
+        );
+    });
+
+    impl_vec4_tests!(u8, u8vec4, U8Vec4, U8Vec3, U8Vec2, BVec4, bvec4);
+    impl_vec4_eq_hash_tests!(u8, u8vec4);
+
+    impl_vec4_scalar_shift_op_tests!(U8Vec4, 0, 2);
+    impl_vec4_shift_op_tests!(U8Vec4);
+
+    impl_vec4_scalar_bit_op_tests!(U8Vec4, 0, 2);
+    impl_vec4_bit_op_tests!(U8Vec4, 0, 2);
 }
 
 mod i16vec4 {
     use glam::{
-        i16vec4, BVec4, I16Vec2, I16Vec3, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec4,
+        bvec4, i16vec4, BVec4, I16Vec2, I16Vec3, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4,
+        U8Vec4, UVec4,
     };
 
     glam_test!(test_align, {
@@ -1616,6 +2352,15 @@
     glam_test!(test_try_from, {
         assert_eq!(
             I16Vec4::new(1, 2, 3, 4),
+            I16Vec4::from(U8Vec4::new(1, 2, 3, 4))
+        );
+        assert_eq!(
+            I16Vec4::new(1, 2, 3, 4),
+            I16Vec4::from(I8Vec4::new(1, 2, 3, 4))
+        );
+
+        assert_eq!(
+            I16Vec4::new(1, 2, 3, 4),
             I16Vec4::try_from(U16Vec4::new(1, 2, 3, 4)).unwrap()
         );
         assert!(I16Vec4::try_from(U16Vec4::new(u16::MAX, 2, 3, 4)).is_err());
@@ -1716,7 +2461,39 @@
         );
     });
 
-    impl_vec4_signed_integer_tests!(i16, i16vec4, I16Vec4, I16Vec3, I16Vec2, BVec4);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I16Vec4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX)
+                .wrapping_add_unsigned(U16Vec4::new(1, 1, 1, 1)),
+            I16Vec4::new(i16::MIN, i16::MIN, i16::MIN, i16::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I16Vec4::new(i16::MIN, i16::MIN, i16::MIN, i16::MIN)
+                .wrapping_sub_unsigned(U16Vec4::new(1, 1, 1, 1)),
+            I16Vec4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I16Vec4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX)
+                .saturating_add_unsigned(U16Vec4::new(1, 1, 1, 1)),
+            I16Vec4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I16Vec4::new(i16::MIN, i16::MIN, i16::MIN, i16::MIN)
+                .saturating_sub_unsigned(U16Vec4::new(1, 1, 1, 1)),
+            I16Vec4::new(i16::MIN, i16::MIN, i16::MIN, i16::MIN)
+        );
+    });
+
+    impl_vec4_signed_integer_tests!(i16, i16vec4, I16Vec4, I16Vec3, I16Vec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(i16, i16vec4);
 
     impl_vec4_scalar_shift_op_tests!(I16Vec4, -2, 2);
@@ -1728,7 +2505,8 @@
 
 mod u16vec4 {
     use glam::{
-        u16vec4, BVec4, I16Vec4, I64Vec4, IVec4, U16Vec2, U16Vec3, U16Vec4, U64Vec4, UVec4,
+        bvec4, u16vec4, BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec2, U16Vec3, U16Vec4, U64Vec4,
+        U8Vec4, UVec4,
     };
 
     glam_test!(test_align, {
@@ -1743,6 +2521,20 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U16Vec4::new(1, 2, 3, 4),
+            U16Vec4::try_from(I8Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U16Vec4::try_from(I8Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U16Vec4::try_from(I8Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U16Vec4::try_from(I8Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U16Vec4::try_from(I8Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert_eq!(
+            U16Vec4::new(1, 2, 3, 4),
+            U16Vec4::from(U8Vec4::new(1, 2, 3, 4))
+        );
+
+        assert_eq!(
+            U16Vec4::new(1, 2, 3, 4),
             U16Vec4::try_from(I16Vec4::new(1, 2, 3, 4)).unwrap()
         );
         assert!(U16Vec4::try_from(I16Vec4::new(-1, 2, 3, 4)).is_err());
@@ -1858,7 +2650,23 @@
         );
     });
 
-    impl_vec4_tests!(u16, u16vec4, U16Vec4, U16Vec3, U16Vec2, BVec4);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U16Vec4::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX)
+                .wrapping_add_signed(I16Vec4::new(1, 1, 1, 1)),
+            U16Vec4::new(u16::MIN, u16::MIN, u16::MIN, u16::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U16Vec4::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX)
+                .saturating_add_signed(I16Vec4::new(1, 1, 1, 1)),
+            U16Vec4::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX)
+        );
+    });
+
+    impl_vec4_tests!(u16, u16vec4, U16Vec4, U16Vec3, U16Vec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(u16, u16vec4);
 
     impl_vec4_scalar_shift_op_tests!(U16Vec4, 0, 2);
@@ -1869,7 +2677,10 @@
 }
 
 mod ivec4 {
-    use glam::{ivec4, BVec4, I16Vec4, I64Vec4, IVec2, IVec3, IVec4, U16Vec4, U64Vec4, UVec4};
+    use glam::{
+        bvec4, ivec4, BVec4, I16Vec4, I64Vec4, I8Vec4, IVec2, IVec3, IVec4, U16Vec4, U64Vec4,
+        U8Vec4, UVec4,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -1883,6 +2694,9 @@
     });
 
     glam_test!(test_try_from, {
+        assert_eq!(IVec4::new(1, 2, 3, 4), IVec4::from(U8Vec4::new(1, 2, 3, 4)));
+        assert_eq!(IVec4::new(1, 2, 3, 4), IVec4::from(I8Vec4::new(1, 2, 3, 4)));
+
         assert_eq!(
             IVec4::new(1, 2, 3, 4),
             IVec4::from(U16Vec4::new(1, 2, 3, 4))
@@ -1976,7 +2790,39 @@
         );
     });
 
-    impl_vec4_signed_integer_tests!(i32, ivec4, IVec4, IVec3, IVec2, BVec4);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            IVec4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX)
+                .wrapping_add_unsigned(UVec4::new(1, 1, 1, 1)),
+            IVec4::new(i32::MIN, i32::MIN, i32::MIN, i32::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            IVec4::new(i32::MIN, i32::MIN, i32::MIN, i32::MIN)
+                .wrapping_sub_unsigned(UVec4::new(1, 1, 1, 1)),
+            IVec4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            IVec4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX)
+                .saturating_add_unsigned(UVec4::new(1, 1, 1, 1)),
+            IVec4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            IVec4::new(i32::MIN, i32::MIN, i32::MIN, i32::MIN)
+                .saturating_sub_unsigned(UVec4::new(1, 1, 1, 1)),
+            IVec4::new(i32::MIN, i32::MIN, i32::MIN, i32::MIN)
+        );
+    });
+
+    impl_vec4_signed_integer_tests!(i32, ivec4, IVec4, IVec3, IVec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(i32, ivec4);
 
     impl_vec4_scalar_shift_op_tests!(IVec4, -2, 2);
@@ -1987,7 +2833,10 @@
 }
 
 mod uvec4 {
-    use glam::{uvec4, BVec4, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec2, UVec3, UVec4};
+    use glam::{
+        bvec4, uvec4, BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4, U8Vec4, UVec2,
+        UVec3, UVec4,
+    };
 
     glam_test!(test_align, {
         use std::mem;
@@ -2003,6 +2852,17 @@
     glam_test!(test_try_from, {
         assert_eq!(
             UVec4::new(1, 2, 3, 4),
+            UVec4::try_from(I8Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(UVec4::try_from(I8Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(UVec4::try_from(I8Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(UVec4::try_from(I8Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(UVec4::try_from(I8Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert_eq!(UVec4::new(1, 2, 3, 4), UVec4::from(U8Vec4::new(1, 2, 3, 4)));
+
+        assert_eq!(
+            UVec4::new(1, 2, 3, 4),
             UVec4::try_from(I16Vec4::new(1, 2, 3, 4)).unwrap()
         );
         assert!(UVec4::try_from(I16Vec4::new(-1, 2, 3, 4)).is_err());
@@ -2104,7 +2964,23 @@
         );
     });
 
-    impl_vec4_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            UVec4::new(u32::MAX, u32::MAX, u32::MAX, u32::MAX)
+                .wrapping_add_signed(IVec4::new(1, 1, 1, 1)),
+            UVec4::new(u32::MIN, u32::MIN, u32::MIN, u32::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            UVec4::new(u32::MAX, u32::MAX, u32::MAX, u32::MAX)
+                .saturating_add_signed(IVec4::new(1, 1, 1, 1)),
+            UVec4::new(u32::MAX, u32::MAX, u32::MAX, u32::MAX)
+        );
+    });
+
+    impl_vec4_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(u32, uvec4);
 
     impl_vec4_scalar_shift_op_tests!(UVec4, 0, 2);
@@ -2116,7 +2992,8 @@
 
 mod i64vec4 {
     use glam::{
-        i64vec4, BVec4, I16Vec4, I64Vec2, I64Vec3, I64Vec4, IVec4, U16Vec4, U64Vec4, UVec4,
+        bvec4, i64vec4, BVec4, I16Vec4, I64Vec2, I64Vec3, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec4,
+        U8Vec4, UVec4,
     };
 
     glam_test!(test_align, {
@@ -2133,6 +3010,14 @@
     glam_test!(test_try_from, {
         assert_eq!(
             I64Vec4::new(1, 2, 3, 4),
+            I64Vec4::from(I8Vec4::new(1, 2, 3, 4))
+        );
+        assert_eq!(
+            I64Vec4::new(1, 2, 3, 4),
+            I64Vec4::from(U8Vec4::new(1, 2, 3, 4))
+        );
+        assert_eq!(
+            I64Vec4::new(1, 2, 3, 4),
             I64Vec4::from(I16Vec4::new(1, 2, 3, 4))
         );
         assert_eq!(
@@ -2158,7 +3043,39 @@
         assert!(I64Vec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
     });
 
-    impl_vec4_signed_integer_tests!(i64, i64vec4, I64Vec4, I64Vec3, I64Vec2, BVec4);
+    glam_test!(test_wrapping_add_unsigned, {
+        assert_eq!(
+            I64Vec4::new(i64::MAX, i64::MAX, i64::MAX, i64::MAX)
+                .wrapping_add_unsigned(U64Vec4::new(1, 1, 1, 1)),
+            I64Vec4::new(i64::MIN, i64::MIN, i64::MIN, i64::MIN)
+        );
+    });
+
+    glam_test!(test_wrapping_sub_unsigned, {
+        assert_eq!(
+            I64Vec4::new(i64::MIN, i64::MIN, i64::MIN, i64::MIN)
+                .wrapping_sub_unsigned(U64Vec4::new(1, 1, 1, 1)),
+            I64Vec4::new(i64::MAX, i64::MAX, i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_add_unsigned, {
+        assert_eq!(
+            I64Vec4::new(i64::MAX, i64::MAX, i64::MAX, i64::MAX)
+                .saturating_add_unsigned(U64Vec4::new(1, 1, 1, 1)),
+            I64Vec4::new(i64::MAX, i64::MAX, i64::MAX, i64::MAX)
+        );
+    });
+
+    glam_test!(test_saturating_sub_unsigned, {
+        assert_eq!(
+            I64Vec4::new(i64::MIN, i64::MIN, i64::MIN, i64::MIN)
+                .saturating_sub_unsigned(U64Vec4::new(1, 1, 1, 1)),
+            I64Vec4::new(i64::MIN, i64::MIN, i64::MIN, i64::MIN)
+        );
+    });
+
+    impl_vec4_signed_integer_tests!(i64, i64vec4, I64Vec4, I64Vec3, I64Vec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(i64, i64vec4);
 
     impl_vec4_scalar_shift_op_tests!(I64Vec4, -2, 2);
@@ -2170,7 +3087,8 @@
 
 mod u64vec4 {
     use glam::{
-        u64vec4, BVec4, I16Vec4, I64Vec4, IVec4, U16Vec4, U64Vec2, U64Vec3, U64Vec4, UVec4,
+        bvec4, u64vec4, BVec4, I16Vec4, I64Vec4, I8Vec4, IVec4, U16Vec4, U64Vec2, U64Vec3, U64Vec4,
+        U8Vec4, UVec4,
     };
 
     glam_test!(test_align, {
@@ -2187,6 +3105,20 @@
     glam_test!(test_try_from, {
         assert_eq!(
             U64Vec4::new(1, 2, 3, 4),
+            U64Vec4::try_from(I8Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U64Vec4::try_from(I8Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U64Vec4::try_from(I8Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U64Vec4::try_from(I8Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U64Vec4::try_from(I8Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
+            U64Vec4::from(U8Vec4::new(1, 2, 3, 4))
+        );
+
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
             U64Vec4::try_from(I16Vec4::new(1, 2, 3, 4)).unwrap()
         );
         assert!(U64Vec4::try_from(I16Vec4::new(-1, 2, 3, 4)).is_err());
@@ -2223,7 +3155,23 @@
         assert!(U64Vec4::try_from(I64Vec4::new(1, 2, 3, -4)).is_err());
     });
 
-    impl_vec4_tests!(u64, u64vec4, U64Vec4, U64Vec3, U64Vec2, BVec4);
+    glam_test!(test_wrapping_add_signed, {
+        assert_eq!(
+            U64Vec4::new(u64::MAX, u64::MAX, u64::MAX, u64::MAX)
+                .wrapping_add_signed(I64Vec4::new(1, 1, 1, 1)),
+            U64Vec4::new(u64::MIN, u64::MIN, u64::MIN, u64::MIN)
+        );
+    });
+
+    glam_test!(test_saturating_add_signed, {
+        assert_eq!(
+            U64Vec4::new(u64::MAX, u64::MAX, u64::MAX, u64::MAX)
+                .saturating_add_signed(I64Vec4::new(1, 1, 1, 1)),
+            U64Vec4::new(u64::MAX, u64::MAX, u64::MAX, u64::MAX)
+        );
+    });
+
+    impl_vec4_tests!(u64, u64vec4, U64Vec4, U64Vec3, U64Vec2, BVec4, bvec4);
     impl_vec4_eq_hash_tests!(u64, u64vec4);
 
     impl_vec4_scalar_shift_op_tests!(U64Vec4, 0, 2);
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index db8ce15..a50a5b1 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -2274,9 +2274,9 @@
 
 [[package]]
 name = "glam"
-version = "0.25.0"
+version = "0.29.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
+checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
 
 [[package]]
 name = "glob"
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 4782645..e0e923d 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -128,7 +128,7 @@
 gdbstub = "=0.7.2"
 gdbstub_arch = "=0.3.0"
 getrandom = "=0.2.12"
-glam = "=0.25.0"
+glam = "=0.29.2"
 glob = "=0.3.1"
 googletest = "=0.11.0"
 googletest_macro = "=0.11.0"