Render de céu Roblox
Produz um recorte transparente em PNG de um item de um lugar Roblox usando apenas capturas de tela do Studio. Nenhum plugin é necessário; o script incluído reproduz a técnica que o plugin Photobooth usa.
Primeiro: verifique o modelo
Este skill foi feito para rodar no Claude Haiku 5.5 (claude-haiku-5-5). O Haiku é significativamente
mais rápido, e o trabalho aqui é um procedimento fixo e roteirizado que não precisa de um modelo maior como
Opus 5.5, que é feito para codificação e tarefas mais complexas. Antes de fazer qualquer outra coisa, verifique
qual modelo você é. Se você não for Claude Haiku 5.5, pare e peça ao usuário para trocar
antes de começar: no Claude Code eles podem executar /model claude-haiku-5-5, ou selecionar Haiku 5.5 no
seletor de modelo do aplicativo desktop. Continue quando eles tiverem trocado. Se eles disserem que querem ficar no
modelo atual, prossiga com ele.
Como funciona (para que você possa raciocinar sobre falhas)
O Roblox não pode renderizar com fundo transparente, então a transparência é medida:
- Uma cópia do item é fotografada na frente de um fundo preto liso e novamente na frente de um fundo branco liso. Nada mais muda entre as duas fotos.
- Por pixel: se ele for branco em uma e preto na outra, é fundo (alfa 0). Se for
idêntico em ambas, é item sólido (alfa 1). No meio,
alfa = 1 - (branco - preto) / 255. Isso lida com vidro e bordas anti-aliasing. - A cor vem de uma terceira foto em preto com a aparência própria do lugar (bloom, correção de cor), dividida pelo alfa.
Tudo que faz isso falhar é algo que difere entre as duas fotos além do fundo, ou algo diferente do item que está na imagem. É sobre isso que a próxima seção se trata.
Esteja ciente do mundo
Uma captura de tela captura tudo que está na frente da câmera e tudo que está iluminando o item. Antes e depois de um render, pense em:
- Coisas no caminho. Construções, terreno, outros modelos, a baseplate, partículas de objetos
próximos. O script evita tudo isso nunca fotografando o item onde ele está: ele clona o
item, levanta o clone para o céu vazio e coloca um plano de fundo bem atrás dele. Ele verifica
se o local de estagiamento está realmente vazio (sem partes dentro de
clearancestuds, nada diretamente acima, o chão bem abaixo) e sobe 1500 studs de cada vez até que esteja. Leia a linhaestagiado em Y=no relatório; se ela disser que a altitude forçada não está clara, ou não conseguir encontrar céu claro, escolha umaaltitudevocê mesmo depois de olhar o quão alto o mapa é. - Coisas que projetam sombras. Algo entre o item e o sol projeta sombra nele mesmo se estiver fora do quadro. O script faz raycast em direção ao sol e informa se algo for atingido.
- De onde a luz vem. O sol (ou lua) é a única luz direcional e está sempre
acima do horizonte.
lighting = "studio"(padrão) move temporariamente a hora do dia para que o sol fique sobre o ombro esquerdo da câmera, e aumenta a luz ambiente, para que todo item seja iluminado da mesma forma independentemente do lugar.lighting = "world"mantém a iluminação do lugar; o relatório então informa se o sol está na frente ou ATRÁS do lado visível. Atrás significa um render escuro. - Olhando para cima.
lookStraightUp = truerotaciona o clone e aponta a câmera para +Y, então a única coisa que pode ficar atrás do item é o céu. Use quando o mapa for tão alto ou desordenado que céu claro ao lado seja difícil de encontrar. O custo: a câmera agora está embaixo, o sol nunca pode ficar atrás dela, e o alinhamento da luz chave do relatório cai (cerca de 0,6 em vez de 1,0). Na prática, ainda renderiza bem; só tem menos controle sobre sombreamento. - Efeitos do céu. Névoa atmosférica, nuvens, raios solares, profundidade de campo e desfoque ficam entre a câmera e o fundo. O script os remove ou desabilita durante as fotos.
- Brilho. O fundo é uma parte Neon porque Neon ignora iluminação e sombras, dando uma cor exata e lisa. Mas Neon brilha, e o brilho se espalha sobre partes finas do item e as faz parecer translúcidas. Desligar os BloomEffects não para isso (o motor cai para um brilho padrão); um BloomEffect habilitado com Intensidade 0 e Tamanho 0 para, e o script adiciona um para as fotos de medição. Se um item sólido sair fantasmagórico, esta é a primeira coisa a suspeitar.
- Coisas que se movem. Partículas, feixes, fogo, fumaça e rastros estão em lugares diferentes em cada
foto e se transformam em bolhas pretas. Eles são desligados no clone por padrão. Com
particles = trueeles são mantidos e congelados durante as fotos. - Sobreposições do Studio. Caixas de seleção, contornos de hover e telas do StarterGui estariam na captura de tela. O script limpa a seleção e as esconde, e só usa um quadrado centralizado do viewport, longe dos widgets de canto.
- O viewport em si. O tamanho da saída é limitado pelo lado mais curto do viewport do Studio, e o Studio deve estar no modo Editar com a visualização 3D visível. O Modo Gráfico "OpenGL" não funciona.
O script coloca cada um deles de volta quando termina, inclusive em erro. O item original nunca é movido ou modificado.
Fluxo de trabalho
Não execute comandos de temporização enquanto o trabalho estiver em andamento. O Claude Code adiciona timestamp a cada chamada, então o tempo de execução é medido a partir da transcrição da sessão em uma única chamada no final (passo 7, e Benchmark abaixo). Todo trabalho termina com essa temporização, e a mensagem final para o usuário termina com o tempo total. Não pule e não espere ser perguntado.
-
Encontre a instância do Studio (
list_roblox_studios) e confirme qual lugar usar se mais de um estiver aberto. Então execute esta verificação de status através deexecute_luau(datamodelEdit), comwantdefinido como o início de uma palavra no nome do item, em minúsculas. Em uma chamada, ele informa se o renderizador e exportador já estão instalados nesta sessão do Studio e lista itens correspondentes (os filhos de um item são omitidos, então uma pasta de ferramentas aparece uma vez, com sua contagem de filhos):local want = "espada" -- início de uma palavra no nome do item, minúsculo; "" para pular a busca local function matches(d) if not (d:IsA("Model") or d:IsA("Tool") or d:IsA("Accessory") or d:IsA("BasePart") or d:IsA("Folder")) then return false end local name, i = d.Name, string.find(string.lower(d.Name), want, 1, true) while i do -- apenas no início de uma palavra: "Gatos", "Gato Voador", "GatoTorre", não "Localização" if i == 1 or not string.match(string.sub(name, i - 1, i - 1), "%a") or string.match(string.sub(name, i, i), "%u") then return true end i = string.find(string.lower(name), want, i + 1, true) end return false end local out, hits = {}, {} if want ~= "" then for _, d in workspace:GetDescendants() do if matches(d) then local p, inside = d.Parent, false while p and not inside do inside, p = hits[p] == true, p.Parent end if not inside then hits[d] = true table.insert(out, d:GetFullName() .. " (" .. d.ClassName .. ", " .. #d:GetChildren() .. " filhos)") if #out >= 40 then table.insert(out, "(mais; estreite want)") break end end end end end return "renderer=" .. tostring(shared.SkyRenderVersion) .. " exporter=" .. tostring(shared.SkyExportVersion) .. "\n" .. table.concat(out, "\n")As versões atuais são renderer=1 exporter=1. Um número que corresponde significa que o script está instalado e atualizado: pule sua Leitura e colagem (passo 2 abaixo para o renderizador, passo 1 de "Salvando PNGs sem HTTP" para o exportador).
nilou um número diferente significa cole-o. Se a lista não tornar o item claro, recorra asearch_game_tree. -
Carregue o renderizador, a menos que a verificação de status mostre
renderer=1. Leiascripts/render_item.luaue passe o arquivo inteiro, inalterado, como ocodedeexecute_luau(datamodelEdit). Comtarget = nilele apenas instala três funções e retorna "SkyRender instalado". Elas permanecem disponíveis pelo resto da sessão do Studio:shared.SkyRender(config)renderiza um item, retorna um relatório de textoshared.SkyRenderBoard(names)mostra resultados para inspeçãoshared.SkyRenderClear()remove o quadro e todos os resultados armazenados
Se uma chamada posterior disser que
shared.SkyRenderé nil (Studio foi reiniciado), cole o arquivo novamente. Quando você alterarrender_item.luauouexport_nohttp.luau, aumenteshared.SkyRenderVersionoushared.SkyExportVersionno final do arquivo e o número acima, juntos. -
Renderize. Cada chamada é curta:
return shared.SkyRender({ target = workspace.BananaSword, name = "banana" })Para um lote, faça um loop em uma chamada e junte os relatórios:
local out = {} for _, tool in workspace.Mug:GetChildren() do table.insert(out, shared.SkyRender({ target = tool, name = tool.Name })) end return table.concat(out, "\n\n") -
Leia o relatório. Um bom parece com:
OK 512x512px "banana" -> CoreGui.SkyRenderResults.banana raio do item 2.45 studs, câmera a 18.7 studs de distância, estagiado em Y=3001 iluminação do studio, alinhamento da luz chave 1.00 (1 = ideal) cobertura: 8.8% opaco, 0.4% semitransparente, limites x 44-474 y 148-365 calibração do fundo (neon) branco=255,255,255 preto=0,0,0 osScale=1 tempo 3.41s (relógio de parede: estagiamento, fotos, composição e restauração)Verifique: calibração é 255 / 0; limites não tocam 0 ou size-1 (cortado); a divisão entre opaco e semitransparente faz sentido para o item (uma espada sólida deve ser quase toda opaca, um vidro deve ter uma parte semitransparente real). Aja sobre qualquer coisa sob
NOTAS:. -
Olhe. Números não dizem se o item está virado para o lado errado. Chame
shared.SkyRenderBoard({ "banana" })(ou{}para todo resultado). Ele constrói um quadro temporário no céu mostrando cada imagem sobre magenta e sobre cinza escuro, e retorna a posição exatacamera_positionelook_at_positionpara passar parascreen_capture.screen_capturenão desenha GUIs, e é por isso que o quadro usa decalques em partes. Julgue: ângulo certo? item inteiro no quadro? bordas limpas em ambos os fundos? lado iluminado visível? sem bolhas estranhas? Re-renderize com opções alteradas até que esteja certo, entãoshared.SkyRenderBoard(nil)para remover o quadro. -
Entregue (veja abaixo), então
shared.SkyRenderClear()a menos que o usuário queira os resultados mantidos na sessão. -
Temporize (obrigatório, todo trabalho). Como a última chamada de ferramenta do trabalho, depois que os PNGs são salvos e o Studio está limpo, execute
python scripts/benchmark.py. Então termine sua mensagem final para o usuário com o resultado, neste formato:Tempo total: 2m 10s para 6 imagens (21.6 s por imagem), execução fria.Adicione a tabela de fases acima dessa linha quando o trabalho foi mais de uma única imagem ou quando algo foi lento. O total é a última linha da mensagem, nunca omitido, e nunca apenas em um resultado de ferramenta que o usuário pode não ver.
Benchmark (prompt do usuário para a última mensagem)
Sempre, no final de cada trabalho (passo 7 do fluxo de trabalho), quer o usuário tenha pedido ou não. Custa uma
chamada de ferramenta: o Claude Code escreve cada prompt, chamada de ferramenta e resultado na transcrição da sessão
(~/.claude/projects/<project>/<session>.jsonl) com um timestamp, e scripts/benchmark.py
os lê.
- Quando: como a última chamada de ferramenta da vez do trabalho. Ela vê todas as chamadas até e incluindo ela mesma, então apenas a mensagem final (alguns segundos) é omitida. Se o usuário depois perguntar sobre um trabalho finalizado, execute-o novamente para obter o valor completo.
- Execute:
python scripts/benchmark.pyescolhe a sessão mais recente que executou este skill e seu último pedido de render. Passe um id de sessão ou caminho.jsonlpara escolher outra sessão,--liste--turn <n>para escolher outro pedido nela, e--callspara listar cada chamada com sua temporização. - Relatório: a tabela de fases (encontrar, configurar, render, exportar, montar, limpar, contabilidade, resposta), cada uma dividida em tempo do modelo (pensar e escrever a chamada, incluindo as colagens de script) e tempo da ferramenta (esperar por resultados). Chamadas paralelas são contadas uma vez, então as fases somam o total. Depois a contagem de imagens e segundos por imagem.
- Detalhe do render (opcional): a linha
timeem cada relatório de render é medida dentro do Studio ao redor desse render. Use-a para comparar renders individuais.
Diga se a execução foi fria (renderizador e exportador colados neste trabalho) ou quente (já instalados), já que as colagens são a maior parte do tempo de configuração de uma execução fria. Finalize a mensagem final com a linha Tempo total: do passo 7.
Opções
Todas opcionais exceto target. Padrões entre colchetes.
| Opção | Significado |
|---|---|
target | A Instância a renderizar. Modelos, partes, Ferramentas, Acessórios e Pastas funcionam. |
name ["render"] | Rótulo para o resultado. Reutilizar um nome substitui o resultado anterior. |
viewDir [(-1, 0.6, -1)] | Direção do item em direção à câmera, em eixos mundiais como o item está atualmente. (0,0,-1) olha para sua face -Z; aumente Y para olhar de cima. |
up [(0,1,0)] | Qual direção mundial é para cima na imagem. Use para colocar uma espada na diagonal, etc. |
fov [20] | Estreito é plano e parecido com ícone. 50-70 exagera a perspectiva. |
size [512] | Saída quadrada em pixels, limitada pelo lado mais curto do viewport. |
padding [0.08] | Margem como uma fração da imagem. |
lighting ["studio"] | "studio" ou "world", veja acima. |
particles [false] | Manter efeitos de partícula (congelados) em vez de desligá-los. |
lookStraightUp [false] | Estagiar com a câmera apontando para +Y, veja acima. |
altitude [auto] | Forçar a altura de estagiamento. |
clearance [400] | Studs de espaço vazio necessários ao redor do local de estagiamento. |
backdrop ["neon"] | "neon", ou "fog" (um plano simples escondido em névoa sólida) como fallback. |
refit [true] | Testar foto primeiro, então re-enquadrar para que os pixels visíveis preencham a imagem. As caixas delimitadoras das partes são soltas, então sem isso os itens saem pequenos. |
keepLook [true] | Pegar cor de uma foto com o bloom do lugar e correção de cor ativos. Desligar usa a medição de transparência para cor também (mais rápido, mas sem bloom, efeitos de pós-processamento). |
ambient [Color3.fromRGB(204, 204, 204)] | Cor da luz ambiente durante a foto de cor. Ignorado se keepLook=true. |
resultsParent [game.CoreGui] | Onde a placa de resultados e os itens estagiados vão. Prefira CoreGui para que não salvem. |
Salvando PNGs sem HTTP
O Roblox Studio pode salvar imagens sem HTTP via file.write em scripts, mas file.write não é executado
no sandbox Edit onde o script do renderizador roda. As imagens são armazenadas em CoreGui.SkyRenderResults.<name>
e o exportador deve ser executado do Run sandbox file.write. Ele é instalado uma vez por sessão de Studio e
então invocado quando você precisa de PNGs.
-
Instale o exportador quando o passo de status acima mostrar
exporter=nilou um número diferente. Leiascripts/export_nohttp.luaue passe o arquivo inteiro comocodedeexecute_luaucomsandbox="Run". Ele adiciona uma funçãoshared.SkyExportAll()que escreve todos os resultados de render parascripts/exports/<name>.png. -
Use. Depois de renderizar e inspecionar (passos 3-5), execute:
return shared.SkyExportAll()em
sandbox="Run". Ele retorna os caminhos:salvo scripts/exports/banana.png (512x512)Então você pode pegar os arquivos de imagem com
browse_folder.
Falhas comuns
renderer=nildepois de colar. O caminho do arquivo está errado, ou você colou sandbox"Edit"para o script errado. Verifique se você leuscripts/render_item.luauliteralmente: o nome do arquivo e o caminho devem ser exatos.shared.SkyRender is nil. O Studio foi reiniciado ou o script nunca foi colado nesta sessão. Cole novamente.- O tempo é longo. Execuções frias duram ~40s devido a colagens de script. Execuções quentes são ~8s. Se ambas forem lentas, a máquina pode estar sobrecarregada.
- A imagem está cortada. O viewport do Studio ou sua configuração de "Interface" (Guias UI) estreita o
viewport 3D. Redimensione o Studio para dar mais espaço ao viewport ou use um
sizemenor. - Itens de vidro saem opacos ou com bordas sujas. A medição alfa falha em superfícies que refratam
ou refletem o fundo de forma diferente dependendo da cor do fundo. Use
backdrop="fog"como fallback. - O progresso trava. O Studio pode travar se o script for muito longo. Reinicie o Studio e cole novamente.
- Sobreposições antigas. O script desliga a seleção, contornos e StarterGui, mas a janela de código pode estar sobre o viewport. O usuário deve mover ou fechar janelas flutuantes antes de renderizar.