arena/agent.md

27 KiB

Update: Restrained Team Card Styling

  • Team score cards keep the existing label, elite/normal count, click behavior, and focused-team state.
  • Team color is limited to a compact team marker and muted inner divider instead of a full-height side stripe or filled card background.
  • Hover and focus states are quieter: no raised hover motion, reduced brightness, and a subtle inset focus treatment instead of an outer glow.

Update: Battle Notice Rolling Text

  • battleDeathNotice.js now renders notice text inside a message span, measures the rendered content width on the next animation frame, and switches to a rolling track only when the text exceeds the notice box content width.
  • Overflowing battle notices duplicate the message in an aria-hidden track and use aria-label on the status node so assistive text is not repeated.
  • Rolling speed, gap, and duration clamps are tuned by UI.BATTLE_NOTICE_ROLL_* constants; non-overflowing notices keep the normal centered display.

Update: Special Projectile Trail

  • Special projectile movement can leave short-lived visual afterimages controlled by SPECIAL_EFFECT.PROJECTILE.TRAIL.
  • Trail sprites copy the projectile's current texture frame, scale, rotation, and flip state, then fade out without affecting hit detection or damage.
  • Trail density and cost are bounded by TRAIL.INTERVAL_MS and TRAIL.LIFETIME_MS.

Update: Split Special Projectile Visual Configs

  • Special projectile visual asset settings are split by caster type: melee visuals live under SPECIAL_EFFECT.MELEE, and ranged visuals live under SPECIAL_EFFECT.RANGE.
  • SPECIAL_EFFECT.PROJECTILE now owns shared movement, hit-detection, and trail tuning only, such as acceleration, travel duration, hold time, target area, arena clamp, hit radius, lifetime, and afterimages.

Update: One-Shot Accelerating Special Projectile

  • Melee special sprites now use SPECIAL_EFFECT.MELEE.REPEAT = 0, so the configured sprite sheet plays once instead of looping while the projectile travels.
  • special-melee-effect-1 has its frameSequence commented out for now, restoring the natural sprite-sheet order. A commented example remains next to the asset for quick tuning later.
  • Special projectile movement now uses a tween instead of constant physics.moveTo. SPECIAL_EFFECT.PROJECTILE.startHoldMs controls the stationary pre-launch tell, travelDurationMs controls launch speed when set, and movementEase controls the acceleration curve; speed remains the fallback if travelDurationMs is unset.

Update: Special Effect Frame Sequence Refresh

  • Special effect animations now compare the existing Phaser animation against the current configured frames, repeat count, and frame rate. If the config changed, the old global animation key is removed and recreated so frameSequence edits take effect without stale animation data.
  • frameSequence remains 1-based for sprite-sheet inspection, then converts through generateFrameNumbers(..., { frames }), preserving repeated frames when a special asset enables a custom sequence.

Update: Special Effect Frame Rate And Render Budget

  • Special effect sprite animations now multiply their configured frameRate by SPECIAL_EFFECT.FRAME_RATE_MULTIPLIER. This changes only visual frame playback; caster hold time, launch delay, projectile speed, travel distance, and timers keep their existing progress speed.
  • The special focus blur snapshot is skipped when the living fighter count is above SPECIAL_EFFECT.FOCUS_LAYER.BLUR_MAX_FIGHTERS. The dim layer and raised caster focus still render, avoiding the expensive full-arena render-texture blur during larger battles.
  • Special projectile hit checks now use the per-frame combat spatial index to inspect only fighters near the projectile segment when the index is available, while preserving the full-array fallback.

Update: Elite Kill Splash

  • Elite fighters now trigger a kill splash when they directly kill an enemy. The splash is centered on the killed fighter's body position.
  • Splash damage is COMBAT.ELITE_KILL_SPLASH_DAMAGE_PERCENT of the killed fighter's max HP and applies to living enemy fighters inside COMBAT.ELITE_KILL_SPLASH_RADIUS.
  • Splash kills still use the normal kill/death flow for logs, death statistics, despawn, split-on-death, scoreboard, and match-finish checks. COMBAT.ELITE_KILL_SPLASH_CHAIN_ENABLED is false by default, so splash kills do not recursively trigger more splashes unless explicitly enabled.
  • A short team-colored pixel-dot burst is rendered for the splash when supplemental combat effects are enabled, avoiding smooth vector circles.

