CommunityBildgithub.com

Wh1msicaly/roblox-sky-render

Rendere ein Roblox-Item (Modell, Werkzeug, Accessoire, Teil) als transparentes PNG mit Hintergrundfreiheit, indem es in den leeren Himmel kopiert und mit schwarzem sowie weißem Hintergrund aufgenommen wird, basierend auf Demos der Photobooth-Plugin-Technik.

Was ist roblox-sky-render?

Diese Fähigkeit (Skill) ermöglicht es, einzelne Roblox-Objekte (Modelle, Werkzeuge, Accessoires, Teile, Ordner) als hochwertige, transparente PNG-Bilder darzustellen. Da Roblox Studio standardmäßig keinen transparenten Hintergrund rendern kann, wird die Transparenz durch einen cleveren Messprozess ermittelt: Das Objekt wird ohne Position oder Rotation verändert in den leeren Himmel kopiert und nacheinander gegen einen schwarzen und einen weißen Hintergrund fotografiert. Aus der Differenz der beiden Aufnahmen wird für jeden Pixel der Alpha-Kanal (Deckkraft) berechnet, und die Farbe des Endbildes stammt von einer separaten Aufnahme mit der Beleuchtung des Ortes, geteilt durch den Alpha-Wert. Die Fähigkeit ist speziell für den schnellen Claude Haiku 5.5 optimiert (kann aber auch mit anderen Modellen ausgeführt werden) und nutzt die Roblox-Studio-MCP-Werkzeuge `execute_luau` und `screen_capture`. Alle wichtigen Störeinflüsse wie Himmel, Wolken, Nebel, Glühen, Schatten und Studio-Overlays werden automatisch entfernt oder neutralisiert, sodass das Ergebnis einer echten PNG-Render-Pipeline ähnelt. Der Workflow umfasst die Überprüfung des Modells, das Lesen und Konfigurieren des Renderings (einschließlich Batch-Verarbeitung), die Bewertung der Ergebnisse mit einem integrierten Board und die finale Zeitmessung über ein Benchmarking-Skript.

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

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Roblox Sky Render

Erstellt eine transparente PNG-freigestellte Ausgabe eines einzelnen Objekts aus einer Roblox-Welt, ohne Plugins. Das gebündelte Skript reproduziert die Technik, die das Photobooth-Plugin verwendet.

Zuerst: Modell prüfen

Dieser Skill ist für Claude Haiku 5.5 (claude-haiku-5-5) ausgelegt. Haiku ist deutlich schneller, und die Aufgabe ist ein festes, skriptgestütztes Verfahren, das kein größeres Modell wie Opus 5.5 benötigt, das für Programmierung und komplexere Aufgaben gedacht ist. Bevor du etwas anderes tust, überprüfe, welches Modell du bist. Wenn du nicht Claude Haiku 5.5 bist, stoppe und bitte den Benutzer, zu wechseln, bevor du beginnst: In Claude Code können sie /model claude-haiku-5-5 ausführen oder im Desktop-App-Modellauswahl Haiku 5.5 wählen. Fahre fort, sobald sie gewechselt haben. Wenn sie auf dem aktuellen Modell bleiben möchten, führe die Aufgabe trotzdem aus.

Funktionsweise (damit du Fehler nachvollziehen kannst)

Roblox kann nicht mit transparentem Hintergrund rendern, daher wird Transparenz gemessen:

  1. Eine Kopie des Objekts wird vor einem flachen schwarzen Hintergrund und dann vor einem flachen weißen fotografiert. Sonst ändert sich nichts zwischen den beiden Aufnahmen.
  2. Pro Pixel: wenn es in einem Bild weiß und im anderen schwarz ist, ist es Hintergrund (Alpha 0). Wenn es in beiden identisch ist, ist es solides Objekt (Alpha 1). Dazwischen: alpha = 1 - (weiß - schwarz) / 255. Das berücksichtigt Glas und Anti-Aliasing-Kanten.
  3. Die Farbe stammt von einer dritten Aufnahme auf Schwarz mit der eigenen Beleuchtung des Ortes (Bloom, Farbkorrektur), geteilt durch Alpha.

Alles, was dies scheitern lässt, ist etwas, das sich zwischen den beiden Aufnahmen außer dem Hintergrund unterscheidet, oder etwas anderes als das Objekt im Bild. Darum geht es im nächsten Abschnitt.

Achte auf die Welt

