Skip to main content

mockframe

Macht aus einem App-Screenshot ein perspektivisch gerendertes Gerätebild. Kein Browser, keine gekauften 3D-Modelle, keine GPU.

Gerendertes iPhone 16 Pro mit einem App-Screenshot auf dem Display, leicht nach links gedreht, vor hellem Verlauf
mockframe render heute.png --auto-device --bg light -o hero.png

Das Gehäuse entsteht prozedural aus Millimeterangaben und wird mit einem eigenen Software-Rasterizer schattiert. Ein neues Gerät ist deshalb ein Tabelleneintrag, keine Asset-Datei.

Version 0.1, 34 Tests grün. Ein Bild in 1400 x 1750 braucht auf einem Apple-Silicon-Mac rund drei bis vier Sekunden.

Warum kein fertiges 3D-Modell

Der naheliegende Weg wäre, ein iPhone-Modell zu kaufen und es zu rendern. Drei Gründe dagegen, in dieser Reihenfolge.

Lizenz. Modelle von Sketchfab, TurboSquid oder CGTrader sind überwiegend „editorial use only" oder verbieten die Weitergabe im Produkt. Ein Modell in ein Repo zu legen, das andere klonen, ist eine andere Rechtslage als ein Bild damit zu rendern. Prozedurale Geometrie aus öffentlich bekannten Maßen umgeht das Problem, statt es zu verwalten.

Geometrie. Ein Telefongehäuse ist ein Rounded Rect, extrudiert entlang eines gekrümmten Kantenprofils. Das sind vierzig Zeilen Code. Ein importiertes Modell bringt Material-Setups, Skalierungsfragen und Dreiecksmüll mit, ohne etwas zu lösen, was hier schwer wäre.

Gerätewahl. Wenn die Geometrie aus Zahlen entsteht, ist ein neues Modell ein Tabelleneintrag. Bei importierten Meshes ist es eine neue Datei, ein neues Material und ein neuer Kalibrierungslauf.

Was das kostet: der Rasterizer kann genau eine Klasse von Objekten, und Dinge, die ein fertiges Modell mitbringt, fehlen hier noch — Kamerabuckel, Antennenlinien, echte Glasrefraktion. Die Abwägung steht ausführlich in PROJEKT.md.

Architektur

graph TD
    CLI["cli.py — Kommandozeile"]
    SCENE["scene.py — Komposition, Presets"]
    GEO["geometry.py — Mesh, Projektion"]
    RAST["raster.py — Z-Buffer, Culling"]
    SHADE["shading.py — Material, Umgebungen"]
    SCR["screen.py — Warp, Aspect-Pruefung"]
    DEV["devices.py — Geraetetabelle, Kantenprofil"]

    CLI --> SCENE
    SCENE --> GEO
    SCENE --> RAST
    SCENE --> SCR
    RAST --> SHADE
    GEO --> DEV
    SCR --> DEV
    SCENE --> DEV

devices.py importiert nichts und wird von allem gelesen. Deshalb ist ein neues Gerät eine Tabellenzeile und keine Codeänderung.

Zwei Entscheidungen prägen den Rest. Die Glasebene wird bewusst nicht mitrasterisiert, sondern separat per Vier-Punkt-Perspektivwarp komponiert: sie ist planar, deshalb ist der Warp exakt und schärfer als eine Texturinterpolation über Dreiecke. Und die Normalen werden analytisch berechnet statt über Nachbarfacetten gemittelt — das ist der Grund, warum auf der schmalen Seitenschiene keine Facettenspuren auftreten.

Der vollständige Ablauf eines Renderings, inklusive Abbruchzweig bei falschem Seitenverhältnis: ARCHITECTURE.md.

Benutzen

Mit Claude Code — einmalig, danach genügt „mach mir ein Hero-Bild":

/plugin marketplace add moOritzl/claude-plugins
/plugin install mockframe@moritzlenhard

Ohne Claude Code, oder mit einem anderen Agenten:

uvx mockframe render shot.png --auto-device -o hero.png

uvx lädt das Paket beim ersten Aufruf und legt im Projekt nichts ab. Ohne uv: brew install uv auf macOS, sonst die Anleitung von Astral.

Das Unterkommando capture braucht zusätzlich macOS mit Xcode, alles andere läuft plattformunabhängig.

Entwicklung

Python 3.11 oder neuer. Alles landet in einer venv im Projektordner, nichts im System-Python.

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

-e installiert editierbar, Änderungen an src/mockframe/ wirken sofort. [dev] zieht pytest mit; ohne den Zusatz kommen nur die Laufzeitabhängigkeiten numpy, Pillow und scipy.

Der Skill ruft bewusst immer uvx mockframe, also die veröffentlichte Version. Beim Entwickeln deshalb .venv/bin/mockframe ... direkt aufrufen.

Kommandos

mockframe steht hier und im Rest der Datei für den Aufruf, den du oben gewählt hast: uvx mockframe ohne Installation, .venv/bin/mockframe aus dem Projektordner, oder das blanke mockframe bei aktivierter venv.

mockframe devices                                  # Tabelle mit Quellenangabe
mockframe render shot.png --device iphone-16-pro --preset hero-left
mockframe render shot.png --auto-device --bg dark
mockframe hdri-synth studio.npy                    # synthetische Environment-Map
mockframe capture --screens today,history --render   # nur macOS

--auto-device leitet das Gerät aus der Screenshot-Auflösung ab. 1206 x 2622 ist ein iPhone 16 Pro, und das Werkzeug weiß das.