Update: Team Card Focus Toggle

  • Team cards in the left HUD still select a random living fighter from the clicked team and zoom the camera in.
  • Clicking the same already-focused team card again clears the selected fighter, requests CAMERA.MIN_ZOOM, restores the match status summary, and removes the focused team-card state. If automatic spectator focus is active, that camera mode immediately reapplies its own zoom; this is intended.

Update: Special Effect Projectile

  • Special battle effects are implemented separately from meteor/frost barrages in src/game/combat/specialEffects.js.
  • Tuning lives under SPECIAL_EFFECT in src/constants.js; the same object is also exposed as WORLD_EFFECT.SPECIAL for world-effect domain access.
  • Each live match schedules one special-effect attempt at a random time between SPECIAL_EFFECT.TRIGGER_DELAY_MIN_MS and TRIGGER_DELAY_MAX_MS. It retries briefly only when no eligible caster exists, and never fires more than once per match.
  • Eligible casters are living, non-elite, non-magic fighters from teams that are not currently tied for first by represented living count. SPECIAL_EFFECT.CASTER.BALANCE_NON_MAGIC_TYPES first balances between available non-magic caster types, then picks a fighter inside that type, so ranged casters are not drowned out by the larger melee roster. The caster holds Hurt frame index 1 long enough for the zoom/focus layer to read, then the attack animation launches a giant projectile.
  • The caster receives realtime special invulnerability for SPECIAL_EFFECT.CASTER.INVULNERABLE_MS. Normal attacks, world-effect damage/frost survivor effects, and special instant kills all skip fighters whose invulnerability window is still active.
  • During that Hurt-frame preparation hold, combat is frozen by pausing fighter AI, Arcade Physics, and the scene clock, so combat/world timers do not advance. A realtime cinematic timer releases the pause when the attack motion begins.
  • While the caster holds the Hurt frame, SPECIAL_EFFECT.CASTER_SPARKLE plays only frames 2, 3, and 4 from public/assets/effects/special/effect.png above the caster's eye area, then removes the sparkle before the attack motion begins.
  • The caster is emphasized with a temporary focus stack: a blurred render-texture snapshot of the battlefield, a dim layer, then the caster and special launch/projectile effects above that layer. SPECIAL_EFFECT.FOCUS_LAYER controls depths, blur, alpha, and fades.
  • SPECIAL_EFFECT.CAMERA.CENTER_ON_CASTER_AT_START makes the camera center on the caster location immediately when the special cast begins, before the slower zoom/focus motion continues.
  • When the special projectile starts moving, the special camera stops zooming in and zooms out in place through SPECIAL_EFFECT.CAMERA.PROJECTILE_VIEW_ZOOM and PROJECTILE_ZOOM_OUT_MS; it does not follow the projectile.
  • Special melee sprites can use explicit 1-based frameSequence arrays, but special-melee-effect-1 currently leaves the sequence disabled to play the sheet once in natural order. The projectile uses startHoldMs to remain visible near the caster before traveling.
  • At target-selection time, the projectile locks onto the densest enemy tile area using represented stackCount population. SPECIAL_EFFECT.PROJECTILE.targetAreaTiles controls that scan footprint.
  • The moving special projectile visual is selected by caster type: melee casters fire one random sprite from SPECIAL_EFFECT.MELEE.ASSETS, while ranged casters use SPECIAL_EFFECT.RANGE. Projectile movement uses a tweened Arcade Physics sprite so acceleration can be tuned while path hit checks still run per update. Projectile travel is clamped by SPECIAL_EFFECT.PROJECTILE.arenaEdgePadding, and any living fighter intersecting the projectile path is killed instantly, with kill/death records flowing through the normal combat cleanup path.
  • Special preparation pauses existing combat objects as well as fighters: active battle tweens, world-effect fall tweens, combat-object animations, physics velocities, scene time, and Arcade Physics are restored only after the realtime Hurt-frame hold finishes.

Update: Large-Battle Render Budget

  • When the user-entered total fighter count is greater than PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD, match setup enforces PERFORMANCE.LARGE_BATTLE_RENDERED_FIGHTER_LIMIT as a hard budget for physically rendered fighter plans.
  • Randomized compression still rolls blocks first. If the resulting rendered count exceeds the budget, failed normal 100-member blocks and normal remainder groups are promoted to elite groups until the rendered count is within the limit or no promotable groups remain.
  • stackCount is preserved, so team totals, death statistics, spectator weighting, and dense-area targeting continue to use the represented population.

Update: Field HUD Text Removal

  • Zoom-visible fighter HUD slots no longer create battlefield name text. Team identity is carried by the team-colored sprite shadow, so selected and zoom-visible fighters only borrow health-bar HUD objects.

