Vovó 도움말

액션이 실행되는 방식

장면이 액션을 보여 주는 순간부터 Vovó가 액션을 어떻게 다루는지입니다. Vovó가 보장하는 것과 액션이 기대해서는 안 되는 것을 다룹니다. 남에게 넘기거나 판매할 액션을 쓰는 사람을 위한 설명이며, 액션을 쓰는 방법은 액션에 있습니다.

자신만의 페이지

액션은 하나하나가 독립된 문서이며, 장면의 페이지가 마련해 주는 프레임에 들어갑니다. 액션의 HTML에 style.css와 script.js가 써 넣어지고 스크립트가 맨 끝에 오므로, HTML이 준비된 뒤에 스크립트가 실행됩니다. 액션 하나가 고장 나도 다른 액션은 함께 쓰러지지 않습니다. 장면은 액션을 장면의 순서대로 겹쳐 보여 주며, 첫 번째가 맨 아래에 놓입니다.

프레임은 클릭도 키도 받지 않습니다. 오버레이는 보는 것이지 누르는 것이 아닙니다. 방송 운영자가 하는 일은 패드, 액션의 패널, 꾸미기에서 하고, 이벤트로 액션에 전달됩니다.

액션은 열린 페이지가 자신을 보여 주는 동안에만, 그리고 활성 프로필에서만 이벤트를 듣습니다. 열린 페이지가 하나도 없으면 팔로우를 세는 것도 없습니다.

네트워크 없음, 브라우저에는 아무것도 남기지 않음

액션이 닿을 수 있는 것은 자신의 파일과 Vovó가 건네주는 것뿐입니다. 이미지, 소리, 동영상, 글꼴은 액션의 파일에서 이름으로 가져오거나 이벤트가 알려 준 주소(이모트, 커버, 꾸미기에서 고른 파일)에서 가져오며, 인터넷에서는 절대 가져오지 않습니다. 코드와 스타일은 script.js와 style.css뿐입니다. 파일이나 다른 곳의 스크립트와 스타일시트는 쓸 수 없고, eval도 워커도 없습니다. fetch, XMLHttpRequest, WebSocket은 액션 자신의 파일에 대해서도 거부되므로, 필요한 데이터는 스크립트에 넣습니다. 브라우저 저장소(localStorage, 쿠키, IndexedDB)는 없습니다. 액션이 간직할 것은 vovo.state에 간직합니다.

바깥에서 필요한 것은 선언한 권한 안에서 Vovó에게 요청합니다. 채팅 한 줄, 이름으로 부르는 웹훅, 패드의 소리, 공식 플레이어의 클립 같은 것입니다.

열린 모든 페이지가 실행합니다

같은 액션은 그 장면이 열린 모든 곳에서 실행됩니다. OBS, 장면 미리 보기 창, 브라우저 탭, 동시에 두 소스에서도 그렇습니다. 각 사본은 같은 이벤트를 받고 같은 것을 그립니다. 그래서 페이지는 그리고 재생하기만 하고, 한 번만 일어나야 하는 일은 Vovó에게 요청합니다. Vovó는 같은 이벤트를 처리하면서 요청한 페이지들에 대해 한 번만 합니다. 채팅 한 줄, 추첨, 음성, 웹훅, 패드의 소리, OBS의 소스, 액션 자체의 이벤트가 그렇습니다.

Vovó는 처리 중인 이벤트로 한 페이지의 호출과 다른 페이지의 호출을 구분합니다. 리스너가 끝난 뒤에 하는 호출(await 뒤, 애니메이션이 끝날 때, 타이머 안)은 { event: e }로 응답하는 이벤트를 밝힙니다. e는 리스너가 받은 객체입니다. 이것이 없으면 Vovó는 두 번째 페이지인지 두 번째 호출인지 구분할 수 없습니다.

vovo.on("raid", async (e) =>
{
    const gift = await vovo.draw(["a hug", "a song", "a dance"]);
    vovo.show("raid", { user: e.user, gift: gift.value });
    vovo.chat.send(e.user + " gets " + gift.value + "!", { event: e });
});

페이지가 스스로 시작하는 일에는 뒤에 이벤트가 없습니다. 액션의 setInterval은 모든 페이지에서 돌고, 로드될 때 하는 일도 마찬가지입니다. 그러면 Vovó는 요청된 내용만으로 판단할 수 있으므로(5초 안의 같은 채팅 줄, 같은 음성, 같은 웹훅이나 자체 이벤트는 하나로 봅니다), 세는 일이나 한 번만 일어나야 하는 일은 timer 트리거에 둡니다. 이것은 앱의 것이며 모든 페이지에 하나입니다.

상태이지, 다시 재생이 아닙니다