Passt der Screenshot nicht zum Gerät, bricht der Lauf ab statt still zu strecken:

Abbruch: Screenshot 1920x1080 (Verhaeltnis 1.7778) passt nicht zu
iPhone 16 Pro (Natural Titanium) (erwartet 0.4600).

Das ist Absicht. Ein gestrecktes Rendering sieht fast richtig aus, und der Fehler fällt oft erst auf, wenn das Bild schon veröffentlicht ist.

HDRI

Die eingebaute Umgebung ist eine Formel aus Gaußkeulen. Sie ist sauber, aber glatt, weil eine Formel keine Struktur hat. Der Wechsel auf eine echte Environment Map ist der größte Qualitätssprung pro Zeile Code, und er ersetzt genau eine Funktion — die Schnittstelle ist sample(R), ein Reflexionsvektor rein, lineare Radianz raus.

Analytische Studioumgebung Synthetische HDRI
Rendering mit analytischer Studioumgebung, helle Titanschiene Dasselbe Rendering mit synthetischer HDRI, dunklere Schiene mit hartem Lichtabriss
Standard, keine Datei nötig --hdri studio.npy

Beide Bilder sind derselbe Aufruf, dasselbe Gerät, dasselbe Preset. Nur die Umgebung unterscheidet sich. Die synthetische Map ist nicht automatisch die schönere Wahl — sie hat einen dunklen Grundton mit einer einzelnen Softbox, was die Schiene kontrastreicher, aber auch härter macht. Sie existiert, um den Sampling-Pfad zu belegen:

mockframe hdri-synth studio.npy
mockframe render shot.png --hdri studio.npy

Für Produktbilder eine echte Studio-HDRI von Poly Haven nehmen, die stehen unter CC0. Für .exr oder .hdr zusätzlich pip install -e ".[hdr]", die Datei selbst einlesen und an HDRIEnvironment(array) geben. Das ist der einzige Weg hier, der eine eigene Installation braucht statt uvx — er läuft nicht über die Kommandozeile, sondern im eigenen Python.

Environment Maps sind nicht eingecheckt, *.npy ist ignoriert. Die synthetische ist 6 MB groß und aus dem Code bitgleich reproduzierbar; ein Test hält den Hash fest.

Tests

pytest -q

test_convergence.py ist der Test, auf den es ankommt. Bei korrekter Interpolation darf das Bild nicht von der Dreieckszahl abhängen. Er existiert, weil im Prototyp die barycentrischen Gewichte um eine Position rotiert zugeordnet waren: w0 ist die Kantenfunktion für v0 nach v1 und damit das Gewicht von v2, nicht von v1. Der Fehler war im Bild als Leitermuster auf der Seitenschiene deutlich sichtbar, aber Hochfrequenzmetriken fielen dadurch nur von 2,93 auf 2,47. Der Konvergenztest fällt eindeutig durch.

Bei Renderern ist das generell der Test, der trägt: variiere einen Parameter, der das Ergebnis nicht verändern darf, und prüfe, dass er es nicht tut.

Genauigkeit der Maße

Breite, Höhe und Dicke stammen aus Apples Tech-Specs. Eckradius und Bezelbreite sind nicht offiziell dokumentiert und sind Näherungen. Jeder Tabelleneintrag hat ein source-Feld, und ein Test schlägt fehl, wenn es leer ist. Ohne das weiß in drei Monaten niemand mehr, welche Zahl geprüft ist und welche geraten.

Stand

Fünf Geräte, vier Kamerapresets, vier Hintergründe, analytische Studioumgebung, HDRI-Sampling, Seitenverhältnis-Prüfung, Aufnahme aus dem iOS-Simulator.

Was fehlt: Kamerabuckel auf der Rückseite, Antennenlinien, Bodenreflexion, das Duo-Preset. Für das Duo braucht es zuerst den Kamerabuckel, weil dort ein Gerät angeschnitten sichtbar ist.

Der Rasterizer ist eine Python-Schleife über Dreiecke. Vektorisierung über Kacheln oder Numba würde die Renderzeit spürbar drücken, ist aber Komfort und kommt deshalb nach der Bildqualität. Die begründete Reihenfolge steht in PROJEKT.md.

Lizenz und Rechtliches

MIT, siehe LICENSE.

NOTICE hält fest, was die Lizenz nicht abdeckt: das Projekt ist nicht mit Apple verbunden, das Repo enthält keine Assets Dritter, und für Bilder, die in den App Store gehen, gelten zusätzlich Apples eigene Marketingvorgaben.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mockframe-0.1.0.tar.gz (27.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mockframe-0.1.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file mockframe-0.1.0.tar.gz.

File metadata

  • Download URL: mockframe-0.1.0.tar.gz
  • Upload date:
  • Size: 27.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for mockframe-0.1.0.tar.gz
Algorithm Hash digest
SHA256 57adbcc2e2d16ab59e7a7b09f7e30a55e9d7d0dba718b90f95df788a551bc7eb
MD5 7d9a0c4c2f76edcdae0e275898fc5236
BLAKE2b-256 d547a9737b30b1b1ebaf143b4b8e1884621a815bb0a7921464a30d132ae921ad

See more details on using hashes here.

File details

Details for the file mockframe-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mockframe-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for mockframe-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b45fcd2a4f4b499b599fddc4173a0b1440bda44bcfe1227d880e2a776be1c319
MD5 a0f42339bad6c5670179b0360c616196
BLAKE2b-256 b89787e38c758b637e0a03d6afca8c33aec224497c712208c5ba8bf10147c2bb

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page