Update: Large-Battle Elite Probability

  • When the user-entered total fighter count is greater than PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD, randomized elite compression uses FIGHTER.ELITE.RANDOMIZED_COMPRESSION.LARGE_BATTLE_ELITE_BLOCK_PROBABILITY instead of the normal block probability.
  • The large-battle elite probability is 0.8 by default and is clamped against the normal probability so large battles never use a lower elite block ratio than regular randomized compression.

Update: Elite Magic Attack Effect Scale

  • Instant-spell attack effects use FIGHTER.ATTACK_EFFECT_SCALE_MULTIPLIER for their normal visual scale.
  • Elite magic fighters multiply that normal spell-effect scale by FIGHTER.ELITE.ATTACK_EFFECT_SCALE_MULTIPLIER, so giant elite casters can have attack effects sized independently from fighter body scale.
  • Elite spawn plans select skins only from the configured FIGHTER.ELITE.TYPE list (melee, magic); normal plans retain the full skin pool.

Update: Elite Stacking Compression

  • Below FIGHTER.ELITE.RANDOMIZED_COMPRESSION.MIN_TEAM_SIZE, complete FIGHTER.ELITE.STACK_SIZE = 100 blocks use fixed elite compression; with the current threshold of 100, entries containing a complete block use randomized compression instead.
  • At or above the randomized-compression threshold, each complete 100-member block becomes one elite with probability ELITE_BLOCK_PROBABILITY = 0.6; a non-elite block remains 100 rendered normal fighters. When the total requested fighter count is above the large-battle threshold, the probability increases to LARGE_BATTLE_ELITE_BLOCK_PROBABILITY = 0.8.
  • Elite fighters use nested FIGHTER.ELITE settings for their type, 5x visual scale, magic attack-effect scale, HP ratio, attack range, attack damage, and attack/movement speed formulas. A bonus multiplier of 0 disables that added elite bonus; 1 applies the configured stack exponent fully.
  • Critical hits and world effects distinguish elite targets: elites take max-HP based critical/meteor/frost damage (10%/40%/20%), while normal fighters take 2x critical hit damage and the existing fixed meteor/frost damage.
  • COMBAT.KILL_REWARD_ENABLED is false for elite-compressed battles. Kills still update logs and death statistics, but no fighter heals, grows, or gains attack/movement speed from a kill.
  • Team cards display living physical composition as E : elite count | N : normal count. Death statistics, spectator thresholds/centers, and dense-area world-effect targeting continue to use represented stackCount population.
  • Elite representative fighters do not expand Slime spawnMultiplier or splitOnDeath; applying a randomly selected per-unit trait to an aggregated army would duplicate the represented population.

Update: Focused Combat Effects In Large Battles

  • When the live fighter count reaches PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD, supplemental combat visuals are suppressed unless a meteor camera focus is active.
  • Large-battle suppression covers critical-hit labels, instant-spell attack sprites, kill-heal sprites, and kill-growth tweens; damage outcomes remain unchanged. Kill healing/growth is now disabled by the elite-compression policy.
  • Meteor/frost world-effect visuals remain visible because they establish the temporary camera focus. Projectile visuals remain active because their current objects also perform hit detection.

Update: Dense-Area Meteor Barrage

  • Fire and frost world effects now target the WORLD_EFFECT.AREA_TILES tile square containing the highest living-fighter density instead of a random fighter location.
  • Each activation renders that large warning area, then drops WORLD_EFFECT.IMPACT_COUNT_MIN to IMPACT_COUNT_MAX smaller strikes within it. Only the smaller impact zones apply damage, frost, and lingering slow areas.
  • WORLD_EFFECT.WARNING_DURATION_MS tunes how long the large targeting warning remains visible. IMPACT_AREA_TILES, IMPACT_STAGGER_MS, and IMPACT_VISUAL_SCALE tune the barrage footprint, rhythm, and sprite size, while SIZE_SCALE_VARIANCE randomizes individual impact scale.
  • WORLD_EFFECT.INTERVAL delays the first barrage from match start; WORLD_EFFECT.REPEAT_INTERVAL controls later normal barrages, while sudden-death repetition continues to use SUDDEN_DEATH.INTERVAL_MS.
  • Meteor screen shake scales from the same size multiplier, with base values in WORLD_EFFECT.METEOR_SHAKE_DURATION_MS and WORLD_EFFECT.METEOR_SHAKE_INTENSITY.

