# Architecture — HS_DollyCam ## System Overview HS_DollyCam is a multi-script Second Life HUD system. The Controller resides in the ROOT prim of a single-prim HUD; all other scripts are linked children. Communication is exclusively via `llMessageLinked` with integer channel codes. ## Component Diagram ``` ┌─────────────────────────────────────────────────────────────┐ │ HS_CamController.lsl (ROOT) │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ Chat parser (/88) │ Preset manager │ State mgmt │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ┌────┘ │ │ │ └────┐ │ │ ▼ ▼ ▼ ▼ ▼ │ │ ┌─────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌──────┐ │ │ │ Menu │ │Playlist │ │Engine │ │Markers │ │ FOV │ │ │ │ │ │ │ │Tour │ │ │ │ │ │ │ └──┬───┘ └────┬─────┘ └───┬────┘ └───┬────┘ └──┬───┘ │ │ │ │ │ │ │ │ │ └ └ └ └ ┘ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────┐ │ │ │ HS_CamEngineCore.lsl │ │ │ │ Camera permissions, │ │ │ │ llSetCameraParams, │ │ │ │ Follow/Lock math │ │ │ └──────────────┬──────────────────┘ │ │ │ │ │ ┌──────┴──────┐ │ │ │ SL Viewer │ │ │ │ (Camera) │ │ │ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Component Details ### 1. HS_CamController.lsl (ROOT — Main Orchestrator) **Responsibility:** Central command router and state coordinator. **Key responsibilities:** - Chat command parsing on channel 88 (`/88 help`, `/88 save`, `/88 load`, `/88 moveto`, `/88 tour`, etc.) - Preset management via Linkset Data (`P1`, `P2`, … keys) - State persistence: Follow/Lock state, Marker visibility, Camera state - Routing all high-level commands to specialized helper scripts - Demo mode enforcement (`DEMO_MAX_SLOTS`) **Key constants:** - `CH = 88` — Chat channel - `CE_CMD_*` — Engine command channels (1000–1060) - `CE_EVT_*` — Engine event channels (2000–2060) - `PH_CMD_*` — Playlist command channels (6100–6104) - `MC_CMD = 5100` — Marker command channel - `MN_CMD = 5200` — Menu command channel **Notable patterns:** - `loadPreset(idx)` — reads Linkset Data, extracts position/focus/FOV into temp globals - `packPreset(pos, foc, rot, fovRad)` — serializes camera state to pipe-delimited string - `engineMove(pos, foc, durMs)` — sends `CE_CMD_MOVE` to Engine, hides HUD during animated moves - `phStop(reason)` — forwards `PH_CMD_STOP` to all helpers ### 2. HS_CamPlaylist.lsl (Notecard-Driven Playlist Engine) **Responsibility:** Asynchronous notecard reading and playlist execution. **Key responsibilities:** - Reads playlist notecards line-by-line - Supports `moveto`, `goto`, `load`, `wait`, `tour...endtour`, `dollyzoom`, `fov`, `lock`, `follow` commands - Builds `CE_CMD_TOUR` payloads for tour blocks - Uses `llGetNotecardLineSync` with `NAK` fallback - Compact notecard tours avoid slow multi-line notecard reads **Memory optimization:** - `loadPreset()` uses targeted field parsing (not full `llParseString2List`) - Tour blocks store indices first, load position/focus at `endtour` - Token helpers instead of full `llParseString2List(line, [" "], [])` ### 3. HS_CamTourCommands.lsl (Secondary Tour Command Helper) **Responsibility:** Chat/menu one-shot tour builders. **Key responsibilities:** - Handles `/88 tour ...`, `/88 dollyzoom ...`, menu `TOURRUN` payloads - Builds `CE_CMD_TOUR` payloads without adding memory pressure to Playlist - Targeted preset parsing for position/focus/FOV fields **Design principle:** Keep heavy tour parsing out of Playlist; this script absorbs the memory cost. ### 4. HS_CamEngineTour.lsl (Continuous Tour Runtime) **Responsibility:** High-frequency multi-waypoint camera tour playback. **Key responsibilities:** - Receives `CE_CMD_TOUR` from Playlist and TourCommands - Requests current camera state from Core via `CE_CMD_GET_STATE` - Builds runtime lists: positions, focuses, holds, weights, segment lengths, cumulative lengths, point times - Drives camera via `CE_INT_SET_CAM` to EngineCore - Implements Catmull-Rom spline interpolation and trapezoidal motion profiles - Throttled camera-frame sending via `tourSendCam()` at ~30Hz **Memory-critical decisions:** - Active tour lists stay in script memory (never Linkset Data) - Segment caching reduces repeated `llList2Vector` access - `CE_CMD_TOUR` payload parsed with targeted pipe-field helpers ### 5. HS_CamEngineCore.lsl (Camera Engine Core) **Responsibility:** Low-level camera interface to Second Life viewer. **Key responsibilities:** - Camera permissions (`PERMISSION_CONTROL_CAMERA`, `PERMISSION_TRACK_CAMERA`) - Executes `llSetCameraParams` for all camera movement - Follow mode math (World/Local/Yaw coordinate frames) - Lock mode math (tracks target position) - Configuration dump consumed by Playlist and TourEngine **Hot path:** `CE_INT_SET_CAM` parsing uses direct separator lookup (no `llParseString2List`). **Tour-related config keys:** - `tour_max_points=20` — Max waypoints per segment - `tour_cam_min_interval=0.033` — ~30Hz camera update cap - `tour_pos_epsilon=0.005` — Position change threshold - `tour_focus_epsilon=0.005` — Focus change threshold ### 6. HS_CamMenu.lsl (Dialog Menu / UI) **Responsibility:** Touch-based dialog menus and UI command dispatch. **Key responsibilities:** - Dialog menus with page state - Menu-driven tour building - Nearby target lists (avatars/objects) - UI command dispatch via `MN_CMD` to Controller **Design note:** Menu paths are secondary to notecard playlist workflows. ### 7. HS_CamMarkers.lsl (Visual Marker Helper) **Responsibility:** Rez marker pyramids at preset positions. **Key responsibilities:** - Rezzes `HS_CamMarker` objects at preset positions - Uses `MARKER_CH = -880088` region channel - Uses `llRegionSayTo` for marker communication when keys are known - Mixed marker list (known to be less memory-efficient, but marker use is rare) ### 8. HS_CamFov.lsl (FOV Controller) **Responsibility:** Field of View adjustments and FOV state synchronization. **Key responsibilities:** - FOV clamping (`RLV_FOV_MIN_DEG=10`, `RLV_FOV_MAX_DEG=179`) - FOV state sync across scripts - RLVa integration ## Data Flow ### Preset Save Flow ``` User: /88 save 3 → Controller: requests camera state from Core (CE_CMD_GET_STATE) ← Core: returns current pos/focus/rot (CE_EVT_STATE) → Controller: packs preset, writes to Linkset Data (P3) ← Controller: confirms save to user ``` ### Smooth Move Flow ``` User: /88 moveto 5 2500 → Controller: phStop() (stops any active playlist/tour) → Controller: engineMove(, , 2500) ← EngineCore: camera permission (if needed) → EngineCore: llSetCameraParams (smooth interpolation) ← EngineCore: CE_EVT_MOVE_DONE when complete → Controller: hudShow() ``` ### Continuous Tour Flow ``` User: /88 tour 10000 spline 1 3 5 7 → Controller: phChatTour(msg) → TourCommands: builds CE_CMD_TOUR payload ← TourCommands: sends CE_CMD_TOUR to TourEngine → TourEngine: requests current state from Core ← TourEngine: builds runtime lists (positions, focuses, holds, segments) → TourEngine: CE_INT_SET_CAM frames @ ~30Hz ← EngineCore: llSetCameraParams (continuous drive) ← TourEngine: CE_INT_TOUR_BEGIN / CE_INT_TOUR_END ``` ### Notecard Playlist Flow ``` User: /88 play MyTour → Controller: phPlay("MyTour", 0) → Playlist: reads notecard line-by-line ← Playlist: executes moveto/goto/load/wait commands ← Playlist: builds tour blocks, sends CE_CMD_TOUR to TourEngine ← TourEngine: drives continuous tour ← Playlist: chains next command on MOVE_DONE ``` ## Linkset Data Keys | Key | Format | Purpose | |-----|--------|---------| | `P1`…`P999` | `px|py|pz|fx|fy|fz|rx|ry|rz|rs|fovRad` | Preset storage | | `HS_CAMS` | `shown|N` | Marker visibility state | | `HS_FOLLOW` | `on|uuid` | Follow target state | | `HS_LOCK` | `on|arg` | Lock target state | ## Communication Channel Map | Prefix | Range | Direction | Purpose | |--------|-------|-----------|---------| | `CE_CMD_` | 1000–1060 | Ctrl→Core, Playlist, TourEngine | Engine commands | | `CE_EVT_` | 2000–2060 | Core→Ctrl, Playlist | Engine events | | `CE_INT_` | 3000–3003 | TourEngine→Core | Internal engine ops | | `PH_CMD_` | 6100–6104 | Ctrl→Playlist, TourCommands | Playlist commands | | `MC_CMD` | 5100 | Ctrl→Markers | Marker commands | | `MC_EVT_*` | 5101 | Markers→Ctrl | Marker events | | `MN_CMD` | 5200 | Menu→Ctrl | Menu commands | | `CH` | 88 | User→Ctrl | Chat commands | | `MARKER_CH` | -880088 | Markers→Region | Marker region say | ## Memory Architecture Principles 1. **Hot paths are timer-driven or high-frequency link_message** — `CE_INT_SET_CAM` in EngineCore, tour playback in TourEngine 2. **No `llParseString2List` in hot paths** — Use `llSubStringIndex` for separator lookup, `llGetSubString` for field extraction 3. **Runtime data in script memory, not Linkset Data** — Tour lists are read every timer tick; Linkset Data reads add latency 4. **Short-lived data patterns** — Tour blocks store indices, load position/focus at `endtour`, build final payload directly 5. **Mixed-type lists are expensive** — Avoid in all scripts; use parallel single-type lists instead