365 Live Shop 스킨 마켓에 스킨을 올리기 위한 규격입니다. 이 페이지의 숫자·목록은 실제 검증 코드에서 실시간으로 생성됩니다 — 문서와 심사 기준이 어긋나지 않습니다.
my-skin.zip ├─ skin.json 필수 — 메타 + 토큰 ├─ style.css 선택 — 없어도 됩니다 (토큰만으로 성립하는 스킨도 정상) ├─ templates/ 선택 — 없으면 플랫폼 기본 템플릿 사용 │ ├─ home.tpl detail.tpl page.tpl │ └─ parts/ header.tpl nav.tpl hero.tpl ├─ preview/ │ └─ thumb.png 필수 — 마켓 목록 썸네일 (400×300 권장) └─ LICENSE.txt README.md 선택
| 항목 | 상한 |
|---|---|
| zip 전체 크기 | 5MB |
| 파일 개수 | 50개 |
| 개별 파일 크기 | 2MB |
| 압축 해제 총량 | 10MB — 신고값이 아니라 실제로 풀리는 바이트를 셉니다. 헤더를 속인 zip 은 해제 중에 거부됩니다. |
| 폴더 깊이 | 최대 2단계 (templates/parts/… 까지) |
skin.jsonpreview/thumb.png.json .css .tpl .png .jpg .jpeg .webp .txt .md
.php .phtml .js .svg .htaccess 등은
화이트리스트 방식이라 목록에 없는 것 전부가 거부 대상입니다.templates/ templates/parts/ preview/ assets/ — 그 외 위치의 파일은 거부됩니다. 루트에는 skin.json style.css 등 파일만.
A-Z a-z 0-9 _ - . / 만. 공백·한글·특수문자 불가..(상위 경로) · 절대경로 · 역슬래시 · 심볼릭 링크 · 같은 이름 중복 — 전부 거부최대 64KB. UTF-8. 예시:
{
"format_version": "1.0",
"id": "aurora-mint",
"name": "Aurora Mint",
"version": "1.0.0",
"author": "studio-nine",
"industries": ["jewelry", "general"],
"description": "밝고 가벼운 데일리 주얼리용 스킨",
"license": "proprietary",
"tokens": {
"palette": { "bg": "#FFFFFF", "primary": "#2E7D6B", "accent": "#C9A227" },
"font": { "head": "noto-serif-kr", "body": "pretendard", "headWeight": "600" },
"header": "center", "nav": "icon", "hero": "slider",
"grid_cols": 4, "card_ratio": "1 / 1", "radius": "3px",
"price_style": "breakdown", "uppercase_nav": false
},
"customizable": ["palette.primary", "palette.accent", "grid_cols"]
}
| 필드 | 규칙 |
|---|---|
format_version | 반드시 "1.0" |
id | 소문자·숫자·하이픈 2~40자 (^[a-z0-9][a-z0-9-]{1,39}$).
zip 을 풀 폴더의 신원입니다 — 이름을 바꿔 올리면 거부됩니다. 마켓 전체에서 유일해야 하며,
먼저 올린 제작자의 소유가 됩니다 |
name | 60자 이하, 비면 거부 |
version | semver X.Y.Z (예: 1.0.0) |
author license | 60자 이하 문자열 (선택) |
description | 300자 이하 (선택) |
industries | a-z 0-9 _ 2~20자 문자열 배열 (선택, 형식이 다르면 그 항목만 버려짐) |
customizable | 사장님이 관리자에서 덮어쓸 수 있게 여는 토큰 경로 배열 (예: palette.primary) |
#RRGGBB 또는 #RGB)| 키 | 기본값 | 뜻 |
|---|---|---|
palette.bg |
#FFFFFF |
페이지 배경 |
palette.surface |
#FAFAFA |
카드·패널 배경 |
palette.ink |
#1B2230 |
본문 글자색 |
palette.primary |
#1B2230 |
주 색상(버튼·강조) |
palette.accent |
#C9A227 |
포인트 색 |
palette.muted |
#8B93A5 |
보조 글자색 |
palette.line |
#E6E9EF |
구분선 |
palette.onPrimary |
#FFFFFF |
primary 위 글자색 |
palette.topbar |
"" |
상단 띠 배경 — 빈 문자열("")이면 띠 없음 |
palette.topbarInk |
#FFFFFF |
상단 띠 글자색 |
| 키 | 기본값 | 규칙 |
|---|---|---|
font.head / font.body |
pretendard |
아래 플랫폼 폰트 ID 만. 자유 문자열·외부 CDN 불가 |
font.headWeight |
700 |
100~900 의 백 단위 (예: "600") |
font.headSpacing |
-0.02em |
-0.02em / 1px 형식 |
| 키 | 기본값 | 허용 값 |
|---|---|---|
header |
left |
left center overlay |
nav |
text |
text icon dropdown |
hero |
tile |
slider fullbleed tile |
price_style |
breakdown |
breakdown simple |
grid_cols | 4 | 정수 2~6 |
card_ratio | 1 / 1 | 1 / 1 같은 비율 형식 |
radius | 6px | 6px / 0.5rem / 50% |
uppercase_nav | false | true / false |
topbar_text | "" | 80자 이하 문자열 |
토큰은 CSS 커스텀 프로퍼티(--bg --primary --font-head
--radius --cols --card-ratio …)로 변환돼 style.css 에서 쓸 수 있습니다.
| ID | 이름 | 비고 |
|---|---|---|
system | 시스템 기본 | 시스템 스택 |
pretendard | Pretendard | 웹폰트 self-host |
noto-serif-kr | Noto Serif KR | 웹폰트 self-host |
nanum-myeongjo | Nanum Myeongjo | 웹폰트 파일 미배포 — 시스템 폰트로 폴백 |
gowun-dodum | Gowun Dodum | 웹폰트 파일 미배포 — 시스템 폰트로 폴백 |
실제 font-family 와 @font-face 는 플랫폼이 만듭니다.
스킨은 ID 만 고릅니다 — 외부 폰트 CDN 은 어디에서도 부를 수 없습니다.
최대 200KB. UTF-8. 토크나이저로 파싱해 화이트리스트로 판정합니다.
| 항목 | 정책 |
|---|---|
| at-rule | 허용: @media @supports @keyframes @font-face @-webkit-keyframes @layer @page @import @charset 는 금지 |
url() | 패키지 안의 상대경로만. 외부 URL·절대경로·.. 금지.data: 는 base64 이미지(png/jpeg/gif/webp)만, 64KB 이하 |
@font-face | src 는 /fonts/ 아래 플랫폼 폰트 경로만 |
| CSS 이스케이프 | \40 같은 유니코드 이스케이프 금지 (우회 차단) |
| 스크립트 벡터 | expression() behavior: -moz-binding
javascript: 등 전부 금지 |
| 법정 표기 보호 | .ls-legal 계열 선택자는 선택 자체가 금지.site-foot footer ls-legal 가 들어간 선택자에는
display:none visibility:hidden opacity:0 height:0
font-size:0 clip-path 등 숨기는 선언을 쓸 수 없습니다 |
style.css 는 선택입니다. 토큰만으로 성립하는 스킨도 정상 등록됩니다.템플릿은 실행되지 않고 해석됩니다. 슬롯은 아래 6개가 전부이고, 없는 슬롯은 플랫폼 기본 템플릿이 대신 그립니다.
templates/home.tpl templates/detail.tpl templates/page.tpl templates/parts/header.tpl templates/parts/nav.tpl templates/parts/hero.tpl
{{ product.name }} 출력 — 언제나 HTML 이스케이프
{{ product.price | won }} 필터
{% if product.in_stock %} … {% else %} … {% endif %}
{% for p in products %} … {% endfor %} ({{ loop.index }} {{ loop.first }} {{ loop.last }})
{% component product_card p %} 플랫폼이 그리는 컴포넌트
{# 주석 #}
raw 필터(이스케이프를 끌 방법이 없습니다 — HTML 이 필요하면 rich_text 컴포넌트)not and or,
== != > < >= <=, 정수·문자열 리터럴a.b.c 점 표기만. 없는 경로는 빈 문자열(에러가 나지 않습니다)won number date upper lower truncate default — truncate:40 default:'문의' 처럼 인자를 받습니다.
product_card price_block category_nav pagination gold_notice ar_button rich_text
가격 계산·법정 표기·이미지 서빙은 컴포넌트(플랫폼) 몫입니다. 스킨은 위치만 정합니다.
| 항목 | 상한 |
|---|---|
| 템플릿 파일 크기 | 128KB |
| AST 노드 수 | 4,000 |
| 블록 중첩 깊이 | 16 |
| 렌더 1회 반복 총량 | 20,000회 |
| 출력 크기 | 512KB |
레이아웃(<html>·<head>·footer)은 플랫폼 소유입니다.
스킨 템플릿은 그 안쪽만 그립니다. 법정 표기 footer 는 스킨이 지울 수 없습니다.
객체는 넘어오지 않습니다. 스칼라와 배열뿐이고, 아래 표에 없는 것은 스킨이 존재조차 모릅니다
(store_id·원가·마진율·고객 개인정보·세션 등).
가격은 계산이 끝난 값만 옵니다.
store |
name tagline logo_url industry_label tel has_tel |
settings |
hero_title hero_subtitle hero_image_url |
categories[] |
id name url is_active |
notice |
문자열 (금 시세 안내 문구 또는 빈 문자열) |
meta |
view page_no total_pages total is_logged_in category_name active_cat |
customer |
name |
products[] |
id name subtitle sku url thumb_url has_image has_multi_images is_featured weight_g weight_label weight_don purity_label stone_note is_made_to_order stock_type_label stock_qty in_stock show_stock ar_enabled sellable price_reason price_type is_gold_linked price price_display trade_date |
products[].images[] |
url |
products[].price_breakdown |
gold supply supply_display vat vat_display total total_display |
products[].price_breakdown.lines[] |
label amount amount_display note |
product |
summary summary_html detail_html |
product.category |
name |
product.options[] |
type label |
product.options[].items[] |
label extra_price extra_display |
page |
title body_html |
in_stock·price_display 같은 판정·표기는 서버가 끝내서 넘깁니다.
템플릿에는 산술이 없으므로 boolean·완성된 문자열을 그대로 쓰면 됩니다.
customer 는 비로그인 시 null 입니다.
version 은 semver X.Y.Z. (id, version) 쌍이 스킨의 신원입니다.올리기 전에 스스로 검증하면 심사가 빨라집니다. 로컬 검증기는 서버 업로드 검사와 같은 클래스로 만들어졌습니다.
skin.json 의 id 를 반드시 자신의 것으로 바꾸세요 —
id 는 먼저 올린 제작자의 소유가 됩니다.php check.php my-skin.zip 으로 실행합니다.
구조·skin.json·CSS·템플릿 검사를 서버와 같은 규칙으로 돌리고, 거부 사유를 줄 번호와 함께 보여줍니다.문의: 제작자 콘솔 로그인 후 대시보드 안내를 참고하세요.
이 페이지는 서버 검증 코드(PkgGuard · SkinSchema · CssGuard · LiveTpl · SkinFonts)에서 생성됐습니다 · 2026-09-10