362e089be0
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).
260 lines
8.6 KiB
Markdown
260 lines
8.6 KiB
Markdown
# `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:
|
||
|
||
```json
|
||
["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 Kleinbuchstaben `a–z`, Ziffern `0–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):**
|
||
|
||
```json
|
||
"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):**
|
||
|
||
```json
|
||
"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):**
|
||
|
||
```json
|
||
"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](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):**
|
||
|
||
```json
|
||
"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`):**
|
||
|
||
- `id` muss vorhanden und ein String sein; doppelte IDs sind Fehler.
|
||
- `type` muss einer von `float`, `int`, `enum`, `bool`, `color` sein.
|
||
- Für `float` müssen `minimum`, `maximum` und `default` vorhanden sein.
|
||
- `dmx_slots` muss 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](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):**
|
||
|
||
```json
|
||
"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.json` muss an der Paketwurzel liegen.
|