feat(midsummer): dancing maypole pinned to map centre

This commit is contained in:
Erik 2026-06-19 09:27:26 +02:00
parent 2fb6fd2f3e
commit da0cc79def
3 changed files with 94 additions and 0 deletions

View file

@ -4,6 +4,7 @@ import { PlayerDots } from './PlayerDots';
import { TrailsSVG } from './TrailsSVG';
import { HeatmapCanvas } from './HeatmapCanvas';
import { PortalMarkers } from './PortalMarkers';
import { Maypole } from '../midsummer/Maypole';
import type { TelemetrySnapshot } from '../../types';
interface Props {
@ -143,6 +144,7 @@ export const MapView: React.FC<Props> = ({ players, getColor, onSelectPlayer, sh
selectedPlayer={selectedPlayer}
/>
<PortalMarkers imgW={imgSize.w} imgH={imgSize.h} enabled={showPortals} />
<Maypole imgW={imgSize.w} imgH={imgSize.h} />
</>
)}
</div>

View file

@ -0,0 +1,41 @@
import React from 'react';
import { useMidsummer } from '../../hooks/useMidsummer';
interface Props {
imgW: number;
imgH: number;
}
// Kept small for perf — these orbit the pole via one CSS animation.
const FROG_COUNT = 6;
// Default: dead centre of the Dereth map image. To plant at a landmark,
// import { worldToPx } from '../../utils/coordinates' and compute from
// world coords instead.
const center = (imgW: number, imgH: number) => ({ x: imgW / 2, y: imgH / 2 });
/**
* Midsommarstång planted inside the map's pan/zoom group, so it scales and
* pans with the world automatically. Carries its own ring of dancing frogs
* (one CSS rotation) so the spectacle is independent of who is online.
*/
export const Maypole: React.FC<Props> = ({ imgW, imgH }) => {
const { enabled } = useMidsummer();
if (!enabled || imgW === 0) return null;
const { x, y } = center(imgW, imgH);
return (
<div className="ms-maypole" style={{ left: x, top: y }} aria-hidden="true">
<div className="ms-maypole-pole" />
<div className="ms-maypole-ring">
{Array.from({ length: FROG_COUNT }).map((_, i) => (
<span
key={i}
className="ms-frog"
style={{ transform: `rotate(${(360 / FROG_COUNT) * i}deg) translateY(-40px)` }}
>
🐸
</span>
))}
</div>
</div>
);
};