# A photo mode for your game (photo.mode) ## What it is for `photo.mode` opens a photo mode in any game: a key (or a call) freezes the game, a free camera flies around the place where the player stood, and the player picks a field of view, a roll, an exposure and a filter, hides the HUD and takes a picture. The kit holds the camera state and the pause; the photo overlay (shipped with the kit as an `ui.webui` fragment) drives it and the page draws the picture, because only the page can read the canvas. It decides nothing of your game: a mod or the game can forbid opening it with a hook. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "photo.mode" } gripforge_gamekit_configure { project_id: "gkp_…", id: "photo.mode", config: { "radius": 20, "filters": ["none", "sepia", "noir"] } } ``` It requires `game.engine` and `input.actions`. By default the key `O` opens and closes the mode; flight keys are input actions too (W A S D or the arrows, R and F) that the player can rebind in the input settings. ## First example The test installs the kit with the filters `none` and `noir`, then drives the `photo.mode` service: 1. `capture()` before entering answers `null`: there is no shot outside the mode. 2. `enter()` answers `true`, and the game phase becomes `paused`. 3. `set({ filter: "noir" })` picks a filter; `capture()` calls the capture source with `[width, height, camera]` and answers its picture (a data URL). The size defaults to 1920 x 1080 and is clamped to 16..8192 per side. 4. `photo.shots` counts the pictures taken. A source that answers nothing, or fails, is not a shot. On the web, the photo overlay registers the capture source for you with `setCaptureSource`. ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `radius` | number (1..500) | `12` | how far the camera may fly from where the player stood | | `fov` | number (10..120) | `60` | field of view when the mode opens, in degrees | | `fovMin` | number (5..90) | `15` | narrowest field of view | | `fovMax` | number (30..150) | `110` | widest field of view | | `filters` | list of strings | `none, mono, sepia, warm, cool, vivid, noir, dream` | filters offered, in order; `none` is always added first if missing | | `pauseWorld` | boolean | `true` | freeze the game while the mode is open | All six are moddable. The filter names are the ones the photo overlay knows. ## Services, events, variables The service `photo.mode`: - `enter()`: opens the mode when the game is playing. Answers `false` if it is already open, if the game is not playing, or if a hook cancelled it. - `exit()`: closes it and, if the kit paused the game, resumes it. Answers `false` when it was not open. - `active()`: `true` while the mode is open. - `camera()`: the current camera `{ position, yaw, pitch, roll, fov, exposure, filter, hideHud, anchor, radius }`, or `null`. - `look(dyaw, dpitch)`: turns the camera; pitch is limited to 85 degrees. - `move(forward, right, up)`: moves the camera along its view, kept inside `radius` of the anchor. - `set(patch)`: any of `fov` (clamped to `fovMin`..`fovMax`), `roll` (+-90 degrees), `exposure` (-3..3), `filter` (must be one of `filters`), `hideHud`. - `reset()`: back to the camera the mode opened with. - `filters()`: the list of filters. - `capture(width?, height?)`: asks the capture source for a picture; answers it, or `null`. - `setCaptureSource(fn)`: gives the function that draws the picture. - `shots()`: pictures taken so far. Events: `photo.entered` (`anchor`), `photo.exited` (`shots`), `photo.captured` (`width`, `height`, `filter`). The kit listens to `game.phase`: if anything else resumes the game (a menu), the mode closes with it. Variables: `photo.active` (boolean, mode open) and `photo.shots` (number, pictures taken). Input actions: `photo_mode`, `photo.forward`, `photo.right`, `photo.up`. ## Hooks and modding The hook `photo.enter` is run just before the mode opens, with `{ anchor }` (where the player stands). It is cancellable: a game or a mod forbids the photo mode during a scene, a fight or a timed run, and then `enter()` answers `false`, nothing is paused and nothing is emitted. The settings `radius`, `fov`, `fovMin`, `fovMax`, `filters` and `pauseWorld` can be changed by a mod. ## Engines The logic is the same Rust module everywhere. The overlay (look, fly, field of view, roll, exposure, filters, HUD hiding, shutter, and the button that opens the mode) is an `ui.webui` fragment; the capture source reads the rendered canvas of the page. ## When it does not do what you expect - `enter()` answers `false`: the mode is already open, the game is not in the `playing` phase, or a `photo.enter` tap cancelled it. - `capture()` answers `null`: the mode is closed, no capture source was set, or the source answered nothing. - A filter does not apply: its name is not in `filters`. - The camera stops at a distance: it is confined to `radius` around where the player stood. - The game keeps running behind the overlay: `pauseWorld` is `false`. ## Limits - Only the number of pictures is saved. A loaded game is never in photo mode, and a save made inside it resumes playing. - The kit does not write the picture to disk: the page that gave the capture source decides what to do with it. - It needs a capture source to take a picture; without a page (headless) the camera still moves but nothing is captured. ## Versions Kit version 1.2.0. 1.1.0 added the `photo.enter` hook and the moddable settings; 1.2.0 made the photo keys input actions that the player can rebind.