Update: Direct Fighter Counts And Spawn Zones

  • Live match entries interpret a suffix such as Alice*250 as that team's assigned fighter count; entries without a suffix receive one assigned fighter.
  • The former team-size inputs are removed. Presentation mode retains its fixed preview size through suffixed internal entries.
  • SPAWN.MAX_FIGHTER_COUNT caps only fighters assigned through participant input. Slime spawnMultiplier and splitOnDeath additions are game traits and are not counted against that input cap.
  • Match-start validation shows a styled fighter-cap warning card beneath the participant nickname input, emphasizes requested and allowed counts separately, and clears when names are edited or a valid match is submitted.
  • For starting-zone placement, SPAWN.FIGHTERS_PER_STARTING_ZONE defines how many assigned fighters share each team zone.

Update: Large Battle Performance

  • Combat target acquisition now builds a per-frame spatial grid so every fighter that needs a fresh target can search nearby cells instead of scanning the full battlefield array.
  • Large battle thresholds and related tuning live in PERFORMANCE inside src/constants.js, including target grid size, HUD pool size, minimap dot size, and large-battle corpse despawn delay.
  • Fighter health HUD objects are pooled. Fighters no longer own permanent HUD objects, and selected or zoom-visible nearby fighters borrow health-bar slots without battlefield name text.
  • The minimap is separated from the field camera. During live matches, ArenaScene draws a lightweight graphics minimap through a dedicated minimap-hud camera while the main camera ignores the minimap object and the HUD camera ignores field objects. Presentation/waiting mode hides the minimap.
  • Dead fighter despawn switches to the large-battle delay when the current fighter count reaches PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD.

Update: Dead Fighter Despawn

  • Dead fighters now keep their initial opacity at death, then fade out over FIGHTER.DEAD_DESPAWN_DELAY_MS before being removed.
  • Adjust the corpse lifetime in src/constants.js by changing FIGHTER.DEAD_DESPAWN_DELAY_MS; adjust the final fade target with FIGHTER.DEAD_DESPAWN_ALPHA.
  • Despawn uses the Phaser scene timer and a matching tween so pause/state cleanup follows the existing match lifecycle.

Update: Team Shadow Rendering

  • Team color is now represented by recoloring the built-in floor shadow pixels on each fighter spritesheet instead of rendering a duplicated teamMarker sprite.
  • fighterAssets.js owns lazy team-shadow texture and animation generation for actual skin + action + teamColor combinations. Avoid pre-generating every team/skin/action combination because that can move the bottleneck into startup texture creation and memory use.
  • fighterFactory.js should keep each fighter to one Phaser sprite. Name labels and health bars remain separate HUD objects, but there is no per-fighter team marker sprite to synchronize.
  • combat.js must resolve action animations through ensureFighterTeamAnimation() so action changes keep the team-colored shadow.
  • Frost stun uses body tint only. Do not use tint for persistent team identity.

Agent: Arena Picker

0. 필수

  • 작업이 완료되면 작업에 관련된 모든 문서를 업데이트한다

1. 프로젝트 정의

Arena Picker는 Phaser 3 게임 엔진과 Vite 번들러를 기반으로 구축된 대규모 팀 전투 시뮬레이션 웹 애플리케이션입니다. 사용자가 입력한 여러 명의 참가자(닉네임)를 바탕으로 각 참가자를 하나의 팀으로 설정하고, 지정된 인원만큼의 캐릭터를 생성하여 자동 전투를 시뮬레이션합니다.

서버 런타임은 Fastify를 사용하며, MongoDB 커넥션 풀을 유지해 유니크 방문자 수와 전투 사망 통계를 기록하는 간단한 통계 API를 제공합니다.

2. 프로젝트 전체 구조 (Directory Tree)

