action.json과 pad.json
Vovó가 폴더나 zip에서 읽는 두 파일의 모든 키입니다. Vovó 자체 코드에서 생성되므로 항상 이 버전과 일치합니다. Vovó는 파일이 들어올 때마다 확인하고, 무엇이 잘못됐는지 한 문장으로 말하며 거부합니다. 모르는 키는 아무 말 없이 건너뛰지만, 스키마를 읽는 편집기는 거기에 밑줄을 긋습니다.
키는 소문자, 숫자, _로 이루어지고 이름에는 -도 쓸 수 있으며, 각각 최대 32자입니다.
편집기가 키를 완성하고 실수에 밑줄을 긋게 하려면, 예시처럼 파일 맨 위에 스키마를 적으세요. vovo dev는 액션의 부분들 옆에 action.schema.json을 씁니다. Vovó의 소스에는 둘 다 api 폴더에 있습니다.
action.json
액션의 매니페스트로, 이름, 듣는 것, 요청하는 것, 방송 운영자에게 제공하는 것을 담습니다. 패키지나 폴더 안에서 index.html, style.css, script.js, files/ 옆에 둡니다.
{
"$schema": "./action.schema.json",
"name": "Raffle",
"id": "example.raffle",
"version": "1.2.0",
"api": 1,
"author": "A maker",
"site": "https://example.com/raffle",
"description": "!join in chat joins the wheel; the panel draws the winner.",
"license": "MIT",
"triggers": ["chat", "timer"],
"bindings": [
{ "event": "chat", "filter": [{ "field": "text", "op": "starts", "value": "!join" }] },
{ "event": "timer", "filter": [{ "field": "every", "op": "is", "value": 300 }] }
],
"permissions": ["chat.send"],
"controls": [
{ "key": "open", "label": "Entries open", "kind": "toggle" },
{ "key": "prize", "label": "Prize", "kind": "text" }
],
"settings": [
{ "key": "color", "label": "Wheel colour", "kind": "color", "default": "#840926" },
{ "key": "size", "label": "Size", "kind": "number", "min": 200, "max": 800, "step": 10, "unit": "px", "default": 420 },
{ "key": "side", "label": "Side", "kind": "choice", "options": ["Left", "Right"], "default": "Right" }
],
"panel": [
{ "kind": "control", "key": "open" },
{ "kind": "control", "key": "prize" },
{ "kind": "form", "name": "add", "label": "Put someone in", "button": "Put", "fields": [{ "key": "who", "label": "Name" }] },
{ "kind": "button", "name": "draw", "label": "Draw", "confirm": true },
{ "kind": "list", "key": "names", "label": "In the wheel", "empty": "Nobody yet", "buttons": [{ "name": "out", "label": "Take out", "confirm": true }] }
]
}
$schema(텍스트): 편집기가 이 파일의 스키마를 찾는 곳으로,vovo dev가 옆에 쓰는./action.schema.json입니다. Vovó는 여기서 아무것도 읽지 않습니다.name(텍스트; 필수): 이름이며 프로필 안에서 하나뿐입니다. 이미 있는 액션과 같은 이름으로 가져온 액션은 그 자리를 대신할지 묻거나 "Raffle 2"로 들어옵니다.id(텍스트, 한 줄, 최대 64자): 만든 사람이 한 번 정하고 바꾸지 않는 이름입니다. 만든 사람의 이름과 액션의 이름을 점으로 이어example.raffle처럼 소문자, 숫자,-로 씁니다. 더 새로운 버전을 가져오면, 그 액션이 그때 어떤 이름이든 이것으로 업데이트할 액션을 찾습니다. 없으면 이름으로 찾습니다. Vovó 안에서 만든 사본에는 남지 않습니다.version(텍스트, 한 줄, 최대 32자): 액션 자체의 버전으로 액션 목록에 표시됩니다. 패키지가 액션의 자리를 대신할 때는 그 액션이 가지고 있던 버전과 나란히 보여 주고, 패키지가 같은 버전이거나 더 오래된 버전이면 그렇게 알려 줍니다. 점으로 나눈 숫자는 숫자로 읽습니다(1.10.0은1.9.2보다 새 버전이고,1.0.0-beta.1은1.0.0보다 앞입니다). 다르게 쓰면 두 버전은 같거나 다를 뿐입니다. 없으면1.0.0입니다.api(정수, 1 이상; 필수): 작성 기준이 된 API 버전:1. 이 Vovó보다 새로운 버전은 어떻게 하면 되는지와 함께 거부됩니다.triggers(이벤트 목록): 듣는 이벤트: API의 이벤트이거나,vovo.emit과vovo emit으로 일으키는 자체 이름입니다. API 이름과 비슷한 이름은 의도한 이름과 함께 거부됩니다. 컨트롤, 설정, 패널을 선언한 액션에는control,settings,panel이 목록에 없어도 전달됩니다.bindings(목록): 트리거의 조건.permissions(권한 목록): Vovó에게 요청할 수 있는 것으로, 가져오는 사람에게 표시됩니다. Vovó가 모르는 권한은 의도한 권한과 함께 거부됩니다.persistent(true 또는 false): 이벤트가 올 때 나타나는 대신 화면에 계속 있는지(채팅, 목표 막대)를 나타내며, 편집기와 액션 목록이 이렇게 부릅니다. 동작 방식은 바뀌지 않습니다.operator(true 또는 false): 방송 운영자 전용: 패드, 단축키, 타이머, 자신의 컨트롤, OBS와 컴퓨터가 알리는 것만 듣고, 시청자, 채팅, 보상, 웹훅, 다른 액션의 이벤트는 절대 듣지 않습니다. 다른 사람이 일으킬 수 있는 트리거는 거부됩니다.controls(목록, 최대 32개): 실행 중에 패드가 바꾸는 것.settings(목록, 최대 32개): 사용하는 사람이 코드 없이 바꿀 수 있는 것.panel(목록): 방송 운영자에게 패널에서 보여 주는 것.author(텍스트, 한 줄, 최대 80자): 만든 사람.site(웹 주소, 최대 200자): 액션이나 만든 사람에 대해 더 읽을 수 있는 곳.description(텍스트, 한 줄, 최대 300자): 무엇을 하는지 한 줄로, 가져올 때 표시됩니다.license(텍스트, 한 줄, 최대 100자): 어떤 조건으로 넘겨주는지를 만든 사람의 말로 적습니다. 라이선스 이름(MIT,CC-BY-4.0)이나 직접 쓴 한 줄이며, 가져올 때와 액션 목록에 표시됩니다. 라이선스 전문은 이 파일 옆에LICENSE(또는LICENSE.md,LICENSE.txt)로 두며, 텍스트는 최대 64KB이고, 액션이 들어오기 전에 가져오기 대화 상자에서 읽을 수 있습니다. Vovó는 적힌 내용을 알려 줄 뿐 누구에게도 강제하지 않습니다. 키도 계정도 구매도 확인하지 않습니다.
조건
각 트리거를 다시, 액션을 일으키려면 모두 맞아야 하는 조건과 함께 편집기가 저장하는 형태로 적습니다. triggers의 이름마다 하나씩, 순서는 상관없습니다. 하나씩 맞지 않으면 모든 조건이 아무 말 없이 빠지고 각 트리거는 무엇에나 일어납니다.
event(이벤트; 필수):triggers에 있는 이름 중 하나.filter(목록): 그 조건입니다. 없으면 그런 이벤트마다 액션이 일어납니다.
조건 하나
이벤트 필드 하나를 값과 비교합니다. 텍스트는 대소문자 구분 없이 비교하고, 텍스트로 쓴 숫자는 숫자로 읽습니다.
field(텍스트; 필수): 이벤트의 필드로, API 레퍼런스의 이름대로 씁니다:viewers,reward,text.timer의 간격은every필드(초, 5 이상),hotkey의 조합은keys필드이며, 둘 다is를 씁니다.op(is,not,above,atleast,below,atmost,contains,starts중 하나; 필수): 비교 방법:is와not은 그대로,above,atleast,below,atmost는 숫자로,contains와starts는 텍스트로 비교합니다.value(텍스트, 숫자, 또는 true/false; 필수): 필드와 비교할 값.
컨트롤
액션이 실행되는 동안 패드가 바꾸는 것: 각각 키 이름으로 vovo.state에 저장되고 control 이벤트로 액션에 전달되며, 목록에 적지 않아도 받습니다.
key(키; 필수):vovo.state에 저장되는 자리이며, 두 컨트롤이 같은 키를 쓸 수 없습니다.label(텍스트; 필수): 패드에서 부르는 이름.kind(toggle,choice,counter,text중 하나; 필수): 켜짐이나 꺼짐, 선택지 중 하나, 한 번에 하나씩 올리거나 내리는 정수, 또는 최대 300자의 텍스트 한 줄.options(텍스트 목록): 선택의 선택지, 둘 이상.max(숫자): 카운터의 목표로, 숫자 옆에 표시됩니다.
설정
액션을 쓰는 사람이 코드 없이 꾸미기에서 바꿀 수 있는 것: vovo.settings.<key>로, CSS에서는 --vovo-<key>로 읽으며, 켜짐·꺼짐과 선택은 문서의 data-vovo-<key>로도 읽습니다. 고른 값은 액션과 함께 남고, 패키지에는 기본값만 담깁니다. 텍스트는 최대 여덟 개입니다.
kind(color,number,toggle,choice,text,file,font,camera중 하나; 필수): 무엇인지는 아래 부분에서 설명합니다.key(키; 필수): 액션이 읽는 이름이며, 두 설정이 같은 키를 쓸 수 없고accent도 안 됩니다.label(텍스트, 최대 60자; 필수): 꾸미기에서 부르는 이름.
설정: color
색입니다. 액션이 정하지 않으면 Vovó의 와인색 #840926입니다.
default(색,#RRGGBB): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: number
최솟값부터 최댓값까지 단계별로 움직이는 숫자입니다. 액션이 정하지 않으면 최솟값입니다.
min(숫자; 필수): 최솟값.max(숫자; 필수): 최댓값으로, 최솟값보다 커야 합니다.step(숫자): 한 단계의 크기로 0보다 커야 하며, 없으면 1입니다.unit(px,%,s,ms,em,deg중 하나): CSS 변수에 붙는 단위이며, 없으면 그냥 숫자입니다.default(숫자): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: toggle
켜짐이나 꺼짐이며, 액션이 정하지 않으면 꺼짐입니다.
default(true 또는 false): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: choice
선택지 중 하나이며, 액션이 정하지 않으면 첫 번째입니다.
options(텍스트 목록, 2부터 12까지; 필수): 선택지로, 각각 한 번씩만 씁니다.default(텍스트): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: text
텍스트 한 줄이며, 액션이 정하지 않으면 비어 있습니다.
default(텍스트, 한 줄, 최대 200자): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: file
사용하는 사람이 고르는 이미지, 소리, 동영상으로 최대 50MB입니다. 액션의 처음 값은 자체 파일 중 하나(경로로 지정)이거나 없음입니다.
accept(image,sound,video중 하나): 무엇이 될 수 있는지이며, 액션이 정하지 않으면 이미지입니다.default(파일 경로 또는null): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: font
컴퓨터 글꼴 중 하나로 패밀리 이름으로 지정하며, 액션이 정하지 않으면 Segoe UI입니다.
default(텍스트, 한 줄, 최대 64자): 액션의 처음 값이며, 없으면 종류의 기본값입니다.
설정: camera
컴퓨터의 카메라 중 하나. 액션을 쓰는 사람이 꾸미기에서 고르며, 액션이 놓은 자리에 보입니다(vovo.camera.place, camera.show 권한 필요). 최대 넷. 처음에는 카메라가 없으므로 기본값이 없습니다.
패널
액션이 사이드바의 패널에서 방송 운영자에게 보여 주는 것: 순서대로 놓인 조각으로, 각각 kind로 종류를 밝히고 Vovó가 그립니다. 거기서 한 일은 panel 이벤트로 액션에 전달되며, 목록에 적지 않아도 받습니다. panel 조각은 다음 패널까지의 조각을 담는 새 패널을 시작하고, 첫 패널 앞의 조각은 모든 패널에 나타납니다. tab도 같은 방식으로 패널을 구역으로 나눕니다. 버튼, 양식, 목록 버튼의 이름은 액션 안에서 하나뿐입니다. 액션은 패널을 최대 24개 선언하며, 패널마다 조각은 최대 40개, 탭은 최대 12개입니다.
kind(panel,tab,heading,note,control,button,form,list중 하나; 필수): 무엇인지는 아래 부분에서 설명합니다.
패널: panel
여기서 새 패널이 시작되며, 패널에 자신의 항목이 생깁니다.
label(텍스트, 최대 30자; 필수): 패널에서의 이름.icon(텍스트, 최대 32자): Vovó 아이콘의 이름이나 이모지이며, 없으면 패드에 있는 액션의 첫 버튼 아이콘입니다.
패널: tab
패널의 구역: 다음 탭까지 뒤따르는 조각들.
label(텍스트, 최대 30자; 필수): 이름.
패널: heading
뒤따르는 조각들 위의 제목으로, 그 조각들은 카드 하나를 함께 씁니다.
label(텍스트, 최대 60자; 필수): 표시할 글.
패널: note
무언가를 알리는 한 줄.
label(텍스트, 최대 60자; 필수): 표시할 글.
패널: control
액션의 컨트롤 중 하나로, 패드에서처럼 여기서 조작합니다.
key(키; 필수): 컨트롤의 키.
패널: button
버튼.
name(이름; 필수):panel이벤트에서 누른 것으로 전달되는 이름.label(텍스트, 최대 60자; 필수): 표시할 글.confirm(true 또는 false): 첫 번째로 누르면 묻고, 두 번째에 실행합니다.
패널: form
칸 몇 개와 버튼: 입력한 내용은 누를 때 이벤트의 values로 함께 갑니다. 칸이 하나인 양식은 패널 안에서 바로 입력합니다.
name(이름; 필수):panel이벤트에서 보낸 것으로 전달되는 이름.label(텍스트, 최대 60자; 필수): 표시할 글.button(텍스트): 버튼에 표시할 글.fields(목록, 1부터 4까지; 필수): 양식의 칸.
양식의 칸
각각 패널에서 입력하는 한 줄로, 키 이름으로 양식과 함께 보내집니다.
key(이름; 필수): 이벤트values에서의 키이며, 양식 안에서 한 번만 씁니다.label(텍스트, 최대 60자; 필수): 칸의 이름.
패널: list
액션 상태에서 읽는 목록으로, 항목마다 한 줄이며 수천 줄도 됩니다. 여덟 줄이 넘는 목록에는 자체 검색이 있습니다.
key(텍스트; 필수): 목록을 담은vovo.state의 키.path(텍스트): 그 안에서 목록까지의 키를 점으로 이어 씁니다:round.names.label(텍스트, 최대 60자; 필수): 이름.show(텍스트): 항목이 객체일 때: 한 줄에 보여 줄 필드, 또는 각 항목으로{field}를 채우는 한 줄.empty(텍스트): 비어 있는 동안 표시할 글.buttons(목록, 최대 3개): 각 줄의 버튼: 누르면 그 줄의item과index가 액션에 전달됩니다.
목록의 버튼
목록의 줄마다 붙는 버튼.
name(이름; 필수):panel이벤트에서 누른 것으로 전달되는 이름.label(텍스트, 최대 60자; 필수): 표시할 글.confirm(true 또는 false): 첫 번째로 누르면 묻고, 두 번째에 실행합니다.
pad.json
패드용 버튼 묶음: 소리와 동영상이 든 zip이나 폴더로, 루트의 pad.json이 그룹과 그 버튼을 알려 줍니다. 없으면 폴더마다 그룹이 되고 소리나 동영상마다 파일 이름의 버튼이 됩니다. 다시 가져오면 이름을 댄 것만 갱신하고 나머지는 그대로 둡니다.
{
"$schema": "./pad.schema.json",
"groups": [
{
"name": "Sounds",
"color": "#2F6FDB",
"buttons": [
{ "label": "Applause", "icon": "👏", "sound": "sounds/applause.mp3", "favorite": true, "hotkey": "F13" },
{ "label": "Drum roll", "sound": "sounds/drums.ogg", "volume": 130 },
{ "label": "Rain", "video": "videos/rain.mp4", "key": "luma", "loop": true }
]
},
{
"name": "Live",
"buttons": [
{ "label": "Raffle", "action": "Raffle" },
{ "label": "Entries", "action": "Raffle", "control": "open" },
{ "label": "Starting", "scene": "Starting soon" },
{ "label": "Camera", "scene": "Game", "source": "Camera" },
{ "label": "Blur", "source": "Camera", "filter": "Blur" },
{ "label": "One minute", "team": "One minute, then I'm back." }
]
}
]
}
$schema(텍스트): 편집기가 이 파일의 스키마를 찾는 곳으로, 예를 들어 옆에 둔./pad.schema.json입니다. Vovó는 여기서 아무것도 읽지 않습니다.groups(목록; 필수): 순서대로 놓인 그룹.
그룹
패드의 그룹과 그 버튼을 순서대로.
name(텍스트, 최대 60자; 필수): 이름입니다. 프로필에 같은 이름의 그룹이 있으면(대소문자 구분 없이) 갱신됩니다.color(색,#RRGGBB): 그룹의 색입니다. 없으면 이미 있는 그룹은 제 색을 유지하고 새 그룹은 다음 색을 받습니다.buttons(목록): 그룹의 버튼.
버튼
버튼과 그 동작: Vovó는 다음 순서로 처음 찾은 것을 읽습니다: sound, video, control이 있는 action, action, filter가 있는 source 또는 source가 있는 scene, scene. 묶음 하나로 가져오는 버튼은 최대 2,000개입니다.
label(텍스트, 최대 60자; 필수): 패드에서의 이름입니다. 그룹에 같은 이름의 버튼이 있으면(대소문자 구분 없이) 갱신됩니다.icon(텍스트): Vovó 아이콘의 이름이나 이모지.sound(파일 경로): 묶음 안의 소리로, 그 안의 경로로 지정합니다: MP3, OGG, WAV, M4A, WEBM, FLAC, 최대 20MB.video(파일 경로): 묶음 안의 동영상으로, 그 안의 경로로 지정합니다: MP4, M4V, 최대 200MB이며 무대 전체 위에서 재생됩니다.key(텍스트): OBS 필터처럼 동영상에서 무엇을 빼는지:none,luma(검정),chroma(초록),chroma:#RRGGBB.loop(true 또는 false): 버튼을 다시 누를 때까지 동영상이 계속 반복됩니다.action(텍스트): 프로필의 액션 중 하나로, 이름으로 지정하며 그 액션의button이벤트로 일어납니다.control(키):action과 함께: 그 액션의 컨트롤 중 하나를 키로 지정하며, 패드의 버튼처럼 조작합니다.value(텍스트):control과 함께, 선택일 때 고를 선택지입니다. 없으면 차례로 돌아갑니다.scene(텍스트): OBS 장면으로, 이름으로 지정해 방송에 내보냅니다.source(텍스트):scene과 함께: 그 장면의 소스를 보이거나 숨깁니다.filter와 함께: 필터가 붙은 소스입니다.filter(텍스트):source와 함께: 그 소스의 필터 하나를 켜거나 끕니다.team(텍스트, 최대 300자): 스트리머로서 팀 대화에 쓰는 메시지 한 줄. 방송이나 채팅에는 나가지 않으며, 기기의 패드에는 이 버튼이 없습니다.favorite(true 또는 false): 즐겨찾기에 넣을지 여부입니다. 없으면 이미 있는 버튼은 그대로입니다.hotkey(텍스트): 어떤 프로그램에서든 버튼을 누르는 조합으로, 평소 쓰는 대로 씁니다:F13,Ctrl+Shift+1. 프로필의 두 버튼이 같은 조합을 쓸 수 없습니다.volume(정수, 0부터 150까지): 소리나 동영상의 음량으로, 파일 대비 백분율입니다. 없으면 이미 있는 버튼은 제 음량을 유지합니다.