Skip to content
Back to skills

Balance

ASecurity

게임 밸런싱 — 장르 프로파일 + 결정론적 시뮬레이터로 병목·인플레·난이도 절벽을 수치로 낸다. 트리거 "밸런스", "경제", "수치", "난이도".

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsbashnode

Works with

  • cli

Security analysis

A100/100

Scanned November 9, 2026

npx -y skills add snwlee/Nereus --skill balance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Balance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Balance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/snwlee-balance/badge)](https://www.skillsdirectory.com/skills/snwlee-balance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: balance
description: 게임 밸런싱 — 장르 프로파일 + 결정론적 시뮬레이터로 병목·인플레·난이도 절벽을 수치로 낸다. 트리거 "밸런스", "경제", "수치", "난이도".
---

# balance

nereus:common 규칙을 따른다. 담당 에이전트: economy-designer.
**엔진과 무관하다** — 로블록스든 Unity든 같은 절차다.

## 왜 시뮬레이터인가

밸런싱을 체크리스트로 하면 게이트가 사람 판단에 의존해 검증이 불가능해진다.
시뮬레이터는 결정론적이라 (1) 회귀 테스트가 성립하고 (2) 수식을 고쳤을 때 무엇이 달라졌는지 보이고
(3) finish 게이트가 "밸런스가 깨졌다"를 기계적으로 판정할 수 있다.

## 1. 장르 프로파일을 먼저 고른다

```js
import { loadProfile, listProfiles } from "../../lib/profiles.mjs";
const profile = loadProfile("casual-puzzle");
```

쓸 수 있는 장르는 `node plugins/nereus-game/lib/profiles.mjs` 로 확인한다. 지금 다섯이다:

| 프로파일 | 주 실패 양상 | 절벽 임계 |
|---|---|---|
| `sim-tycoon` | `bottleneck` | 8 |
| `narrative` | `pacing` | 6 |
| `battle-pvp` | `dominant-strategy` | 4 |
| `obby-platformer` | `cliff` | 3 |
| `casual-puzzle` | `cliff` | 2 |

임계가 장르마다 다르다는 것이 요점이다. 같은 곡선이 오비에서는 초록이고 퍼즐에서는 벽이다.

알 수 없는 장르는 **던진다**. 기본값으로 떨어지지 않는다 — 다른 장르로 밸런싱하면 수치가
그럴듯한 채로 틀리고, 그건 수치가 없는 것보다 나쁘다.

장르가 정하는 것: 핵심 루프(`loop`), 봐야 할 지표(`metrics`), **주 실패 양상**(`balance.failureMode`),
절벽 임계(`balance.cliffRatio`).

## 2. 경제를 데이터로 옮긴다

밸런싱 대상을 `{ income, stages }` 로 정규화한다. 이 형태로 못 옮기면 아직 설계가 안 끝난 것이다.

```js
const economy = {
  income: { base: 10, growth: 1.1 },          // 턴당 기본 수입과 증가 계수
  stages: [{ name: "1단계", cost: 50 }, { name: "2단계", cost: 300 }],
};
```

도메인별로 `stages` 가 뜻하는 것이 다르다 — 타이쿤은 업그레이드 단계, 오비는 구간,
전투는 파워 티어, 진행은 레벨 구간이다. 비용 축만 같으면 된다.

## 3. 돌린다

```js
import { simulate } from "../../lib/balance-sim.mjs";
const r = simulate({ profile, economy, turns: 60, seed: 1 });
```

`seed` 를 고정한다. 같은 입력이면 같은 출력이어야 게이트로 쓸 수 있다.

## 4. 결과를 읽는다

| 지표 | 뜻 | 대응 |
|---|---|---|
| `bottlenecks` | 시뮬 종료까지 **못 깬 단계 이름** | 그 단계 비용을 내리거나, 그 앞에 수입원을 추가한다. 타이쿤의 1순위 |
| `inflation` | 턴당 수입 증가율 − 턴당 비용 증가율 | 양수가 지속되면 후반이 무의미해진다. 비용 곡선을 가파르게 하거나 자원 싱크를 넣는다 |
| `cliffs` | 앞 단계 대비 비용 배수가 `cliffRatio` 를 넘는 단계 인덱스 | 중간 단계를 끼워 넣는다. 오비의 1순위 — 이탈이 여기서 난다 |
| `clearedStages` / `totalStages` | 도달률 | 목표 턴 안에 몇 단계까지 가는가 |

`primaryFailure` 가 `bottleneck` 이면 병목을, `cliff` 면 절벽을 먼저 본다. 장르가 정한다.

## 5. 도메인별 추가 점검

시뮬레이터가 못 보는 축은 사람이 본다. (출처: CCGS `balance-check` 의 판단 기준)

- **전투** — 티어별 DPS·처치 시간, 지배 전략(하나만 쓰면 되는 것)이 있는가
- **경제** — 수도꼭지와 배수구가 짝을 이루는가. 싱크 없는 파우셋은 반드시 인플레를 만든다
- **진행** — 데드존(아무 보상 없이 긴 구간)과 파워 스파이크가 의도된 것인가
- **루트** — 희귀도 분포, 천장(pity) 유무, 인벤토리 압박

## 6. 게이트

수치를 낸 것으로 끝내지 않는다. 기준을 태스크의 완료 조건에 적는다 —
예: "`bottlenecks` 가 비어 있고 `cliffs` 가 2개 이하". 기준 없는 수치는 판정이 아니다.

## 시뮬레이터가 아직 재지 않는 것

시뮬레이터의 실패 축은 셋이다 — 병목·절벽·지배 전략. **캐주얼 퍼즐의 고유 실패인
"수명(에너지) 고갈로 세션이 강제 종료된다"는 이 셋 어디에도 없다.** `casual-puzzle` 로
밸런싱하면 곡선의 벽은 잡히지만 수명 게이트는 잡히지 않는다.

그러니 퍼즐을 볼 때는 시뮬레이터 결과를 "곡선은 통과"로만 읽고, 수명·재시도 경제는
따로 판정한다. 재지 않은 것을 통과로 읽지 않는다 — 그건 기준 없는 초록이다.
네 번째 축을 넣으려면 `balance-sim.mjs` 에 `economy.lives` 입력과 재시도 벽 계산이 필요하다.

## 하지 말 것

- 난수를 `Math.random` 으로 쓰지 않는다. 시드 기반만 쓴다.
- 알 수 없는 장르를 기본 프로파일로 대체하지 않는다.
- 시뮬 결과를 근거 없이 "괜찮아 보인다"로 넘기지 않는다. 임계를 먼저 정한다.

## 확률 아이템은 여기서 끝나지 않는다

경제 설계가 **유료 확률 아이템**(알·펫 뽑기, 상자, 스핀)을 만들면 `nereus-game:compliance` 로 넘긴다.
확률 공개는 **법적 요건**이라 밸런스 판단과 분리한다 — 밸런스는 우리가 정하고, 규정은 남이 정한다.

## 증분·방치형 페이싱 — `sim-tycoon`

시뮬레이터는 병목과 절벽을 본다. 타이쿤·클리커·방치형이 실제로 무너지는 곳은 그 사이다 —
"환생 6이 몇 주 걸린다", "레벨 50 가격이 레벨 0 의 6억 배다", "오프라인이 며칠치를 준다".
셋 다 **수입 없이 설정만으로** 계산되므로 시뮬레이션 전에 판정한다.

```bash
echo '{"genre":"sim-tycoon","config":{
  "upgrades":[{"id":"Income","baseCost":10,"costGrowth":1.15,"maxLevel":40}],
  "rebirth":{"baseRequirement":1e6,"requirementGrowth":1.8,"multiplierPerRebirth":0.5},
  "offline":{"maxHours":8,"efficiency":0.5},
  "peakBalance":1e12}}' | node plugins/nereus-game/lib/economy-curve.mjs
```

JS 에서는 `checkPacing({ profile, config })`. 기준은 프로파일의 `pacing` 이고 지금은 `sim-tycoon` 만 선언한다
(없는 장르는 `no-baseline` — 통과가 아니다).

| 위반 | 뜻 | 대응 |
|---|---|---|
| `rebirth-ratio` | 연속 환생 대기 비율이 범위(x1.2~x1.6) 밖 | 가산 배율이면 비율이 `requirementGrowth` 로 수렴한다 — 그 값이 곧 장기 비율이다. 낮추거나 곱셈 배율(`multiplierGrowth`, 비율 r/q 로 일정)로 바꾼다 |
| `steep-growth` | 여러 번(30+) 사는 업그레이드의 성장 계수가 1.15 초과 | 1.07~1.15. 드물게 사는 큰 업그레이드만 1.5~3 |
| `free-upgrade` | 가격 1 미만 | buy max 루프가 멈추지 않는다 |
| `offline-efficiency` · `offline-cap` | 효율 0.25~0.5 · 상한 8~12시간 밖 | 켜두는 쪽이 늘 낫게, 깨진 타임스탬프가 며칠치를 주지 않게 |
| `precision` | 최대 잔액이 1e15 초과 | 배정밀도 정수 한계(2^53). 가수·지수 쌍이나 log10 으로 저장한다 |

`unmeasured` 에 실린 축(`rebirth`·`offline`·`peakBalance`)은 재지 않은 것이다. 비어 있지 않으면 통과로 읽지 않는다.
큰 수 표기는 `formatNumber` — 반올림을 먼저 해야 `999950` 이 `1000.0K` 가 아니라 `1.0M` 이 된다.
엔진에서의 서버 구현(구매·환생·오프라인을 서버가 소유)은 엔진 스킬이 갖는다 — 로블록스는 `nereus-game:roblox` 의 `references/simulator-economy.md`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.