---
id: wiki-2026-0508-skybound-skill-slot-limit-weapon5-passive5
title: Skybound Skill Slot Limit Weapon 5 Passive 5
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Skill Slot Cap, 5+5 Build Constraint, Skybound Build Limit]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [skybound, build, slots, balance, game-design]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: skybound-engine
---

# Skybound Skill Slot Limit Weapon 5 Passive 5

## 매 한 줄
> **"매 build constraint = creative pressure"**. 5 weapon + 5 passive cap 은 player 의 every choice 를 meaningful 하게 — unlimited 면 평균화, limited 면 build identity. 매 vampire-survivors-genre 의 canonical structure 의 Skybound adaptation.

## 매 핵심

### 매 디자인 의도
- **Decision pressure**: 6번째 offer 시 swap-or-skip 의 active choice.
- **Build identity**: 5+5 슬롯 = recognizable archetype (DPS, support, tank, etc.).
- **Evolution gates**: weapon + passive pair → evolved form. cap 이 evolution 의 prerequisite scaffolding.
- **Run length pacing**: cap reached 시점이 mid-run pivot.

### 매 enforcement
- UI affordance: full slot → "replace?" modal.
- Server-side validation: client-trusted slot count 의 X.
- Save-state schema: fixed-size arrays of length 5.

### 매 응용
1. Skybound weapon/passive system.
2. Roguelite build crafting.
3. Generic inventory cap pattern.

## 💻 패턴

### Slot data model
```typescript
const MAX_WEAPONS = 5;
const MAX_PASSIVES = 5;
interface PlayerBuild {
  weapons: (WeaponInstance | null)[]; // length === MAX_WEAPONS
  passives: (PassiveInstance | null)[]; // length === MAX_PASSIVES
}
function emptyBuild(): PlayerBuild {
  return {
    weapons: Array(MAX_WEAPONS).fill(null),
    passives: Array(MAX_PASSIVES).fill(null),
  };
}
```

### Add-or-upgrade resolution
```typescript
function applyOffer(build: PlayerBuild, offer: Upgrade): "added" | "leveled" | "needs_replace" {
  const slots = offer.kind === "weapon" ? build.weapons : build.passives;
  const existingIdx = slots.findIndex((s) => s?.id === offer.id);
  if (existingIdx >= 0) {
    slots[existingIdx]!.level += 1;
    return "leveled";
  }
  const emptyIdx = slots.findIndex((s) => s === null);
  if (emptyIdx >= 0) {
    slots[emptyIdx] = newInstance(offer);
    return "added";
  }
  return "needs_replace";
}
```

### Replace flow
```typescript
function replaceSlot(
  build: PlayerBuild,
  kind: "weapon" | "passive",
  index: number,
  offer: Upgrade,
): void {
  const slots = kind === "weapon" ? build.weapons : build.passives;
  if (index < 0 || index >= slots.length) throw new Error("bad slot");
  // optionally: track replaced item for telemetry / refund
  metrics.increment(`build.replaced.${slots[index]?.id ?? "empty"}`);
  slots[index] = newInstance(offer);
}
```

### Offer pool with slot awareness
```typescript
function rollOffer(build: PlayerBuild, level: number): UpgradeId[] {
  const owned = new Set([
    ...build.weapons.filter(Boolean).map((w) => w!.id),
    ...build.passives.filter(Boolean).map((p) => p!.id),
  ]);
  const weaponsFull = build.weapons.every((w) => w !== null);
  const passivesFull = build.passives.every((p) => p !== null);
  const eligible = ALL_UPGRADES.filter((u) => {
    if (owned.has(u.id) && !u.canLevel) return false;
    if (u.kind === "weapon" && weaponsFull && !owned.has(u.id)) return false;
    if (u.kind === "passive" && passivesFull && !owned.has(u.id)) return false;
    return u.minLevel <= level;
  });
  return sampleN(eligible, 3);
}
```

### Evolution gate check
```typescript
function checkEvolutions(build: PlayerBuild): EvolutionId[] {
  return EVOLUTIONS.filter((evo) => {
    const w = build.weapons.find((s) => s?.id === evo.weaponId);
    const p = build.passives.find((s) => s?.id === evo.passiveId);
    return w && w.level >= w.maxLevel && p !== undefined;
  }).map((evo) => evo.id);
}
```

### Save-state validator (Zod)
```typescript
import { z } from "zod";
const BuildSchema = z.object({
  weapons: z.array(WeaponSchema.nullable()).length(MAX_WEAPONS),
  passives: z.array(PassiveSchema.nullable()).length(MAX_PASSIVES),
});
```

## 매 결정 기준
| 상황 | 슬롯 cap |
|---|---|
| Vampire-survivors clone | 6+6 (canonical) or 5+5 (tighter) |
| Skybound | **5+5** — pacing fits 15-min runs |
| Deck-builder | no slot cap (deck size = cap) |
| Hero shooter | per-class fixed slots |

**기본값**: 5+5 with replace modal + evolution gate.

## 🔗 Graph
- 응용: [[Skybound Knowledge Hub]]

## 🤖 LLM 활용
**언제**: roguelite slot / build cap design + offer pool integration 시.
**언제 X**: open-ended sandbox (Minecraft 류) — slot cap 이 antipattern.

## ❌ 안티패턴
- **Soft cap (warn only)**: player 가 cap 무시 → balance breaks.
- **Client-only enforcement**: cheat vector.
- **Variable cap mid-run**: build planning 의 ruin.
- **No replace UI**: cap 도달 시 offer 가 dead → frustration.

## 🧪 검증 / 중복
- Verified (Skybound design doc 2026-04-26 + Vampire Survivors 6+6 reference).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-04-26 | Original design note |
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — FULL spec rewrite with slot system patterns |
