Elemental Sandbox
이펙트가 가장 안 값나갑니다. 가져올 규칙은 하나 — 기록은 무차원으로, 치수는 매 프레임 해석.
이펙트 코드는 한 줄도 안 가져왔는데, 규칙 한 문장이 제 코드 43곳의 성격을 정했습니다. 이 레포의 화려한 부분은 웹 전용이라 제 엔진으로 안 넘어옵니다. 넘어온 건 “인스턴스는 seed와 비율만 기억하고, 미터·초·라디안은 매 프레임 설정에서 다시 계산한다” 한 줄입니다. 그리고 그 자로 제 프로젝트를 재보니 — 정확히 반대로 짜여 있었습니다.
무엇을 만든 것인가
브라우저에서 도는 스킬샷 이펙트 놀이터다. 캐릭터가 바닥에 서 있고, 키로 스킬을 뽑으면 지면 조준 표시가 마우스를 따라 움직이고, 클릭하면 발사된다. 게임이 아니다 — 적도 체력도 없다. 목적은 “이펙트를 눈으로 보면서 숫자를 만지는 것” 하나다.
그리고 간판 주장이 사실이었다. “전부 코드로 생성” — 클론해서 전수 확인하니 바이너리는 열 개뿐이고 그중 이펙트용이 하나도 없다. 스프라이트시트도, 플립북도, 이펙트 텍스처도 0개다.
| 무엇 | 어떻게 만들었나 |
|---|---|
| 얼음 결정 | 절차적 지오메트리 |
| 번개 | 버텍스 셰이더가 배치하는 리본 스트립 한 장 |
| 운석 | CPU에서 파쇄면으로 깎은 구체 |
| 빔 | 반지름 셋으로 세 번 그린 파라메트릭 튜브 |
| 조준선·화상·용암 균열 | 전부 거리장 + 노이즈 셰이더 |
| 안개·불티·파편 | GPU 파티클 — 실루엣도 절차적 |
런타임 의존성이 두 개다. 그리고 레포 나이가 5일, 커밋 18개, 기여자 1명이다.
왜 일시정지 중에 슬라이더가 먹히나
위 도판의 셋이 동시에 성립하기 때문인데, 두 번째가 핵심이다. 얼음 가시 하나가 기억하는 것에 미터도 라디안도 초도 없다. 직선 위 위치가 비율이고, 좌우 오프셋이 비율이고, 나머지는 난수 몇 개다. 저장하는 유일한 실단위는 “발생 시각” — 그건 치수가 아니라 사건이라서다.
그러니 매 프레임 update()가 설정 객체에 대고 다시 곱한다. 높이 슬라이더를 당기면 이미 서 있는 얼음밭이 다시 자란다.
표현 못 하는 값의 예외 처리도 좋다. 면 개수나 휘어짐처럼 위치·크기 곱하기로 표현할 수 없는 파라미터 넷은 지오메트리에 구워야 해서, 보통은 “재시작해야 반영되는 상수”가 된다. 저자는 그 넷만 문자열 키로 해싱해서 바뀔 때만 통째로 다시 만들고, 인스턴스의 seed와 발생 시각은 그대로 옮겨 태운다 — 모양은 새로, 정체성은 유지.
그리고 주석에 판단 근거가 적혀 있다. “결정 하나가 108삼각형이라 근사하느니 그냥 다시 만드는 게 싸다.” 비싸서 못 하던 걸 비용을 실제로 재보고 뚫은 사례다.
직접 돌려서 확인했다
문서를 믿지 않고 클론해서 로컬에서 돌렸다. 브라우저 창이 화면에 안 떠 있으면 프레임을 안 그려서 캡처가 계속 실패했는데 — 프레임 루프를 고정 스텝으로 직접 호출하는 방식으로 우회했다. 부수 효과로 결정론적 타임스텝을 얻었고, 그래서 아래 검증이 가능해졌다.
얼음을 쏘고 54프레임 진행한 뒤 일시정지하고, 시간을 1틱도 안 흘린 채 설정값 셋만 바꿔 세 프레임을 더 그렸다.
| 경과 시각 | 높이 | 기울기 | |
|---|---|---|---|
| BEFORE | 13.95 | 3.1 | 0.42 |
| AFTER | 13.95 (동일) | 7.44 | 0.97 |
주장은 참이었다. 경과 시각이 완전히 같은데 이미 서 있던 결정들이 더 높이 자라고 바깥으로 기울었다. 연기 기둥과 눈송이 입자와 캐릭터 포즈는 픽셀 단위로 그대로다 — 시뮬레이션이 다시 돈 게 아니라 같은 순간을 새 치수로 다시 해석한 것이다. 드로우콜도 두 프레임 모두 115로 같았다.
그리고 실측이 자기신고와 갈렸다. 대기 상태 드로우콜은 32로 일치했는데, 얼음밭이 서 있을 때는 제 쪽이 95~115로 자기신고(~69)보다 높았다. 캡처 시점과 해상도 차이다 — 자기신고를 그대로 인용하면 안 된다. 슬라이더 개수도 실측 918개로 주장(938)과 20 차이가 났다.
그리고 제 코드를 대봤다
넘어온 규칙은 이것 하나다.
어빌리티 인스턴스는 seed와 비율만 기억한다. 미터·초·라디안은 매 프레임 설정에서 다시 계산한다.
제 무협 게임 프로젝트는 정확히 반대로 짜여 있었다. 보스가 초식을 낼 때 전조 시간이 코루틴 시작 시점에 굳는다. 플레이 중에 전조 시간을 바꿔도 이미 진행 중인 전조에는 반영되지 않는다.
전체를 세니 시작 시점에 굳히는 방식 43곳, 매 프레임 다시 읽는 방식 22곳이었다.
이펙트 코드는 한 줄도 안 가져왔는데 제 코드 43곳의 성격이 정해졌다. 이 분류에서 기대할 건 그런 종류다.
라이선스는 두 곳을 봐야 한다
코드 포팅은 기각이다. 라이선스상 자유롭지만 웹 셰이더와 3D 평면 전제라 제 엔진의 2D 파이프라인으로 옮길 값이 없다.
그리고 통째로 가져가는 건 위험하다. 같은 레포가 라이선스 파일에는 관대한 조건을 적어 두고 README에는 “이 프로젝트 목적으로 있는 그대로 제공된다”고 다른 말을 한다. 번들된 캐릭터 모델과 환경 프로브는 원 라이선스 유지라고만 적혀 있다.
의존 대상이 아니라 교재로 다룰 것. 5일 된 레포에 기여자 한 명이다. 게임 쪽 레포는 수명이 짧아 이 구분이 특히 중요하다.
마지막으로 — 이 레포가 잘한 것 하나 더
목표로 삼은 참고 이미지 넉 장을 레포 루트에 넣어 뒀다. “무엇에 맞춰 튜닝했는지”를 남긴 것이다. 그리고 README에 “알려진 거친 부분” 일곱 건을 스스로 적었다 — 정렬 아티팩트, 평면 바닥 전제, 비어 있는 패스까지.
기법으로 가장 이식성 높은 건 무차원 기록, 길이 0 프레임, 그리고 이 마지막 것이다. 엔진과 언어에 무관한 설계 규칙이기 때문이다. 나머지는 수동 엔진이라서 직접 해야 하는 일이라 — 엔진이 이미 해 주는 환경에서는 값이 급락한다.