diff --git a/actions/arch-package/arch-package.sh b/actions/arch-package/arch-package.sh
--- a/actions/arch-package/arch-package.sh
+++ b/actions/arch-package/arch-package.sh
@@ -181,6 +181,9 @@ COMPRESSZST=(zstd -c -T0 --ultra -20 -)
 EOF
 
 # Write PKGBUILD
+# libxkbcommon-x11 is a hard dependency next to libxkbcommon: the apps build winit's X11 backend,
+# which loads it at startup on X11 and XWayland, and panics without it ("Library
+# libxkbcommon-x11.so could not be loaded"; photocraft#201). Arch packages it separately.
 cat > "$work/PKGBUILD" <<EOF
 # Maintainer: Storyteller Authors
 pkgname=$(printf '%q' "$pkgname")
@@ -190,7 +193,7 @@ pkgdesc=$(printf '%q' "$pkgdesc")
 arch=($(printf '%q' "$arch"))
 url=$(printf '%q' "$url")
 license=($license_str)
-depends=('glibc' 'gcc-libs' 'hicolor-icon-theme' 'libxkbcommon' 'vulkan-icd-loader')
+depends=('glibc' 'gcc-libs' 'hicolor-icon-theme' 'libxkbcommon' 'libxkbcommon-x11' 'vulkan-icd-loader')
 optdepends=(
   'alsa-lib: sound support'
   'pipewire-alsa: audio playback and recording via PipeWire'
diff --git a/tests/test_arch.py b/tests/test_arch.py
--- a/tests/test_arch.py
+++ b/tests/test_arch.py
@@ -210,6 +210,32 @@ exit 0
             )
             self.assertIn("provides=(myapp=1.2.3-2)", pkgbuild)
 
+    def test_pkgbuild_depends_on_the_x11_keyboard_library(self):
+        """The PKGBUILD depends on libxkbcommon-x11 as well as libxkbcommon.
+
+        winit's X11 backend loads libxkbcommon-x11 at startup and panics without it, and Arch
+        ships it apart from libxkbcommon: a package without it could not open its window on
+        X11 or XWayland.
+        """
+        with tempfile.TemporaryDirectory() as tmpdir:
+            tmp_path = Path(tmpdir)
+            tarball = self._create_fixture_tarball(tmp_path)
+            tools = self._setup_mock_tools(tmp_path)
+            capture = tmp_path / "capture"
+            capture.mkdir()
+            res = subprocess.run(
+                [str(ARCH_SCRIPT), str(tarball), "x86_64", str(tmp_path / "out")],
+                capture_output=True,
+                text=True,
+                env={**os.environ, "PATH": f"{tools}:{os.environ['PATH']}", "MOCK_CAPTURE": str(capture)},
+            )
+            self.assertEqual(res.returncode, 0, f"{res.stderr}\n{res.stdout}")
+            depends = next(
+                line for line in (capture / "PKGBUILD").read_text().splitlines() if line.startswith("depends=(")
+            )
+            for package in ("'libxkbcommon'", "'libxkbcommon-x11'"):
+                self.assertIn(package, depends)
+
     def test_package_function_rejects_symlinked_license_dir(self):
         with tempfile.TemporaryDirectory() as tmpdir:
             tmp_path = Path(tmpdir)
