Install
openclaw skills install demo-slapGenerate CS2 highlights and fragmovies from demos using the Demo-Slap API, with optional Leetify integration and Demo-Slap match history fallback to select recent matches. Use when a user asks to record a highlight, render a clip, make a fragmovie, clip a round, or turn a CS2 demo into MP4 video.
openclaw skills install demo-slapGenerate MP4 highlights and fragmovies from CS2 demos.
This skill is designed for OpenClaw environments where background jobs, local helper scripts, and chat-aware delivery are available. It uses Python 3 scripts and the requests package for HTTP API access.
Expected runtime inputs:
DEMOSLAP_API_KEYLEETIFY_API_KEYDEMO_SLAP_WATCHDOG_JOB_IDRun bundled scripts relative to the skill root, usually from scripts/.
| Script | Purpose |
|---|---|
demo_slap_matches.py | List recent matches from Demo-Slap /public-api/matches |
demo_slap_resolve.py | Try to resolve replay/demo URL from Demo-Slap match history by index; fail clearly if the API exposes only jobId |
demo_slap_match_pick.py | Pick a Demo-Slap match by index and return structured match info including jobId |
demo_slap_analyze.py | Submit a demo for analysis, poll until done, output highlights JSON |
demo_slap_render.py | Render one or more highlights, poll until done, output clip URL |
demo_slap_common.py | Shared utilities (config, API calls, state) |
| Script | Purpose |
|---|---|
leetify/leetify_matches.py | List recent matches |
leetify/leetify_resolve.py | Resolve replay URL by username + match index |
leetify/leetify_save_id.py | Save username -> Steam64 ID mapping |
leetify/leetify_common.py | Shared Leetify utilities |
LEETIFY_API_KEY is available.LEETIFY_API_KEY is not configured but DEMOSLAP_API_KEY is available, use Demo-Slap match history from /public-api/matches.https://api-doc.demo-slap.net/Use these files as optional local runtime state during execution:
data/state.jsondata/highlights.jsondata/history.logdata/steam_ids.jsondata/config.jsonThese files are runtime helpers for local operation and are not required to understand or inspect the skill package itself.
state.json tracks the current operation:
{
"status": "idle|analyzing|rendering|done|error",
"job_id": "...",
"render_job_id": "...",
"chat_id": "telegram:182314856",
"clip_urls": {"highlight_id": "https://..."},
"progress": "polling 3/30",
"last_completed_op": "analyze|render",
"notification": {
"sent": false,
"sent_at": null,
"last_attempt_at": null,
"error": null
},
"updated_at": "ISO timestamp"
}
Preferred path when LEETIFY_API_KEY is available:
python3 scripts/leetify/leetify_matches.py <USERNAME> [--limit 10]
Fallback path when LEETIFY_API_KEY is missing but DEMOSLAP_API_KEY is available:
python3 scripts/demo_slap_matches.py [<USERNAME>] [--limit 10]
/public-api/matcheshttps://api-doc.demo-slap.net/ if schema details are needed<USERNAME> is provided and mapped, filter matches to that player's Steam ID when possiblepython3 scripts/demo_slap_match_pick.py [<USERNAME>] --match-index <N>
jobId as the primary handle for downstream Demo-Slap operationsPreferred path when using Leetify:
python3 scripts/leetify/leetify_resolve.py <USERNAME> --match-index <N>
When using Demo-Slap fallback:
python3 scripts/demo_slap_match_pick.py [<USERNAME>] --match-index <N>
jobId as the selected match identifierdemoUrl is present, you may still use analyze-by-URLdemoUrl is absent, skip URL resolution and continue by API endpoints that accept the existing analyze jobIdGET /public-api/analyze/{jobId}/status and GET /public-api/analyze/{jobId}/data to inspect existing highlightsjobIdpython3 -u scripts/demo_slap_analyze.py --url '<REPLAY_URL>' --username <USERNAME> --chat-id <CHAT_ID>
Run with exec(background: true) and keep the returned process/session id.
Optional deployment-specific watchdog pattern for OpenClaw environments:
cron tool, keep it scoped to the active run and disable it again after terminal delivery.scripts/demo_slap_watchdog.sh status|tail|job only as a local helper for inspecting runtime state, logs, or deployment-specific job references.data/state.json and data/highlights.json as the source of truth during runtime.Agent workflow:
LEETIFY_API_KEY exists/public-api/matches if LEETIFY_API_KEY is missing and DEMOSLAP_API_KEY existsjobIdjobId instead of forcing analyze-by-URL# Single highlight
python3 -u scripts/demo_slap_render.py <JOB_ID> <HIGHLIGHT_ID> --chat-id <CHAT_ID>
# Fragmovie
python3 -u scripts/demo_slap_render.py <JOB_ID> <ID1> <ID2> ... --fragmovie --chat-id <CHAT_ID>
Run with exec(background: true) and keep the returned process/session id.
Optional deployment-specific watchdog pattern for OpenClaw environments:
cron tool, keep it scoped to the active run and disable it again after terminal delivery.scripts/demo_slap_watchdog.sh status|tail|job only as a local helper for inspecting runtime state, logs, or deployment-specific job references.data/state.json and data/highlights.json as the source of truth during runtime.Agent workflow:
Estimated finish: line and tell the user the ETA if presentCritical: set <CHAT_ID> from inbound metadata of the originating request. Treat hardcoded chat identifiers as local examples only, not as a reusable default.
Read data/state.json.
python3 scripts/leetify/leetify_save_id.py <USERNAME> <STEAM_64_ID>
Prefer environment variables:
DEMOSLAP_API_KEY - requiredLEETIFY_API_KEY - optional, only for Leetify-backed match discoveryDEMO_SLAP_WATCHDOG_JOB_ID - optional deployment-specific helper for watchdog inspection scriptsSource selection rules:
LEETIFY_API_KEY exists, use Leetify for match discovery.LEETIFY_API_KEY is absent but DEMOSLAP_API_KEY exists, use Demo-Slap /public-api/matches for match discovery.DEMOSLAP_API_KEY is always required for analyze/render.Optional local fallback for controlled self-hosted setups: put them in data/config.json.
For access and support, please join our Discord community: https://discord.gg/8nfh26W9wQ