Ein Screenshot erfasst alles, was sich vor der Kamera befindet und was das Objekt beleuchtet. Vor und nach einem Render solltest du Folgendes bedenken:

  • Dinge im Weg. Gebäude, Gelände, andere Modelle, die Basisplatte, Partikel von nahen Objekten. Das Skript vermeidet all dies, indem es das Objekt nie dort fotografiert, wo es sich befindet: Es klont das Objekt, hebt den Klon in den leeren Himmel und platziert eine Hintergrundebene direkt dahinter. Es prüft, ob der Platz tatsächlich leer ist (keine Teile innerhalb von clearance Studs, nichts direkt darüber, der Boden weit darunter) und steigt 1500 Studs auf einmal, bis er es ist. Lies die Zeile staged at Y= im Bericht; wenn sie besagt, dass die erzwungene Höhe nicht frei ist oder kein klarer Himmel gefunden werden kann, wähle selbst eine altitude aus, nachdem du gesehen hast, wie hoch die Karte ist.
  • Dinge, die Schatten werfen. Etwas zwischen dem Objekt und der Sonne wirft einen Schatten, auch wenn es nicht im Bild ist. Das Skript raycastet zur Sonne und sagt dir, ob etwas getroffen wird.
  • Wo das Licht herkommt. Die Sonne (oder der Mond) ist die einzige gerichtete Lichtquelle und steht immer über dem Horizont. lighting = "studio" (Standard) verschiebt vorübergehend die Tageszeit, sodass die Sonne über der linken Schulter der Kamera steht, und erhöht das Umgebungslicht, sodass jedes Objekt unabhängig vom Ort gleich beleuchtet wird. lighting = "world" behält die Beleuchtung des Ortes; der Bericht sagt dann, ob die Sonne vor oder HINTER der sichtbaren Seite steht. Hinten bedeutet einen dunklen Render.
  • Nach oben schauen. lookStraightUp = true dreht den Klon und richtet die Kamera auf +Y, sodass hinter dem Objekt nur Himmel sein kann. Verwende es, wenn die Karte so hoch oder überladen ist, dass klarer Himmel zur Seite schwer zu finden ist. Der Nachteil: Die Kamera ist jetzt darunter, die Sonne kann nie dahinter kommen, und die Ausrichtung des Hauptlichts im Bericht sinkt (ca. 0,6 statt 1,0). In der Praxis rendert es trotzdem gut; es hat nur weniger Kontrolle über die Schattierung.
  • Himmel-Effekte. Atmosphärennebel, Wolken, Sonnenstrahlen, Tiefenschärfe und Unschärfe befinden sich zwischen Kamera und Hintergrund. Das Skript entfernt oder deaktiviert sie während der Aufnahmen.
  • Glühen. Der Hintergrund ist ein Neon-Teil, da Neon Beleuchtung und Schatten ignoriert und eine exakte, flache Farbe liefert. Aber Neon glüht, und das Glühen überläuft auf dünne Teile des Objekts und lässt sie durchscheinend erscheinen. BloomEffekte auszuschalten stoppt das nicht (die Engine fällt auf ein Standard-Glühen zurück); ein aktivierter BloomEffect mit Intensität 0 und Größe 0 stoppt es, und das Skript fügt für die Messaufnahmen einen hinzu. Wenn ein solides Objekt jemals geisterhaft erscheint, ist dies das Erste, was du vermuten solltest.
  • Dinge, die sich bewegen. Partikel, Strahlen, Feuer, Rauch und Spuren befinden sich in jeder Aufnahme an einer anderen Stelle und werden zu schwarzen Klumpen. Sie werden standardmäßig am Klon ausgeschaltet. Mit particles = true werden sie behalten und während der Aufnahmen eingefroren.
  • Studio-Overlays. Auswahlboxen, Hover-Konturen und StarterGui-Bildschirme wären im Screenshot. Das Skript löscht die Auswahl und blendet sie aus, und verwendet nur ein zentriertes Quadrat des Viewports, weg von den Ecken-Widgets.
  • Der Viewport selbst. Die Ausgabegröße ist durch die kürzere Seite des Studio-Viewports begrenzt, und Studio muss sich im Edit-Modus mit sichtbarem 3D-View befinden. Der Grafikmodus "OpenGL" funktioniert nicht.

Das Skript setzt jedes dieser Elemente zurück, wenn es fertig ist, auch bei Fehlern. Das Originalobjekt wird nie bewegt oder verändert.

Workflow

