Roblox sky render
Produce un recorte de calidad PNG transparente de un objeto de una experiencia de Roblox usando solo capturas de pantalla de Studio. No se necesita ningún plugin; el script incluido reproduce la técnica que utiliza el plugin Photobooth.
Primero: verifica el modelo
Esta habilidad está diseñada para ejecutarse en Claude Haiku 5.5 (claude-haiku-5-5). Haiku es significativamente más rápido, y el trabajo aquí es un procedimiento fijo y guionizado que no necesita un modelo más grande como Opus 5.5, que está pensado para codificación y tareas más complejas. Antes de hacer cualquier otra cosa, verifica qué modelo eres. Si no eres Claude Haiku 5.5, detente y pide al usuario que cambie antes de comenzar: en Claude Code pueden ejecutar /model claude-haiku-5-5, o seleccionar Haiku 5.5 en el selector de modelo de la aplicación de escritorio. Continúa una vez que hayan cambiado. Si dicen que quieren quedarse en el modelo actual, continúa con él.
Cómo funciona (para que puedas razonar sobre fallos)
Roblox no puede renderizar con un fondo transparente, por lo que la transparencia se mide:
- Se fotografía una copia del objeto frente a un fondo negro plano y luego frente a uno blanco plano. Nada más cambia entre las dos tomas.
- Por píxel: si es blanco en una y negro en la otra, es fondo (alfa 0). Si es idéntico en ambas, es objeto sólido (alfa 1). En el medio,
alfa = 1 - (blanco - negro) / 255. Eso maneja vidrio y bordes suavizados. - El color proviene de una tercera toma sobre negro con el aspecto propio de la experiencia (brillo, corrección de color), dividido por alfa.
Todo lo que hace que esto falle es algo que difiere entre las dos tomas aparte del fondo, o algo que no sea el objeto en la imagen. De eso trata la siguiente sección.
Ten en cuenta el mundo
Una captura de pantalla captura todo lo que está frente a la cámara y todo lo que ilumina el objeto. Antes y después de un render, piensa en:
- Cosas en el camino. Edificios, terreno, otros modelos, la baseplate, partículas de objetos cercanos. El script evita todo esto al no disparar nunca el objeto donde está: clona el objeto, eleva el clon al cielo vacío y coloca un plano de fondo justo detrás. Verifica que el punto de montaje esté realmente vacío (sin piezas dentro de
clearancestuds, nada directamente arriba, el suelo muy abajo) y sube 1500 studs a la vez hasta que lo esté. Lee la líneastaged at Y=en el informe; si dice que la altitud forzada no está despejada, o no puede encontrar cielo despejado, elige unaaltitudtú mismo después de mirar cuán alto es el mapa. - Cosas que proyectan sombras. Algo entre el objeto y el sol lo sombrea incluso si está fuera del encuadre. El script lanza rayos hacia el sol y te dice si algo es alcanzado.
- De dónde viene la luz. El sol (o la luna) es la única luz direccional y siempre está sobre el horizonte.
lighting = "studio"(predeterminado) mueve temporalmente la hora del día para que el sol esté sobre el hombro izquierdo de la cámara y aumenta la luz ambiental, por lo que cada objeto se ilumina de la misma manera independientemente de la experiencia.lighting = "world"mantiene la iluminación de la experiencia; el informe entonces dice si el sol está frente a DETRÁS del lado visible. Detrás significa un render oscuro. - Mirando directamente hacia arriba.
lookStraightUp = truerota el clon y apunta la cámara hacia +Y, por lo que lo único que puede estar detrás del objeto es el cielo. Úsalo cuando el mapa sea tan alto o desordenado que sea difícil encontrar cielo despejado a un lado. El costo: la cámara ahora está debajo, el sol nunca puede estar detrás de ella, y la alineación de la luz clave del informe disminuye (aproximadamente 0.6 en lugar de 1.0). En la práctica, aún se renderiza bien; solo tiene menos control sobre el sombreado. - Efectos de cielo. La neblina atmosférica, las nubes, los rayos de sol, la profundidad de campo y el desenfoque se encuentran entre la cámara y el fondo. El script los elimina o desactiva mientras dispara.
- Brillo. El fondo es una pieza Neon porque Neon ignora la iluminación y las sombras, dando un color plano exacto. Pero Neon brilla, y el brillo se derrama sobre partes delgadas del objeto y hace que se lean como transparentes. Apagar los BloomEffects no detiene eso (el motor vuelve a un brillo predeterminado); un BloomEffect habilitado con Intensidad 0 y Tamaño 0 sí lo hace, y el script agrega uno para las tomas de medición. Si un objeto sólido alguna vez sale fantasmal, esto es lo primero que debes sospechar.
- Cosas que se mueven. Partículas, vigas, fuego, humo y estelas están en un lugar diferente en cada toma y se convierten en manchas negras. Por defecto, se desactivan en el clon. Con
particles = truese mantienen y congelan mientras se dispara. - Superposiciones de Studio. Los cuadros de selección, los contornos de desplazamiento y las pantallas de StarterGui estarían en la captura de pantalla. El script limpia la selección y los oculta, y solo usa un cuadrado centrado del viewport, lejos de los widgets de las esquinas.
- El viewport en sí. El tamaño de salida está limitado por el lado más corto del viewport de Studio, y Studio debe estar en modo Editar con la vista 3D visible. El modo gráfico "OpenGL" no funciona.
El script restaura cada uno de estos cuando termina, incluso en caso de error. El objeto original nunca se mueve ni se modifica.
Flujo de trabajo
No ejecutes ningún comando de temporización mientras el trabajo está en curso. Claude Code marca la hora de cada llamada, por lo que la ejecución se cronometra a partir de la transcripción de la sesión en una sola llamada al final (paso 7, y Benchmark a continuación). Cada trabajo termina con esa temporización, y el mensaje final al usuario termina con el tiempo total. No lo omitas y no esperes a que te lo pidan.
-
Encuentra la instancia de Studio (
list_roblox_studios) y confirma qué experiencia usar si hay más de una abierta. Luego ejecuta esta verificación de estado a través deexecute_luau(datamodelEdit), conwantestablecido al inicio de una palabra en el nombre del objeto, en minúsculas. En una llamada, informa si el renderizador y el exportador ya están instalados en esta sesión de Studio y lista los objetos coincidentes (los hijos de un objeto se omiten, por lo que una carpeta de herramientas aparece una vez, con su recuento de hijos):local want = "sword" -- inicio de una palabra en el nombre del objeto, minúsculas; "" para saltar la búsqueda 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 -- solo al inicio de una palabra: "Cats", "Flying Cat", "CatTower", no "Location" 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()} children)`) if #out >= 40 then table.insert(out, "(more; narrow want)") break end end end end end return `renderer={shared.SkyRenderVersion} exporter={shared.SkyExportVersion}\n` .. table.concat(out, "\n")Las versiones actuales son renderer=1 exporter=1. Un número que coincida significa que ese script está instalado y actualizado: omite su lectura y pegado (paso 2 a continuación para el renderizador, paso 1 de "Guardar PNGs sin HTTP" para el exportador).
nilo un número diferente significa pégalo. Si la lista no deja claro el objeto, recurre asearch_game_tree. -
Carga el renderizador, a menos que la verificación de estado haya mostrado
renderer=1. Leescripts/render_item.luauy pasa el archivo completo, sin cambios, como elcodedeexecute_luau(datamodelEdit). Contarget = nilsolo instala tres funciones y devuelve "SkyRender installed". Permanecen disponibles durante el resto de la sesión de Studio:shared.SkyRender(config)renderiza un objeto, devuelve un informe de textoshared.SkyRenderBoard(names)muestra los resultados para inspecciónshared.SkyRenderClear()elimina el tablero y todos los resultados almacenados
Si una llamada posterior dice que
shared.SkyRenderes nil (Studio se reinició), pega el archivo nuevamente. Cuando cambiesrender_item.luauoexport_nohttp.luau, incrementashared.SkyRenderVersionoshared.SkyExportVersional final del archivo y el número anterior, juntos. -
Renderiza. Cada llamada es corta:
return shared.SkyRender({ target = workspace.BananaSword, name = "banana" })Para un lote, itera en una sola llamada y une los informes:
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") -
Lee el informe. Uno bueno se ve así:
OK 512x512px "banana" -> CoreGui.SkyRenderResults.banana item radius 2.45 studs, camera 18.7 studs away, staged at Y=3001 studio lighting, key light alignment 1.00 (1 = ideal) coverage: 8.8% opaque, 0.4% semi-transparent, bounds x 44-474 y 148-365 backdrop (neon) calibration white=255,255,255 black=0,0,0 osScale=1 time 3.41s (wall clock: staging, shots, composite and restore)Verifica: la calibración es 255 / 0; los límites no tocan 0 o tamaño-1 (recortado); la división entre opaco y semitransparente tiene sentido para el objeto (una espada sólida debería ser casi toda opaca, un vidrio debería tener una parte semitransparente real). Actúa sobre cualquier cosa bajo
NOTAS:. -
Míralo. Los números no te dicen si el objeto está mirando en la dirección equivocada. Llama a
shared.SkyRenderBoard({ "banana" })(o{}para cada resultado). Construye un tablero temporal en el cielo mostrando cada imagen sobre magenta y sobre gris oscuro, y devuelve la posición exacta decamera_positionylook_at_positionpara pasar ascreen_capture.screen_captureno dibuja GUIs, por eso el tablero usa calcomanías en piezas. Juzga: ¿ángulo correcto? ¿objeto completo en el encuadre? ¿bordes limpios en ambos fondos? ¿lado iluminado visible? ¿sin manchas extrañas? Vuelve a renderizar con opciones cambiadas hasta que esté bien, luegoshared.SkyRenderBoard(nil)para eliminar el tablero. -
Entrega (ver más abajo), luego
shared.SkyRenderClear()a menos que el usuario quiera mantener los resultados en la sesión. -
Mide el tiempo (obligatorio, cada trabajo). Como la última llamada de herramienta del trabajo, después de que los PNGs se hayan guardado y Studio esté limpio, ejecuta
python scripts/benchmark.py. Luego termina tu mensaje final al usuario con el resultado, en esta forma:Tiempo total: 2m 10s para 6 imágenes (21.6 s por imagen), ejecución en frío.Agrega la tabla de fases arriba de esa línea cuando el trabajo haya sido de más de una imagen o cuando algo haya sido lento. El total es la última línea del mensaje, nunca omitida, y nunca solo en un resultado de herramienta que el usuario podría no ver.
Benchmark (indicación del usuario al último mensaje)
Siempre, al final de cada trabajo (paso 7 del flujo de trabajo), ya sea que el usuario lo haya solicitado o no. Cuesta una llamada de herramienta: Claude Code escribe cada indicación, llamada de herramienta y resultado en la transcripción de la sesión (~/.claude/projects/<project>/<session>.jsonl) con una marca de tiempo, y scripts/benchmark.py los lee.
- Cuándo: como la última llamada de herramienta del turno del trabajo. Ve todas las llamadas hasta e incluyéndose a sí mismo, por lo que solo el mensaje final (un par de segundos) se omite. Si el usuario pregunta más tarde sobre un trabajo terminado, ejecútalo de nuevo entonces para la cifra completa.
- Ejecutar:
python scripts/benchmark.pyselecciona la sesión más reciente que ejecutó esta habilidad y su última solicitud de render. Pasa un id de sesión o ruta.jsonlpara elegir otra sesión,--listy--turn <n>para elegir otra solicitud en ella, y--callspara listar cada llamada con su temporización. - Informe: la tabla de fases (encontrar, configurar, render, exportar, ensamblar, limpiar, contabilidad, responder), cada una dividida en tiempo de modelo (pensar y escribir la llamada, incluyendo los pegados de script) y tiempo de herramienta (esperar resultados). Las llamadas paralelas se cuentan una vez, por lo que las fases suman el total. Luego el recuento de imágenes y segundos por imagen.
- Detalle del render (opcional): la línea
timeen cada informe de render se mide dentro de Studio alrededor de ese render. Úsala para comparar renders individuales.
Di si la ejecución fue en frío (renderizador y exportador pegados en este trabajo) o en caliente (ya instalados), ya que los pegados son la mayor parte del tiempo de configuración de una ejecución en frío. Termina el mensaje final con la línea Tiempo total: del paso 7.
Opciones
Todas son opcionales excepto target. Los valores predeterminados están entre corchetes.
| Opción | Significado |
|---|---|
target | La Instancia a renderizar. Modelos, piezas, Tools, Accesorios y Carpetas funcionan todos. |
name ["render"] | Etiqueta para el resultado. Reutilizar un nombre reemplaza el resultado anterior. |
viewDir [(-1, 0.6, -1)] | Dirección desde el objeto hacia la cámara, en ejes del mundo tal como está el objeto actualmente. (0,0,-1) mira hacia su cara -Z; eleva Y para mirarlo desde arriba. |
up [(0,1,0)] | Qué dirección del mundo es hacia arriba en la imagen. Úsalo para colocar una espada en diagonal, etc. |
fov [20] | Un valor estrecho es plano y parecido a un icono. 50-70 exagera la perspectiva. |
size [512] | Salida cuadrada en píxeles, limitada por el lado más corto del viewport. |
padding [0.08] | Margen como fracción de la imagen. |
lighting ["studio"] | "studio" o "world", ver arriba. |
particles [false] | Mantener efectos de partículas (congelados) en lugar de apagarlos. |
lookStraightUp [false] | Montar con la cámara apuntando hacia +Y, ver arriba. |
altitude [auto] | Forzar la altura de montaje. |
clearance [400] | Studs de espacio vacío requeridos alrededor del punto de montaje. |
backdrop ["neon"] | "neon", o "fog" (un plano simple oculto en niebla sólida) como respaldo. |
refit [true] | Toma de prueba primero, luego reencuadrar para que los píxeles visibles llenen la imagen. Los cuadros delimitadores de las piezas son sueltos, por lo que sin esto los objetos salen pequeños. |
keepLook [true] | Tomar el color de una toma con el brillo y la corrección de color de la experiencia. |
...
(El contenido se ha truncado para la traducción)