CommunityImagengithub.com

Wh1msicaly/roblox-sky-render

Renderiza un objeto de Roblox (modelo, herramienta, accesorio, pieza) como una imagen limpia con fondo transparente usando solo capturas de pantalla de Roblox Studio, colocando una copia en un cielo vacío y fotografiándola contra fondos blanco y negro.

¿Qué es roblox-sky-render?

Esta habilidad permite a un agente de IA, como Claude Code o Cursor, capturar un objeto de Roblox y producir una imagen recortada con fondo transparente, ideal para iconos, miniaturas, sprites o renders en lote. Utiliza únicamente las herramientas MCP de Roblox Studio (execute_luau y screen_capture) para simular la técnica del plugin Photobooth, midiendo la transparencia a partir de dos tomas con fondos blanco y negro. El script limpia el entorno eliminando interferencias como terrenos, sombras, partículas y efectos de niebla, y restaura todo al finalizar. Es compatible con cualquier instancia de Roblox Studio en modo Edición y se optimiza para Claude Haiku 5.5 por su velocidad en tareas de procedimiento fijo.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Wh1msicaly/roblox-sky-render/tree/HEAD

Installed? Explore more Imagen skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

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:

  1. 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.
  2. 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.
  3. 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 clearance studs, nada directamente arriba, el suelo muy abajo) y sube 1500 studs a la vez hasta que lo esté. Lee la línea staged at Y= en el informe; si dice que la altitud forzada no está despejada, o no puede encontrar cielo despejado, elige una altitud tú 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 = true rota 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 = true se 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.

  1. 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 de execute_luau (datamodel Edit), con want establecido 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). nil o un número diferente significa pégalo. Si la lista no deja claro el objeto, recurre a search_game_tree.

  2. Carga el renderizador, a menos que la verificación de estado haya mostrado renderer=1. Lee scripts/render_item.luau y pasa el archivo completo, sin cambios, como el code de execute_luau (datamodel Edit). Con target = nil solo 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 texto
    • shared.SkyRenderBoard(names) muestra los resultados para inspección
    • shared.SkyRenderClear() elimina el tablero y todos los resultados almacenados

    Si una llamada posterior dice que shared.SkyRender es nil (Studio se reinició), pega el archivo nuevamente. Cuando cambies render_item.luau o export_nohttp.luau, incrementa shared.SkyRenderVersion o shared.SkyExportVersion al final del archivo y el número anterior, juntos.

  3. 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")
    
  4. 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:.

  5. 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 de camera_position y look_at_position para pasar a screen_capture. screen_capture no 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, luego shared.SkyRenderBoard(nil) para eliminar el tablero.

  6. Entrega (ver más abajo), luego shared.SkyRenderClear() a menos que el usuario quiera mantener los resultados en la sesión.

  7. 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.

  1. 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.
  2. Ejecutar: python scripts/benchmark.py selecciona la sesión más reciente que ejecutó esta habilidad y su última solicitud de render. Pasa un id de sesión o ruta .jsonl para elegir otra sesión, --list y --turn <n> para elegir otra solicitud en ella, y --calls para listar cada llamada con su temporización.
  3. 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.
  4. Detalle del render (opcional): la línea time en 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ónSignificado
targetLa 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)

Skills relacionados