--- title: OpenCS2 Dataset - Viewer emoji: 🎯 colorFrom: yellow colorTo: gray sdk: docker app_port: 7860 pinned: false license: mit short_description: Browse the CS2 dataset by match, map, round, and POV. --- # OpenCS2 Dataset - Viewer ![OpenCS2 Dataset — 10 tick-aligned player POVs, inputs, world state, and audio, built from professional HLTV demos.](static/header.webp) Browser for [`blanchon/cs2_dataset_render`](https://huggingface.co/datasets/blanchon/cs2_dataset_render), the OpenCS2 dataset: a rendered Counter Strike 2 dataset built from professional HLTV demos. The viewer lists every match, map, and round in the dataset and plays the 10 synchronized player POVs back-to-back on a single timeline — without downloading the full archive. It's a pure-frontend SvelteKit app: parquet indexes are read in the browser via [`hyparquet`](https://github.com/hyparquet/hyparquet), preview MP4s stream from Hugging Face, and 10 chunked players stay in sync through a custom [`mediabunny`](https://mediabunny.dev/) pipeline. ## Links - **Dataset:** - **Live viewer (HF Space):** - **Source dataset (raw demos):** - **GitHub:** - **Author:** [Julien Blanchon](https://guybrush.ink/) — [@JulienBlanchon](https://x.com/JulienBlanchon) ## Motivation Counter Strike 2 is an interesting environment for sequential decision-making: long horizons, partial observability, dense visual signal, spatialized audio, 5 vs 5 multi-agent dynamics, and a competitive equilibrium that is genuinely hard. Pro HLTV demos give us tens of thousands of hours of expert play, but until now they've lived in a binary `.dem` format that is not directly trainable. This dataset turns those demos into rendered, frame-accurate, fully-annotated training data. A few of the things it makes tractable: - **Behaviour cloning / VLA policies.** `(frame, audio) → action` for vision-conditioned action models. - **Inverse Dynamics Models (IDM).** `(frame_t, frame_{t+k}) → action` to recover actions from unlabelled video — the workhorse for VPT-style pre-training. - **Forward dynamics / world models.** `(frame, action) → frame_{t+1}` with all 10 player POVs of the same world state available as supervision. - **Spatial-audio conditioning.** Per-player stereo recorded relative to each agent's position and orientation, so models can learn to localize footsteps, gunfire, and callouts. - **Multi-agent training.** All 10 perspectives of the same round are kept aligned tick-for-tick — useful for collaborative policies, opponent modelling, and multi-player world models. - **Multi-view SfM / depth benchmark.** Ground-truth camera intrinsics and metric depth maps from 10 synchronized viewpoints make this a clean reference for structure-from-motion, multi-view stereo, and camera pose estimation. ## What's recorded For every chunk (≤ 1 minute, one player POV): - **Video** — 1280×720 @ 32 fps, near-lossless H.264. One stream per player; ten POVs per round all tick-aligned. - **Audio** — per-player stereo, mixed from each agent's position and orientation (footsteps, gunfire, callouts). - **Inputs** — every tick: keyboard state, mouse delta, fire/jump/use, weapon switches. - **World state** — every tick, for all 10 players: position, velocity, view yaw/pitch, camera intrinsics, health, armor, ammo, primary/secondary weapon, alive flag. - **G-buffers (coming soon)** — per-pixel luminance, depth map, and vertex-ID map for self-supervised pretraining and dense prediction heads. - **Tick-perfect alignment** — every signal is sampled on the same CS2 tick clock. No drift, no resampling artifacts, no per-stream timestamp reconciliation. ## Dataset `blanchon/cs2_dataset_render`, derived from `blanchon/cs2_dataset_demo`. Licensed under `CC-BY-4.0`. Each row is a one-minute-or-shorter chunk of a single player's POV. Four configs are exposed: | Config | Row | Use | | -------------------- | ------------------------------------------------------------------------------------- | ------------------------------------- | | `previews` (default) | One low-res `preview.mp4` per chunk + 1 Hz inputs/world sidecars | Cheap browsing, viewer, sanity checks | | `chunks` | Path-only references to `video.mp4` + `audio.wav`, with embedded inputs/world streams | Full-resolution training | | `matches` | One row per `(match_id, map_name)` with team/event/date metadata | Index / filtering | | `rounds` | One row per `(match_id, map_name, round)` with tick boundaries | Index / filtering | ### Filesystem layout ```text index/ manifest--.parquet # matches index rounds--.parquet # rounds index data/ match_id=/map_name=/player=<0-9>/ chunks-preview--.parquet chunks-full--.parquet chunks/chunk_/{video.mp4,audio.wav} previews/chunk_/{preview.mp4,inputs.preview.json,world.preview.jsonl} ``` Hive-style `key=value` partitioning lets you prune at the path level. Recording starts at `freeze_end_tick` and stops at the player's death tick (or round end for survivors), so player streams have different durations within the same round. ### Quick query ```python from datasets import load_dataset # Default lightweight preview rows previews = load_dataset("blanchon/cs2_dataset_render", split="train", streaming=True) # Full training rows, columnar load chunks = load_dataset( "blanchon/cs2_dataset_render", "chunks", split="train", streaming=True, columns=["video", "audio", "inputs", "worlds", "match_id", "round", "player"], filters=[("player", "==", 0)], ) ``` ```sql -- Match index via DuckDB SELECT match_id, map_name, team1, team2, event, match_date FROM 'hf://datasets/blanchon/cs2_dataset_render/index/manifest-*.parquet' LIMIT 20; ``` ## Develop ```sh bun install bun run dev # vite dev server bun run build # static build → dist/ bun run preview # serve the build bun run check # svelte-check ``` The repo ships a `Dockerfile` and `serve.ts` that mirror the Hugging Face Space deployment. ### Build flags - `PUBLIC_DISABLE_EVAL=1` — hide the evaluation surface (header toggle, eval bar, flag dialog) for public deploys. Set at build time only (`PUBLIC_DISABLE_EVAL=1 bun run build`); the eval module stays in the bundle but is never rendered. ## Viewer internals - **`hyparquet` + `hyparquet-compressors`** read the match and round parquet shards directly from `hf://` URLs. No server, no DuckDB, no WASM bundle larger than necessary. - **`mediabunny`** powers the 10 chunked POV players. One round's worth of `preview.mp4` chunks per player is concatenated into a single virtual timeline; players who died early have shorter timelines and gracefully fall out. - **`world.preview.jsonl`** drives the minimap (player positions, team, alive/dead, weapon) and the per-tick state overlay. - **`inputs.preview.json`** drives the input-overlay HUD (movement keys, mouse, fire/jump). The whole viewer is a static SvelteKit build — there is no backend. ## Citation ```bibtex @misc{blanchon2026opencs2, author = {Julien Blanchon}, title = {OpenCS2 Dataset}, year = {2026}, publisher = {Hugging Face}, howpublished = {\url{https://github.com/julien-blanchon/opencs2-dataset}}, } ``` ## License Code: MIT. Dataset: CC-BY-4.0.