Cutscene cameras from Lua: camera.path, hold, release, shake (F27) #133
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "khyretos/claude/cutscenes-2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Requested by Kees · project thread
Rebased onto main
fcee8fab(after #131 foliage and #132 lint fix). Terrain chunks now follow the camera that's shown, so a cutscene's shot gets the right detail.What
Cutscene cameras for every game, from Lua (GAPS F27, camera part).
kke::CameraDirector: a path through shots (position, look-at point, optional field of view, time; Catmull-Rom), or one held shot. It blends in from what was on screen and back out to gameplay, never jumping, even when a new path starts during another or a release comes half way through a blend. Plus a trauma shake on top of any camera.Application::setCameraDirector: runs after every module's update with the camera gameplay made;camera()is gameplay's again before the next updates, so the player's camera code keeps running underneath.camera.path(shots, {loop, hold, blend, blendOut, seconds}),camera.hold,camera.release,camera.directing,camera.shake(strength, seconds),camera.fov, and theCameraDonehook.camera.position/target/forwardreport the shot on screen. A script's cutscene ends when the script unloads.explosion.luanow shakes in every game (camera.shake), newcutscene.luarecipe with a picture, cookbook "Cutscenes in any game", SCRIPTING rows, GAPS F27 🟡.Tests
CameraDirector.*tests (passes through every shot, smooth, blend in/out without jumps, finishes once, hold, loop, fov, shake fades and caps). Full kke_tests: 1334 passed (23 skipped: valkey and postgres backends) on mainfcee8fab.cutscene.luaplayed in starter_game (tools/check_game, 12 s): fly-around, close-up hold,CameraDonelogged, no errors. Recipe runner shots for cutscene and explosion.🤖 Generated with Claude Code
https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
Title
Cutscene cameras from Lua: camera.path, hold, release, shake (F27)
User description
Requested by Kees · project thread
Rebased onto main
fcee8fab(after #131 foliage and #132 lint fix). Terrain chunks now follow the camera that's shown, so a cutscene's shot gets the right detail.What
Cutscene cameras for every game, from Lua (GAPS F27, camera part).
kke::CameraDirector: a path through shots (position, look-at point, optional field of view, time; Catmull-Rom), or one held shot. It blends in from what was on screen and back out to gameplay, never jumping, even when a new path starts during another or a release comes half way through a blend. Plus a trauma shake on top of any camera.Application::setCameraDirector: runs after every module's update with the camera gameplay made;camera()is gameplay's again before the next updates, so the player's camera code keeps running underneath.camera.path(shots, {loop, hold, blend, blendOut, seconds}),camera.hold,camera.release,camera.directing,camera.shake(strength, seconds),camera.fov, and theCameraDonehook.camera.position/target/forwardreport the shot on screen. A script's cutscene ends when the script unloads.explosion.luanow shakes in every game (camera.shake), newcutscene.luarecipe with a picture, cookbook "Cutscenes in any game", SCRIPTING rows, GAPS F27 🟡.Tests
CameraDirector.*tests (passes through every shot, smooth, blend in/out without jumps, finishes once, hold, loop, fov, shake fades and caps). Full kke_tests: 1334 passed (23 skipped: valkey and postgres backends) on mainfcee8fab.cutscene.luaplayed in starter_game (tools/check_game, 12 s): fly-around, close-up hold,CameraDonelogged, no errors. Recipe runner shots for cutscene and explosion.🤖 Generated with Claude Code
https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
PR Type
Enhancement
Description
Adds
CameraDirectorfor Lua-driven cutscenes with smooth blending.Implements
camera.path,hold,release, andshakefunctions.Introduces
CameraDonehook and terrain updates during shots.Diagram Walkthrough
File Walkthrough
8 files
Defines CameraDirector class for cutscene camera controlImplements Catmull-Rom interpolation and blending logicAdds setCameraDirector callback and gameplay camera storageIntegrates CameraDirector into main loop with blend handlingDeclares camera bindings and director state variablesExposes camera.path, hold, release, shake to Lua scriptsCalls CameraDone hook and uses shownCamera for terrainUpdates to use universal camera.shake instead of view.shake1 files
Releases director when script unloads to restore gameplay1 files
Tests path smoothness, blending, holding, looping, shake4 files
Demonstrates fly-around cutscene with camera.path and holdDocuments cutscene usage and shows cutscene.lua exampleAdds camera.* API reference and CameraDone hook entryMarks ENG-F27 as partly done with camera cutscenes1 files
Registers cutscene.lua recipe for automated testing2 files
PR Reviewer Guide 🔍
📋 Focus areas: 🔴 3 open · ✅ 0 handled. Every push re-checks them; a handled area moves to Resolved findings at the bottom.
Missing Error Handling for Empty Shot Lists
The
playmethod in CameraDirector.cpp (lines 67-80) callsholdwith the first shot if the list has exactly one element, but does not validate that the input vector is non-empty before accessing elements. Whileplaychecks for empty at the start, the logic flow could be improved to ensure robustness against unexpected empty inputs passed from Lua scripts. Additionally, thesamplefunction (lines 34-54) accessesshots.front()andshots.back()without checking if the vector is empty, which would cause undefined behavior if called with an empty list. This could lead to crashes if a script accidentally passes an empty shot list tocamera.path.Potential Division by Zero in Time Calculation
In the
camera.pathbinding (lines 81-84), when shots are not explicitly timed (timed == 0), the code calculates time values using division byn - 1. If a script passes exactly one shot tocamera.path, this results in division by zero, causing undefined behavior or a crash. Although the PR description mentions handling single shots viahold, the current implementation does not prevent the division by zero error in the general case. A check should be added to handle the single-shot case before performing the division.Race Condition in Camera Director State Management
In Application::run() (lines 850-858), the camera director state is updated after module updates. However, there is a potential race condition if multiple modules attempt to set or modify the camera director simultaneously. The
m_cameraDirectedflag is set based on the result ofm_cameraDirector, but ifm_cameraDirectoris modified concurrently (e.g., by another module callingsetCameraDirector), the state could become inconsistent. Additionally, them_gameplayCamerais only updated once per frame, which might not reflect the latest gameplay camera state if multiple modules modify it. This could lead to unexpected camera behavior during rapid scene changes.PR Code Suggestions ✨
Explore these optional code suggestions:
Clarify camera API availability
The documentation mentions that
viewbelongs to the cookbook game, but it doesn'tclarify that
camera.functions are available in all games. Add a sentence toexplicitly state that
camera.is part of the engine API and available in everygame, while
view.*is specific to the cookbook game.docs/cookbook/cameras.md [94-107]
Suggestion importance[1-10]: 6
__
Why: The suggestion correctly identifies a minor documentation gap by clarifying that
camera.*is an engine-wide API whileview.*is cookbook-specific, improving clarity without changing functionality.🧹 Lint report · ❌ 38 problems in 6 checks · 🧹 3 formatting checks to tidy
Nothing here blocks the merge (report only).
MARKDOWN · markdownlint: first lines of the output
CPP · cppcheck: first lines of the output
YAML · yamllint: first lines of the output
BASH · shellcheck: first lines of the output
DOCKERFILE · hadolint: first lines of the output
REPOSITORY · trivy: first lines of the output
🧹 Formatting only (layout, no behaviour; the nightly lint-fix job applies these as a PR): YAML · prettier (57 files checked), BASH · shfmt (11 files checked), JSON · prettier (147 files checked)
✅ Clean: actionlint, git_diff, gitleaks, grype, jsonlint, secretlint, stylelint, trufflehog, xmllint
MegaLinter on soucouyant · full logs in the Actions run · comment
/improvefor AI fix suggestions