ludic/packages/ludic.photo/frame.ludic
Orkuncakilkaya 3b9b4a589b frame allocs: a click is not a frame, a reducer is its dispatch's, a capped push is bounded; ludic.photo at 0
The analysis made every component function a frame root, event handlers (cmp_x_on_delete) too, and
every reducer, whether its action is dispatched every frame or once a trip: a component's 'on'
handlers are no longer roots, and a dispatch is an edge to its action's reducers, so a reducer
counts only when frame code dispatches it. A push into a field declared @max(n) is bounded by the
fence's own check and no longer counted. Maroon Lake: frame_allocs 395 -> 337, frame_keeps 188 -> 169.

ludic.photo: the roll's order and a page of it are kept lists refilled in place (the pack's page
asked for both every frame), its kept lists say @max(256), and a shot's tags, a photograph's fact
and a new roll are declared (once per shot, sale or trip). 18 allocs and 9 keeps -> 0 and 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:02:47 +03:00

38 lines
2 KiB
Text

# frame.ludic - what the camera sees right now: the game offers each subject and tag, and the frame
# takes the best subject's grade - which is what a photographer would say about it
export function photo_frame_begin(photo_st: mut PhotoState) -> void {
photo_st.pht_pending_tags = ""
photo_st.pht_pending_mask = 0
photo_st.pht_pending_legend = 0
photo_st.pht_pending_grade = 0
photo_st.pht_pending_why = PHOTO_WHY_NONE
photo_st.pht_pending_sign = -1
photo_st.pht_pending_stars = false
}
# A subject `sp` (0..31) named `name`, h metres tall, standing at (x, y, z) and doing something worth
# `moment`. True when the lens sees it within its range: it is tagged (once a kind, every legend) and
# scored, and the best score is the frame's.
export function photo_frame_subject(photo_st: mut PhotoState, sp: int, name: string, x: float, y: float, z: float, h: float, legend: bool, moment: int) -> bool {
if not photo_in_view(x, y + 0.8, z, PhotoLens.range()) { return false }
if (photo_st.pht_pending_mask & (1 << sp)) == 0 or legend { photo_frame_tag(photo_st, name) }
photo_st.pht_pending_mask = photo_st.pht_pending_mask | (1 << sp)
if legend { photo_st.pht_pending_legend = photo_st.pht_pending_legend | (1 << sp) }
let g = photo_score(photo_st, x, y, z, h, moment)
if g > photo_st.pht_pending_grade {
photo_st.pht_pending_grade = g
photo_st.pht_pending_why = photo_why_of_comp(photo_st)
}
return true
}
# anything else in the picture worth naming: a landmark, the water, a sign
@alloc_ok("a shot's tags: once per photograph taken")
export function photo_frame_tag(photo_st: mut PhotoState, text: string) -> void {
if len(text) == 0 { return }
if len(photo_st.pht_pending_tags) > 0 { photo_st.pht_pending_tags = photo_st.pht_pending_tags + ", " }
photo_st.pht_pending_tags = photo_st.pht_pending_tags + text
}
export function photo_frame_sign(photo_st: mut PhotoState, sign: int) -> void { photo_st.pht_pending_sign = sign }
export function photo_frame_stars(photo_st: mut PhotoState) -> void { photo_st.pht_pending_stars = true }