diff --git a/src/AcDream.App/Rendering/DollCamera.cs b/src/AcDream.App/Rendering/DollCamera.cs
new file mode 100644
index 00000000..b2ba8ff4
--- /dev/null
+++ b/src/AcDream.App/Rendering/DollCamera.cs
@@ -0,0 +1,37 @@
+using System.Numerics;
+
+namespace AcDream.App.Rendering;
+
+///
+/// Fixed camera for the paperdoll mini-scene. Eye and look-at from
+/// gmPaperDollUI::PostInit (decomp lines 175521–175527):
+/// eye (0.12, -2.4, 0.88) looking at the origin, AC up-axis = +Z.
+///
+/// Uses the same /
+/// convention as
+/// so the doll's triangle winding and back-face
+/// culling match the world render pass.
+///
+/// Per-race camera distance (UpdateForRace) is deferred polish.
+///
+public sealed class DollCamera : ICamera
+{
+ private static readonly Vector3 Eye = new(0.12f, -2.4f, 0.88f);
+ private static readonly Vector3 Target = Vector3.Zero;
+ private static readonly Vector3 Up = Vector3.UnitZ; // AC up-axis = +Z, same as ChaseCamera
+
+ /// Vertical field of view in radians. ~34° default; tune at the visual gate.
+ public float FovRadians { get; set; } = 0.6f;
+
+ public float Near { get; set; } = 0.1f; // same near plane as ChaseCamera / retail znear
+ public float Far { get; set; } = 50f; // doll scene is small; 50 m is ample
+ public float Aspect { get; set; } = 1f;
+
+ ///
+ public Matrix4x4 View =>
+ Matrix4x4.CreateLookAt(Eye, Target, Up);
+
+ ///
+ public Matrix4x4 Projection =>
+ Matrix4x4.CreatePerspectiveFieldOfView(FovRadians, Aspect <= 0f ? 1f : Aspect, Near, Far);
+}
diff --git a/tests/AcDream.App.Tests/Rendering/DollCameraTests.cs b/tests/AcDream.App.Tests/Rendering/DollCameraTests.cs
new file mode 100644
index 00000000..c65afdfb
--- /dev/null
+++ b/tests/AcDream.App.Tests/Rendering/DollCameraTests.cs
@@ -0,0 +1,27 @@
+using System.Numerics;
+using AcDream.App.Rendering;
+using Xunit;
+
+namespace AcDream.App.Tests.Rendering;
+
+public class DollCameraTests
+{
+ [Fact]
+ public void Eye_position_is_the_retail_camera_offset()
+ {
+ var cam = new DollCamera { Aspect = 100f / 214f };
+ Assert.True(Matrix4x4.Invert(cam.View, out var inv));
+ var eye = inv.Translation;
+ Assert.Equal(0.12f, eye.X, 3);
+ Assert.Equal(-2.4f, eye.Y, 3);
+ Assert.Equal(0.88f, eye.Z, 3);
+ }
+
+ [Fact]
+ public void Projection_is_finite_and_uses_aspect()
+ {
+ var cam = new DollCamera { Aspect = 1.5f };
+ Assert.True(float.IsFinite(cam.Projection.M11));
+ Assert.NotEqual(0f, cam.Projection.M34); // perspective w = -z term
+ }
+}