feat: heatmap + evo + decay

This commit is contained in:
2026-10-25 10:25:29 +01:00
parent 0b34e66d81
commit 9bb02463da
6 changed files with 459 additions and 5 deletions
+53
View File
@@ -11,6 +11,11 @@ from games.decorators import require_game_enabled
from .canvas import read_canvas
from .gif import build_evolution_gif
from .heatmap import (
build_heatmap_decay_gif,
build_heatmap_evolution_gif,
build_heatmap_png,
)
from .models import PixelPlacement, PlaceSettings
router = Router()
@@ -47,6 +52,54 @@ def evolution_gif(request: HttpRequest, event_path: str, players: str = ""):
)
@router.get(f"{PREFIX}/heatmap.png", auth=django_auth_is_staff)
@decorate_view(require_game_enabled(path="place"))
def heatmap_png(request: HttpRequest, event_path: str, players: str = ""):
"""Admin-only: how many times each pixel was placed, as a heatmap PNG.
`players` is an optional comma-separated list of usernames to only
count those players' placements (combined)."""
usernames = [name.strip() for name in players.split(",") if name.strip()]
return HttpResponse(
build_heatmap_png(request.event, usernames), content_type="image/png"
)
@router.get(f"{PREFIX}/heatmap-evolution.gif", auth=django_auth_is_staff)
@decorate_view(require_game_enabled(path="place"))
def heatmap_evolution_gif(request: HttpRequest, event_path: str, players: str = ""):
"""Admin-only: the heatmap building up over time, as an animated GIF.
`players` is an optional comma-separated list of usernames to only
count those players' placements (combined)."""
usernames = [name.strip() for name in players.split(",") if name.strip()]
return HttpResponse(
build_heatmap_evolution_gif(request.event, usernames),
content_type="image/gif",
)
@router.get(f"{PREFIX}/heatmap-decay.gif", auth=django_auth_is_staff)
@decorate_view(require_game_enabled(path="place"))
def heatmap_decay_gif(
request: HttpRequest,
event_path: str,
players: str = "",
half_life: int | None = None,
):
"""Admin-only: the heatmap over time, but heat decays so pixels nobody
touches anymore fade back to white.
`players` is an optional comma-separated list of usernames to only
count those players' placements (combined). `half_life` is in
placements, defaults to 10 frames' worth."""
usernames = [name.strip() for name in players.split(",") if name.strip()]
return HttpResponse(
build_heatmap_decay_gif(request.event, usernames, half_life),
content_type="image/gif",
)
@router.get(f"{PREFIX}/placements.csv", auth=django_auth_is_staff)
@decorate_view(require_game_enabled(path="place"))
def placements_csv(request: HttpRequest, event_path: str):