Führe während des Laufs keine Zeitbefehle aus. Claude Code zeichnet jeden Aufruf mit einem Zeitstempel auf, daher wird die Laufzeit aus dem Sitzungstranskript in einem einzigen Aufruf ganz am Ende (Schritt 7 und Benchmark unten) gemessen. Jeder Auftrag endet mit dieser Zeitmessung, und die letzte Nachricht an den Benutzer endet mit der Gesamtzeit. Überspringe es nicht und warte nicht, bis du gefragt wirst.

  1. Finde die Studio-Instanz (list_roblox_studios) und bestätige, welcher Ort verwendet werden soll, wenn mehr als einer geöffnet ist. Führe dann diesen Statuscheck über execute_luau (Datamodel Edit) mit want gesetzt auf den Anfang eines Wortes im Namen des Objekts in Kleinbuchstaben aus. In einem Aufruf meldet es, ob der Renderer und der Exporter bereits in dieser Studio-Sitzung installiert sind, und listet passende Objekte auf (die eigenen Kinder eines Objekts werden ausgelassen, sodass ein Ordner mit Werkzeugen einmal mit seiner Kinderanzahl erscheint):

    local want = "sword" -- start of a word in the item's name, lower case; "" to skip the search
    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 -- only at a word start: "Cats", "Flying Cat", "CatTower", not "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")
    

    Die aktuellen Versionen sind renderer=1 exporter=1. Eine Zahl, die übereinstimmt, bedeutet, dass das Skript installiert und aktuell ist: Überspringe sein Lesen und Einfügen (Schritt 2 unten für den Renderer, Schritt 1 von "PNGs ohne HTTP speichern" für den Exporter). nil oder eine andere Zahl bedeutet, es einzufügen. Wenn die Liste das Objekt nicht klar macht, falle zurück auf search_game_tree.

  2. Lade den Renderer, sofern der Statuscheck nicht renderer=1 anzeigt. Lese scripts/render_item.luau und übergib die gesamte Datei unverändert als code von execute_luau (Datamodel Edit). Mit target = nil installiert es nur drei Funktionen und gibt "SkyRender installed" zurück. Sie bleiben für den Rest der Studio-Sitzung verfügbar:

    • shared.SkyRender(config) rendert ein Objekt, gibt einen Textbericht zurück
    • shared.SkyRenderBoard(names) zeigt Ergebnisse zur Inspektion an
    • shared.SkyRenderClear() entfernt das Board und alle gespeicherten Ergebnisse

    Wenn ein späterer Aufruf sagt, dass shared.SkyRender nil ist (Studio wurde neu gestartet), füge die Datei erneut ein. Wenn du render_item.luau oder export_nohttp.luau änderst, erhöhe shared.SkyRenderVersion oder shared.SkyExportVersion am Ende der Datei und die obige Nummer zusammen.

  3. Rendere. Jeder Aufruf ist kurz:

    return shared.SkyRender({ target = workspace.BananaSword, name = "banana" })
    

    Für einen Batch, loop in einem Aufruf und verbinde die Berichte:

    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. Lies den Bericht. Ein guter sieht so aus:

    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)
    

    Überprüfe: Kalibrierung 255 / 0; Grenzen berühren nicht 0 oder size-1 (abgeschnitten); die Aufteilung zwischen opak und halbtransparent ist für das Objekt sinnvoll (ein solides Schwert sollte fast vollständig opak sein, Glas sollte einen echten halbtransparenten Anteil haben). Reagiere auf alles unter NOTES:.

  5. Schau es dir an. Zahlen sagen dir nicht, ob das Objekt falsch herum zeigt. Rufe shared.SkyRenderBoard({ "banana" }) auf (oder {} für alle Ergebnisse). Es baut ein temporäres Board im Himmel, das jedes Bild über Magenta und über Dunkelgrau zeigt, und gibt die exakte camera_position und look_at_position zurück, die an screen_capture übergeben werden. screen_capture zeichnet keine GUIs, weshalb das Board Decals auf Teilen verwendet. Beurteile: richtiger Winkel? gesamtes Objekt im Bild? saubere Kanten auf beiden Hintergründen? sichtbare Seite beleuchtet? keine fremden Klumpen? Rerendere mit geänderten Optionen, bis es richtig ist, dann shared.SkyRenderBoard(nil), um das Board zu entfernen.

  6. Liefere (siehe unten), dann shared.SkyRenderClear(), es sei denn, der Benutzer möchte die Ergebnisse in der Sitzung behalten.

  7. Messe die Zeit (erforderlich, jeder Auftrag). Als letzten Tool-Aufruf des Auftrags, nachdem die PNGs gespeichert und Studio bereinigt wurde, führe python scripts/benchmark.py aus. Beende dann deine letzte Nachricht an den Benutzer mit dem Ergebnis in folgender Form:

    Total time: 2m 10s for 6 images (21.6 s per image), cold run.
    

    Füge die Phasentabelle über dieser Zeile hinzu, wenn der Auftrag mehr als ein einzelnes Bild war oder wenn etwas langsam war. Die Gesamtzeit ist die letzte Zeile der Nachricht, niemals ausgelassen und niemals nur in einem Tool-Ergebnis, das der Benutzer möglicherweise nicht sieht.

