공동 작업자 제작 안내 · 개발 작업 중
고정 양식 없이 만드는 길드 홍보 페이지
직접 제작한 HTML과 CSS를 업로드하고 미리보기에서 확인한 버전만 게시합니다. 기존 길드 홍보 페이지는 변경하지 않습니다.
파일 구성과 게시 순서
진입 파일 이름은 index.html입니다. 이미지, 글꼴, JavaScript는 함께 업로드하고 CSS·이미지 경로는 상대 경로로 작성하세요. 서버 프로그램, 비밀키, 외부 라이브러리 URL은 넣지 않습니다.
index.html styles/main.css scripts/main.js images/guild-banner.webp
- 관리자가 월드를 선택하고 길드명을 검색합니다. 미등록 길드라면 실제 길드 정보를 확인한 뒤 홍보 슬러그를 정하고, 기존 로그인 계정에 사이트별 작업 권한을 부여합니다. 길드 소유권이나 운영진 권한은 자동으로 생기지 않습니다.
- 작업실에서 ZIP 파일 또는 폴더를 선택하고 업로드 작업을 등록합니다.
- 검증이 완료된 버전의 비공개 미리보기를 열어 레이아웃과 코디를 확인합니다.
- 선택한 버전을 게시하면 실제 공개 주소는 선택한 길드의 기존
/g/길드슬러그가 됩니다. 별도 사이트 주소도 해당 길드 주소로 연결됩니다. - 수정할 때 전체 파일을 새 버전으로 업로드합니다. 이전 완료 버전을 다시 게시하면 복원됩니다.
ZIP 안에 최상위 폴더 하나가 있어도 처리합니다. 미리보기 주소는 제한 시간 뒤 만료되므로 작업실에서 다시 열어야 합니다.
실시간 캐릭터 이미지 API 경로
캐릭터명에서 실제 OCID를 확인한 뒤, 실제 장착 코디를 받아 기존 코디 렌더러로 움직이는 이미지를 만듭니다.
1. 캐릭터 찾기
GET /api/character/basic-by-name?name={캐릭터명}닉네임을 검증하고 outfits 조회에 사용할 OCID를 얻습니다. image는 정적 초상화이며 애니메이션 코디 스프라이트가 아닙니다.
2. 실제 코디 가져오기
GET /api/character/outfits?ocid={OCID}[&date=YYYY-MM-DD]실제 장착 데이터로 만든 AvatarRenderSpec을 기존 코디 렌더러가 움직이는 이미지로 그립니다. date를 지정하면 해당 일별 스냅샷을 사용합니다.
index.html에서 직접 fetch하지 않습니다. 페이지가 격리 sandbox에서 MapleGuild.mount를 요청하면 너공마의 신뢰된 호스트가 위 API를 호출합니다.작업실의 Chrome 미리보기는 실제 공개 페이지의 탭 제목과 같습니다. 제목은 페이지 이름과 길드명으로 만들어집니다. 업로드한 index.html의 <title>은 iframe 문서 안의 제목이므로 최상위 Chrome 탭에는 표시되지 않습니다.
코디엔진 조작 기능
stand1·walk1·sit·jump 등과 update({ motion })
default·blink·smile·wink 등과 update({ emotion })
체크박스로 실제 장비 이펙트를 켜고 끄는 update({ effects: false })
AI에 전달할 프롬프트
AI 작업 프롬프트에는 API 계약, 실제 모션·표정 제어, 이펙트 ON/OFF 동작을 포함했습니다. 아래 예제에는 캐릭터명을 입력하고 세 조작을 적용하는 실제 UI가 있습니다.
너는 너공마(MapleGuild) 공동 작업자가 업로드할 길드 홍보 페이지를 만드는 프론트엔드 제작 AI다. 먼저 요청된 시각 디자인을 만들고, 아래 코디 연결 계약을 그대로 지켜 index.html, styles/site.css, scripts/site.js와 필요한 정적 이미지를 완성하라.
## 실제 너공마 API 연결
길드 페이지에서 캐릭터명을 제출하면 신뢰된 너공마 호스트가 다음 실제 API 요청을 순서대로 수행한다.
1. GET /api/character/basic-by-name?name={encodeURIComponent(characterName)}: 닉네임을 확인하고 ocid/name을 얻는다. 응답 image는 정적 캐릭터 초상화이며 움직이는 코디 이미지가 아니다.
2. GET /api/character/outfits?ocid={encodeURIComponent(ocid)}: 현재 코디는 date 없이, 과거 코디는 snapshotDate=YYYY-MM-DD를 함께 전달해 avatar_looks.normal/additional의 base/1/2/3을 코디 렌더러에 전달한다. preset_no와 character_look_mode가 있으면 활성 값을 사용한다. 과거 데이터는 일별 스냅샷이므로 하루 중 정확한 교체 시각을 단정하지 않는다.
이 요청은 MapleGuild SDK의 mount/update/refresh를 통해 호스트가 처리한다. 업로드 HTML 자체에서 fetch('/api/...')를 호출하지 마라. HTML은 opaque-origin sandbox라 네트워크 연결이 차단되어 있고, API 키/토큰이나 원시 API 응답도 전달되지 않는다.
## index.html에 꼭 구현할 조작 UI
- 실제 캐릭터명을 입력하고 사용자가 제출할 때만 MapleGuild.mount(element, options)를 호출한다. 이름이나 이미지를 예시값으로 고정하지 않는다.
- 캐릭터 모션 선택을 만들고 변경을 적용할 때 widget.update({ motion })을 호출한다. 허용 코드: stand1, stand2, walk1, walk2, prone, fly, jump, sit, ladder, rope, heal, alert, proneStab, swingO1, swingO2, swingO3, swingOF, swingP1, swingP2, swingPF, swingT1, swingT2, swingT3, swingTF, stabO1, stabO2, stabOF, stabT1, stabT2, stabTF, shoot1, shoot2, shootF, dead, ghostwalk, ghoststand, ghostjump, ghostproneStab, ghostladder, ghostrope, ghostfly, ghostsit, climb.
- 캐릭터 표정 선택을 만들고 widget.update({ emotion })을 호출한다. 허용 코드: default, wink, smile, cry, angry, bewildered, blink, blaze, bowing, cheers, chu, dam, despair, glitter, hit, hot, hum, love, oops, pain, troubled, qBlue, shine, stunned, vomit.
- 코디 이펙트 켜기/끄기 체크박스를 만들고 widget.update({ effects: checkbox.checked })를 호출한다. false는 실제 장비/세트 아이템 이펙트를 숨기며 캐릭터 몸과 무기 외형은 유지한다.
- 한 번의 '적용' 제출에서 선택한 모션·표정·이펙트를 함께 갱신해 요청을 합친다. 컨트롤 변경 때마다 연속 호출하지 않는다.
- 현재 SDK 옵션: {characterName, motion, emotion, effects, preset:'base'|1|2|3, lookMode:'normal'|'additional', snapshotDate:'YYYY-MM-DD'(선택), flipped:boolean, scale:0.4..2.5, speed:0.5..2}. preset/lookMode 생략 시 API의 실제 활성 외형을 선택한다.
- 캐릭터 재조회에는 widget.refresh(), 화면 제거에는 widget.destroy()를 사용한다. 상태 캔버스·로딩/실패 문구와 접근 가능한 label을 유지한다.
## 구현·보안 조건
- SDK는 호스트가 /assets/guild-sites/maple-guild-sdk.js 경로로 자동 주입하므로 외부 CDN, 직접 API fetch, 중첩 iframe을 추가하지 않는다.
- 이미지·CSS·JS는 ZIP 또는 폴더에 포함하고 상대 경로를 사용한다. 서버 프로그램, 환경 파일, API 키, 쿠키, 관리자 API를 만들지 않는다.
- 실제 API로 확인되지 않은 캐릭터·장비·프리셋·이펙트로 대체하지 않는다. 요청 실패·존재하지 않는 캐릭터·불러오는 중 상태를 명확히 표시하고 가짜 이미지로 숨기지 않는다.
- index.html에는 문서 자체의 <title>도 작성하되 이 문서는 sandbox iframe 안에 표시된다. 실제 Chrome 탭 제목과 검색 결과 제목은 작업실의 페이지 이름으로 만들어지므로 두 제목이 다를 수 있다고 안내하라.
- 외부 이미지 URL 대신 사이트에 포함된 정적 이미지나 실제 SDK 캔버스만 사용한다. 과한 타이머/자동 refresh로 API를 반복 호출하지 않는다.
- 출력은 완전한 index.html, CSS, JS이며, 필요한 경우 파일 경로까지 명시한다. 마지막에 구현한 API 연동 순서와 세 조작 UI가 실제로 어떤 SDK 호출을 하는지 짧게 설명한다.캐릭터 표시 예제
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>길드 캐릭터 코디</title>
<style>
:root { color-scheme: dark; font-family: system-ui, sans-serif; background: #111720; color: #f5f7fb; }
body { margin: 0; }
main { width: min(720px, 100% - 32px); margin: 24px auto; padding: 24px; border: 1px solid #344251; border-radius: 20px; background: #192330; }
h1 { margin: 0 0 8px; font-size: 1.35rem; }
p { color: #b4c0ce; line-height: 1.6; }
form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; align-items: end; }
label { display: grid; gap: 6px; font-size: .85rem; }
input, select, button { min-height: 44px; padding: 8px 10px; border: 1px solid #536273; border-radius: 9px; background: #121a24; color: inherit; font: inherit; }
.character-name, .snapshot-date { grid-column: 1 / -1; }
.effects { display: flex; align-items: center; gap: 9px; min-height: 44px; }
.effects input { width: 20px; height: 20px; min-height: 0; }
button { cursor: pointer; border-color: #6bbca6; background: #226a5a; font-weight: 700; }
.stage { display: grid; min-height: 340px; place-items: center; margin-top: 16px; border-radius: 14px; background: radial-gradient(ellipse, #31465a, #17202b 68%); }
#character-canvas { width: 320px; max-width: 100%; min-height: 320px; }
.note { font-size: .78rem; }
@media (max-width: 520px) { main { padding: 18px; } form { grid-template-columns: 1fr; } .character-name { grid-column: auto; } }
</style>
</head>
<body>
<main>
<h1>길드 캐릭터</h1>
<p>실제 너공마 API에서 확인한 코디를 불러와 모션·표정·이펙트를 바꿔 보세요.</p>
<form id="look-controls">
<label class="character-name">캐릭터명
<input id="character-name" autocomplete="off" maxlength="24" placeholder="표시할 실제 캐릭터명" required>
</label>
<label class="snapshot-date">과거 코디 날짜(선택)
<input id="snapshot-date" type="date">
</label>
<label>모션
<select id="character-motion"><option value="stand1">서 있기</option><option value="walk1">걷기</option><option value="sit">앉기</option><option value="jump">점프</option></select>
</label>
<label>표정
<select id="character-emotion"><option value="default">기본</option><option value="blink">눈 깜박임</option><option value="smile">웃음</option><option value="wink">윙크</option><option value="cry">울음</option></select>
</label>
<label class="effects"><input id="character-effects" type="checkbox" checked> 코디 이펙트 표시</label>
<button type="submit">캐릭터 불러오기 · 설정 적용</button>
</form>
<div class="stage"><div id="character-canvas" aria-label="캐릭터 애니메이션"></div></div>
<p class="note">이펙트를 끄면 장비·세트 이펙트만 숨기고 캐릭터 몸과 무기는 유지합니다. 불러오지 못한 경우 SDK가 실패 상태를 표시합니다.</p>
</main>
<script src="/assets/guild-sites/maple-guild-sdk.js"></script>
<script>
const form = document.getElementById('look-controls');
const characterRoot = document.getElementById('character-canvas');
let characterWidget = null;
function selectedOptions() {
return {
characterName: document.getElementById('character-name').value.trim(),
snapshotDate: document.getElementById('snapshot-date').value || undefined,
motion: document.getElementById('character-motion').value,
emotion: document.getElementById('character-emotion').value,
effects: document.getElementById('character-effects').checked
};
}
form.addEventListener('submit', (event) => {
event.preventDefault();
const options = selectedOptions();
if (!options.characterName) return;
if (characterWidget) characterWidget.update(options);
else characterWidget = MapleGuild.mount(characterRoot, options);
});
</script>
</body>
</html>연동 범위와 제한
캐릭터 외형은 현재 넥슨 API와 사이트의 코디 렌더러를 사용합니다. 움직이는 그림을 표시하지만 게임 내 장비 교체 이벤트를 실시간으로 받는 것은 아니며, 갱신에는 API와 공유 캐시의 시차가 있을 수 있습니다.
- 업로드 문서는 opaque-origin sandbox에서 실행되며 allow-same-origin을 사용하지 않습니다.
- basic-by-name과 outfits API는 SDK의 신뢰된 부모 호스트가 호출하며 HTML의 직접 fetch는 차단됩니다.
- basic-by-name의 image는 정적 초상화입니다. 애니메이션 코디는 outfits의 avatar_looks를 기존 코디 렌더러로 그립니다.
- Chrome 탭과 공개 페이지 metadata 제목은 작업실의 페이지 이름·길드명을 사용합니다. index.html의 title은 격리 iframe 문서 제목입니다.
- 페이지당 최대 3명, 전송 프레임 최대 12fps입니다.
- 뷰포트 밖에서는 프레임 전송을 일시정지합니다.
- 코디 API 실패·추가 외형 미존재·초기 렌더 시간 초과는 실패 상태로 표시합니다. 일부 개별 이펙트 자산의 오류 전달은 제한됩니다.
- 코디 히스토리는 일별 스냅샷이며 하루 안의 정확한 교체 시각을 제공하지 않습니다.
- 현재 SDK는 이름표·말풍선과 일부 외부 캐시 이펙트의 별도 레이어 제어를 제공하지 않습니다.
다른 사이트에서 직접 불러오는 범용 임베드가 아니라, 이 사이트의 커스텀 길드 페이지 안에서 동작하는 연동입니다. 회원 정보나 관리자 API를 읽는 기능은 제공하지 않습니다.