CoolFace
Apppublic

blanchon/opencs2-dataset-viewer

sourceHugging Facemitupdated 4mo agoView on Hugging Face
8likes
App README

OpenCS2 Dataset - Viewer

[image]

Browser for `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`, preview MP4s stream from Hugging Face, and 10 chunked players stay in sync through a custom `mediabunny` pipeline.

Links

  • Dataset: <https://huggingface.co/datasets/blanchon/cs2datasetrender>
  • Live viewer (HF Space): <https://huggingface.co/spaces/blanchon/opencs2-dataset-viewer>
  • Source dataset (raw demos): <https://huggingface.co/datasets/blanchon/cs2datasetdemo>
  • GitHub: <https://github.com/julien-blanchon/opencs2-dataset>
  • Author: Julien Blanchon@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:

ConfigRowUse
previews (default)One low-res preview.mp4 per chunk + 1 Hz inputs/world sidecarsCheap browsing, viewer, sanity checks
chunksPath-only references to video.mp4 + audio.wav, with embedded inputs/world streamsFull-resolution training
matchesOne row per (match_id, map_name) with team/event/date metadataIndex / filtering
roundsOne row per (match_id, map_name, round) with tick boundariesIndex / filtering

Filesystem layout

text
index/
  manifest-<machine>-<uuid>.parquet     # matches index
  rounds-<machine>-<uuid>.parquet       # rounds index
data/
  match_id=<id>/map_name=<map>/player=<0-9>/
    chunks-preview-<machine>-<uuid>.parquet
    chunks-full-<machine>-<uuid>.parquet
    chunks/chunk_<n>/{video.mp4,audio.wav}
    previews/chunk_<n>/{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.