├── index.html              # 메인 HTML 진입점 및 UI 레이아웃
├── package.json            # 프로젝트 의존성 및 스크립트 정의 (Phaser, Vite, Fastify, MongoDB)
├── config.json             # 로컬 서버/MongoDB 설정 (git ignore)
├── config.json.sample      # 공유용 서버/MongoDB 설정 예시
├── agent.md                # 프로젝트 개요 및 기능 정의 (본 문서)
├── CONTEXT.md              # 상세 개발 가이드 및 로직 설명
├── todo.md                 # 작업 내역 및 잔여 이슈 관리
├── server/                 # Fastify API 서버 및 MongoDB 연결 관리
│   ├── index.js            # Fastify 서버 진입점, Vite 개발 미들웨어, 정적 배포 서빙
│   ├── config.js           # config.json 로드 및 MongoDB URI 조립
│   ├── db.js               # MongoClient 커넥션 풀 생성/재사용/종료
│   ├── deathStats.js       # 전투 종료 시 오늘 일자별 종족 사망 통계 누적 API
│   ├── about.js            # About 개발자정보/개인정보처리방침 기본값 시드 및 조회 API
│   └── visitors.js         # 유니크 방문자 체크 및 통계 API
├── public/                 # 정적 리소스 (게임 에셋)
│   └── assets/
│       ├── effects/        # 공통 전투/월드 이펙트 스프라이트시트
│       │   ├── heal/       # 처치 회복 연출
│       │   ├── world_Effect.png # 화염 메테오 7프레임 이미지
│       │   └── world_Effect_2.png # 냉기 메테오 7프레임 이미지
│       └── characters/     # 20종 이상의 캐릭터 스킨 및 투사체 에셋
│           ├── archer/, armored-axeman/, armored-orc/, ... (중략)
│           └── wizard/     # 각 폴더 내 애니메이션 시트 및 이펙트 포함
└── src/                    # 소스 코드 root
    ├── main.js             # Phaser 게임 인스턴스 생성, 옵션 drawer/재시작/일시정지 UI 제어
    ├── constants.js        # 전역 물리/UI 상수 통합 관리 (공격력, 체력, 줌, 카메라 속도 등)
    ├── styles.css          # UI 스타일링 (인트로, 옵션 drawer, 좌측 HUD 레일, 좌측 하단 킬로그, 상단 전투 안내바)
    ├── game/               # 게임 로직 모듈 (역할별 하위 폴더 구성)
    │   ├── arena/          # 아레나 및 씬 관리
    │   │   ├── ArenaScene.js   # 메인 게임 씬 (Orchestrator, 생명주기 및 모듈 조율)
    │   │   ├── arenaRenderer.js# 경기장 바닥, 격자 및 팀 시작 영역 렌더링
    │   │   └── arenaSpectatorCamera.js # 지능형 관전 카메라 및 줌 로직
    │   ├── combat/         # 전투 시스템
    │   │   ├── combat.js       # 전투 AI, 투사체 및 피격 판정 핵심 엔진
    │   │   ├── combatSettings.js # 전투 속도 및 이동 배율 관리
    │   │   ├── arenaFinalCombatEffects.js # 최종 교전 슬로우 모션 등 연출 효과
    │   │   └── worldEffects.js # 주기적 메테오/냉각지대 및 냉기 동결 효과
    │   ├── fighter/        # 캐릭터 및 에셋
    │   │   ├── fighterAssets.js # 스프라이트 로드 및 팀 실루엣 동적 생성
    │   │   ├── fighterFactory.js # 캐릭터 인스턴스화 및 HUD 동기화
    │   │   ├── fighterManifest.js # 20종 캐릭터 스탯/특성 상세 정의
    │   │   ├── fighterStats.js # 근접/원거리/마법 프로필 판별 및 스탯 해석
    │   │   └── fighterSelection.js # 캐릭터 스킨 무작위 선택 로직
    ├── match/          # 매치 및 진행
    │   ├── matchSetup.js   # 팀 구성(닉네임 배수 파싱 포함) 및 스폰 좌표 계산 (스타팅 영역/랜덤)
    │   └── arenaMatchRuntime.js # 매치 진행 중 헬퍼 (스폰 클러스터, 팀 크기 동기화)
    ...
    ## 7. 주요 기능 상세 (New)

    ### 7.1 닉네임 배수 시스템 (Multi-Spawn)
    - 사용자가 닉네임 뒤에 `*N` (예: `홍길동*2`)을 입력하면 해당 팀은 기본 팀 인원의 N배만큼 생성됩니다.
    - 스타팅 존 모드에서 배수만큼의 독립된 스폰 지점이 할당되어 전략적인 분산 배치가 이루어집니다.
    - 닉네임 표시 시 `*N` 접미사는 자동으로 제거되어 깔끔한 UI를 유지합니다.

    ### 7.2 서든 데스 (Sudden Death) 시스템
    - 매치 시작 후 일정 시간(기본 8초)이 경과하면 전장의 환경이 극도로 위험해지는 서든 데스 상태에 진입합니다.
    - 메테오 생성 주기가 비약적으로 단축(기본 1초)되며, 빙결 효과를 가진 냉기 메테오가 집중 투하됩니다.
    - `constants.js`를 통해 활성화 여부, 시작 시간, 주기 등을 간편하게 조정할 수 있습니다.

    ### 7.3 밀집 구역 기반 월드 이펙트 포격
    - 월드 이펙트는 랜덤 생존자 대신 `WORLD_EFFECT.AREA_TILES` 크기 범위 중 현재 생존 캐릭터가 가장 많이 모인 위치를 표적으로 선택합니다.
    - 선택 범위를 먼저 경고로 표시한 뒤, 그 내부에 작은 화염 또는 냉기 메테오를 3~4발 분산 투하합니다.
    - 피해, 기절, 냉각 감속은 큰 경고 범위 전체가 아니라 각각의 작은 탄착 영역에만 적용됩니다.

    └── ui/                 # UI 컴포넌트 및 API 연동
        ├── arenaKillLog.js # [New] 독립된 킬로그 DOM 조작 모듈
        ├── arenaScoreboard.js # [New] 팀 스코어 badge 업데이트 모듈
        ├── battleDeathNotice.js # [New] 상단 사망 공지 메시지 및 UI 관리
        ├── victoryCelebration.js # [New] 승리 축하 연출 (DOM/Audio) 모듈
        ├── matchForm.js    # 설정 폼 제어 및 localStorage 유지
        ├── aboutDialog.js  # About 다이얼로그, 개발자정보/개인정보처리방침 표시
        ├── deathStats.js   # 사망 통계 API 호출 래퍼
        └── visitorCounter.js # 방문자 체크 API 호출 및 표시

