diff --git a/Cargo.lock b/Cargo.lock
index e68bc44..2985d6a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,7 +14,7 @@ version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
  "winapi",
 ]
@@ -51,24 +51,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clap"
-version = "3.2.20"
+version = "4.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
+checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
 dependencies = [
  "atty",
  "bitflags",
  "clap_lex",
- "indexmap",
  "strsim",
  "termcolor",
- "textwrap",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.2.4"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
 dependencies = [
  "os_str_bytes",
 ]
@@ -185,21 +183,24 @@ dependencies = [
 
 [[package]]
 name = "glam"
-version = "0.21.3"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815"
+checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774"
 
 [[package]]
-name = "hashbrown"
-version = "0.12.3"
+name = "hermit-abi"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.19"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "libc",
 ]
@@ -219,16 +220,6 @@ dependencies = [
  "png",
 ]
 
-[[package]]
-name = "indexmap"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
-dependencies = [
- "autocfg",
- "hashbrown",
-]
-
 [[package]]
 name = "jpeg-decoder"
 version = "0.2.6"
@@ -325,11 +316,11 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.13.1"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.2.6",
  "libc",
 ]
 
@@ -440,21 +431,19 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.5.3"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
 dependencies = [
- "autocfg",
- "crossbeam-deque",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.9.3"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -533,12 +522,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "textwrap"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
-
 [[package]]
 name = "thread_local"
 version = "1.1.4"
diff --git a/Cargo.toml b/Cargo.toml
index 710e41b..b1c5ea2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,12 +7,12 @@ edition = "2018"
 
 [dependencies]
 image = { version = "0.24", default-features = false, features = ["png", "jpeg"] }
-glam = "0.21"
+glam = "0.22"
 rand = { version = "0.8", features = ["small_rng"] }
-rayon = "1.5.3"
+rayon = "1.7.0"
 crossbeam = "0.8.2"
-clap = "3.2"
-num_cpus = "1.13.1"
+clap = "4.0"
+num_cpus = "1.15.0"
 tracing = "0.1"
 tracing-subscriber = { version = "0.3", features = ["env-filter"] }
 
diff --git a/src/cli.rs b/src/cli.rs
index 249890a..6fc5dda 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,4 +1,4 @@
-use clap::{App, Arg};
+use clap::{Arg, Command};
 
 fn integer_non_zero_validator(s: String) -> Result<(), String> {
     match s.parse::<u32>() {
@@ -27,24 +27,27 @@ impl clap::builder::TypedValueParser for AspectRatioParser {
     ) -> Result<Self::Value, clap::Error> {
         if let Some((w, h)) = value.to_str().unwrap().split_once(':') {
             let w: crate::Float = w.parse::<crate::Float>().map_err(|_| {
-                clap::Error::raw(clap::ErrorKind::InvalidValue, "cannot parse width in ratio")
+                clap::Error::raw(
+                    clap::error::ErrorKind::InvalidValue,
+                    "cannot parse width in ratio",
+                )
             })?;
             let h: crate::Float = h.parse::<crate::Float>().map_err(|_| {
                 clap::Error::raw(
-                    clap::ErrorKind::InvalidValue,
+                    clap::error::ErrorKind::InvalidValue,
                     "cannot parse height in ratio",
                 )
             })?;
             if w == 0.0 || h == 0.0 {
                 return Err(clap::Error::raw(
-                    clap::ErrorKind::InvalidValue,
+                    clap::error::ErrorKind::InvalidValue,
                     "w and h cannot be zero",
                 ));
             }
             Ok((w, h))
         } else {
             Err(clap::Error::raw(
-                clap::ErrorKind::InvalidValue,
+                clap::error::ErrorKind::InvalidValue,
                 "ratio must have format w:h",
             ))
         }
@@ -61,40 +64,40 @@ fn aspect_ratio_validator(s: String) -> Result<(), String> {
     }
 }
 
-pub fn build_app() -> App<'static> {
-    App::new(env!("CARGO_PKG_NAME"))
+pub fn build_app() -> Command {
+    Command::new(env!("CARGO_PKG_NAME"))
         .author(env!("CARGO_PKG_AUTHORS"))
         .about(env!("CARGO_PKG_DESCRIPTION"))
         .version(env!("CARGO_PKG_VERSION"))
         .arg(
-            Arg::with_name("scene")
+            Arg::new("scene")
                 .default_value("0")
                 .value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(0..=8))
-                .takes_value(true)
+                .num_args(1)
                 .long("scene"),
         )
         .arg(
-            Arg::with_name("width")
-                .takes_value(true)
+            Arg::new("width")
+                .num_args(1)
                 .long("width")
                 .value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..=100000)),
         )
         .arg(
-            Arg::with_name("aspect ratio")
-                .takes_value(true)
+            Arg::new("aspect ratio")
+                .num_args(1)
                 .long("ratio")
                 .value_parser(AspectRatioParser),
         )
         .arg(
-            Arg::with_name("samples per pixel")
-                .takes_value(true)
+            Arg::new("samples per pixel")
+                .num_args(1)
                 .long("samples")
                 .value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..=100000)),
         )
-        .arg(Arg::with_name("use bvh").takes_value(false).long("bvh"))
+        .arg(Arg::new("use bvh").long("bvh"))
         .arg(
-            Arg::with_name("job")
-                .takes_value(true)
+            Arg::new("job")
+                .num_args(1)
                 .short('j')
                 .value_parser(clap::value_parser!(u32).range(1..)),
         )
diff --git a/src/main.rs b/src/main.rs
index 137f8d8..a14e102 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -78,7 +78,7 @@ fn main() {
     // Parameters
     let matches = cli::build_app().get_matches();
     let scene = matches.get_one::<u32>("scene").unwrap();
-    let use_bvh = matches.is_present("use bvh");
+    let use_bvh = matches.get_flag("use bvh");
     let threads = matches
         .get_one::<u32>("job")
         .copied()