🛠 게임 만들기 가이드
누구나 JS 한 파일로 미니게임을 만들어 씨미게임에 올릴 수 있어요. 캔버스·DOM 자유, 소리도 OK.
🧪 스튜디오에서 업로드하기 →어떻게 동작하나요?
- 게임을 JS 번들(≤2MB) 한 파일로 만들어 업로드합니다
- 자동 보안 스캔 통과 후, 스튜디오에서 본인만 미리보기·테스트할 수 있어요
- 운영자가 직접 플레이해보고 승인하면 모두의 방 만들기 목록에 올라갑니다
게임은 샌드박스 iframe(별도 오리진)에서 실행돼요. 바깥과의 통신은 오직 window.CimeGame SDK를 통해서만 이뤄집니다.
SDK로 할 수 있는 것
라이프사이클 콜백으로 방·라운드·상태를 받고, submitAction으로 행동을 보냅니다.
// 게임 번들은 window.CimeGame SDK로만 통신합니다
CimeGame.onInit(({ roomCode, me, seed }) => {
// roomCode: 방 코드 · me.nickname: 내 닉네임
// seed: 모든 플레이어가 공유하는 랜덤 시드 (맵/문제 동기화용)
});
CimeGame.onRoundStart(({ endsAt, config }) => {
// 라운드 시작 — endsAt(ms 타임스탬프)까지 플레이
// 남은 시간 = endsAt - Date.now()
});
CimeGame.onState((state) => {
// 서버가 브로드캐스트하는 게임 상태 (실시간)
});
CimeGame.onRoundEnd((results) => {
// 라운드 종료 — 정리/결과 화면 등
});
// 플레이어 행동은 액션으로만 전송 — 점수 계산은 서버가 합니다
CimeGame.submitAction({ type: "score", score: 42 });onInit(ctx)— roomCode / me / seed. seed는 모든 플레이어가 같으니 맵·문제 생성에 쓰면 화면이 동기화돼요onRoundStart(round)— endsAt(종료 시각 ms).endsAt - Date.now()로 남은 시간 계산onState(state)— 서버가 실시간으로 뿌리는 상태onRoundEnd(results)— 라운드 종료 시점submitAction({type:"score", score})— 점수 신고
🔒 점수는 서버가 최종 집계합니다 — 신고한 점수는 단조 증가(더 높을 때만 반영)와 상한 규칙으로 검증돼요. 그래서 클라이언트에서 임의로 점수를 부풀려도 반영되지 않습니다 (치트 방지).
소리 넣기
효과음·배경음은 Web Audio API로 직접 합성합니다. 외부 오디오 파일(.mp3/.wav)은 CSP default-src 'none'로 차단되니 로드할 수 없어요.
// 소리는 Web Audio API로 직접 "합성"합니다 (오디오 파일 로드는 CSP로 차단)
let audioCtx;
// ⚠️ AudioContext는 첫 사용자 제스처(클릭/터치/키)에서 생성·resume해야 소리가 납니다
function ensureAudio() {
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (audioCtx.state === "suspended") audioCtx.resume();
}
function beep(freq = 440, ms = 120) {
ensureAudio();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.frequency.value = freq;
osc.connect(gain); gain.connect(audioCtx.destination);
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + ms / 1000);
osc.start();
osc.stop(audioCtx.currentTime + ms / 1000);
}
// 첫 클릭에서 오디오 활성화 + 효과음
document.getElementById("game").addEventListener("click", () => beep(660, 100));⚠️ AudioContext는 반드시 첫 사용자 제스처(클릭/터치/키 입력)에서 생성·resume해야 소리가 납니다. 브라우저 자동재생 정책 + 샌드박스 제약 때문에, 로드 직후 바로 재생하면 무음이 돼요. "시작" 버튼 등 첫 입력에서 resume()를 호출하세요.
디자인 가이드
- iframe은 opaque origin 샌드박스 — 캔버스와 DOM은 자유롭게 그리세요
- 외부 이미지·폰트·네트워크는 전부 차단(CSP)됩니다. 에셋은 전부 코드로 만드세요 — SVG, canvas 드로잉,
data:URI로 인라인 - 픽셀아트는
image-rendering: pixelated로 선명하게 유지 - 화면 맞춤은
window.innerHeight기준으로 스케일하면 기기별 높이에 대응돼요 - 색·톤은 자유예요. 게임에 어울리게 마음껏 꾸미세요 🎨
// 화면 맞춤: window.innerHeight 기준으로 스케일 (기기별 높이 대응)
const BASE_H = 640; // 디자인 기준 높이
function fit(el) {
const scale = window.innerHeight / BASE_H;
el.style.transform = `scale(${scale})`;
el.style.transformOrigin = "top center";
}
window.addEventListener("resize", () => fit(stage));
// 픽셀아트는 뭉개짐 방지
// canvas.style.imageRendering = "pixelated";제약 (업로드 스캐너)
안전을 위해 업로드 시 코드를 정적 스캔합니다. 아래 항목은 주석에 적기만 해도 거부되니 아예 쓰지 마세요.
evalFunctionfetchXHRlocalStoragedocument.cookieWebSocketwindow.top- 동적 코드 실행(
eval,new Function) 금지 - 외부 네트워크(
fetch/XHR/WebSocket) 금지 — 어차피 CSP로도 막혀요 - 쿠키·스토리지·부모 창 접근(
document.cookie,localStorage,window.top) 금지 - 번들 크기 2MB 이하 — 에셋은 SVG/canvas/data URI로 인라인
심사 기준
- 방송에서 시청자와 같이 즐길 수 있는 게임인가
- 모바일에서도 조작 가능한가
- 혐오·사행성 등 부적절한 콘텐츠가 없는가
거부 시 사유를 함께 안내드립니다. 수정 후 재업로드 가능해요.