권장 작업 순서
처음 만드는 경우 이 순서대로 진행하면 막히는 구간이 적습니다.
- 프로필에서 이름, 썸네일, 장르를 먼저 정리합니다.
- 시작설정과 프롬프트에서 첫인상과 대화 규칙을 잡습니다.
- 에셋과 로어북으로 세계관과 시각 정보를 보강합니다.
- 인터랙션과 공개설정은 마지막에 품질 검수하듯 점검합니다.
처음 만드는 경우 이 순서대로 진행하면 막히는 구간이 적습니다.
가이드 문서는 탐색성과 예시 밀도가 중요합니다.
발행 직전에 아래 세 가지를 다시 확인하면 품질 편차가 줄어듭니다.
Reluv 캐릭터 에디터의 전체 구조와 제작 흐름을 이해합니다.
Reluv 캐릭터 에디터는 7개의 탭으로 구성된 종합 제작 도구입니다. 각 탭은 캐릭터의 서로 다른 측면을 담당합니다.
프로필, 시작설정, 프롬프트 탭에서 캐릭터의 외형, 성격, 대화 스타일을 정의합니다.
에셋 탭에서 그룹과 코드:설명으로 이미지를 관리합니다.
로어북에서 캐릭터의 배경 지식과 세계관 설정을 키워드 기반으로 관리합니다.
스탯, 위젯, AI 호출 추출로 동적인 캐릭터 인터랙션을 구현합니다.
5분 안에 첫 번째 캐릭터를 만들어보세요.
캐릭터 이름, 썸네일 이미지, 한줄 소개를 입력합니다. 장르와 해시태그를 선택하세요.
시작설정 탭에서 시작 상황(제목·설명·시작 대사)을 작성합니다. {{char}}·{{user}} 토큰을 활용하세요.
캐릭터 프롬프트에 캐릭터의 성격, 말투, 행동 패턴을 정의합니다.
오른쪽 미리보기 패널에서 실시간으로 결과를 확인합니다.
공개설정 탭에서 공개 범위를 설정하고 공개 요청을 제출합니다.
Ctrl+S로 언제든 임시 저장할 수 있습니다. 브라우저를 닫아도 로컬 스토리지에 자동 저장됩니다.에디터 화면의 각 영역을 이해합니다.
캐릭터의 기본 정보와 외형을 설정합니다.
캐릭터의 이름을 입력합니다. 채팅에서 {{char}} 토큰으로 치환됩니다.
최대 50자 필수
캐릭터를 대표하는 이미지를 업로드합니다. 카드 목록·상세·채팅 화면 등 곳곳에 노출되므로 첫인상을 결정하는 가장 중요한 에셋입니다.
캐릭터를 한 줄로 설명합니다. 카드 목록에서 이름 아래에 표시됩니다.
최대 100자
캐릭터를 설명하는 태그를 선택합니다. 장르·성향·종족·설정 등이 모두 통합된 태그 라이브러리에서 골라 사용합니다.
최대 10개
태그 선택 버튼을 누르면 카테고리별로 분류된 태그 목록이 다이얼로그로 열립니다. 카테고리는 운영 설정에 따라 다를 수 있으며, 예시는 다음과 같습니다.
성인 컨텐츠가 포함된 경우 토글을 활성화합니다. 활성화 시 성인 심사를 거칩니다.
캐릭터의 시작 상황(시나리오)과 사용 안내를 작성합니다.
하나의 캐릭터에 여러 개의 시작 상황을 만들 수 있습니다. 각 시작 상황은 제목 · 설명 · 시작 대사로 구성되며, 사용자는 캐릭터 상세 페이지에서 시작 상황을 골라 대화를 시작합니다.
최대 20개 (운영 설정)
| 항목 | 설명 | 제한 |
|---|---|---|
| 제목 (Title) | 상세 페이지의 시작 상황 선택 화면에 노출되는 이름 | 최대 40자 |
| 설명 (Description) | 선택 화면에서 제목 아래 보조 설명. 어떤 상황인지 한 줄로 안내 | 최대 200자 |
| 시작 대사 (Greeting) | 실제 첫 메시지. 캐릭터의 첫인상을 결정하는 핵심 | 운영 설정 한도(토큰/글자) |
{{char}} — 캐릭터 이름으로 치환{{user}} — 사용자가 선택한 페르소나 이름으로 치환 (페르소나가 없으면 기본 이름){{image::코드}} — 에셋 탭에 등록한 이미지를 본문에 삽입. 에셋 앨범에서 "코드 복사" 버튼으로 {{image::1}} 형태의 토큰을 복사해 붙여넣습니다.{{widget::id}} — 인터랙션 탭에서 만든 위젯을 본문에 삽입. 위젯 편집기의 "코드 복사" 버튼으로 토큰을 얻습니다.*{{char}}이(가) 카페 구석 자리에서 고개를 들어 당신을 바라본다.*
"어, {{user}}? 진짜 왔네. 솔직히 안 올 줄 알았는데."
*커피잔을 가볍게 밀어내며 맞은편 자리를 턱짓한다.*
{{image::1}}
"뭐, 앉아. 할 얘기가 좀 있거든."
에셋 토큰({{image::1}})을 본문 중간에 넣으면 해당 이미지가 렌더됩니다.
위젯 토큰({{widget::xxx}})도 같은 방식으로 삽입할 수 있습니다.
사용자에게 이 캐릭터와 어떻게 대화하면 좋은지 안내하는 텍스트입니다.
플레이 가이드는 기본 마크다운 문법을 지원합니다. 긴 안내문을 구조적으로 쓰고 싶을 때 활용하세요.
| 문법 | 의미 | 예시 |
|---|---|---|
# 제목 | 큰 제목 | # 놀이법 |
## 소제목 | 중간 제목 | ## 대화 팁 |
**굵게** | 굵은 글씨 | 중요 |
*기울임* | 이탤릭 | 기울임 |
- 항목 | 불릿 목록 | • 첫 번째 • 두 번째 |
1. 항목 | 번호 목록 | 1. 먼저 2. 다음 |
> 인용 | 인용 블록 | 인용된 텍스트 |
`코드` | 인라인 코드 | 코드 |
[링크](url) | 하이퍼링크 | 문서 내 링크 이동 |
# 카페 주인 시아와의 대화
**시아**는 말이 많지 않고 눈치가 빠른 편이에요.
단답형 질문보다는 **상황을 묘사하며 말 거는 방식**을 좋아합니다.
## 추천 대화 스타일
- 커피를 주문하면서 이야기를 시작해 보세요
- 시아가 먼저 질문하면 구체적으로 답하는 것이 좋습니다
- 긴 독백보다 짧은 대사가 어울립니다
## 피하면 좋은 것
1. 갑자기 반말로 돌리는 것
2. 무관심한 답변 ("응", "아니" 등)
3. 시아의 과거를 먼저 캐묻는 것
> 천천히 가까워지는 과정을 즐기세요.
최대 2,000자 (운영 설정)
캐릭터의 핵심 정체성과 대화 스타일을 정의합니다. 캐릭터 프롬프트와 예시 대화가 AI가 캐릭터처럼 말하는 데 가장 큰 영향을 미칩니다.
캐릭터의 핵심 성격·외형·배경·말투를 정의하는 가장 중요한 필드입니다. AI가 캐릭터로서 응답할 때 항상 참조합니다. AI가 알아야 할 모든 정보를 자유롭게 기입하세요.
상세 설정 + 추가 형식·지시 합산 15,000자 (운영 설정) 핵심
promptCombined)을 운영 한도와 비교해 표시합니다.
좋은 캐릭터 프롬프트는 다음 요소를 포함합니다:
항목을 구분해 간결하게 적을수록 AI가 더 정확히 따릅니다. 정확한 글자 수는 편집기 우측 하단의 실시간 카운터를 참고하세요.
대화 맥락 뒤에 덧붙는 형식·출력 지시 영역입니다. 상세 설정과 함께 합산되어 글자 수 한도(promptCombined)에 포함됩니다.
AI에게 캐릭터의 대화 스타일과 말투를 학습시키기 위한 짧은 대화 예시입니다. AI는 여기서 캐릭터의 반응 패턴과 어휘 습관을 참고합니다. 실제 채팅창에는 직접 노출되지 않습니다.
최대 5개 · 각 대화당 200 토큰 (운영 설정)
{{user}}, {{char}} 템플릿 변수를 자유롭게 사용할 수 있습니다.대화 1 — 가벼운 인사
{{user}}: 오늘 뭐 했어?
{{char}}: *어깨를 으쓱한다* 별거 없어. 너는?
대화 2 — 고민 상담
{{user}}: 나 요즘 너무 지쳐...
{{char}}: *잠시 말없이 바라보다가 조용히 손을 잡는다* 무리하지 마. 내가 여기 있잖아.
대화 3 — 장난스러운 반응
{{user}}: 너 귀여운 거 알아?
{{char}}: *볼이 붉어진다* ...그런 거 아니거든.
캐릭터의 배경 지식과 세계관을 키워드 기반으로 관리합니다.
로어북은 대화에서 특정 키워드가 언급되면 관련 정보를 AI에게 자동으로 주입하는 시스템입니다. 캐릭터의 방대한 세계관이나 복잡한 배경 설정을 메인 프롬프트에 모두 담지 않고 필요할 때만 꺼내 쓰는 방식으로 토큰을 아낄 수 있습니다.
카드당 최대 항목 수
항상 활성화 항목 최대
항목당 내용 토큰 (기본)
위 값은 운영 설정에 따라 달라질 수 있습니다. 에디터의 실시간 카운터가 우선입니다.
| 필드 | 설명 | 제한 |
|---|---|---|
| 주요 키워드 | 이 키워드가 대화에 등장하면 항목이 활성화됩니다 (쉼표 구분) | 최대 10개 |
| 보조 키워드 | "선택적" 옵션이 켜졌을 때만 사용 — 주요 키워드와 함께 매칭되어야 활성화 | 최대 10개 |
| 내용 | 활성화되면 AI에게 주입될 세계관·설정·규칙 | 약 1,000 토큰 (운영 설정) |
| 우선순위 | 여러 항목이 동시 활성화될 때 어느 항목을 먼저 배치할지 결정 — 숫자가 클수록 우선순위가 높음 | 기본값 100 |
| 항상 활성화 | 키워드 매칭 여부와 상관없이 매 대화마다 프롬프트에 주입 | 최대 5개 |
| 지속 턴 | 한 번 키워드로 활성화된 뒤 N턴 동안 활성 상태를 유지 (0 = 매칭된 턴만) | 기본값 0 |
| 선택적 | 보조 키워드도 매칭되어야만 활성화하도록 제한 | — |
로어북 항목이 프롬프트에 주입되는 경로는 세 가지입니다.
대화 본문에 주요 키워드가 등장하면 해당 항목이 그 턴에 활성화됩니다. 가장 일반적이고 토큰 효율이 좋은 방식입니다.
키워드로 활성화된 뒤 N턴 동안 활성 유지. 장면이 바뀌지 않는 동안 해당 정보를 잊지 않게 할 때 유용합니다. 값이 0이면 매칭된 턴만 활성.
키워드와 상관없이 매 턴 주입. 세계관 근본 규칙, 캐릭터 절대 원칙 등에 사용하되 최대 5개까지만 설정할 수 있습니다 (매번 토큰을 소비하기 때문).
로어북 시스템은 다음 순서로 항목을 처리합니다.
150 이상, "생략되어도 좋은 배경 장식"에는 50 이하처럼 차등을 두면 토큰이 빠듯할 때 품질이 보장됩니다.
주요 키워드: 미나, 언니
보조 키워드: 가족
선택적: ON (미나 + 가족 두 키워드가 모두 언급될 때만 활성)
우선순위: 100
지속 턴: 3 (미나 얘기가 시작되면 3턴 유지)
내용: 미나는 {{char}}의 친언니. 26세, 회사원.
동생인 {{char}}을 매우 아끼지만, 과보호하는 경향이 있다.
현재 {{char}}이 집을 나온 것에 대해 걱정하고 있다.
주요 키워드: 카페, 루나, 단골
우선순위: 80 (생략되어도 대화에 큰 지장 없음)
내용: '카페 루나'는 {{char}}의 단골 카페. 대학 근처 골목에 위치.
아메리카노를 항상 주문하며, 창가 자리를 선호한다.
바리스타 진수와는 안면이 있다.
항상 활성화: ON
우선순위: 200 (예산 초과 시에도 반드시 유지)
내용: 이 세계에서 마법은 존재하지 않는다.
현실 기반의 현대 한국 서울 배경.
초자연적 현상에 대한 언급은 비유나 농담으로만 허용.
로어북 탭 우측 상단의 "내 로어북" 버튼으로, 현재 로어북에서 엔트리를 골라 저장하거나 저장해 둔 로어북을 가져오기할 수 있습니다. (자세한 내용은 라이브러리 섹션)
캐릭터의 이미지를 그룹으로 묶어 관리합니다. 그룹별 코드:설명으로 정리하면, AI가 상황에 맞는 이미지를 자동으로 선택해 대화에 표시합니다.
에셋 탭은 좌우로 분리되어 있습니다.
그룹 추가·이름 변경·순서 변경·대표 표시·삭제·선택. 업로드와 StageCue 미리보기도 여기서 합니다. 그룹은 보통 인물/배경 등 분류 단위(예: 캐릭터 이름)로 씁니다.
선택한 그룹의 이미지 앨범. 코드 [n]·썸네일·설명·대표★·공개/잠금·그룹 이동·코드 복사·일괄 작업을 다룹니다.
그룹_설명 — 첫 번째 _ 앞이 그룹명, 뒤 전체가 설명이 됩니다.
안나_웃음.png → 그룹 안나, 설명 웃음안나_화남_정면.png → 그룹 안나, 설명 화남_정면배경.png (밑줄 없음) → 그룹 없이 전체가 설명그룹의 + 이미지 추가 또는 업로드 버튼으로 파일 선택 다이얼로그를 열어 한 번에 여러 장을 올릴 수 있습니다.
그룹은 이미지를 분류하는 단위입니다. 좌측 그룹 창에서 관리합니다.
| 기능 | 설명 |
|---|---|
| 그룹 추가 | 새 그룹 생성 (이름은 인물/배경 등 분류명) |
| 이름 변경 | 그룹 이름 오른쪽 편집 버튼으로 인라인 수정 |
| 순서 변경 | 드래그 핸들로 그룹 정렬(우선순위) |
| 대표 표시 | 그룹의 대표 이미지(코드) 지정 — 채팅 모드의 캐릭터 아바타 등에 사용 |
| 삭제 | 그룹 삭제(이미지는 미분류로 이동 또는 함께 정리) |
선택한 그룹의 이미지가 카드로 표시됩니다. 각 카드는 다음을 제공합니다.
| 요소 | 설명 |
|---|---|
코드 [n] | 자동 부여되는 숫자 코드. {{image::n}}로 본문/위젯에서 참조 |
| 설명 | 이미지 설명(코드:설명). 직접 입력하거나 "설명 추가" 피커에서 선택 최대 20자 (운영 설정) |
| 대표 ★ | 그룹 대표 이미지로 지정/해제 |
| 공개 / 비공개 👁 | 상세 페이지 갤러리 노출 여부 |
| 잠금 / 해제 🔒 | 특정 조건(획득·결제 등) 충족 시 열람되는 히든 이미지 |
| 그룹 이동 | 이미지를 다른 그룹으로 이동 |
| 코드 복사 | {{image::n}} 토큰을 클립보드로 복사 |
| 큰 이미지 | 썸네일 클릭 시 라이트박스(확대) 팝업 |
그룹 헤더의 전체 선택 후, 선택한 이미지들을 한 번에 처리합니다.
이미지의 설명은 AI가 어떤 이미지인지 이해하는 핵심입니다. 등록된 그룹·코드·설명으로 StageCue 프롬프트가 자동 생성됩니다.
**[그룹명]** 코드:설명 형태의 안내가 자동 작성되어, AI가 상황에 맞는 코드를 출력하면 해당 이미지가 표시됩니다. 좌측 StageCue 미리보기에서 실제 생성 문구를 확인할 수 있습니다.
설명 입력창 옆 "설명 추가" 버튼을 누르면 설정집 피커가 열립니다. 감정·상황·배경 등 자주 쓰는 단어를 골라 설명에 빠르게 넣을 수 있고, 나만의 설정집을 직접 꾸밀 수 있습니다.
코드는 자동 부여(숫자), 설명은 직접 입력/선택. {{image::코드}}로 본문·위젯에서 참조합니다.
그룹으로 분류하고, 그룹마다 대표 이미지를 지정합니다(대본 모드 아바타 등에 활용).
공개 이미지는 상세 페이지 갤러리에 노출됩니다. 비공개로 두면 대화에서만 사용됩니다.
잠금 이미지는 특정 조건(획득·결제 등) 충족 시 열람됩니다. 히든 씬·수집 요소에 활용하세요.
Reluv에 업로드하는 모든 이미지는 아래 가이드라인을 따라야 합니다. 청소년 이용 가능(safety) 콘텐츠와 성인(unsafety) 콘텐츠 각각 허용 기준이 다르며, 어느 쪽에서도 허용되지 않는 금지 항목이 있습니다.
대표 이미지와 앨범 이미지 모두 이 기준을 따릅니다.
판단 기준은 얼굴 / 체형 / 분위기 / 복장 등을 종합적으로 고려합니다. 단순 노출이 아닌 성적 의도 및 연출을 중심으로 판단합니다.
| 구분 | 기준 |
|---|---|
| 일반 노출 (수영복, 운동복 등) | 허용 가능 |
| 특정 부위 강조, 시선 유도 포즈 | 제한 가능 |
| 성적 행위 암시, 유혹 연출 | 제한 |
프로필 탭에서 등록하는 캐릭터 썸네일과, 앨범의 대표로 지정된 이미지에 적용됩니다.
허용 불가 수위 판단 기준
| 구분 | 판단 기준 |
|---|---|
| 직접적인 성적 행위 | 성관계를 묘사한 이미지 / 성행위를 연상시키는 자세 또는 구도 (의상 착용 여부 무관) |
| 성기 접촉 | 본인의 성기를 직접적으로 만지는 표현 (자기 위로 장면 포함) / 타인이 성기를 만지거나 자극하는 표현 (의상 착용 여부 무관) |
| 성기 노출 | 과도한 성기 노출 또는 성기를 강조하는 연출 |
| 여성 캐릭터 한정 | 유두 노출 불가 |
앨범 갤러리에 표시되는 일반 에셋 이미지에 적용됩니다. 대표 이미지와 공통 원칙을 따르면서, 다음 추가 규정이 있습니다.
가림 처리 상세 규정
미사용 / 사용 모두 유색 가림 처리가 되어 있지 않으면 허용되지 않습니다. (가림 처리 기준은 앨범 이미지와 동일)
미사용: 별도의 가림 처리가 없어도 됩니다.
사용 시: 유색 가림 처리가 필수입니다.
캐릭터 이미지에서 촉수 표현이 성기로 오인되는 사례가 보고되고 있습니다. 다음 기준 중 하나라도 해당하면 가림 처리 대상이 됩니다.
| 범주 | 기준 |
|---|---|
| 1. 형태 | 원통형이며 끝이 둥글거나 팽창된 형태 / 굵기 변화가 뚜렷하거나 생물학적 성기를 연상시키는 실루엣 |
| 2. 표현 방식 | 특정 신체 부위에 삽입·밀착·감싸는 연출 / 체액·점액·분비물 등 성적 연상을 유발하는 묘사와 함께 사용 |
| 3. 연출 맥락 | 성적 상황이나 분위기에서 촉수가 주요 초점으로 강조 / 인물의 성적 반응(쾌감, 흥분 등)을 직접적으로 암시하는 장면 |
가림 처리 범위: 삽입·접촉이 일어나는 접점 부위부터 성기로 인식되는 시점까지 가림 처리가 필요합니다.
스탯, 위젯, AI 호출 추출로 동적인 캐릭터 경험을 만듭니다.
인터랙션 시스템은 Reluv의 가장 강력한 기능입니다. 단순한 텍스트 채팅을 넘어, 게임적 요소와 비주얼 UI를 갖춘 인터랙티브 캐릭터를 만들 수 있습니다.
캐릭터의 상태를 저장하는 데이터입니다. HP, 호감도, 인벤토리 등 다양한 값을 관리할 수 있습니다.
| 타입 | 설명 | 예시 |
|---|---|---|
string | 텍스트 값 | 장소: "카페", 기분: "좋음" |
number | 숫자 값 (유효성 검증 가능) | HP: 100, 호감도: 50 |
boolean | 참/거짓 | 첫만남: true, 비밀공유: false |
string[] | 문자열 배열 | 인벤토리: ["검", "포션"] |
object | JSON 객체 | 스탯: {str: 10, dex: 8} |
누가 이 스탯의 값을 바꿀 수 있는지 지정합니다. 선택에 따라 AI가 스탯을 관리할지, 사용자가 UI로 직접 조작할지 결정됩니다.
AI가 자동 갱신하지 않습니다. 사용자가 위젯의 버튼·입력·슬라이더 등을 통해 직접 값을 바꿉니다.
예: 난이도 선택, 배경음 볼륨, 캐릭터 별명
AI가 매 턴 자동으로 값을 갱신합니다. 게임 밸런스·내러티브에 영향을 주는 값(HP, 골드 등)에 적합합니다. AI 지시사항 필드(이 모드에서만 표시)에 언제 값을 바꿔야 하는지를 적으면 일관된 업데이트를 기대할 수 있습니다.
number 타입에는 추가 옵션이 있습니다:
변수 값을 시각적으로 표현하는 UI 컴포넌트입니다. 채팅 화면에서 상태창, 선택지, 정보 패널 등으로 렌더링됩니다.
위젯을 어디에 표시할지 선택합니다. 위치마다 적합한 용도가 다릅니다.
| 위치 | 표시 방식 | 주로 쓰는 용도 |
|---|---|---|
| 사이드 | 채팅 화면 사이드바에 상시 표시 | HP·MP, 능력치, 관계도 등 상태 패널 |
| 정보창 | AI 메시지 하단에 메시지별로 표시 | 현재 장면·분위기, 감정 정보 요약 |
| 선택지 | AI 메시지 하단의 선택 버튼 묶음 | 대화 선택지, 다음 행동 옵션 |
| 시작 | 첫 대화 시작 전에 한 번만 표시 | 시나리오 선택, 초기 옵션 설정 |
| 수동 | 프로필·소개 등에 수동으로 삽입 | 캐릭터 소개 카드, bio 배너 |
| 에셋 | 대화 중 이미지를 감싸는 래퍼 | 이미지 프레임, 접기/펴기, 캡션 표시 |
표시 위치마다 카드 당 허용 개수가 다릅니다. 사이드 1개, 선택지 1개, 시작 1개, 에셋 1개, 정보창 3개, 수동 5개가 일반적인 기본값입니다.
<emo>, {{image::name}}, <img> 등)를 단순 <img> 태그 대신 위젯으로 감싸서 렌더합니다.
이를 통해 이미지에 프레임·접기/펴기·캡션 등 인터랙션을 추가할 수 있습니다.
에셋 위젯이 등록되지 않은 캐릭터는 기존처럼 일반 이미지로 출력됩니다.
위젯 편집기 상단의 HTML | JSX 토글로 작성 방식을 고릅니다. 한 위젯은 둘 중 한 모드만 실제 렌더에 사용되고, 다른 모드의 내용은 초안으로 보존됩니다.
HTML을 직접 작성합니다. 본문에서 {{스탯명}}으로 스탯 값을 참조하고, CSS는 HTML 내부 <style>로 작성합니다. 하단의 "사용 가능한 스탯" 칩을 클릭하면 커서 위치에 {{스탯명}}이 삽입됩니다. 신규 위젯의 기본 모드입니다.
기본은 비주얼 빌더(드래그&드롭, 코딩 불필요)이며, "고급 JSX 전환"으로 코드 편집(JSX + Scoped CSS)으로 승격합니다. 비주얼↔고급 전환은 기존 방식 그대로입니다.
인터랙션 탭의 템플릿 서브탭에서 아래 템플릿을 바로 적용할 수 있습니다. 적용하면 필요한 변수와 위젯이 자동으로 생성됩니다.
HP / MP 프로그레스 바 (사이드바 표시)
호감도·신뢰도 바 (사이드바 표시)
STR·DEX·INT·WIS·CHA 표시 (사이드바)
제목 + 설명이 있는 선택지 버튼, 클릭 시 전송
텍스트만 있는 간결한 선택지 버튼
AI 메시지 하단 장면/감정 요약
첫 대화 시 시작 시나리오 선택 버튼
프로필/bio에 삽입하는 캐릭터 소개 위젯
카드 컨테이너로 이미지를 감싸는 기본 래퍼 (비주얼 모드)
접기/펴기 토글이 있는 이미지 래퍼 (JSX 고급 모드)
AI의 응답에서 특정 값을 뽑아내 변수에 반영하는 규칙입니다. 예를 들어 "감정을 기쁨으로 표시" 같은 응답을 감지해 emotion 변수를 업데이트할 수 있습니다.
| 항목 | 설명 |
|---|---|
| AI 지시문 | AI에게 어떤 형식으로 값을 출력하라고 지시하는 텍스트 |
| 추출 패턴 | AI 응답에서 값을 찾아내는 정규표현식(Regex) |
| 변수 매핑 | 패턴이 잡아낸 값을 어느 변수에 넣을지 연결 |
| 표시 처리 | 추출된 원본 텍스트를 화면·저장·프롬프트에서 어떻게 다룰지 |
목표: AI 응답 끝의 감정 태그를 추출해 emotion 변수에 저장
AI 지시문:
응답 끝에 현재 감정 상태를 다음 형식으로 표시하세요:
[감정: 기쁨|슬픔|분노|두려움|놀람|평온]
추출 패턴:
\[감정:\s*(기쁨|슬픔|분노|두려움|놀람|평온)\]
변수 매핑: 1번 캡처 그룹 → emotion
표시 처리: 화면에서는 숨김(사용자에게 태그가 보이지 않음)
목표: 전투 중 HP 변동량을 hp_delta 변수로 전달
AI 지시문:
전투가 발생하면 응답 끝에 다음 형식으로 표시:
[HP변동: +N 또는 -N]
추출 패턴:
\[HP변동:\s*([+-]?\d+)\]
변수 매핑: 1번 캡처 그룹 → hp_delta
캐릭터의 공개 범위와 상태를 관리합니다.
캐릭터를 누구에게 보여줄지 결정합니다. 언제든 변경할 수 있습니다.
모든 사용자에게 공개됩니다. 카드 목록, 검색, 추천에 노출됩니다.
공유 링크를 가진 사용자만 접근할 수 있습니다. 카드 목록에는 노출되지 않습니다.
제작자 본인만 접근할 수 있습니다. 초안 작성 단계에서 기본값입니다.
카드 상세 페이지 상단에 표시되는 긴 형식의 소개 글입니다. 캐릭터의 배경, 세계관, 플레이 방식, 주의사항 등 사용자가 대화를 시작하기 전 알아야 할 내용을 자유롭게 작성하세요.
기본적인 마크다운 문법이 지원됩니다. 플레이 가이드와 동일한 문법을 사용합니다.
| 문법 | 의미 |
|---|---|
# 제목 / ## 소제목 | 큰 제목 / 중간 제목 |
**굵게** / *기울임* | 강조 표현 |
- 항목 / 1. 항목 | 불릿 / 번호 목록 |
> 인용 | 인용 블록 |
[링크](url) /  | 링크 / 이미지 |
인터랙션 탭에서 만든 수동 위젯을 캐릭터 상세 소개 안에 삽입할 수 있습니다. 각 위젯 편집기의 "코드 복사" 버튼으로 토큰을 얻은 뒤 본문의 원하는 위치에 붙여넣으세요.
# 🗡️ 모험가 한별
판타지 세계의 신참 모험가와 함께 던전을 탐험하세요!
{{widget::hero_intro_card}}
## 캐릭터 특징
- **직업:** 검사 지망생
- **성격:** 밝고 열정적이지만 가끔 무모함
- **좋아하는 것:** 달콤한 디저트, 강한 상대와의 훈련
## 플레이 팁
당신의 선택이 스토리의 결말을 바꿉니다.
신중하게 대답하면 한별은 진지하게 받아주지만,
무례하게 대하면 바로 토라지니 주의하세요.
> *"함께 가자, 모험의 끝까지."*
{{widget::hero_intro_card}} 자리에 인터랙션 탭에서 만든 "수동" 위젯이 그대로 렌더됩니다.
위젯 편집기의 "코드 복사" 버튼으로 정확한 토큰을 얻을 수 있습니다.
{{widget::아이디}} 토큰으로 삽입하면 됩니다.
자주 쓰는 로어북 · 에셋 · 위젯을 라이브러리로 저장해 두고, 다른 캐릭터를 만들 때 가져와 재사용합니다.
저장·가져오기 모두 필요한 항목만 체크해서 처리합니다.
| 종류 | 선택 단위 | 동봉 규칙 |
|---|---|---|
| 내 로어북 | 엔트리별 | 선택한 엔트리만 저장/가져오기 |
| 내 에셋 | 그룹별 | 그룹 선택 시 그 그룹의 이미지가 함께 동봉(자산 참조) |
| 내 위젯 | 위젯별 | 위젯이 참조하는 스탯과 관련 StageCue가 자동 동봉(이름이 같은 스탯은 스킵) |
효과적인 변수 설계 패턴과 고급 사용법을 알아봅니다.
스탯 이름은 한글·영문자·숫자·언더스코어(_)를 사용할 수 있습니다. 한글 이름도 지원합니다(예: 호감도, 현재위치). HTML 위젯에서는 {{스탯명}}으로 값을 참조합니다.
{ } | : - 등), 예약어. 이 문자들은 위젯/CBS 토큰 처리에 쓰입니다.✅ 좋은 예: hp, max_hp, 호감도, 현재위치, is_first_meet
❌ 나쁜 예: my-hp (하이픈), current location (공백), a|b (특수문자)
아래 예시의 스탯들은 모두 AI 제어 권한입니다. 사용자가 직접 바꾸지 않고 AI가 내러티브 흐름에 맞춰 업데이트합니다.
hp (number) — 현재 체력 [0~100, 한 번에 최대 30 변경]
mp (number) — 현재 마나 [0~50, 한 번에 최대 20 변경]
gold (number) — 소지금
level (number) — 레벨 [1~99]
location (string) — 현재 위치
inventory (string[]) — 보유 아이템
quest (string) — 현재 퀘스트
affection (number) — 호감도 [0~100, 한 번에 최대 10 변경]
trust (number) — 신뢰도 [0~100, 한 번에 최대 5 변경]
mood (string) — 현재 기분
relationship (string) — 관계 단계
date_count (number) — 데이트 횟수
secrets_shared (string[]) — 공유한 비밀들
clues (string[]) — 수집한 단서
suspects (string[]) — 용의자 목록
location (string) — 현재 조사 장소
trust_npc (object) — NPC별 신뢰도
time_phase (string) — 시간대 (아침/낮/밤)
case_progress (number) — 사건 진행도 [0~100]
number 타입 스탯에는 단계를 설정할 수 있습니다. 값의 구간마다 라벨과 AI 지시사항을 부여하면, AI가 현재 값이 속한 단계에 맞춰 행동·말투·태도를 조정합니다. (예: 호감도가 낮으면 경계, 높으면 호의적)
| 항목 | 설명 |
|---|---|
| 라벨 | 구간 이름 (예: 경계 / 보통 / 호의적) |
| 상한(max) | 이 단계의 상한값. 값이 이 상한 이하이면 해당 단계로 판정 (구간은 위에서부터 차례로 채워짐) |
| AI 지시사항 | 이 단계일 때 AI가 따를 행동/말투 지침 (매 응답에 반영) |
number로 둔 뒤, 단계 영역에서 행을 추가합니다(라벨·상한·AI 지시사항).스탯: 호감도 (number) — AI 제어, 범위 0~100
단계:
┌ 라벨: 경계 | 상한 30 | AI 지시: 차갑고 거리를 둔다. 짧게 답하고 사적인 질문을 피한다.
├ 라벨: 보통 | 상한 70 | AI 지시: 무난하게 대한다. 가끔 농담을 섞는다.
└ 라벨: 호의적 | 상한 100 | AI 지시: 다정하게 대한다. 먼저 말을 걸고 호감을 드러낸다.
호감도가 25면 경계 단계 지시가, 80이면 호의적 단계 지시가 매 응답에 적용됩니다.
AI 쓰기 권한 변수의 설명(description)은 매 응답마다 AI에게 전달되는 설명입니다. AI는 이 설명을 보고 "이 변수는 어떤 값을 넣어야 하는지"를 판단합니다.
각 스탯 설명 500자 (운영 설정)
변수 정의
이름: affection
타입: number
기본값: 50
validation: { min: 0, max: 100 }
writable: AI 쓰기
설명문 (500자 한도)
{{user}}에 대한 캐릭터의 호감도. 0~100.
증가:
- 친절한 말·배려: +3~5
- 선물/도움: +5~10
- 좋아하는 주제 공감: +5
감소:
- 무례·비꼼: -5~10
- 약속 위반·무시: -10~15
- 배신·편들기: -15~20
값이 실제로 변할 때만 갱신, 아니면 현재 값 유지.
변수 정의
이름: location
타입: string
기본값: "집"
validation: { allowed_values: ["집", "학교", "카페", "공원", "도서관", "편의점"] }
writable: AI 쓰기
설명문
캐릭터의 현재 위치. 다음 중 하나만 사용:
"집", "학교", "카페", "공원", "도서관", "편의점"
캐릭터가 장면 전환이나 이동을 명시할 때마다 업데이트.
이동 중간 상태("이동 중")는 사용하지 말 것 — 반드시
목적지에 도착한 뒤 그 위치로 설정.
값을 변경할 때는 응답 본문에도 자연스러운 이동 묘사를
함께 포함할 것.
변수 정의
이름: inventory
타입: string[]
기본값: []
writable: AI 쓰기
설명문 (500자 한도) — 배열은 허용 아이템과 형식을 명확히 해야 AI가 혼동하지 않습니다.
캐릭터의 현재 보유 아이템 목록.
중요: 항상 전체 배열을 그대로 전달.
["검"]에서 "포션" 획득 → ["검","포션"].
허용 아이템 (정확히 이 이름만):
- "검","방패","활","지팡이"
- "빨간 포션","파란 포션","해독제"
- "열쇠","두루마리","보석","금화"
규칙:
- 획득: 배열에 추가
- 사용/분실: 배열에서 제거
- 중복 불가, 최대 15개
⚠️ 배열 업데이트 방식이 잘못되면 AI가 인벤토리를 지워버리는 일이 자주 생깁니다. "추가"라고만 적으면 AI가 새 아이템 하나만 보내고, 시스템은 그걸 전체 배열로 덮어써 기존 아이템이 사라집니다. "전체 배열을 항상 완전한 형태로 전달"이라는 문장을 반드시 포함하세요.
변수 정의
이름: is_revealed_secret
타입: boolean
기본값: false
writable: AI 쓰기
설명문
캐릭터가 자신의 비밀(과거 사고 이야기)을 {{user}}에게
공개했는지 여부.
true로 바꾸는 조건:
- 호감도(affection)가 80 이상이고
- {{user}}가 캐릭터에게 진지하게 과거를 물어보거나
- 캐릭터가 술에 취해 무의식적으로 언급했을 때
한번 true가 되면 이후 응답에서 다시 false로 돌리지 말 것.
코딩 없이 트리 빌더로 위젯을 구성하는 모든 방법을 알아봅니다. 대부분의 위젯은 이 모드에서 완성됩니다.
레이아웃을 구성하는 컨테이너입니다. 다른 노드를 담는 그릇 역할을 합니다.
| 컨테이너 | 설명 | 주요 속성 |
|---|---|---|
| Box | 범용 레이아웃 컨테이너 | 방향, 정렬, 간격, flex/grid |
| Card | 카드 UI (선택적 헤더) | 제목, 설명, 헤더 표시 |
| Button | 클릭 가능한 버튼 | 스타일, 크기, 액션(채팅/초안/트리거/함수) |
| Alert | 알림/경고 박스 | 스타일(기본/위험), 제목 |
| Tabs | 탭 인터페이스 | 방향, 스타일, 기본 탭 |
| Accordion | 펼침 목록 — 항목을 접었다 펴는 UI | 단일/다중 펼침, 기본 펼침 값 |
| Accordion Item | 펼침 목록의 개별 항목 | 항목 ID, 제목 |
| Table | 표 컨테이너 | 테두리, 줄무늬, 컴팩트 + 행/열 자동 생성 |
| Table Row | 표의 한 행 | 헤더 행 여부 |
| Table Cell | 표의 셀 | 정렬, 컬럼/행 병합 |
실제 콘텐츠를 표시하는 UI 요소입니다.
| 컴포넌트 | 설명 | 변수 바인딩 |
|---|---|---|
| Label | 텍스트 표시 | 텍스트 값에 변수 바인딩 가능 |
| Icon | 아이콘 (Lucide 라이브러리) | — |
| Progress | 프로그레스 바 | 값(value)과 최대값(max)에 바인딩 |
| Badge | 뱃지/태그 | 텍스트에 변수 바인딩 가능 |
| Avatar | 아바타 이미지 (정사각형) | 이미지 소스에 바인딩 가능 |
| Separator | 구분선 | — |
| Image | 이미지 표시 | 소스에 바인딩 가능 |
| 에셋 이미지 | 에셋 위젯 전용 — 대화 중 이미지를 자동 주입 또는 등록 에셋 고정 표시 | 소스: 자동 주입 / 등록 에셋 선택 |
<emo>, {{image::name}}, <img> 태그의 이미지가 런타임에 자동으로 들어옵니다.사용자 입력을 받거나 변수 값을 직접 조작할 수 있는 컴포넌트입니다. 값 필드에 변수를 바인딩하면 자동으로 양방향 동기화됩니다.
| 컴포넌트 | 설명 | 바인딩 필드 |
|---|---|---|
| Select | 드롭다운 선택 | value (string) |
| Input | 텍스트 입력 (text/number/email/password/url) | value (string) |
| Checkbox | 체크박스 | checked (boolean) |
| Switch | 토글 스위치 | checked (boolean) |
| Slider | 숫자 슬라이더 (min/max/step) | value (number) |
| Radio Group | 라디오 버튼 묶음 | value (string) |
입력 컴포넌트의 value(또는 checked) 필드에 변수를 바인딩하면, 사용자가 컴포넌트를 조작할 때마다 해당 변수에 새 값이
자동으로 기록됩니다. 별도의 액션 코드를 작성할 필요가 없으며, 같은 변수를 표시하는 다른 위젯도 즉시 갱신됩니다.
| 단계 | 동작 |
|---|---|
| ① 변수 정의 | 인터랙션 탭의 "변수" 서브탭에서 사용할 변수를 미리 만들어 둡니다. (예: $mode string, $volume number) |
| ② 바인딩 | Input/Select/Slider 등의 속성 패널에서 value 필드를 클릭하고 변수 목록에서 선택합니다. |
| ③ 표시 | 위젯 미리보기와 채팅 화면에서 변수의 현재 값이 컴포넌트에 자동으로 채워집니다. |
| ④ 입력 | 사용자가 값을 바꾸면 시스템이 내부적으로 변수 업데이트 액션을 호출해 즉시 동기화합니다. |
allowed_values)이 설정된 변수에는 옵션 값이 그 목록과 일치해야 합니다.
Button 컴포넌트의 속성 패널에는 클릭 시 무엇을 할지 정하는 액션 항목이 있습니다. 네 가지 타입 중 하나를 선택합니다.
| 액션 타입 | 입력 필드 | 동작 |
|---|---|---|
채팅 전송 chat |
액션 값 (텍스트, $변수 사용 가능) |
입력값을 사용자 메시지로 즉시 전송합니다. |
입력창에 삽입 draft |
액션 값 (텍스트, $변수 사용 가능) |
채팅 입력창에 텍스트를 채워 넣습니다. 사용자가 직접 전송 버튼을 눌러야 합니다. |
변수 업데이트 updateVar |
대상 변수 + 새 값 ($변수 사용 가능) |
지정한 변수의 값을 바꿉니다. 카운터 증감, 토글, 선택 결과 저장 등에 사용합니다. |
시작 시나리오 start |
액션 값 (숫자, $변수 사용 가능) |
시작 위젯에서 시나리오를 선택할 때 사용합니다. 0 = 첫 인사말, 1+ = 대체 인사말[N-1]. 비어 있으면 0으로 처리됩니다. |
모든 노드에 적용할 수 있는 스타일 속성입니다. 속성 패널 하단에서 설정합니다.
아이콘 컴포넌트의 "애니메이션" 속성에서 선택할 수 있습니다.
nonepulsebouncespinfade-inslide-upglow-pulseLoader2 아이콘을 선택하고 애니메이션을 spin으로 설정하면 완성됩니다.
아이콘과 아바타는 기본 프리셋(SM/MD/LG/XL) 외에 자유로운 크기를 직접 입력할 수 있습니다. 정사각형 컴포넌트라 하나의 값으로 가로세로 양쪽이 동시에 설정됩니다.
| 입력 예 | 해석 |
|---|---|
24 | 숫자만 입력 → 24px로 자동 변환 |
24px | 픽셀 단위 그대로 |
1.5em | em 단위 (부모 폰트 크기 기준) |
1rem | rem 단위 (루트 폰트 크기 기준) |
50% | 퍼센트 (부모 크기 기준) |
잘못된 값(예: abc, 24xx)을 입력하면 자동으로 MD 프리셋으로 폴백되어 미리보기가 깨지지 않습니다.
속성 패널의 Size 섹션에서 패딩과 마진을 4면 개별로 조절할 수 있습니다.
4면을 모두 같은 값으로 설정합니다. 빠른 조정에 유용합니다.
4면이 서로 다르면 P/M 입력칸에는 -가 표시됩니다.
왼쪽(L), 오른쪽(R), 위(T), 아래(B)를 각각 독립적으로 조절합니다. 마진도 동일하게 ML/MR/MT/MB로 구분됩니다.
PL과 PR 사이, PT와 PB 사이에 있는 🔗 버튼은 두 면의 값을 묶어 동시에 조절합니다.
padding-inline / padding-block 효과)Table 컨테이너의 속성 패널에는 표 제작을 쉽게 해주는 두 가지 편의 도구가 있습니다.
원하는 행 수와 열 수를 숫자로 입력하고 생성 버튼을 누르면 빈 셀이 자동으로 만들어집니다. "헤더 행 포함" 옵션을 켜면 첫 행이 헤더로 지정됩니다.
쉼표와 줄바꿈으로 표 데이터를 한 번에 입력할 수 있습니다.
입력 예
헤더: 이름, 나이, 직업
본문:
철수, 25, 개발자
영희, 30, 디자이너
민수, 28, 기획자
결과
| 이름 | 나이 | 직업 |
|---|---|---|
| 철수 | 25 | 개발자 |
| 영희 | 30 | 디자이너 |
| 민수 | 28 | 기획자 |
셀 개수가 행마다 다르면 가장 긴 행을 기준으로 열 수가 통일되고, 부족한 셀은 빈 값으로 채워집니다. 셀 값에 쉼표나 줄바꿈이 포함된 경우에는 수동 편집이 더 적합합니다.
비주얼 모드로 표현하기 어려운 복잡한 위젯을 JSX 코드로 직접 작성하는 모드입니다. 대부분의 위젯은 비주얼 모드로 충분하므로, 이 섹션은 동적 렌더링·고급 로직·세밀한 제어가 필요할 때만 참고하세요.
비주얼 모드로 위젯을 만든 뒤, 속성 패널 상단의 "고급 JSX" 버튼을 클릭하면 JSX 모드로 전환됩니다. 전환 시점에 현재 캔버스 트리가 자동으로 JSX 코드로 변환되어 편집기에 채워집니다.
JSX 고급 모드의 위젯은 샌드박스 안에서 실행됩니다. 사용할 수 있는 것과 없는 것을 먼저 이해해야 합니다.
useState, useMemo, useCallback, useRef, useEffectButton, Card, Progress, Tabs, Select, Input, Slider, Switch 등 비주얼 모드에서 쓰이는 모든 컴포넌트Heart, Star, Sword, Shield, Loader2 등 화이트리스트 아이콘cn (className 병합 유틸)window, document, globalThis, localStorage, sessionStoragefetch, XMLHttpRequest, WebSocketeval, Function, setTimeout, setInterval, import()Proxy, Reflect, Symbol
보안 제약은 서버 컴파일러(AST 검증)와 런타임 샌드박스 두 층에서 적용됩니다.
차단된 식별자를 사용하면 컴파일 에러가 발생하거나 실행 시 undefined가 됩니다.
위젯은 변수에 직접 접근하지 않습니다. 모든 변수는 위젯의 props로 전달되고, 위젯은 React 컴포넌트처럼 props를 통해 값을 읽습니다. 변수와 props 이름을 연결하는 것을 props 바인딩이라고 합니다.
$변수명을 그대로 쓸 수 없습니다. JavaScript 기준으로는 $hp가 단순한 변수 이름이므로, 스코프에 선언되지 않은 상태에서는 ReferenceError가 발생합니다.
대신 Props 바인딩 편집기에 $hp → hp 매핑을 추가하고 위젯 안에서는 props.hp로 읽어야 합니다.
JSX 고급 모드의 하단 패널에서 "바인딩 추가" 버튼으로 행을 만듭니다.
변수 → prop 이름
──────────── ────────────
$hp → hp
$max_hp → maxHp
$location → location
$inventory → inventory
왼쪽은 변수 목록에서 선택하고($변수명 형태), 오른쪽은 위젯 코드 안에서 사용할 prop 이름을 직접 입력합니다.
두 이름이 달라도 되고, 일반적으로 camelCase로 바꿔 쓰면 JSX 코드에서 자연스럽습니다.
비주얼 모드에서 JSX 고급으로 전환 시 기존에 연결된 바인딩은 자동으로 이 맵에 채워져 있습니다.
함수 파라미터에서 destructure하거나 props.xxx로 직접 접근합니다.
function Component(props = {}) {
const { hp = 0, maxHp = 100, location = '', inventory = [] } = props;
return (
<div className="space-y-2">
<div>HP: {hp} / {maxHp}</div>
<div>현재 위치: {location}</div>
<div>
{inventory.map((item, i) => (
<span key={i} className="mr-2">{item}</span>
))}
</div>
</div>
);
}
hp = 0 처럼 기본값을 지정하면, 해당 변수가 아직 초기화되지 않았거나 undefined일 때 0이 들어갑니다.
기본값 없이 hp.toFixed() 같은 호출을 하면 런타임 오류로 위젯이 깨집니다.
변수 값은 내부적으로 문자열 기반으로 저장됩니다. 시스템이 JSON 파싱을 시도하지만, 프리미티브 값(number, boolean)도 문자열로 들어올 수 있습니다. 안전하게 쓰려면 필요 시 명시적으로 변환하세요.
function Component(props = {}) {
// 숫자는 Number()로 안전하게 변환
const hp = Number(props.hp) || 0;
const maxHp = Number(props.maxHp) || 100;
const percent = Math.round((hp / maxHp) * 100);
// 배열은 JSON 파싱되어 배열로 오거나, 문자열로 올 수 있음
const inventory = Array.isArray(props.inventory)
? props.inventory
: [];
return (
<div>
<div>HP: {hp} / {maxHp} ({percent}%)</div>
<div>아이템 {inventory.length}개</div>
</div>
);
}
props.hp를 쓰더라도 Props 바인딩 편집기에 $hp → hp 매핑이 없으면, 런타임에 props.hp가 undefined가 되어 아무것도 표시되지 않습니다.
위젯 안에서 외부 상태를 바꾸려면 sendAction을 호출합니다. 직접 변수를 조작하거나 채팅을 보낼 수 없고, 이 API를 통해서만 가능합니다.
| type | payload | 동작 |
|---|---|---|
"updateVar" | { name: string, value: any } | 변수 1개 설정 |
"chat" | { text: string } | 채팅 전송 |
"draft" | { text: string } | 입력창에 초안 채우기 |
"start" | { fmIndex: number } | 시작 시나리오 선택 — 0=첫 인사말, 1+=대체 인사말[N-1] |
고급 JSX 모드에서는 JSX 편집기 아래에 CSS (Global) 편집기가 있습니다.
여기에 작성한 CSS는 모든 위젯이 공유하며, 채팅 화면에서 <style> 태그로 1회 삽입됩니다.
<style>{`...`}</style> 블록은 해당 위젯에만 스코핑되므로, 공통 스타일과 위젯 고유 스타일을 분리할 수 있습니다.
출력 위치를 "에셋"으로 설정한 위젯은 대화 중 이미지를 감싸는 래퍼 역할을 합니다.
props.src와 props.alt가 런타임에 자동으로 주입되며, Props 바인딩에 등록하지 않아도 됩니다.
| prop | 타입 | 설명 |
|---|---|---|
src | string | 이미지 URL (빈 문자열이면 이미지 없음) |
alt | string | 이미지 설명 텍스트 (에셋 이름 또는 태그) |
추가로 캐릭터 변수를 바인딩하려면 Props 바인딩 편집기에서 자유롭게 추가할 수 있습니다. 단, src/alt는 런타임 값이 항상 우선하므로 바인딩으로 덮어쓸 수 없습니다.
function AssetFrame(props = {}) {
const { src, alt = '' } = props;
const [collapsed, setCollapsed] = useState(false);
if (!src) return null;
return (
<div className="asset-frame">
<div className="asset-header">
{alt && <span className="asset-alt">{alt}</span>}
<Button
variant="ghost"
className="asset-toggle"
onClick={() => setCollapsed(v => !v)}
>
{collapsed
? <ChevronDown size={14} />
: <ChevronUp size={14} />}
</Button>
</div>
{!collapsed && (
<img src={src} alt={alt}
className="asset-image" />
)}
</div>
);
}
위 예시의 스타일(.asset-frame 등)은 CSS (Global) 편집기에 작성하면 모든 에셋 이미지에 일괄 적용됩니다.
if (!src) return null;을 반드시 추가하세요.src가 빈 문자열일 때 <img src="">를 렌더하면 브라우저가 페이지를 다시 로드합니다.
AI가 특정 선택지를 제시하는 위젯. 버튼 클릭 시 해당 텍스트를 채팅으로 전송합니다.
function Component(props = {}) {
const choices = [
{ icon: '☕', text: '카페로 가자' },
{ icon: '🌳', text: '공원을 산책하자' },
{ icon: '🏠', text: '집에서 쉬자' },
];
return (
<div className="flex flex-col gap-2">
{choices.map((c, i) => (
<Button
key={i}
variant="outline"
onClick={() => sendAction('chat', { text: c.text })}
>
{c.icon} {c.text}
</Button>
))}
</div>
);
}
이 위젯은 props 바인딩이 필요하지 않습니다. 내부 상수 배열만으로 동작합니다.
Props 바인딩 편집기에 $hp → hp, $mp → mp, $gold → gold를 추가한 상태에서 아래 코드를 사용합니다.
function Component(props = {}) {
const hp = Number(props.hp) || 0;
const mp = Number(props.mp) || 0;
const gold = Number(props.gold) || 0;
return (
<Card>
<CardContent className="space-y-2">
<div className="flex items-center gap-2">
<span>❤️ HP</span>
<Progress value={hp} max={100} className="flex-1" />
<span className="text-xs">{hp}/100</span>
</div>
<div className="flex items-center gap-2">
<span>💙 MP</span>
<Progress value={mp} max={50} className="flex-1" />
<span className="text-xs">{mp}/50</span>
</div>
<div className="flex items-center gap-2">
<span>💰</span>
<span className="font-semibold">{gold} Gold</span>
</div>
</CardContent>
</Card>
);
}
HP 값이 바뀌지 않으면 Props 바인딩 편집기에 $hp 매핑이 있는지 확인하세요. 바인딩이 없으면 props.hp는 undefined가 되어 Number()로 0이 됩니다.
배열 변수를 반복 렌더링하면서 각 아이템을 클릭하면 삭제하는 상호작용. 비주얼 모드로는 표현하기 어려운 동적 반복 패턴입니다.
Props 바인딩: $inventory → inventory
function Component(props = {}) {
const inventory = Array.isArray(props.inventory)
? props.inventory
: [];
const useItem = (item, idx) => {
const next = inventory.filter((_, i) => i !== idx);
sendAction('updateVar', { name: 'inventory', value: next });
sendAction('chat', { text: `${item}을(를) 사용했다.` });
};
if (inventory.length === 0) {
return <Card><CardContent>인벤토리가 비어있습니다.</CardContent></Card>;
}
return (
<Card>
<CardContent className="space-y-1">
{inventory.map((item, i) => (
<Button
key={i}
variant="ghost"
className="w-full justify-between"
onClick={() => useItem(item, i)}
>
<span>{item}</span>
<span className="text-xs text-muted-foreground">사용</span>
</Button>
))}
</CardContent>
</Card>
);
}
sendAction("updateVar", ...)를 호출해도 같은 함수 안의 props.hp는 이전 값입니다. 누적 계산이 필요하면 로컬 변수로 미리 계산한 뒤 한 번만 전달하세요.fetch, document, localStorage, setTimeout, eval, import 등은 자동 차단. sendAction만 외부와 통신 가능.useEffect(() => {...}, [])처럼 빈 배열로 시작해 필요한 것만 추가하세요.$변수명은 인터랙션 탭의 "변수" 서브탭에서 미리 정의되어 있어야 합니다.위젯이 AI 응답에서 특정 값을 추출해 변수에 반영하는 방법을 알아봅니다.
AI 응답 텍스트에서 패턴을 매칭해 값을 뽑아냅니다. 선택지 / 정보창 / 커스텀 추출 규칙에 사용됩니다.
AI 쓰기 변수를 만들면 시스템이 별도의 도구 호출 경로를 자동으로 설정합니다. 제작자가 따로 규칙을 만들 필요가 없어서 이 섹션의 정규식과 무관하게 동작합니다.
AI 응답에서 자주 사용하는 정규식 패턴입니다:
| 패턴 | 의미 | 예시 매칭 |
|---|---|---|
(.*?) | 아무 텍스트 (최소) | 무엇이든 |
(\d+) | 숫자 | 42, 100 |
([+-]?\d+) | 부호 포함 숫자 | +10, -5 |
([\w가-힣]+) | 단어 (한글 포함) | 기쁨, 카페 |
\[.*?\] | 대괄호 안의 텍스트 | [감정: 기쁨] |
\{.*?\} | 중괄호 안의 텍스트 | {위치: 공원} |
에디터에 내장된 정규식 테스트 기능으로 실시간 검증이 가능합니다:
캐릭터를 여러 언어로 제공하는 방법을 알아봅니다.
각 탭 상단의 언어 토글로 다른 언어 버전을 작성할 수 있습니다. 오버라이드하지 않은 필드는 원본 언어(소스 언어)가 사용됩니다.
각 필드의 글자/토큰 제한을 확인합니다.
| 항목 | 제한 |
|---|---|
| 캐릭터 이름 | 50자 |
| 한줄 소개 | 100자 |
| 플레이 가이드 | 2,000자 |
| 캐릭터 상세 소개 | 10,000자 |
| 상세 설정 + 추가 형식·지시 (합산) | 15,000자 |
| 시작 상황 제목 | 40자 |
| 시작 상황 설명 | 200자 |
| 이미지 설명 (에셋) | 20자 |
| 스탯 이름 | 20자 |
| 항목 | 기본값 (참고) |
|---|---|
| 시작 대사 (각 시작 상황) | 2,000자 |
| 예시 대화 (각각) | 500자 |
| 로어북 항목 내용 (각각) | 1,000 토큰 |
| 스탯 설명 | 500자 |
| 항목 | 기본값 (참고) |
|---|---|
| 시작 상황 | 카드당 10개 |
| 이미지 (에셋) | 카드당 약 300장 |
| 이미지 1장 크기 | 15MB |
| 에셋 그룹 | 카드당 30개 |
| 업로드 1회 처리 | 최대 500개 |
| 로어북 항목 | 카드당 25개 |
| 로어북 항상 활성화 | 최대 5개 |
| 주요/보조 키워드 (항목당) | 각 10개 |
| 위젯 (카드당) | 위치별로 다름 |
| 스탯 | 약 30개 |
에디터에서 사용할 수 있는 키보드 단축키입니다.
| 단축키 | 동작 |
|---|---|
Ctrl + S | 임시 저장 (드래프트) |
Ctrl + Z | 실행 취소 (Undo) |
Ctrl + Y | 다시 실행 (Redo) |
Ctrl + Shift + Z | 다시 실행 (Redo, 대안) |
더 좋은 캐릭터를 만들기 위한 실전 팁입니다.
[감정: OOO] 같은 형식이 효과적입니다.자주 묻는 질문과 답변입니다.
토큰은 AI가 텍스트를 처리하는 최소 단위입니다. 한글의 경우 1글자가 대략 2~3토큰에 해당하고, 영문의 경우 1단어가 1~2토큰입니다. 에디터에서 실시간으로 토큰 수를 확인할 수 있습니다.
공개 요청을 제출하면 카드가 심사 대기 상태로 바뀝니다. 운영진이 가이드라인 위반 여부를 검토한 후 승인하면 공개됨 상태가 되어 다른 사용자에게 노출됩니다. 부적절한 콘텐츠가 있으면 수정 요청 또는 반려 안내가 올 수 있습니다.
성인 컨텐츠 토글을 활성화하면 별도의 NSFW 심사를 거칩니다. 에셋에 NSFW가 감지되면 배지로 표시되며, 미처리된 NSFW가 있으면 공개가 차단됩니다.
위젯 컴파일 오류가 있으면 공개가 차단됩니다. 에러 목록이 표시되니, 각 오류를 수정한 후 다시 시도하세요. 비주얼 모드(캔버스)를 사용하면 컴파일 오류 가능성이 줄어듭니다.
네, 에디터에 내장된 변환기를 사용하면 됩니다. HTML/CSS 위젯, CBS 스크립트, 스탯, AI 호출 추출 규칙 등이 자동 변환됩니다. 다만, 일부 고급 기능은 수동 조정이 필요할 수 있습니다.
자동 저장은 변경 후 1초 뒤 로컬 스토리지에 저장됩니다. 브라우저를 닫아도 복구됩니다. 임시 저장(Ctrl+S)은 서버에 드래프트로 저장됩니다. 다른 기기에서도 접근 가능하며, 더 안전합니다.
사용자/위젯 제어 스탯은 사용자가 위젯이나 UI로 직접 값을 변경할 수 있습니다. 난이도, 설정값, 별명처럼 사용자의 선택을 저장할 때 씁니다.
AI 제어 스탯은 AI만 값을 바꿀 수 있습니다. HP, 골드, 호감도처럼 내러티브·밸런스에 영향을 주는 값에 적합합니다. AI 지시사항에 "언제 얼마만큼 바꿀지"를 적어두면 AI가 그 기준에 맞춰 자동으로 업데이트합니다.