> For the complete documentation index, see [llms.txt](https://ckaanf.gitbook.io/ckaanf-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ckaanf.gitbook.io/ckaanf-docs/project/undefined/undefined-1/page-1.md).

# 확장 프로그램 개발 (3) - 기능 추가 편

[1편: 확장 프로그램 개발기](https://romanc3.tistory.com/165)\
[2편: 운영 및 유지보수 편](https://romanc3.tistory.com/166)

***

## ⌨️ 기능 추가의 계기: 단순한 '전달자'에서 '의사결정 보조 도구'로

2편에서 외부 설정 주입(Gist)과 킬스위치, 그리고 테스트 코드를 구축하면서 확장 프로그램의 운영 안정성을 어느 정도 확보할 수 있었다.

하지만 실제로 내가 메이플을 플레이하며 경매장을 이용할 때마다 마음 한구석에 계속 맴돌던 질문이 있었다.

> **"그래서 이 템을 사면 내 캐릭터 최종뎀이 정확히 몇 퍼센트 오르는 거지?"**\
> **"그리고 이 매물, 직작하는 것보다 싼 건가? 아니면 바가지인가?"**

기존 버전의 확장 프로그램은 경매장의 찜 목록을 환산기 아이템메이커에 '전달(Bridge)'해 주는 역할에 충실했다. 즉, 찜 목록을 가져와 아이템메이커에 넣고, 유저가 직접 환산 사이트의 시뮬레이터를 돌려봐야만 강해지는 수치를 확인할 수 있었다.

하지만 경매장에 올라와 있는 10개, 20개의 찜 매물을 하나하나 환산기에 넣어보는 작업은 여전히 번거로웠다. **"확장 프로그램 팝업 안에서 찜한 매물들의 최종뎀 상승량과 가성비, 그리고 직작 대비 가격의 타당성을 즉시 볼 수 있다면 어떨까?"**

이 물음에서 출발한 것이 이번 **v2.0.0 대규모 기능 추가**였다.

***

## \[환산기 계산식을 로컬로 끌고 오기 (3차 에르미트 스플라인과의 사투)]

가장 큰 기술적 난관은 \*\*"환산기 서버에 부하를 주지 않고 어떻게 최종뎀을 계산할 것인가?"\*\*였다.

경매장 찜 목록에 아이템이 30개 있다면, 이를 계산하기 위해 환산기 서버 API를 30번 호출하는 것은 명백한 민폐이자 서비스 이용약관 위배 소지가 컸다. 결국 답은 하나였다. **모든 계산을 브라우저 로컬 CPU에서 끝내는 것.**

이를 위해 환산주스탯 사이트의 프론트엔드 번들을 깊게 분석했다. 환산기는 캐릭터의 환산 주스탯 구간별 보스 데미지 기여도를 단순 선형 비례가 아니라 **3차 에르미트 스플라인(Hermite Spline) 보간법**으로 곡선 모델링하고 있었다.

```javascript
// 3차 에르미트 기저 함수
function hermiteInterpolate(p0, p1, m0, m1, t) {
    const t2 = t * t;
    const t3 = t2 * t;
    const h00 = 2 * t3 - 3 * t2 + 1;
    const h10 = t3 - 2 * t2 + t;
    const h01 = -2 * t3 + 3 * t2;
    const h11 = t3 - t2;
    return h00 * p0 + h10 * m0 + h01 * p1 + h11 * m1;
}
```

이 곡선 함수와 직업별 주스탯/부스탯/공마 가중치 테이블을 분석하여 `fd_calculator.js`라는 독립된 로컬 연산 엔진으로 구현해 냈다.

덕분에 환산기 서버로 단 1건의 네트워크 요청도 보내지 않고, 유저가 이전에 조회했던 캐릭터 스펙 데이터(`character-store`)를 기반으로 \*\*0.01초 만에 찜 목록의 모든 아이템에 대한 최종뎀 상승량(eff)과 100억 메소당 효율(eff100B)\*\*을 실시간으로 뽑아낼 수 있게 되었다.

***

## \[직작할까, 완제 살까? 경매장 가격의 타당성 검증하기]

메이플 유저들이 경매장에서 템을 볼 때 겪는 가장 큰 딜레마는 \*\*"직작 vs 완제 구매"\*\*다.

특히 2026년 들어 스타포스 30성 확장, 15성 이상 하락 방지, 메소 잠재 재설정 시스템 등 인게임 강화 메타가 크게 바뀌면서 유저들이 체감하는 직작 기댓값도 과거와 완전히 달라졌다.

그래서 경매장 매물의 가격이 적정한지 판정해 주는 \*\*가치평가 모델(`evaluateCraftVsBuy`)\*\*을 설계했다.

1. **직작 총원가 산출**: $C\_{\text{craft}} = C\_{\text{base}} + C\_{\text{star}} + C\_{\text{poten}} + C\_{\text{flame}} + C\_{\text{scroll}}$\
   (노작값, 스타포스 구간별 비용/파괴 기댓값, 잠재 등업 천장 및 재설정 메소)
2. **불운 리스크 프리미엄**: 강화 운이 평균 이하인 상위 75% 유저를 위한 안전마진 계수
3. **가위 사용 가능 횟수(가횟) 감가 모델**: 신품(10회) 대비 가횟이 깎인 매물(5회, 3회, 막가횟 1회)에 대한 시장 리셀 감가율 자동 보정

이를 통해 각 매물 카드에 **🟢 기댓값 대비 저렴(추천) / 🟡 적정 / 🔴 기댓값 초과** 신호등 배지를 달아주고, \[상세 보기]를 누르면 스타포스 얼마, 잠재 얼마 등 세부 원가 브레이크다운을 투명하게 볼 수 있도록 만들었다.

***

## \[스펙업 순서로의 딥링크: 고민의 시간을 줄여주는 원클릭 연동]

기존에는 환산기 '아이템메이커'로만 템을 보낼 수 있었다. 하지만 환산기에서 가장 유용한 기능 중 하나는 바로 **'스펙업 순서'의 추가스펙 시뮬레이터**다.

내가 찜한 경매장 아이템을 스펙업 순서에 넣고, 코어 강화나 심볼 레벨업과 함께 섞어서 전체적인 스펙업 동선을 보고 싶다는 니즈가 컸다.

그래서 이번에 **\[스펙업 순서로 추가]** 버튼을 신설했다. 버튼 하나만 누르면:

1. 해당 아이템의 최종뎀과 가격을 계산하고,
2. `추가스펙(에테르넬 시프글러브 12성 크뎀8%/올스탯7%/LUK10%)`처럼 성급과 핵심 잠재가 담긴 직관적인 이름으로 포맷팅한 뒤,
3. 환산기 `spec-order` 페이지의 `bookMarkSimulList` 로컬스토리지에 안전하게 머지(Merge) 주입한다.

유저는 그저 버튼 하나 누르고 환산기 탭으로 넘어가서 우선순위 표에 예쁘게 정렬된 내 장비를 확인하기만 하면 된다.

***

## \[컴플라이언스와 약관: 스카우터 개발진과의 소통, 그리고 안전한 로컬화]

기능이 고도화될수록 항상 경계해야 하는 것은 \*\*'서비스 이용약관'과 '도덕적 해이'\*\*였다.

스카우터 이용약관 제15조에는 자동화 수단에 의한 API 접근, 서비스 백엔드로의 무단 사용 등을 엄격히 금지하고 있다. 다행히 스카우터 개발진 분들과 사전에 로컬스토리지 연동 규격에 대해 긍정적인 협의를 마칠 수 있었고, 여기에 더해 프로젝트 코드베이스를 전수 검사하여 과거 미사용으로 방치되어 있던 `api.maplescouter.com` 호출 잔재를 완전히 들어냈다.

* **스카우터 서버 호출 횟수: 0회 (완전 로컬화)**
* **스카우터 트래픽 기여**: 경매장 유저를 환산 사이트 본체로 유입시켜 PV 및 배너 광고 노출에 기여하는 상생(Win-Win) 구조

팬 사이트 생태계의 도구들은 원작자와 다른 커뮤니티 개발자들의 노고를 존중할 때 비로소 롱런할 수 있다는 점을 다시금 깊이 되새겼다.

***

## \[테스트 코드의 위력: 21개의 방어선]

2편에서 테스트 코드의 중요성을 뼈저리게 느꼈다고 썼는데, 이번 3편에서는 그 결실을 보았다.

방어율 무시의 복리 곱연산 $1 - \prod(1 - d\_i)$, 섀도어의 이중 부스탯(`["DEX", "STR"]`), 데몬어벤져의 HP 주스탯, 제논의 3주스탯, 마법사 장비에 공격력이 붙었을 때의 0 마스킹, 30성 스타포스 경계값, 시드링 1\~4레벨 승급 판정 등...

조금만 방심해도 수치가 왜곡될 수 있는 복잡한 도메인 로직이었지만, **21개의 단위 및 E2E 통합 테스트**를 촘촘히 짜두고 TDD 방식으로 기능을 붙여나갔다.

```bash
$ node --test test/*.test.js
✔ Background 스크립트 탭 제어 테스트
✔ E2E-1. 실제 넥슨 경매장 패킷 전수 매핑 및 스카우터 규격 무결성
✔ E2E-2. 실전 매물 1: 에테르넬 글러브 최종뎀, 직작 원가 및 추가스펙 페이로드
✔ E2E-3. 실전 매물 2: 미트라의 분노 엠블렘 잠재 직작 평가
✔ E2E-4. 스카우터 탭 주입용 sortObjectKeys 키 정렬 무결성
✔ 1~13. 세트 효과, 특수 직업, 시드링 보호, IGR 복리, 스타포스 30성 경계값
...
tests 21 | pass 21 | fail 0
```

테스트 터미널에서 초록색 `pass 21`이 찍히는 순간의 짜릿함은 개발자만이 알 수 있는 쾌감이었다.

***

## \[마무리]

처음에는 단순히 "경매장 템 복붙하기 귀찮아서" 만들었던 조그만 스크립트였는데, 어느새 3차 보간식 엔진과 직작 가치평가 모델, 그리고 21개의 견고한 테스트 러너를 갖춘 어엿한 프로덕트(v2.0.0)로 성장했다.

내가 겪는 일상의 작은 불편함을 코드로 직접 정의하고, 수학과 알고리즘으로 풀어내며, 실제 사용자의 관점에서 유용한 가치로 완성해 나가는 이 과정이야말로 사이드 프로젝트가 주는 최고의 묘미가 아닐까 싶다.

*(본 프로젝트는 넥슨 및 환산주스탯 사이트와 무관한 개인 비공식 팬 프로젝트이며, 모든 계산은 사용자 브라우저 로컬에서 안전하게 처리됩니다.)*
