## 1. Maya-style Viewport Controls

- [x] 1.1 Refactor `ViewportPanel::HandleInput()` to use Alt+LMB for orbit, Alt+MMB for pan, Alt+RMB for dolly
- [x] 1.2 Remove legacy input mappings (LMB orbit, MMB pan, Shift+LMB pan) from `HandleInput()`
- [x] 1.3 Keep mouse scroll zoom working without Alt modifier
- [x] 1.4 Add Alt key detection via `io.KeyAlt` in ImGui and ensure Alt is not consumed by ImGui menu navigation

## 2. ViewportCamera Dual-Mode Support

- [x] 2.1 Add `enum class CameraMode { Free, UsdCamera }` and a `m_mode` member to `ViewportCamera`
- [x] 2.2 Add `m_usdCameraPath` (SdfPath) and `m_savedFreeCameraState` struct to persist free camera state across mode switches
- [x] 2.3 Add `SetUsdCamera(const UsdStageRefPtr& stage, const SdfPath& cameraPath)` method that reads UsdCamera attributes (focalLength, horizontalAperture, verticalAperture, clippingRange, projection) and world transform
- [x] 2.4 Implement `ComputeUsdCameraViewMatrix()` deriving the view matrix from the UsdCamera prim's world-space transform
- [x] 2.5 Implement `ComputeUsdCameraProjectionMatrix()` deriving the projection matrix from UsdCamera focalLength, aperture, and clip attributes
- [x] 2.6 Modify `GetViewMatrix()` and `GetProjectionMatrix()` to dispatch based on `m_mode` (free vs USD camera)
- [x] 2.7 Add `SwitchToFreeCamera()` that restores the saved free camera state
- [x] 2.8 Disable orbit/pan/zoom/dolly calls when `m_mode == UsdCamera` (no-op in USD camera mode)

## 3. Camera Selector UI

- [x] 3.1 Add method `FindCameraPrims(const UsdStageRefPtr& stage)` to traverse the stage and return a vector of SdfPaths for all UsdCamera-typed prims
- [x] 3.2 Cache the camera list in `ViewportPanel` and invalidate on stage change
- [x] 3.3 Add an ImGui combo dropdown above the viewport canvas in `ViewportPanel::Render()` with "Free Camera" as the first entry followed by discovered camera prim paths
- [x] 3.4 Wire the dropdown selection to call `ViewportCamera::SetUsdCamera()` or `SwitchToFreeCamera()`
- [x] 3.5 Reset the camera selector to "Free Camera" when a new stage is loaded via `ViewportPanel::SetStage()`

## 4. Frame Selected Prim

- [x] 4.1 Add `m_selectedPrimPath` string member to `ViewportPanel` and a setter `SetSelectedPrimPath(const std::string&)`
- [x] 4.2 Wire `Application` to call `ViewportPanel::SetSelectedPrimPath()` from the `SceneHierarchyPanel::SetOnPrimSelected()` callback
- [x] 4.3 Add F key handler in `ViewportPanel::HandleInput()`: compute bounding box of the selected prim using `UsdGeomBBoxCache` and call `FrameBoundingBox`
- [x] 4.4 If viewport is in USD camera mode when F is pressed, switch to free camera mode first then frame
- [x] 4.5 Add A key handler in `ViewportPanel::HandleInput()`: call `FrameScene()` to frame all

## 5. Integration and Verification

- [x] 5.1 Verify Maya-style Alt+button navigation works for orbit, pan, and dolly in the viewport
- [x] 5.2 Verify camera selector dropdown lists free camera and all stage camera prims
- [x] 5.3 Verify switching to a USD camera renders from that camera's viewpoint
- [x] 5.4 Verify switching back to free camera restores the previous free camera position
- [x] 5.5 Verify F key frames the selected prim and A key frames the entire stage
- [x] 5.6 Build and run the application to confirm no regressions in existing viewport rendering
