From 09d19a6f56f3a968c0dd7250ec370952fa1d399b Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Sun, 28 Jun 2026 08:53:01 +0200 Subject: [PATCH] Keep POV camera layouts action neutral --- scene_camera_adapters.py | 30 ++++++++++++++++++++++++------ tools/prompt_smoke.py | 3 ++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/scene_camera_adapters.py b/scene_camera_adapters.py index 954f1d6..fdbd56e 100644 --- a/scene_camera_adapters.py +++ b/scene_camera_adapters.py @@ -838,6 +838,24 @@ def camera_geometry_phrase(parsed: dict[str, Any], compact_labels: Mapping[str, return ", ".join(compact_parts) +def pov_camera_geometry_phrase(parsed: dict[str, Any], compact_labels: Mapping[str, str] | None = None) -> str: + elevation = str(parsed.get("orbit_elevation_label") or "").strip() + distance = str(parsed.get("orbit_distance_label") or "").strip() + custom = str(parsed.get("custom_camera_prompt") or "").strip() + if custom: + elevation = elevation or camera_elevation_from_text(custom) + distance = distance or camera_distance_from_text(custom) + parts = [part for part in (elevation, distance) if part and part != "auto"] + if parts: + return ", ".join(parts) + compact_parts = [ + _compact_label(parsed.get(key), compact_labels) + for key in ("shot_size", "distance") + ] + compact_parts = [part for part in compact_parts if part and part != "auto"] + return ", ".join(compact_parts) + + def camera_direction_from_text(text: Any) -> str: source = str(text or "").lower() for label in CAMERA_DIRECTIONS: @@ -901,15 +919,15 @@ def scene_direction_detail( face_verb = "face" if subject == "the subjects" else "faces" if pov_labels: if "right side" in direction: - return f"{subject} {is_verb} in right-side profile; {midground} run behind {pronoun} toward {background}, with {detail_label} kept at the frame edges" + return f"{subject} stays readable in the first-person action while {midground} run along the viewer's right-side background toward {background}, with {detail_label} kept at the frame edges" if "left side" in direction: - return f"{subject} {is_verb} in left-side profile; {midground} run behind {pronoun} toward {background}, with {detail_label} kept at the frame edges" + return f"{subject} stays readable in the first-person action while {midground} run along the viewer's left-side background toward {background}, with {detail_label} kept at the frame edges" if "back-right" in direction or "back-left" in direction: - return f"{subject} stays close in one continuous diagonal first-person body angle; {midground} lead toward {background} behind {pronoun} at the edges, not in the lower foreground" + return f"{subject} stays close in one continuous first-person action frame; {midground} lead diagonally toward {background} at the edges, not in the lower foreground" if direction == "back view": - return f"the viewer looks past {subject}'s back toward {midground}, then into {background}; only POV body cues sit low in frame" + return f"{subject} and the action stay primary while {midground} and {background} remain beyond the body, not between viewer and action; only POV body cues sit low in frame" if "front-right" in direction or "front-left" in direction: - return f"{subject} fills the first-person front-quarter view; {midground} recede diagonally behind {pronoun} toward {background}" + return f"{subject} fills the first-person action frame while {midground} recede diagonally behind {pronoun} toward {background}" return f"{subject} faces the viewer in first-person view; {midground} and {background} stay behind {pronoun}, not between viewer and body" if "right side" in direction or "left side" in direction: return f"{subject} {is_verb} held in side profile along the {foreground}; {midground} run laterally behind {pronoun}, with {background} still readable" @@ -1021,7 +1039,7 @@ def scene_camera_directive( direction_detail = scene_direction_detail(direction, profile, pov_labels, subject_kind) distance_detail = scene_distance_detail(distance, profile, subject_kind, pov_labels) elevation_detail = scene_elevation_detail(elevation, profile, subject_kind, pov_labels) - geometry = camera_geometry_phrase(parsed, compact_labels) + geometry = pov_camera_geometry_phrase(parsed, compact_labels) if pov_labels else camera_geometry_phrase(parsed, compact_labels) geometry_clause = f" ({geometry})" if geometry else "" if pov_labels: return ( diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 61ab6fe..6690e35 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -991,7 +991,8 @@ def smoke_row_camera_policy() -> None: 20, ) _expect("Hotel corridor camera layout from POV" in semi_public_scene, "row camera semi-public scene did not use hotel corridor profile") - _expect("back view" in semi_public_scene, "row camera semi-public scene missed orbit direction") + _expect("back view" not in semi_public_scene, "POV camera scene should not inject orbit back view as body orientation") + _expect("partner's back" not in semi_public_scene, "POV camera scene should not force the visible partner's back") _expect("first-person spatial geometry" in semi_public_scene, "row camera semi-public POV scene lost first-person geometry") _expect(updated_semi_public.get("scene_camera_profile_key") == "hotel_corridor", "row camera semi-public scene did not expose text-matched profile key") _expect("hotel corridor" in semi_public_composition.lower(), "row camera semi-public composition did not become location-aware")