Benchmark (Benutzeraufforderung zur letzten Nachricht)

Immer am Ende jedes Auftrags (Workflow-Schritt 7), unabhängig davon, ob der Benutzer darum gebeten hat. Es kostet einen Tool-Aufruf: Claude Code schreibt jede Aufforderung, jeden Tool-Aufruf und jedes Ergebnis mit einem Zeitstempel in das Sitzungstranskript (~/.claude/projects/<project>/<session>.jsonl), und scripts/benchmark.py liest sie.

  1. Wann: als letzter Tool-Aufruf des Auftragszuges. Es sieht alle Aufrufe bis einschließlich sich selbst, sodass nur die letzte Nachricht (ein paar Sekunden) fehlt. Wenn der Benutzer später nach einem abgeschlossenen Auftrag fragt, führe es dann erneut für die vollständige Zahl aus.
  2. Ausführen: python scripts/benchmark.py wählt die neueste Sitzung aus, die diesen Skill ausgeführt hat, und deren letzte Renderanfrage. Gib eine Sitzungs-ID oder einen .jsonl-Pfad an, um eine andere Sitzung auszuwählen, --list und --turn <n>, um eine andere Anfrage darin auszuwählen, und --calls, um jeden Aufruf mit seiner Zeitmessung aufzulisten.
  3. Bericht: die Phasentabelle (find, setup, render, export, assemble, cleanup, bookkeeping, reply), jeweils aufgeteilt in Modellzeit (Denken und Schreiben des Aufrufs, einschließlich der Skript-Einfügungen) und Toolzeit (Warten auf Ergebnisse). Parallele Aufrufe werden einmal gezählt, sodass die Phasen in der Summe die Gesamtzeit ergeben. Dann die Bildanzahl und Sekunden pro Bild.
  4. Render-Detail (optional): die time-Zeile in jedem Render-Bericht wird innerhalb von Studio um diesen Render herum gemessen. Verwende sie, um individuelle Render zu vergleichen.

Gib an, ob der Lauf kalt (Renderer und Exporter in diesem Auftrag eingefügt) oder warm (bereits installiert) war, da die Einfügungen den größten Teil der Einrichtungszeit eines kalten Laufs ausmachen. Beende die letzte Nachricht mit der Total time:-Zeile aus Schritt 7.

Optionen

Alle optional außer target. Standardwerte in Klammern.

OptionBedeutung
targetDie zu rendernde Instanz. Modelle, Teile, Werkzeuge, Accessoires und Ordner funktionieren alle.
name ["render"]Bezeichnung für das Ergebnis. Die Wiederverwendung eines Namens ersetzt das frühere Ergebnis.
viewDir [(-1, 0.6, -1)]Richtung vom Objekt zur Kamera in Weltachsen, wie das Objekt derzeit sitzt. (0,0,-1) schaut auf seine -Z-Seite; erhöhe Y, um darauf herabzusehen.
up [(0,1,0)]Welche Weltrichtung im Bild oben ist. Verwende es, um ein Schwert diagonal zu legen usw.
fov [20]Eng ist flach und ikonenartig. 50-70 übertreibt die Perspektive.
size [512]Quadratische Ausgabe in Pixeln, begrenzt durch die kürzere Seite des Viewports.
padding [0.08]Rand als Bruchteil des Bildes.
lighting ["studio"]"studio" oder "world", siehe oben.
particles [false]Partikeleffekte (eingefroren) behalten, anstatt sie auszuschalten.
lookStraightUp [false]Mit Kamera, die auf +Y zeigt, aufbauen, siehe oben.
altitude [auto]Erzwinge die Aufbauhöhe.
clearance [400]Studs Leerraum, der um den Aufbauplatz erforderlich ist.
backdrop ["neon"]"neon" oder "fog" (eine einfache Ebene in festem Nebel versteckt) als Fallback.
refit [true]Testaufnahme zuerst, dann neu einrahmen, sodass die sichtbaren Pixel das Bild füllen. Teil-Bounding-Boxen sind locker, daher kommen Objekte ohne dies klein heraus.
keepLook [true]Farbe aus einer Aufnahme mit dem Bloom und der Farbkorrektur des Ortes nehmen.

Verwandte Skills