feat(cli): add agent-first media treatment tools

This commit is contained in:
ukimsanov
2026-07-24 18:42:07 -07:00
parent e710a1686f
commit 4582881d00
28 changed files with 3402 additions and 62 deletions
+88 -8
View File
@@ -1,6 +1,21 @@
# Color grading — grade blocks and LUTs
Use `grade` when you need the actual HyperFrames `data-color-grading` value to paste onto an `<img>` or `<video>`. Core presets and params-backed library looks resolve locally; future CDN-backed library looks require network unless already frozen:
Use `grade` when you need a canonical HyperFrames grading/effects payload for
an `<img>` or `<video>`. Core presets and params-backed LUT entries resolve
locally; future CDN-backed LUT entries require network unless already
frozen. Persist a decided payload with the CLI rather than editing HTML by
hand:
For a vague but explicit polish request, do not jump directly from intent to a
preset name. Read `media-treatments.md`, choose a treatment whose subject and
avoid rules match the actual media, apply its conservative base with only
justified bounded tuning, then complete its visual verification steps. A named
owned treatment uses the exact preset/payload in its recipe; do not run the
generic grade/LUT resolver first.
Stop here and use that treatment workflow for requests such as retro, old home
video, camcorder, film, print, ASCII, glitch, privacy, or a media reveal. Do not
assemble those from a generic LUT plus handmade CSS vignette/grain/opacity.
**Never `cat`/read a `.cube` file into context.** A 3D LUT is ~size^3 lines of raw numbers (33^3 ≈ 36k lines at the default size). It bloats context and carries zero human/agent-legible signal. To understand or choose a LUT, use `hyperframes grade-compare` to see it rendered, or `cube-validate.mjs` for a one-line `{ok,size}` check. Read `.media/index.md` or `luts/index.json` for the description. Never read the LUT body itself.
@@ -17,7 +32,16 @@ Preset-first output uses the core runtime vocabulary and does not freeze a file:
}
```
Paste it as an attribute value after JSON string escaping:
Apply that payload to one unambiguous real media element:
```bash
hyperframes media-treatment --project . --file index.html \
--selector '#hero' \
--grading '{"preset":"warm-daylight","intensity":1}' --apply --json
```
Use `--dry-run` before writing when scope is uncertain and `--clear` to remove
the treatment. The low-level persisted result is still normal HTML:
```html
<video
@@ -27,7 +51,45 @@ Paste it as an attribute value after JSON string escaping:
></video>
```
Looks beyond the preset vocabulary freeze a validated `.cube` under `.media/luts/` and return a block that references it:
Direct attribute authoring is a fallback for environments where the CLI is not
available, not the primary agent workflow.
To build a treatment that is not already represented by a recipe, inspect the
canonical toolbox first:
```bash
hyperframes media-treatment --capabilities --json
```
It reports valid adjustment, finishing, effect, palette, preset, and animated
property ranges from Core. Compose one nested payload and pass it back through
`hyperframes media-treatment`; the command rejects unknown keys before mutation.
Do not generate or hand-edit a LUT merely to combine controls already owned by
the realtime shader.
For seek-safe effect motion, animate only the runtime-supported CSS properties
on that same real media element with its registered paused GSAP timeline:
| CSS property | Range |
| ---------------------------------- | ------- |
| `--hf-color-grading-intensity` | 0 to 1 |
| `--hf-color-grading-lut-intensity` | 0 to 1 |
| `--hf-color-grading-exposure` | -2 to 2 |
| `--hf-color-grading-blur` | 0 to 1 |
| `--hf-color-grading-bloom` | 0 to 3 |
| `--hf-color-grading-kuwahara` | 0 to 1 |
| `--hf-color-grading-pixelate` | 0 to 1 |
| `--hf-color-grading-ascii` | 0 to 1 |
| `--hf-color-grading-dither` | 0 to 1 |
Author the initial value directly in the media element's inline `style`, then
use finite `tl.to()` keyframes. Do not use a frame-zero `tl.set()`, CSS
animation clocks, timers, random values, or `onUpdate` callbacks. The static
`data-color-grading` payload remains the fallback and source of the other
controls.
For a reusable color transform beyond the preset vocabulary, freeze a validated
`.cube` under `.media/luts/` and return a block that references it:
```bash
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "teal orange blockbuster" --project . --json
@@ -59,17 +121,35 @@ For a LUT generated by your own script, ingest it with `--from`; media-use valid
node <SKILL_DIR>/scripts/resolve.mjs --type lut --from custom.cube --project .
```
Parametric math (`buildCube`) cannot reproduce real film stocks or emulsion looks. Use a CDN-backed scanned `.cube` entry or ingest a real scanned `.cube` for those.
Parametric math (`buildCube`) cannot reproduce real film stocks or emulsion
transforms. Use a CDN-backed scanned `.cube` entry or ingest a real scanned
`.cube` for those.
For visual selection, list reusable looks with `resolve --type grade --candidates`, write the promising entries to a `grades.json`, run `hyperframes grade-compare --for <frame> --grades grades.json`, then commit the winner with `resolve -t grade` as the final `data-color-grading` block.
For visual selection, list reusable LUT candidates with
`resolve --type grade --candidates`, write the promising entries to a
`grades.json`, run
`hyperframes grade-compare --for <frame> --grades grades.json`, then commit the
winner with `resolve -t grade` as the final `data-color-grading` block.
Smart grade is `grade --for <media>`. It runs local `ffmpeg`/`ffprobe` signalstats, merges a bounded `adjust` suggestion into the returned block, and prints the measured evidence to stderr. Stdout remains valid JSON under `--json`; the suggestion is a starting point for the agent to tune, not an automatic neutralization of intentional color.
Use `grade --for <media> --analyze` when you only need side-effect-free
`ffmpeg`/`ffprobe` signalstats evidence. It returns a bounded `adjust`
suggestion without writing a manifest record. The suggestion is a starting
point for visual review, not an automatic neutralization of intentional color.
```bash
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "warm cinematic" --for ./frame.png --project . --json
node <SKILL_DIR>/scripts/resolve.mjs --type grade --for ./frame.png --analyze --project . --json
```
Library looks live in `luts/index.json`. Each entry keeps `id`, `description`, `tags`, and `intensity`, then supplies either compact `params` for on-demand `buildCube(params)` generation or a direct CDN `url` for future scanned `.cube` files. Do not commit generated `.cube` bodies; resolve validates generated or downloaded cubes as it freezes them under `.media/luts/`.
Without `--analyze`, `grade --for` merges measured values into the resolved
grade and records that candidate in `.media`; use that form only when you
intend to keep the candidate.
Library LUT entries live in `luts/index.json`. Each entry keeps `id`,
`description`, `tags`, and `intensity`, then supplies either compact `params`
for on-demand `buildCube(params)` generation or a direct CDN `url` for future
scanned `.cube` files. Do not commit generated `.cube` bodies; resolve
validates generated or downloaded cubes as it freezes them under
`.media/luts/`.
```bash
node skills/media-use/scripts/resolve.mjs --type lut --intent "teal orange blockbuster" --project . --json