---
type: tutorial
title: 엔진 키트 engine-kit
summary: 평이한 리듀서에서 적합한 리플레이 run을 내는 선택적 작성 키트로, 결정론, 고정 스텝 루프, 트레이스 인코딩, 그리고 로컬 자체 확인을 당신을 위해 처리합니다.
---

`@caputchin/engine-kit`은 평이한 게임 리듀서를 적합한 [`run`](/docs/marketplace-game-development/replay-contract)으로 바꾸는 선택적 작성 키트로, 결정론, 고정 스텝 루프, 트레이스 인코딩을 당신을 위해 처리합니다. 그것은 그 산출물을 내는 한 편리한 방법일 뿐, 필수가 아닙니다: 당신은 키트를 통째로 무시하고 손으로 쓴 맨 `run`을 낼 수 있습니다. 평범한 게임 로직을 쓰고 결정론, 리플레이 루프, 트레이스 인코딩을 당신을 위해 처리받고 싶을 때 그것으로 손을 뻗으세요.

키트는 전체 [리플레이 계약](/docs/marketplace-game-development/replay-contract) 표면을 다시 export하니, 키트 사용자는 단일 임포트 자리를 가집니다.

```bash
npm install @caputchin/engine-kit
```

## 아이디어: 리듀서를 쓰면, run을 얻는다

키트의 핵심 수는 당신의 게임을 **순수 리듀서**로 표현하게 하는 것입니다: 현재 상태와 한 틱의 입력을 받아 다음 상태를 반환하는 함수. 그 리듀서에 결정론적 프리미티브를 더해, 키트의 `toRun` 어댑터가 구성상 계약에 부합하는 `run(seed, config, trace)`를 냅니다.

```js
import { defineEngine, toRun, cap } from "@caputchin/engine-kit";

const engine = defineEngine({
  setup(seed) {
    const rng = cap.rng(seed);          // deterministic, seeded RNG
    return { score: 0, targets: spawn(rng), rng };
  },
  tick(state, input) {
    // pure: same (state, input) always yields the same next state
    return applyInput(state, input);
  },
  result(state) {
    return { passed: state.score >= 3, score: state.score, durationMs: state.elapsed };
  },
});

export const run = toRun(engine);       // a conforming RunFn
```

## 결정론적 프리미티브

키트는 교차 런타임 결정론을 가장 자주 깨는 두 가지를, 둘 다 시드되고 재현 가능하게 줍니다:

- `cap.rng(seed)`(그리고 `cap.rngFromState`) - 시드 가능한 PRNG. `Math.random()` 대신 모든 무작위 선택에 그것을 쓰세요.
- `cap.math` - 런타임에 걸쳐 일치하는 결정론적 초월 함수(`sin`, `cos`, ...), 그러지 않을 수 있는 플랫폼 `Math`의 것 대신.

## 선택적 심

- `applyShim()` - 비결정론적 글로벌(벽시계, `Math.random`)을 중립화하니, 우연한 호출이 리플레이에서 조용히 갈라지는 대신 개발에서 시끄럽게 실패합니다.
- `applyDomShim()` - 프레임워크 경로를 위한 최소 헤드리스 DOM이니, 작은 DOM 표면을 건드리는 리듀서가 DOM 없는 아이솔레이트에서도 여전히 리플레이됩니다.

## 공개 전에 로컬에서 돌리기

키트의 `replay` 하니스는 서버가 할 것과 같은 방식으로 트레이스를 당신의 엔진에 통과시키고, `selfCheck`는 일련의 케이스를 돌려 어떤 비결정성이든 당신이 공개하기 **전에** 보고합니다:

```js
import { selfCheck } from "@caputchin/engine-kit";

const report = selfCheck(engine, { cases: myCases });
if (!report.ok) console.error(report.violations);
```

깨끗한 로컬 `selfCheck`는 마켓플레이스의 공개 자체 확인이 통과할 것이라는 최고의 예측자입니다(그것은 같은 결정론 기준입니다). 키트는 또한 `package.json` 스크립트나 CI에서 이것을 돌리는 CLI를 냅니다.

## 트레이스 인코딩

`encodeTrace` / `decodeTrace`는 컴팩트하고 버전 지정된 트레이스 형식을 주니, 당신의 라이브 게임이 내는 입력 스트림이 정확히 당신의 `run`이 리플레이에서 디코드하는 것입니다. 양쪽에서 그것들을 쓰면 둘이 록스텝으로 유지됩니다.

## 키트를 건너뛸 때

이미 결정론적 로직이 있거나(고정소수점 시뮬레이션, 스펙 부동소수점용으로 컴파일된 WASM 모듈) 게임이 충분히 단순해 `run`을 손으로 쓰는 게 사소할 때 그것을 건너뛰세요. 플랫폼은 키트가 당신의 `run`을 냈는지 결코 알거나 신경 쓰지 않습니다; 그것은 계약을 로드하고 리플레이만 합니다.

## 함께 보기

- [리플레이 계약](/docs/marketplace-game-development/replay-contract): 이 키트가 내는 `run` / 시드 / 판정.
- [마켓플레이스 게임 빌드하기](/docs/marketplace-game-development/build-a-marketplace-game): 이 키트가 뒷받침할 수 있는 로직의 게임.
- [caputchin.json 매니페스트](/docs/marketplace-game-development/the-caputchin-json-manifest#the-run-artifact): 낸 `run`을 산출물로 내기.
