@ericrisco/rsc 0.1.50 → 0.1.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/manifest.json +17 -17
- package/package.json +1 -1
- package/skills/forecasting/SKILL.md +17 -17
- package/skills/game-storytelling/SKILL.md +14 -39
- package/skills/gamedev-multiplayer/SKILL.md +35 -48
- package/skills/gamedev-pathing/SKILL.md +20 -29
- package/skills/gamedev-shipping/SKILL.md +28 -44
- package/skills/godot/SKILL.md +17 -36
- package/skills/grants/SKILL.md +2 -20
- package/skills/harness/SKILL.md +26 -85
- package/skills/harness/evals/cases.yaml +1 -1
- package/skills/hiring/SKILL.md +14 -26
- package/skills/instagram-api/SKILL.md +12 -22
- package/skills/machine-learning/SKILL.md +21 -53
- package/skills/observability/SKILL.md +2 -4
- package/skills/rag/SKILL.md +21 -38
- package/skills/security-scan/SKILL.md +46 -67
- package/skills/security-scan/references/tools.md +0 -1
- package/skills/security-scan/references/triage.md +0 -1
- package/skills/tauri/SKILL.md +6 -11
- package/skills/webhooks/SKILL.md +17 -34
package/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.52",
|
|
3
3
|
"counts": {
|
|
4
4
|
"skills": 258
|
|
5
5
|
},
|
|
@@ -1802,7 +1802,7 @@
|
|
|
1802
1802
|
},
|
|
1803
1803
|
{
|
|
1804
1804
|
"id": "forecasting",
|
|
1805
|
-
"description": "Use when
|
|
1805
|
+
"description": "Use when projecting history forward — sales, demand, units, revenue, signups, traffic — into a defensible number with an error band: method by data shape, rolling-origin backtest, MASE vs the naive baseline. NOT an assumption-driven P&L or runway model (that is `financial-model`), NOT sizing reorder points or safety stock (that is `inventory`).",
|
|
1806
1806
|
"tags": [
|
|
1807
1807
|
"forecasting",
|
|
1808
1808
|
"demand-planning",
|
|
@@ -1869,7 +1869,7 @@
|
|
|
1869
1869
|
},
|
|
1870
1870
|
{
|
|
1871
1871
|
"id": "game-storytelling",
|
|
1872
|
-
"description": "Use when
|
|
1872
|
+
"description": "Use when a game's story is the work: premise and pillars, branching topology, meaningful choice, dialogue state, quests, environmental storytelling, ludonarrative harmony. Author portable — engine wiring is `godot`/`unity`/`unreal`. NOT the mechanics and economy the story serves (that is `game-design`), NOT level layout (that is `level-design`).",
|
|
1873
1873
|
"tags": [
|
|
1874
1874
|
"game",
|
|
1875
1875
|
"narrative",
|
|
@@ -1889,7 +1889,7 @@
|
|
|
1889
1889
|
},
|
|
1890
1890
|
{
|
|
1891
1891
|
"id": "gamedev-multiplayer",
|
|
1892
|
-
"description": "Use when adding multiplayer
|
|
1892
|
+
"description": "Use when adding multiplayer or netcode to a game — client-server vs P2P, server authority and anti-cheat, state replication vs RPCs, prediction and reconciliation, lag compensation, plus Godot 4 / Unity NGO / Unreal wiring. NOT single-player gameplay (that is `godot`, `unity`, `unreal`), NOT matchmaking or server hosting (that is `deployment`).",
|
|
1893
1893
|
"tags": [
|
|
1894
1894
|
"multiplayer",
|
|
1895
1895
|
"netcode",
|
|
@@ -1910,7 +1910,7 @@
|
|
|
1910
1910
|
},
|
|
1911
1911
|
{
|
|
1912
1912
|
"id": "gamedev-pathing",
|
|
1913
|
-
"description": "Use when
|
|
1913
|
+
"description": "Use when making NPCs, enemies, or units navigate a level — grid vs waypoint vs navmesh, A*/JPS, navmesh baking and agent radius, off-mesh links, steering, RVO crowd avoidance, and flow fields in Godot 4.x, Unity, Unreal. NOT collision response or character controllers (that is gamedev-physics), NOT aggro or difficulty design (that is game-design).",
|
|
1914
1914
|
"tags": [
|
|
1915
1915
|
"pathfinding",
|
|
1916
1916
|
"navmesh",
|
|
@@ -1970,7 +1970,7 @@
|
|
|
1970
1970
|
},
|
|
1971
1971
|
{
|
|
1972
1972
|
"id": "gamedev-shipping",
|
|
1973
|
-
"description": "Use when exporting,
|
|
1973
|
+
"description": "Use when exporting, packaging, signing, or publishing a game — export presets per engine, macOS notarization, cross-origin isolation for threaded web builds, Android AAB/keystore, iOS provisioning, store submission (Steam, Play, App Store, itch.io), headless build CI. NOT gameplay code inside the artifact (that is `godot`, `unity`, `unreal`), NOT hosting a web app or container (that is `deployment`).",
|
|
1974
1974
|
"tags": [
|
|
1975
1975
|
"export",
|
|
1976
1976
|
"build",
|
|
@@ -2103,7 +2103,7 @@
|
|
|
2103
2103
|
},
|
|
2104
2104
|
{
|
|
2105
2105
|
"id": "godot",
|
|
2106
|
-
"description": "Use when writing, reviewing, or debugging Godot 4.x games in GDScript
|
|
2106
|
+
"description": "Use when writing, reviewing, or debugging Godot 4.x games in GDScript or C# — scenes, nodes, custom Resources, autoload/EventBus signals, typed GDScript, CharacterBody2D/3D movement, GUT/gdUnit4 — or porting Godot 3 APIs to 4. NOT Unity/Unreal (that is `unity`/`unreal`), NOT `.gdshader` code (`gamedev-shaders`), NOT GDExtension C++ tooling (`cpp`).",
|
|
2107
2107
|
"tags": [
|
|
2108
2108
|
"godot",
|
|
2109
2109
|
"gdscript",
|
|
@@ -2150,7 +2150,7 @@
|
|
|
2150
2150
|
},
|
|
2151
2151
|
{
|
|
2152
2152
|
"id": "grants",
|
|
2153
|
-
"description": "Use when
|
|
2153
|
+
"description": "Use when pursuing non-dilutive public or foundation funding — money you neither repay nor give equity for: finding a fit call, go/no-go, registration (UEI/PIC/BDNS), or writing the rubric-scored application, logic model, budget justification, or LOI. NOT an equity round (that is `fundraising`), NOT a paying-customer SOW (that is `proposals`).",
|
|
2154
2154
|
"tags": [
|
|
2155
2155
|
"grants",
|
|
2156
2156
|
"subsidies",
|
|
@@ -2170,7 +2170,7 @@
|
|
|
2170
2170
|
},
|
|
2171
2171
|
{
|
|
2172
2172
|
"id": "harness",
|
|
2173
|
-
"description": "Use
|
|
2173
|
+
"description": "Use when governing a workspace's control plane, code or not — the `01-TOOLS/` tooling layer, the `02-DOCS/` chaos→knowledge wiki, the root Knowledge map. Audits it, migrates legacy `XX-*` folders, scaffolds provider tooling, sweeps the inbox, writes root CLAUDE.md/AGENTS.md. NOT the bootstrap front door (that is `init`, which hands off here).",
|
|
2174
2174
|
"tags": [
|
|
2175
2175
|
"harness",
|
|
2176
2176
|
"company",
|
|
@@ -2214,7 +2214,7 @@
|
|
|
2214
2214
|
},
|
|
2215
2215
|
{
|
|
2216
2216
|
"id": "hiring",
|
|
2217
|
-
"description": "Use when
|
|
2217
|
+
"description": "Use when a role is open and you must write the job post, screen inbound candidates, structure the interview loop, or score them to a defensible Hire / On-Hold / No-Hire — including whether an AI résumé filter is legal. NOT after the offer is accepted — onboarding, payroll, performance (that is `people-ops`), NOT offer terms (that is `contracts`).",
|
|
2218
2218
|
"tags": [
|
|
2219
2219
|
"hiring",
|
|
2220
2220
|
"recruiting",
|
|
@@ -2315,7 +2315,7 @@
|
|
|
2315
2315
|
},
|
|
2316
2316
|
{
|
|
2317
2317
|
"id": "instagram-api",
|
|
2318
|
-
"description": "Use when wiring an agent into Instagram's Graph API
|
|
2318
|
+
"description": "Use when wiring an agent into Instagram's Graph API: publishing a Reel through the create/poll/publish container dance, reading per-media insights, checking the 24h publish cap, or ingesting Reel metrics into 02-DOCS/wiki/shortform. NOT TikTok (that is `tiktok-api`), NOT YouTube (that is `youtube-api`), NOT cross-platform cadence (that is `social-publisher`).",
|
|
2319
2319
|
"tags": [
|
|
2320
2320
|
"instagram",
|
|
2321
2321
|
"graph-api",
|
|
@@ -2740,7 +2740,7 @@
|
|
|
2740
2740
|
},
|
|
2741
2741
|
{
|
|
2742
2742
|
"id": "machine-learning",
|
|
2743
|
-
"description": "Use when
|
|
2743
|
+
"description": "Use when predicting a column from rows of tabular features with classic models — scikit-learn pipelines, RandomForest, XGBoost/LightGBM, leak-free cross-validation, metrics for imbalanced classes, or a model that aced CV then collapsed in production. NOT PyTorch neural nets (that is `deep-learning`), NOT cleaning the dirty table first (that is `data-cleaning`), NOT forecasting a dated series (that is `forecasting`), NOT text/token modeling (that is `nlp`).",
|
|
2744
2744
|
"tags": [
|
|
2745
2745
|
"machine-learning",
|
|
2746
2746
|
"scikit-learn",
|
|
@@ -3196,7 +3196,7 @@
|
|
|
3196
3196
|
},
|
|
3197
3197
|
{
|
|
3198
3198
|
"id": "observability",
|
|
3199
|
-
"description": "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts.
|
|
3199
|
+
"description": "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts. NOT outside-in uptime probes, on-call rotation, or who-gets-paged (that is `monitoring`).",
|
|
3200
3200
|
"tags": [
|
|
3201
3201
|
"observability",
|
|
3202
3202
|
"opentelemetry",
|
|
@@ -3662,7 +3662,7 @@
|
|
|
3662
3662
|
},
|
|
3663
3663
|
{
|
|
3664
3664
|
"id": "rag",
|
|
3665
|
-
"description": "Use when building grounded Q&A over your own
|
|
3665
|
+
"description": "Use when building grounded Q&A over your own corpus — chunk, retrieve hybrid, rerank, ground, cite chunk ids, refuse when the sources fall short — or when the right document is retrieved but the answer is still wrong, invented, or unmeasured. NOT operating the store itself — collection schema, HNSW ef_search, quantization (that is `vector-db`).",
|
|
3666
3666
|
"tags": [
|
|
3667
3667
|
"rag",
|
|
3668
3668
|
"retrieval-augmented-generation",
|
|
@@ -4175,7 +4175,7 @@
|
|
|
4175
4175
|
},
|
|
4176
4176
|
{
|
|
4177
4177
|
"id": "security-scan",
|
|
4178
|
-
"description": "Use when
|
|
4178
|
+
"description": "Use when automated scanners drive a security sweep of a repo or app — SAST, dependency/lockfile CVEs, secrets in the tree or git history, IaC misconfig — and the raw output has to become one deduped, exploitability-ranked report CI can gate on. NOT threat-modeling, OWASP design reasoning, or hand-authoring the fix (that is `secure-coding`).",
|
|
4179
4179
|
"tags": [
|
|
4180
4180
|
"security",
|
|
4181
4181
|
"sast",
|
|
@@ -4664,7 +4664,7 @@
|
|
|
4664
4664
|
},
|
|
4665
4665
|
{
|
|
4666
4666
|
"id": "tauri",
|
|
4667
|
-
"description": "Use when building a lightweight cross-platform desktop (or v2 mobile) app with Tauri — a Rust core plus the OS-native WebView
|
|
4667
|
+
"description": "Use when building a lightweight cross-platform desktop (or v2 mobile) app with Tauri — a Rust core plus the OS-native WebView: Rust commands and IPC, streaming to the frontend, the default-deny capabilities/permissions ACL, bundling and signed auto-updates. NOT a Chromium+Node shell needing Node APIs in a main process (that is electron).",
|
|
4668
4668
|
"tags": [
|
|
4669
4669
|
"tauri",
|
|
4670
4670
|
"desktop",
|
|
@@ -5140,7 +5140,7 @@
|
|
|
5140
5140
|
},
|
|
5141
5141
|
{
|
|
5142
5142
|
"id": "webhooks",
|
|
5143
|
-
"description": "Use when building the
|
|
5143
|
+
"description": "Use when building the receiving end of a webhook — a provider-agnostic endpoint that proves pushed events are authentic and never processes one twice: raw-body HMAC, ~5-min replay window, idempotency on the event id, fast-ack-then-queue. NOT the Stripe-Signature scheme (that is stripe), NOT outbound clients you call (that is api-connector-builder).",
|
|
5144
5144
|
"tags": [
|
|
5145
5145
|
"webhooks",
|
|
5146
5146
|
"inbound-webhooks",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: forecasting
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when projecting history forward — sales, demand, units, revenue, signups, traffic — into a defensible number with an error band: method by data shape, rolling-origin backtest, MASE vs the naive baseline. NOT an assumption-driven P&L or runway model (that is `financial-model`), NOT sizing reorder points or safety stock (that is `inventory`)."
|
|
4
4
|
tags: [forecasting, demand-planning, time-series, sales-forecast, statsforecast]
|
|
5
5
|
recommends: [inventory, financial-model, unit-economics, data-cleaning, analyze, duckdb]
|
|
6
6
|
origin: risco
|
|
@@ -51,13 +51,13 @@ When in doubt between two, fit both plus the baseline in one `StatsForecast` run
|
|
|
51
51
|
|
|
52
52
|
The metrics are not decoration — they decide what you ship.
|
|
53
53
|
|
|
54
|
-
- **WAPE, not MAPE.** MAPE divides by the actual, so it explodes and misleads whenever actuals approach zero (constant in SKU and intermittent data). WAPE = total absolute error / total actual volume —
|
|
55
|
-
- **Pair WAPE with bias.** WAPE
|
|
56
|
-
- **MASE < 1.0 is the pass/fail line.** MASE is scale-free
|
|
57
|
-
- **Rolling-origin, never a single holdout.** Time-series CV repeats the train/test split across multiple cutoffs (expanding window),
|
|
58
|
-
- **Always emit an interval.** A point forecast cannot express uncertainty, and point metrics cannot evaluate a distribution. Report `level=[80]` or `[95]`. The interval is not optional polish
|
|
54
|
+
- **WAPE, not MAPE.** MAPE divides by the actual, so it explodes and misleads whenever actuals approach zero (constant in SKU and intermittent data). WAPE = total absolute error / total actual volume — volume-weighted and stable. It is the default magnitude metric.
|
|
55
|
+
- **Pair WAPE with bias.** WAPE is *how big* the error is; bias is the *direction* — whether you systematically over- or under-forecast. A 10% WAPE with +9% bias means you are almost always forecasting high, an actionable problem quite different from random error.
|
|
56
|
+
- **MASE < 1.0 is the pass/fail line.** MASE is scale-free: your error over the naive forecast's error. Below 1.0 you beat naive; at or above it, ship the naive forecast instead. The single most important number in the readout.
|
|
57
|
+
- **Rolling-origin, never a single holdout.** Time-series CV repeats the train/test split across multiple cutoffs (expanding window), a far more reliable estimate than one lucky/unlucky split. Use `cross_validation(h=…, n_windows=…)`.
|
|
58
|
+
- **Always emit an interval.** A point forecast cannot express uncertainty, and point metrics cannot evaluate a distribution. Report `level=[80]` or `[95]`. The interval is half the deliverable, not optional polish.
|
|
59
59
|
|
|
60
|
-
Formulas (WAPE, MASE, bias, pinball, coverage), rolling-origin mechanics, and how to read a backtest table are in `references/accuracy-and-backtesting.md
|
|
60
|
+
Formulas (WAPE, MASE, bias, pinball, coverage), rolling-origin mechanics, and how to read a backtest table are in [`references/accuracy-and-backtesting.md`](references/accuracy-and-backtesting.md). Per-method when-to-use and the exact statsforecast one-liner for each are in [`references/methods-cheatsheet.md`](references/methods-cheatsheet.md).
|
|
61
61
|
|
|
62
62
|
## Minimal pipeline
|
|
63
63
|
|
|
@@ -116,24 +116,24 @@ out.to_csv("forecast.csv", index=False)
|
|
|
116
116
|
- **Structural breaks.** A pricing change, a relaunch, a regime shift. Do not train across the break — train on the post-break segment, even if it is short, or the model averages two different worlds.
|
|
117
117
|
- **Promotions and outliers.** A promo spike is not baseline demand. Mark promo periods and either model them as a regressor or exclude them from the level estimate; otherwise the forecast inherits a spike that will not recur.
|
|
118
118
|
- **Granularity.** Forecast at the level you act on. If you must report higher, aggregate the forecasts — and check the aggregate is plausible (this often catches per-SKU nonsense).
|
|
119
|
-
- **Hierarchy reconciliation.** When SKU forecasts must sum to a category total, reconcile (bottom-up or MinT). Brief note here; the mechanics belong in `references/methods-cheatsheet.md
|
|
119
|
+
- **Hierarchy reconciliation.** When SKU forecasts must sum to a category total, reconcile (bottom-up or MinT). Brief note here; the mechanics belong in [`references/methods-cheatsheet.md`](references/methods-cheatsheet.md).
|
|
120
120
|
|
|
121
121
|
## Anti-patterns
|
|
122
122
|
|
|
123
|
-
|
|
|
123
|
+
| Anti-pattern | Why it bites | Do instead |
|
|
124
124
|
|---|---|---|
|
|
125
|
-
| Report a single point number |
|
|
126
|
-
| Tune ARIMA orders before any baseline |
|
|
127
|
-
| Score with MAPE on intermittent demand |
|
|
128
|
-
| Single train/test holdout |
|
|
129
|
-
| Fit a model on 8 months of monthly data |
|
|
130
|
-
| "The model picked it, so it's right" |
|
|
131
|
-
| Trust SKU forecasts without checking the sum |
|
|
125
|
+
| Report a single point number | A point hides uncertainty the reader needs to plan around. | Report point + 80/95% interval |
|
|
126
|
+
| Tune ARIMA orders before any baseline | If you cannot beat the free baseline, the tuning was wasted. | Compute naive/seasonal-naive first |
|
|
127
|
+
| Score with MAPE on intermittent demand | MAPE explodes near zero actuals and lies about accuracy. | Use WAPE + bias |
|
|
128
|
+
| Single train/test holdout | One split is one sample; CV estimates real out-of-sample error. | Rolling-origin CV (`n_windows≥3`) |
|
|
129
|
+
| Fit a model on 8 months of monthly data | Too few points; the model overfits and underreports its own error. | SeasonalNaive only under 2 cycles |
|
|
130
|
+
| "The model picked it, so it's right" | A forecast you cannot defend is worse than no forecast. | State method + MASE vs naive |
|
|
131
|
+
| Trust SKU forecasts without checking the sum | Per-SKU errors compound; the total exposes nonsense fast. | Sanity-check vs the aggregate |
|
|
132
132
|
|
|
133
133
|
## Handoffs
|
|
134
134
|
|
|
135
135
|
- **`../inventory/SKILL.md`** — feed it the demand number; it sizes reorder points and safety stock. Forecasting produces the demand; it does not size the stock.
|
|
136
136
|
- **`../financial-model/SKILL.md`** — when the projection is driven by *assumptions and drivers* (pricing, hiring), not history, that is a model, not a forecast.
|
|
137
137
|
- **`../unit-economics/SKILL.md`** — contribution margin, CAC/LTV, payback. No time series, route there.
|
|
138
|
-
-
|
|
138
|
+
- **`../data-cleaning/SKILL.md`** — dirty input (dupes, missing rows, mixed units) goes here *before* you model.
|
|
139
139
|
- **`../analyze/SKILL.md`** — when the question is "why" or a backward-looking metric/aggregation rather than forward extrapolation.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: game-storytelling
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when a game's story is the work: premise and pillars, branching topology, meaningful choice, dialogue state, quests, environmental storytelling, ludonarrative harmony. Author portable — engine wiring is `godot`/`unity`/`unreal`. NOT the mechanics and economy the story serves (that is `game-design`), NOT level layout (that is `level-design`)."
|
|
4
4
|
tags: [game, narrative, story, dialogue, quest, branching, worldbuilding]
|
|
5
5
|
recommends: [game-design, level-design]
|
|
6
6
|
profiles: [full]
|
|
@@ -9,23 +9,11 @@ origin: risco
|
|
|
9
9
|
|
|
10
10
|
# Game Storytelling — Narrative Design (engine-agnostic)
|
|
11
11
|
|
|
12
|
-
*Design the story as a system the player operates, not a script they watch. This skill owns the narrative graph — premise, pillars, branches, choices, dialogue state, quests, and the storytelling embedded in the world
|
|
12
|
+
*Design the story as a system the player operates, not a script they watch. This skill owns the narrative graph — premise, pillars, branches, choices, dialogue state, quests, and the storytelling embedded in the world.*
|
|
13
13
|
|
|
14
|
-
You produce **design artifacts**: a premise/theme/pillars doc, a branch topology, a state/flag table, dialogue in a portable format (Ink/Yarn/Twee/articy), quest specs, and environmental beats.
|
|
14
|
+
You produce **design artifacts**: a premise/theme/pillars doc, a branch topology, a state/flag table, dialogue in a portable format (Ink/Yarn/Twee/articy), quest specs, and environmental beats. Story is a **system in service of play**; when you catch yourself designing a great scene the mechanics can't honor, reconcile it (see Ludonarrative harmony) rather than ship the dissonance.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Use when the request is about: a game's story or premise; branching or non-linear narrative; a dialogue system, tree, or conversation logic; quests, objectives, or mission structure; worldbuilding/lore for a game; meaningful choice vs. the illusion of choice; environmental or systemic storytelling; or story that "fights" the gameplay (ludonarrative dissonance).
|
|
19
|
-
|
|
20
|
-
Do NOT use (delegate or decline):
|
|
21
|
-
|
|
22
|
-
- Core loop, verbs, systems, progression, economy, difficulty, or balance → **game-design**.
|
|
23
|
-
- Spatial layout, encounter placement, sightlines, blockout, pacing *of a space* → **level-design**.
|
|
24
|
-
- Implementing the dialogue runner, save/serialize of story state, or wiring Ink/Yarn/articy into a build → the engine skill (**godot/unity/unreal**).
|
|
25
|
-
- Prose fiction, a screenplay, or a novel with no interactive/branching structure → general writing.
|
|
26
|
-
- Marketing copy, store page, or trailer script → **marketing**.
|
|
27
|
-
|
|
28
|
-
Story is a **system in service of play**. When you catch yourself designing a great scene the mechanics can't honor, reconcile it (see Ludonarrative harmony) rather than ship the dissonance.
|
|
16
|
+
Boundaries: **game-design** owns what the player *does* — core loop, verbs, systems, progression, economy, difficulty, balance — and the story serves those verbs; call it when resolving dissonance needs a *mechanic* change, or when designing the conditions for systemic/emergent story. **level-design** owns spatial layout, encounter placement, sightlines, blockout and the pacing *of a space* — the space environmental storytelling lives inside; co-own the set-dressing. **godot / unity / unreal** implement the dialogue runner, quest state, save-serialization of story state, and the Ink/Yarn/articy plugin glue — author portable, they wire it. **marketing** owns the store page, premise pitch and trailer copy (external-facing, not in-game narrative). Prose fiction, a screenplay, or a novel with no interactive/branching structure is general writing, not this skill.
|
|
29
17
|
|
|
30
18
|
## Premise, theme, and pillars (do this first)
|
|
31
19
|
|
|
@@ -119,25 +107,18 @@ Deliver story *through the world* so the player assembles it and feels ownership
|
|
|
119
107
|
- **VO considerations** *(design-side, not recording — that's audio/engine)* — write for the ear (contractions, short clauses); budget line counts early (VO is expensive and near-frozen once recorded); keep a **stable line ID** on every spoken line; don't splice recorded fragments across variables (gender/number/name concatenation breaks in most languages).
|
|
120
108
|
- **Localization-readiness** *(so the loc pipeline can do its job)* — externalize all player-facing text to string tables keyed by stable id; **never concatenate** sentences or embed grammar in code (gender/plural/word-order differ per language — use full templated strings with ICU-style placeholders); allow +30–40% text expansion; keep variables as named tokens (`{playerName}`), not positional; leave translator notes per line.
|
|
121
109
|
|
|
122
|
-
## Anti-patterns
|
|
110
|
+
## Anti-patterns
|
|
123
111
|
|
|
124
|
-
|
|
|
112
|
+
| Anti-pattern | Do instead |
|
|
125
113
|
| --- | --- |
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
| "
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
|
|
135
|
-
## Related skills
|
|
136
|
-
|
|
137
|
-
- **game-design** — the verbs, systems, economy, and balance the story must serve; call it when resolving dissonance needs a *mechanic* change, or when designing systemic/emergent story conditions.
|
|
138
|
-
- **level-design** — the spatial layout and encounter flow environmental storytelling lives inside; co-own set-dressing narrative.
|
|
139
|
-
- **godot / unity / unreal** — the engine that wires the dialogue runner, quest state, save/serialize, and Ink/Yarn/articy plugins. Author portable; they implement.
|
|
140
|
-
- **marketing** — store page, premise pitch, trailer copy (external-facing, not in-game narrative).
|
|
114
|
+
| Branching everything because "players love choices" | Pure trees explode (2^N). Use foldback + gates; reconverge on beats. |
|
|
115
|
+
| A choice that feels huge but no later node reads it back | If no later node reads the flag, the choice is noise. Show the consequence or cut it. |
|
|
116
|
+
| Both options lead to the same scene, and it's sold as a big decision | Fine as expression, not as stakes. Never sell a fake choice as consequential. |
|
|
117
|
+
| Explaining in the story why he's a mass murderer | Words don't beat verbs. Fix the ludonarrative dissonance, don't narrate around it. |
|
|
118
|
+
| Adding an audio log to explain the backstory | Text-dump is the fallback. Try to *show* it environmentally first. |
|
|
119
|
+
| Hardcoding strings, "we'll localize later" | Concatenation and hardcoded text break loc. Externalize to keyed string tables now. |
|
|
120
|
+
| A quest that can't be failed because it's simpler that way | Sometimes right; but soft-locking the game on a missed step is a defect — leave an escape. |
|
|
121
|
+
| Wiring the Ink file into Unity here | Not this skill. Author portable narrative; hand wiring to the engine skill. |
|
|
141
122
|
|
|
142
123
|
## Checklist
|
|
143
124
|
|
|
@@ -151,9 +132,3 @@ Deliver story *through the world* so the player assembles it and feels ownership
|
|
|
151
132
|
- [ ] Environmental/diegetic delivery preferred over text-dumps and non-diegetic narration where the world can carry it.
|
|
152
133
|
- [ ] All player-facing text externalized to keyed string tables; no concatenation; variables are named tokens; +30–40% expansion allowed.
|
|
153
134
|
- [ ] VO lines have stable IDs, are written for the ear, and the script is locked before recording is proposed.
|
|
154
|
-
|
|
155
|
-
## References
|
|
156
|
-
|
|
157
|
-
- `references/branching-and-state.md` — topologies + diagrams, meaningful vs. illusory choice, state modeling, and the combinatorial-explosion containment kit.
|
|
158
|
-
- `references/dialogue-tools.md` — Ink/Yarn/Twine/articy compared, the four primitives, a "pick one" guide, and the same conversation in three formats.
|
|
159
|
-
- `references/environmental-storytelling.md` — show-don't-tell catalog, diegetic vs. non-diegetic delivery, systemic/emergent storytelling and the anecdote factory.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gamedev-multiplayer
|
|
3
|
-
description: "Use when adding multiplayer
|
|
3
|
+
description: "Use when adding multiplayer or netcode to a game — client-server vs P2P, server authority and anti-cheat, state replication vs RPCs, prediction and reconciliation, lag compensation, plus Godot 4 / Unity NGO / Unreal wiring. NOT single-player gameplay (that is `godot`, `unity`, `unreal`), NOT matchmaking or server hosting (that is `deployment`)."
|
|
4
4
|
tags: [multiplayer, netcode, replication, networking, prediction, authority]
|
|
5
5
|
recommends: [godot, unity, unreal, gamedev-physics]
|
|
6
6
|
profiles: [full]
|
|
@@ -14,6 +14,16 @@ topology, put authority in the right place, replicate the right state, and hide
|
|
|
14
14
|
opening the door to cheaters. This skill owns the *networking* decisions; the engine skills own
|
|
15
15
|
the local gameplay those decisions sit on top of.
|
|
16
16
|
|
|
17
|
+
Route elsewhere when the ask is not netcode:
|
|
18
|
+
|
|
19
|
+
| The ask | Route to | Why not here |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| Single-player movement, AI, input, animation, save files | [`godot`](../godot/SKILL.md) / [`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md) | The engine skill owns local gameplay; no network dimension. |
|
|
22
|
+
| Physics determinism, collision, character controllers | [`gamedev-physics`](../gamedev-physics/SKILL.md) | Netcode *consumes* determinism; it does not own the physics fix. |
|
|
23
|
+
| Matchmaking, lobby backend, dedicated-server hosting, relays, DB, game-server CI | [`deployment`](../deployment/SKILL.md) | Running the fleet, not designing the in-game net layer. |
|
|
24
|
+
| Web realtime — chat, presence, a generic WebSocket app | [`webhooks`](../webhooks/SKILL.md) | Not a game world/simulation. |
|
|
25
|
+
| General threat modeling, authz review | [`secure-coding`](../secure-coding/SKILL.md) | This skill keeps only the game-specific anti-cheat controls. |
|
|
26
|
+
|
|
17
27
|
## Version contract — read first
|
|
18
28
|
|
|
19
29
|
Target the current APIs. **Never emit these deprecated / removed APIs:**
|
|
@@ -30,19 +40,6 @@ community UNet-like fork), say so; this skill targets first-party NGO. In NGO 2.
|
|
|
30
40
|
`[ServerRpc]` / `[ClientRpc]` still compile (and enforce `…ServerRpc` / `…ClientRpc` method-name
|
|
31
41
|
suffixes) — cover them but prefer the unified form on new code.
|
|
32
42
|
|
|
33
|
-
## Fires on / When NOT
|
|
34
|
-
|
|
35
|
-
**Fires on:** "how do I sync players", replication, netcode, RPCs, authority, online co-op or PvP,
|
|
36
|
-
"client and server disagree", rubber-banding / teleporting players, prediction & reconciliation,
|
|
37
|
-
lag compensation, tick rate / send rate, spawning networked objects, "the client can cheat".
|
|
38
|
-
|
|
39
|
-
**When NOT (route away):**
|
|
40
|
-
|
|
41
|
-
- Single-player movement, AI, input, animation, save files → the engine skill: `godot`, `unity`, `unreal`.
|
|
42
|
-
- Physics determinism, collision, character controllers → `gamedev-physics` (netcode *consumes* it).
|
|
43
|
-
- Matchmaking service, lobby backend, dedicated-server hosting/orchestration, relays, DB → `deployment`.
|
|
44
|
-
- Web realtime (chat, presence, generic WebSocket app) that is not a game world → `webhooks` / a backend skill.
|
|
45
|
-
|
|
46
43
|
## Topologies & authority
|
|
47
44
|
|
|
48
45
|
Pick the topology first; everything else follows from it.
|
|
@@ -61,7 +58,8 @@ requests), never results. **Never trust the client:** the client cannot set its
|
|
|
61
58
|
score, currency, or hit results — it *asks*, the server *decides*, everyone else *observes*. A client
|
|
62
59
|
that says "I moved to X / I did 40 damage / I have 999 gold" is either lagging or cheating; treat both
|
|
63
60
|
the same. The one thing a client legitimately owns is its own input and, by convention, cosmetic-only
|
|
64
|
-
state. See references/prediction-and-latency.md for how to
|
|
61
|
+
state. See **[references/prediction-and-latency.md](references/prediction-and-latency.md)** for how to
|
|
62
|
+
keep this responsive.
|
|
65
63
|
|
|
66
64
|
## State replication vs RPCs
|
|
67
65
|
|
|
@@ -88,7 +86,7 @@ is the #1 cause of "it works for the host but not the client" bugs.
|
|
|
88
86
|
## The hard problems
|
|
89
87
|
|
|
90
88
|
Latency (round-trip time, RTT) is the enemy; jitter and packet loss make it worse. Four techniques,
|
|
91
|
-
covered in depth in **references/prediction-and-latency.md**:
|
|
89
|
+
covered in depth in **[references/prediction-and-latency.md](references/prediction-and-latency.md)**:
|
|
92
90
|
|
|
93
91
|
1. **Client-side prediction** — the owning client applies its own input *immediately* instead of waiting a
|
|
94
92
|
full RTT for the server, so local movement feels instant.
|
|
@@ -140,7 +138,8 @@ func request_fire(target: Vector3) -> void:
|
|
|
140
138
|
- `MultiplayerSynchronizer` streams a chosen property list (position, etc.) from the authority to peers;
|
|
141
139
|
set its replication interval and visibility (`set_visibility_for(peer, bool)`) to scope bandwidth.
|
|
142
140
|
- `MultiplayerSpawner` replicates instancing of scenes under a path so late peers get existing objects.
|
|
143
|
-
- Details, prediction wiring, and the full player-scene pattern:
|
|
141
|
+
- Details, prediction wiring, and the full player-scene pattern:
|
|
142
|
+
**[references/godot-high-level-multiplayer.md](references/godot-high-level-multiplayer.md)**.
|
|
144
143
|
|
|
145
144
|
### Unity — Netcode for GameObjects
|
|
146
145
|
|
|
@@ -168,7 +167,8 @@ public class Player : NetworkBehaviour {
|
|
|
168
167
|
- `NetworkVariable<T>(value, readPerm, writePerm)` — `NetworkVariableWritePermission.Server` (default) vs
|
|
169
168
|
`.Owner`; subscribe via `OnValueChanged`. Use `NetworkTransform` for pos/rot sync.
|
|
170
169
|
- Prefer the unified `[Rpc(SendTo.X)]`; legacy `[ServerRpc]`/`[ClientRpc]` still work but need the
|
|
171
|
-
method-name suffixes. Full patterns:
|
|
170
|
+
method-name suffixes. Full patterns:
|
|
171
|
+
**[references/unity-and-unreal-netcode.md](references/unity-and-unreal-netcode.md)**.
|
|
172
172
|
|
|
173
173
|
### Unreal — Actor replication
|
|
174
174
|
|
|
@@ -196,7 +196,8 @@ void AMyPawn::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const {
|
|
|
196
196
|
- **Relevancy** keeps bandwidth sane: `NetCullDistanceSquared`, `bAlwaysRelevant`, `IsNetRelevantFor`, and
|
|
197
197
|
dormancy (`SetNetDormancy`) stop replicating actors a client can't perceive. Movement replicates via
|
|
198
198
|
`CharacterMovementComponent`, which already does prediction+reconciliation for you.
|
|
199
|
-
- RepNotify vs Multicast, GAS/Network Prediction notes:
|
|
199
|
+
- RepNotify vs Multicast, GAS/Network Prediction notes:
|
|
200
|
+
**[references/unity-and-unreal-netcode.md](references/unity-and-unreal-netcode.md)**.
|
|
200
201
|
|
|
201
202
|
## Security / anti-cheat basics
|
|
202
203
|
|
|
@@ -219,32 +220,18 @@ void AMyPawn::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const {
|
|
|
219
220
|
- Always test **with simulated latency and packet loss**, not just on localhost — localhost hides every
|
|
220
221
|
prediction/reconciliation bug. Test the client path, not only the host's.
|
|
221
222
|
|
|
222
|
-
##
|
|
223
|
-
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
- **`deployment`** — dedicated-server hosting, matchmaking/lobby backend, relays, and CI for game servers.
|
|
238
|
-
- **`secure-coding`** — general threat modeling; this skill keeps only the game-specific anti-cheat controls.
|
|
239
|
-
|
|
240
|
-
## Checklist
|
|
241
|
-
|
|
242
|
-
- [ ] Topology chosen (dedicated / listen / P2P) and the *same code* runs on server and listen host.
|
|
243
|
-
- [ ] Server-authoritative: clients send intent only; server validates and owns all gameplay state.
|
|
244
|
-
- [ ] Each networked value is either replicated (state/nouns) or an RPC (events/verbs) — not the wrong one.
|
|
245
|
-
- [ ] Ownership/authority set explicitly per object; authority-only logic guarded on the host.
|
|
246
|
-
- [ ] Owning-client movement predicted + reconciled; remote entities snapshot-interpolated.
|
|
247
|
-
- [ ] Hitscan uses server-side lag compensation; simulation on a fixed tick, decoupled from render FPS.
|
|
248
|
-
- [ ] Only need-to-know state replicated per client (relevancy/visibility scoped); RPCs rate-limited.
|
|
249
|
-
- [ ] Tested with simulated latency + packet loss across multiple instances, exercising the client path.
|
|
250
|
-
- [ ] No banned APIs (UNet/HLAPI, Godot 3.x `master`/`puppet`/`rset`, `Tick`-polled Unreal replication).
|
|
223
|
+
## Anti-patterns
|
|
224
|
+
|
|
225
|
+
| Anti-pattern | Why it bites | Do instead |
|
|
226
|
+
| --- | --- | --- |
|
|
227
|
+
| Writing net code before the topology is chosen | Authority and cost model change everything downstream | Pick dedicated / listen / P2P first, and make the *same code* run on server and listen host |
|
|
228
|
+
| Trusting a client-reported result (health, position, score, hit) | That is the cheat surface, and lag looks identical to cheating | Clients send intent only; the server validates and owns all gameplay state |
|
|
229
|
+
| RPCing state that must stay consistent | A dropped unreliable event desyncs that client permanently | Replicate nouns (state), RPC verbs (events) — replicated values self-correct |
|
|
230
|
+
| Ownership/authority left implicit | The #1 cause of "works for the host, breaks for the client" | Set authority/ownership explicitly on spawn |
|
|
231
|
+
| Forgetting the listen-server host is also a client | Authority-only logic double-executes on the host | Guard it behind `is_server()` / `HasAuthority()` |
|
|
232
|
+
| Making the owning client wait a full RTT for its own input | Movement feels sluggish and unresponsive | Predict locally + reconcile; snapshot-interpolate remote entities |
|
|
233
|
+
| Client-side hit detection for hitscan | Trivially spoofed, and unfair to the higher-ping shooter | Server-side lag compensation: rewind to the shooter's render time |
|
|
234
|
+
| Tying simulation to render FPS | Sim diverges between machines at different frame rates | Fixed timestep on the sim, interpolate on the render |
|
|
235
|
+
| Replicating everything, every tick, to everyone | Melts bandwidth and leaks wallhack fuel | Scope by relevancy/visibility and send rate; rate-limit RPCs |
|
|
236
|
+
| Testing only on localhost | 0 ms RTT masks the exact desync/rubber-band bugs players will hit | Inject latency + packet loss across instances, exercising the client path |
|
|
237
|
+
| Emitting UNet/HLAPI, Godot 3.x `master`/`puppet`/`rset`, or `Tick`-polled Unreal replication | Removed or legacy — it will not compile or will silently underperform | The current APIs in the version contract above |
|