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:
- 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.
- 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. - 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
clearanceStuds, nichts direkt darüber, der Boden weit darunter) und steigt 1500 Studs auf einmal, bis er es ist. Lies die Zeilestaged 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 einealtitudeaus, 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 = truedreht 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 = truewerden 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.
-
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 überexecute_luau(DatamodelEdit) mitwantgesetzt 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).
niloder eine andere Zahl bedeutet, es einzufügen. Wenn die Liste das Objekt nicht klar macht, falle zurück aufsearch_game_tree. -
Lade den Renderer, sofern der Statuscheck nicht
renderer=1anzeigt. Lesescripts/render_item.luauund übergib die gesamte Datei unverändert alscodevonexecute_luau(DatamodelEdit). Mittarget = nilinstalliert 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ückshared.SkyRenderBoard(names)zeigt Ergebnisse zur Inspektion anshared.SkyRenderClear()entfernt das Board und alle gespeicherten Ergebnisse
Wenn ein späterer Aufruf sagt, dass
shared.SkyRendernil ist (Studio wurde neu gestartet), füge die Datei erneut ein. Wenn durender_item.luauoderexport_nohttp.luauänderst, erhöheshared.SkyRenderVersionodershared.SkyExportVersionam Ende der Datei und die obige Nummer zusammen. -
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") -
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:. -
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 exaktecamera_positionundlook_at_positionzurück, die anscreen_captureübergeben werden.screen_capturezeichnet 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, dannshared.SkyRenderBoard(nil), um das Board zu entfernen. -
Liefere (siehe unten), dann
shared.SkyRenderClear(), es sei denn, der Benutzer möchte die Ergebnisse in der Sitzung behalten. -
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.pyaus. 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.
- 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.
- Ausführen:
python scripts/benchmark.pywä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,--listund--turn <n>, um eine andere Anfrage darin auszuwählen, und--calls, um jeden Aufruf mit seiner Zeitmessung aufzulisten. - 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.
- 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.
| Option | Bedeutung |
|---|---|
target | Die 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. |