vovo.state는 페이지가 아니라 Vovó가 간직합니다. 페이지가 로드되면(OBS 시작, 소스 새로 고침, 패닉 종료, Vovó 다시 열기) 스크립트가 실행되기 전에 상태를 전부 갖고 있으며, 한 페이지에서 설정한 키는 다른 페이지에도 곧바로, 아무 알림 없이 전달됩니다. 다른 페이지도 같은 이벤트를 스스로 처리했기 때문입니다. 이벤트는 절대 다시 재생되지 않습니다. 레이드가 왔을 때 없었던 페이지는 나중에도 그것을 알지 못합니다. 그래서 액션은 다시 보여 줘야 하는 것(목표의 숫자, 추첨의 이름들, 카운트다운이 끝나는 때)을 모두 상태에 두고, 로드될 때 그것으로 그립니다.

function draw()
{
    document.getElementById("count").textContent = vovo.state.count || 0;
}

vovo.on("follow", () =>
{
    vovo.state.count = (vovo.state.count || 0) + 1;
    draw();
});

draw();

현재 값과 계속 흐르는 측정값

네 가지 이벤트는 한 순간이면서 값이기도 합니다: obs.scene, media.track, twitch.viewers, screen.shared. 로드된 액션은 자신이 듣는 것마다 가장 최근 값을 방금 일어난 것처럼 곧바로 받으므로, 다음 곡을 기다리지 않고 재생 중인 곡을 보여 줍니다. 이것은 로드될 때마다, 모든 페이지에서, 뒤에 이벤트 없이 다시 옵니다. 그것으로 그리되, 한 번만 일어나야 하는 일로 응답하지는 마세요.

audio.level, screen.color, input.move, speech.text는 측정값이며 초당 최대 60번 옵니다. 전달되고 잊히며, 열린 페이지가 그것을 듣는 액션을 보여 주는 동안에만 읽습니다. 리스너는 가볍게 두고, 움직임은 CSS에 맡기세요.

로드, 다시 로드, 패닉

페이지는 언제든, 여러 번 로드될 수 있습니다. OBS는 장면이 보일 때 소스를 시작하고, 숨겨진 동안에는 종료할 수 있으며, 다시 보일 때 새로 고칠 수 있습니다. Vovó도 액션의 코드나 파일이 바뀌면 액션을 다시 로드합니다. 패닉은 모든 장면을 한꺼번에 비우고 액션을 다시 로드하며, 액션이 하던 일은 거기서 멈춥니다. 패닉이 끝나면 액션은 한 번 더 로드되어 상태에서 시작합니다. 패닉 중에는 액션에 아무것도 전달되지 않고, 그 사이에 온 것은 나중에도 재생되지 않습니다. 컨트롤의 값은 상태이므로 유지됩니다.

그러므로 액션은 앞선 페이지가 하다 만 일에 기대지 않고, 언제든 상태만으로 올바르게 떠야 합니다.

무대

액션은 짧은 변이 1080인 CSS 픽셀 무대에 그립니다. 16:9 방송은 해상도와 상관없이 1920 × 1080이고(4K 소스는 두 배 크기로 선명하게 그립니다), 세로 방송은 1080 × 1920이며, 다른 모양의 화면은 그 모양입니다. 액션의 문서는 무대와 같은 크기이고 투명하므로 100vw × 100vh가 화면 전체이고, 그리지 않은 곳에는 게임이 보입니다. 다른 사람의 방송을 위해 만드는 액션은 모양을 가정하지 않습니다. 가장자리 기준으로, 퍼센트로 배치하고, 세로 방송에는 @media (orientation: portrait)를 쓰세요.

OBS의 브라우저

OBS는 자체 브라우저로 장면을 보여 줍니다. Vovó의 편집기와 미리 보기 창의 브라우저보다 오래됐고(OBS 32에서는 Chromium 127), 그래픽 카드의 도움 없이 돌 수도 있습니다. 새로운 CSS나 JavaScript 기능은 기대기 전에 이 버전에서 되는지 확인하고, 넘기기 전에 OBS에서 직접 액션을 보세요. 거기서는 소리가 클릭 없이 바로 나고 방송으로 나갑니다. 스트리머만 들어야 하는 것은 액션에 넣지 않습니다.

OBS의 페이지에는 콘솔이 없습니다. 액션이 잡지 않은 오류와 Vovó가 호출에 대해 알려 주는 말은 액션의 이름과 줄 번호와 함께 Vovó의 콘솔에 옵니다. console.log는 오지 않습니다. 그것을 보려면 미리 보기 주소(vovo dev가 보여 줍니다)를 브라우저에서 열고 개발자 도구를 쓰세요.

속도와 한도

속도를 넘은 호출은 버려지며 줄을 서지 않습니다. 그 Promise는 이유와 함께 거부됩니다.

넘기기 전에