Recovery integration API #
All scene types below are exported from hexwork_render::scene.
pub enum SemanticRole { Player, Actor, Threat, Npc, Item, Connector, Interaction }
pub struct EntityDescriptor {
pub id: u64,
pub anchor: [f32; 3], // centered feet/access-cell XY, unchanged Z
pub height: f32,
pub glyph: char,
pub role: SemanticRole,
pub local_light: u8,
}
pub struct SceneBounds { pub min: [i32;3], pub max: [i32;3] }
// inclusive bounds, matching worldgen Bounds/Session TacticalContext
pub struct RenderScratch { /* retained private buffers */ }
// RenderScratch: Default + Debug; half_samples() and cell_roles() accessors
pub fn render_scene(
grid: &hexwork_core::voxel::ChunkedGrid,
view: &hexwork_render::camera::View,
palette: &hexwork_render::palette::Palette,
framebuffer: &mut hexwork_render::FrameBuffer,
lights: &[(i32,i32,i32,u8)],
entities: &[EntityDescriptor],
bounds: &SceneBounds,
scratch: &mut RenderScratch,
);
pub fn entity_eligible(grid: &ChunkedGrid, player_eye: [f32;3], entity: &EntityDescriptor, bounds: &SceneBounds) -> bool;
pub fn eligibility_samples(entity: &EntityDescriptor) -> [[f32;3];2];
pub fn sample_visible(grid: &ChunkedGrid, eye: [f32;3], point: [f32;3], bounds: &SceneBounds) -> bool;
// Pair positive light at point with sample_visible for that SAME point.
pub fn ascii_scene(fb: &mut FrameBuffer, scratch: &RenderScratch);
pub fn semantic_color(role: SemanticRole, local_light: u8, palette: &Palette) -> [u8;3];
pub fn semantic_ascii(role: SemanticRole, glyph: char) -> char;
pub fn edge_join(mask: u8) -> char; // N=1,E=2,S=4,W=8
Actor positions are occupancy coordinates (Session rounds to cells). Apply camera::voxel_center([f32;3]) -> [f32;3] once: XY +0.5, Z unchanged. Camera helper positions and descriptor anchors are already centered. camera::chase_orbit_elevated(actor_pos,yaw,elevation) -> View and camera::collision_safe_chase(grid,actor_pos,yaw,elevation) -> View use centered positions.
Eligibility samples: actors/player torso min(height/2,0.9) and head min(max(height-0.1,0),1.6), item +0.15, connector/interaction +0.5. Helper tests either sample LOS, positive descriptor light, active bounds and 48m player-eye range; active-location membership remains caller-owned. Descriptor light must represent eligible locally lit samples, not camera light. For exact per-sample correspondence, Entry should test each returned sample's light and LOS together. Display frustum is never part of eligibility. Production render is perspective only; existing tactical_map remains separate. FP excludes Player role.
ANSI exports:
pub enum ColorMode { TrueColor, Ansi256, NoColor }
pub fn encode_full_mode(fb: &FrameBuffer, out: &mut String, mode: ColorMode);
pub fn encode_diff_mode(prev: &FrameBuffer, next: &FrameBuffer, out: &mut String, mode: ColorMode);
Modes live in hexwork_render::ansi. Force full on mode changes. Run ascii_scene rather than a glyph-density conversion that discards semantic punctuation. No-color preserves glyphs and emits explicit bold/normal plus final reset.