Der Nutzer hat recht: Der Ordner war voller Entwicklungs-Muell. Jetzt ist sauber getrennt: ROOT (was der Nutzer sieht und braucht): - run.py = das Programm - hms_app/ = der Anwendungscode - HMS MediaEngine.app = macOS Doppelklick-Starter - HMS-Start.vbs = Windows Doppelklick-Starter - HMS-Install.vbs = Windows Erst-Installation - HMS-Mac-Install.command = macOS Homebrew-Installation - HMS-Portable-Install.command = macOS Portable-Installation (16GB-Fix) - installer_gui.py = grafischer Installer - launcher.pyw + launcher_core.py = interne Start-Logik - LIESMICH.txt = 10-Zeilen-Kurzanleitung - .gitignore _entwicklung/ (alles andere, NICHT benoetigt): - packages/ apps/ native/ plugins/ tools/ schemas/ tests/ docs/ build/ fixture_profiles/ - PLAN.md STATUS.md ERRORS.md TEST_REPORT.md CHANGELOG.md README.md - pyproject.toml uv.lock setup_*.sh/ps1 make_mac_app.py Diese Trennung gilt ab sofort fuer alle Commits. Der Nutzer kann _entwicklung/ loeschen wenn er Platz braucht - die App laeuft ohne. Verifiziert: App startet nach Aufraeumen unveraendert (Health 200).
8.6 KiB
plugin.json – Manifest-Referenz
Dieses Dokument beschreibt alle Felder des Plugin-Manifests plugin.json. Grundlage sind das JSON-Schema schemas/plugin/plugin_manifest_v1.schema.json und der Validator packages/plugin_sdk/hms_plugin_sdk/manifest.py (PLAN.md §14.2–14.3).
Schema-Version und API-Version
| Feld | Typ | Pflicht | Wert |
|---|---|---|---|
schema_version |
integer | ja | 1 (konstant) |
api_version |
integer | ja | 1 (konstant) |
schema_version und api_version müssen exakt 1 sein. Der Validator lehnt jede andere Version ab (manifest.py).
Pflichtfelder
Das Schema verlangt folgende Felder auf oberster Ebene:
["schema_version", "id", "name", "version", "api_version", "kind", "vendor", "entrypoints", "capabilities", "failure_mode"]
id
- Typ: string
- Pflicht: ja
- Regeln: Reverse-DNS-Notation, mindestens 5 Zeichen, mindestens zwei durch
.getrennte Teile, nur Kleinbuchstabena–z, Ziffern0–9,.,_,-. Kein..erlaubt. - Beispiel:
com.hms.fx.vignette
name
- Typ: string, minLength 1
- Pflicht: ja
- Beispiel:
Vignette
version
- Typ: string
- Pflicht: ja
- Regeln: Semantische Version
X.Y.Z(genau drei durch.getrennte Ganzzahlen). - Beispiel:
1.0.0
kind
- Typ: enum
- Pflicht: ja
- Werte:
source,generator,filter,transition,mixer,output,control,automation(PLAN.md §14.1) - Beispiel:
filter
vendor
- Typ: string, minLength 1
- Pflicht: ja
- Beispiel:
HMS
entrypoints
- Typ: object, minProperties 1
- Pflicht: ja
- Beschreibung: Backend-Entrypoints mit Shader-Pässen. Erlaubte Backend-Schlüssel:
d3d11,gl,gles.
Jeder Entrypoint ist ein Objekt mit:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
type |
string | ja | Entrypoint-Typ, z. B. hlsl, glsl, glsl_es, hlsl_multipass, glsl_multipass, glsl_es_multipass |
passes |
array, minItems 1 | ja | Liste der Shader-Pässe |
Jeder Pass ist ein Objekt mit genau einem Shader-Pfad:
- D3D11:
pixel_shader(z. B.shaders/d3d11/main.hlsl) - GL/GLES:
fragment(z. B.shaders/gl/main.frag)
Beispiel (Einpass, Vignette):
"entrypoints": {
"d3d11": {
"type": "hlsl",
"passes": [{"pixel_shader": "shaders/d3d11/main.hlsl"}]
},
"gl": {
"type": "glsl",
"passes": [{"fragment": "shaders/gl/main.frag"}]
},
"gles": {
"type": "glsl_es",
"passes": [{"fragment": "shaders/gles/main.frag"}]
}
}
Beispiel (Multipass, Gaussian Blur, PLAN.md §14.3):
"entrypoints": {
"d3d11": {
"type": "hlsl_multipass",
"passes": [
{"pixel_shader": "shaders/d3d11/horizontal.hlsl"},
{"pixel_shader": "shaders/d3d11/vertical.hlsl"}
]
},
"gl": {
"type": "glsl_multipass",
"passes": [
{"fragment": "shaders/gl/horizontal.frag"},
{"fragment": "shaders/gl/vertical.frag"}
]
},
"gles": {
"type": "glsl_es_multipass",
"passes": [
{"fragment": "shaders/gles/horizontal.frag"},
{"fragment": "shaders/gles/vertical.frag"}
]
}
}
Der Validator prüft, dass jeder deklarierte Shader-Pfad relativ und sicher ist (kein absoluter Pfad, kein ..) und – wenn ein Plugin-Root übergeben wird – tatsächlich existiert (manifest.py).
capabilities
- Typ: object
- Pflicht: ja
- Pflichtfelder:
minimum_tier,supported_backends
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
minimum_tier |
enum | ja | DESKTOP_FULL, DESKTOP_LITE, PI_LITE, HEADLESS_CONTROL |
requires_input_texture |
boolean | nein | true, wenn der Effekt eine Eingangs-Textur braucht (Filter) |
supported_backends |
array, minItems 1 | ja | d3d11, gl, gles |
Beispiel (Vignette):
"capabilities": {
"minimum_tier": "PI_LITE",
"requires_input_texture": true,
"supported_backends": ["d3d11", "gl", "gles"]
}
failure_mode
- Typ: enum
- Pflicht: ja
- Werte:
bypass,hold,black - Beschreibung: Verhalten bei einem Pluginfehler.
bypassüberbrückt den Effekt (PLAN.md §3.5, §14.5). - Beispiel:
bypass
Optionale Felder
parameters
- Typ: array
- Pflicht: nein (im Schema), aber empfohlen
- Beschreibung: Liste der Plugin-Parameter. Details siehe parameters-and-dmx.md.
Jeder Parameter ist ein Objekt mit:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
id |
string, minLength 1 | ja | Eindeutige Parameter-ID |
label |
string, minLength 1 | ja | Anzeigename |
type |
enum | ja | float, int, enum, bool, color |
default |
beliebig | ja | Standardwert |
minimum |
number | nein | Untergrenze (für float/int) |
maximum |
number | nein | Obergrenze (für float/int) |
values |
array | nein | Werte für enum |
dmx_slots |
array, maxItems 8 | nein | DMX-Slot-Belegung (1–8) |
curve |
string | nein | Kurvenform, z. B. quadratic |
Beispiel (Vignette):
"parameters": [
{"id": "amount", "label": "Amount", "type": "float", "minimum": 0, "maximum": 1, "default": 0.5, "dmx_slots": [1]},
{"id": "radius", "label": "Radius", "type": "float", "minimum": 0, "maximum": 2, "default": 0.5, "dmx_slots": [2]},
{"id": "softness", "label": "Softness", "type": "float", "minimum": 0, "maximum": 1, "default": 0.4, "dmx_slots": [3]},
{"id": "roundness", "label": "Roundness", "type": "float", "minimum": 0, "maximum": 1, "default": 0.5, "dmx_slots": [4]},
{"id": "center_x", "label": "Center X", "type": "float", "minimum": 0, "maximum": 1, "default": 0.5, "dmx_slots": [5]},
{"id": "center_y", "label": "Center Y", "type": "float", "minimum": 0, "maximum": 1, "default": 0.5, "dmx_slots": [6]},
{"id": "color", "label": "Color", "type": "color", "default": [0, 0, 0], "dmx_slots": [7]},
{"id": "invert", "label": "Invert", "type": "bool", "default": 0, "dmx_slots": [8]},
{"id": "mix", "label": "Mix", "type": "float", "minimum": 0, "maximum": 1, "default": 1, "dmx_slots": []}
]
Validator-Regeln für Parameter (manifest.py):
idmuss vorhanden und ein String sein; doppelte IDs sind Fehler.typemuss einer vonfloat,int,enum,bool,colorsein.- Für
floatmüssenminimum,maximumunddefaultvorhanden sein. dmx_slotsmuss eine Liste von Ganzzahlen sein.- Die Summe aller
dmx_slotsüber alle Parameter darf 8 nicht überschreiten (PLAN.md §14.7).
adaptive_quality
- Typ: object
- Pflicht: nein (im Schema), aber für qualitätsabhängige Effekte empfohlen
- Pflichtfelder:
default,variants - Beschreibung: Adaptive-Quality-Varianten. Details siehe adaptive-quality.md.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
default |
string | ja | Standard-Variante, z. B. auto |
variants |
array, minItems 1 | ja | Liste der Varianten |
transition_ms |
number, minimum 0 | nein | Übergangszeit in Millisekunden |
semantic_parameters_unchanged |
array of string | nein | Parameter, deren Semantik beim Wechsel unverändert bleibt |
Jede Variante ist ein Objekt mit:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
id |
string | ja | Varianten-ID, z. B. low, medium, high |
internal_scale |
number, exclusiveMinimum 0, maximum 1 | nein | Interne Auflösungsskala |
samples |
integer, minimum 1 | nein | Sample-Anzahl |
Beispiel (Vignette):
"adaptive_quality": {
"default": "auto",
"variants": [
{"id": "low", "internal_scale": 1.0, "samples": 1},
{"id": "medium", "internal_scale": 1.0, "samples": 1},
{"id": "high", "internal_scale": 1.0, "samples": 1}
],
"transition_ms": 180,
"semantic_parameters_unchanged": ["mix"]
}
Validierung
Die Validierung (manifest.py) umfasst (PLAN.md §14.5):
- Manifest-Schema;
- eindeutige Plugin-ID und semantische Version;
- API-Kompatibilität;
- Pfad- und ZIP-Sicherheit;
- erlaubte Dateitypen und Größenlimits;
- Shader-Kompilierung;
- Capability-Prüfung;
- vollständige, vorab kompilierbare Adaptive-Quality-Varianten und unveränderte Parametersemantik;
- Lizenzmetadaten;
- Hash des Pakets.
ZIP-Sicherheit (§27.2)
Beim Installieren als ZIP gelten zusätzlich (manifest.py):
- maximal 512 Dateien (
MAX_PLUGIN_FILES); - maximale entpackte Gesamtgröße 32 MiB (
MAX_TOTAL_UNPACKED); - maximale Dateigröße 8 MiB (
MAX_FILE_SIZE); - erlaubte Dateiendungen:
.json,.hlsl,.frag,.vert,.glsl,.png,.md,.txt,.toml,.csv; - keine absoluten Pfade, kein
..; plugin.jsonmuss an der Paketwurzel liegen.