diff --git a/crates/qbz-slint/ui/assets/icons/arrow-left.svg b/crates/qbz-slint/ui/assets/icons/arrow-left.svg
new file mode 100644
index 000000000..9f150d689
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/arrow-left.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/book-open.svg b/crates/qbz-slint/ui/assets/icons/book-open.svg
new file mode 100644
index 000000000..74a2b9a84
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/book-open.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/bug.svg b/crates/qbz-slint/ui/assets/icons/bug.svg
new file mode 100644
index 000000000..db2b46047
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/bug.svg
@@ -0,0 +1,13 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/cast.svg b/crates/qbz-slint/ui/assets/icons/cast.svg
new file mode 100644
index 000000000..1f364e5e5
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/cast.svg
@@ -0,0 +1,6 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/check.svg b/crates/qbz-slint/ui/assets/icons/check.svg
new file mode 100644
index 000000000..a5f899b7e
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/check.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/chevron-left.svg b/crates/qbz-slint/ui/assets/icons/chevron-left.svg
new file mode 100644
index 000000000..cebe22eb2
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/chevron-left.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/chevron-right.svg b/crates/qbz-slint/ui/assets/icons/chevron-right.svg
new file mode 100644
index 000000000..241d11d55
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/chevron-right.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/ellipsis.svg b/crates/qbz-slint/ui/assets/icons/ellipsis.svg
new file mode 100644
index 000000000..441d6cc0a
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/ellipsis.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/heart.svg b/crates/qbz-slint/ui/assets/icons/heart.svg
new file mode 100644
index 000000000..ae810a263
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/heart.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/info.svg b/crates/qbz-slint/ui/assets/icons/info.svg
new file mode 100644
index 000000000..461364582
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/info.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/keyboard.svg b/crates/qbz-slint/ui/assets/icons/keyboard.svg
new file mode 100644
index 000000000..aa1e2edd5
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/keyboard.svg
@@ -0,0 +1,11 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/list-filter.svg b/crates/qbz-slint/ui/assets/icons/list-filter.svg
new file mode 100644
index 000000000..71c7b0f4e
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/list-filter.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/log-out.svg b/crates/qbz-slint/ui/assets/icons/log-out.svg
new file mode 100644
index 000000000..24dd708a1
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/log-out.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/maximize-2.svg b/crates/qbz-slint/ui/assets/icons/maximize-2.svg
new file mode 100644
index 000000000..9c37cabf9
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/maximize-2.svg
@@ -0,0 +1,6 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/menu.svg b/crates/qbz-slint/ui/assets/icons/menu.svg
new file mode 100644
index 000000000..c343236cc
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/menu.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/minimize-2.svg b/crates/qbz-slint/ui/assets/icons/minimize-2.svg
new file mode 100644
index 000000000..fd47bb399
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/minimize-2.svg
@@ -0,0 +1,6 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/pause.svg b/crates/qbz-slint/ui/assets/icons/pause.svg
new file mode 100644
index 000000000..d7474dd2c
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/pause.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/play.svg b/crates/qbz-slint/ui/assets/icons/play.svg
new file mode 100644
index 000000000..403df1dda
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/play.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/plus.svg b/crates/qbz-slint/ui/assets/icons/plus.svg
new file mode 100644
index 000000000..8d7806007
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/plus.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/repeat-1.svg b/crates/qbz-slint/ui/assets/icons/repeat-1.svg
new file mode 100644
index 000000000..92ab7d019
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/repeat-1.svg
@@ -0,0 +1,7 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/repeat.svg b/crates/qbz-slint/ui/assets/icons/repeat.svg
new file mode 100644
index 000000000..93ed4dc7a
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/repeat.svg
@@ -0,0 +1,6 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/search.svg b/crates/qbz-slint/ui/assets/icons/search.svg
new file mode 100644
index 000000000..73d54d42a
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/search.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/settings.svg b/crates/qbz-slint/ui/assets/icons/settings.svg
new file mode 100644
index 000000000..5f2931c4a
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/settings.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/shuffle.svg b/crates/qbz-slint/ui/assets/icons/shuffle.svg
new file mode 100644
index 000000000..7186daa23
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/shuffle.svg
@@ -0,0 +1,7 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/skip-back.svg b/crates/qbz-slint/ui/assets/icons/skip-back.svg
new file mode 100644
index 000000000..ce7489434
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/skip-back.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/skip-forward.svg b/crates/qbz-slint/ui/assets/icons/skip-forward.svg
new file mode 100644
index 000000000..490b9b89f
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/skip-forward.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/volume-2.svg b/crates/qbz-slint/ui/assets/icons/volume-2.svg
new file mode 100644
index 000000000..50a973b8a
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/volume-2.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/qbz-slint/ui/assets/icons/x.svg b/crates/qbz-slint/ui/assets/icons/x.svg
new file mode 100644
index 000000000..52576d2ce
--- /dev/null
+++ b/crates/qbz-slint/ui/assets/icons/x.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/qbz-slint/ui/primitives/QbzIcon.slint b/crates/qbz-slint/ui/primitives/QbzIcon.slint
new file mode 100644
index 000000000..6a84ea062
--- /dev/null
+++ b/crates/qbz-slint/ui/primitives/QbzIcon.slint
@@ -0,0 +1,14 @@
+// Monochrome Lucide icon.
+//
+// Slint's `@image-url` needs a literal path, so the caller supplies the
+// `source` (an `@image-url` of an SVG in ui/assets/icons/) and a `tint`
+// theme color; QbzIcon applies `colorize` and a contain fit.
+
+import { Theme } from "../foundation/semantic-colors.slint";
+
+export component QbzIcon inherits Image {
+ in property tint: Theme.text-secondary;
+
+ colorize: root.tint;
+ image-fit: contain;
+}