3. 상세 기술 가이드 (Context Routing)

토큰 절약 및 효율적인 정보 조회를 위해 상세 로직은 기능별로 분리되어 보관됩니다. 특정 모듈 작업 시 아래의 관련 문서를 먼저 읽으십시오.

  • [인프라 및 전역 설정] context/core.md: main.js, constants.js, 개발/유지보수 공통 규칙.
  • [서버 및 API] context/server.md: Fastify 서버, MongoDB 연동, 방문자 및 사망 통계 API 상세.
  • [아레나 및 카메라] context/arena.md: ArenaScene 오케스트레이션, 지능형 카메라 추적, 미니맵 가이드라인.
  • [전투 엔진] context/combat.md: 전투 AI, 엘리트 피해 판정, 비활성화된 처치 보너스 경로, 슬로우모션 및 월드 이펙트 연출.
  • [캐릭터 및 에셋] context/fighter.md: 캐릭터 공장, 동적 실루엣 생성, 종족 및 특성(Slime 등) 정의.
  • [매치 로직 및 UI] context/match-ui.md: 팀 구성 및 스폰 알고리즘, HUD 레이아웃, 킬로그, 승리 연출 UI.
  • [스타일 및 디자인] context/style.md: CSS 모듈 구조, 디자인 변수, 반응형 및 애니메이션 가이드.

4. 기술 사양

  • Framework: Phaser 3.90.0 (Arcade Physics 기반)
  • Build Tool: Vite 7.1.12
  • Server: Fastify 5.x (@fastify/static, @fastify/middie)
  • Database: MongoDB 7.x Node Driver
  • UI Logic: Vanilla JS & CSS (Flexbox/Grid 활용)

5. 서버/API 설정

  • 개발/운영 서버는 npm run dev 또는 npm start로 실행하며 기본 포트는 config.jsonSERVER_PORT 값인 9736입니다.
  • config.json은 로컬 설정 파일이므로 저장소에 커밋하지 않습니다. 새 환경에서는 config.json.sample을 복사해 사용합니다.
  • 기본 API:
    • GET /api/health: 서버 및 MongoDB 설정 여부 확인.
    • POST /api/visitors/check: 현재 브라우저 방문자를 체크하고 유니크 방문자 수를 반환.
    • GET /api/visitors/stats: 전체 유니크 방문자 수 조회.
    • GET /api/about: 데이터베이스에서 실시간으로 개발자정보와 개인정보처리방침 Markdown 조회 (캐시 없이 즉시 반영).
    • GET /api/death-stats/today: 오늘의 종족별 전투 사망 통계 조회.
    • POST /api/death-stats/today: 종료된 전투의 종족별 사망 수를 오늘 집계에 누적.

6. 관련 문서

  • CONTEXT.md: 상세 개발 가이드 및 핵심 로직 설명 (필독)
  • todo.md: 작업 내역 및 잔여 이슈 관리