mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-10 18:31:30 -06:00
Merge remote-tracking branch 'upstream/main' into aep-import-lumetri
# Conflicts: # crates/aep/src/container/effect_map.rs # crates/aep/src/export/effects.rs # crates/aep/src/import/effects.rs # crates/aep/tests/it/export/effects.rs # crates/aep/tests/it/import/effects.rs # docs/aep-import.md
This commit is contained in:
+78
-1
@@ -1,6 +1,6 @@
|
||||
# After Effects project format (`.aep`)
|
||||
|
||||
> **Last reviewed:** 2026-11-05 · **Last updated:** 2026-11-07 · **Change:** footage: an image sequence without a filename prefix stores only the suffix `Utf8`, and one imported with Force alphabetical order stores its file list in `LIST StVc` / `StVS` (section 3, footage); before that: versions: `svap` is the version that wrote the file, `head` bytes 4 to 7 the version it is written for, and what a Save a Copy As 25.x / 24.x of After Effects 2026 changes (section 1, "Versions"); before that: the stretch numerator is signed (a negative one reverses the layer, 981-983); layer styles (3.12b, 950-980); before that: footage: `sspc@118` of an image sequence is its folder's modification time (860, read-back x1-x3); before that: text: paragraph `/24`, `/35` and style `/68` are neutral for 0 and 1 (732-734, edited in place); before that: keyframes: the ease of mask path keys (599, 700), the spatial speed unit of fractional values (597, 598, 730); before that: text: character and paragraph settings, manual kerning, vertical text, `/nil` is neutral (S17: 538-578, 595, 596); before that: cameras, lights and 3D rotations (S16: the auto Position of a two-node camera is where After Effects renders it, 537; camera and light defaults read back 255, 256; Orientation `otst/otda` 488), Timewarp (529-533), an expression on an effect parameter (534); before that: text: style slot /13 is superscript / subscript (526-528; every scripted text of the corpus is superscript), wrapping box text 517; before that: effects of batch 5 (409-450, 511-516: integer sliders, checkbox defaults in `pard`, arbitrary data of Hue/Saturation and Levels, the parameters of Invert, Fast Box Blur, Gaussian Blur, Drop Shadow, Glow; section 3.7); before that: shape items of batch 5 (451-484, 519: ellipse, fill and stroke opacity, fill rule, group transform, shape layer anchor, trim paths, rectangle roundness, polystar fields, gradient default, nested groups, the defaults of every item; section 3.9); before that: track mattes: mode at `ldta` byte 107 and the matte layer id at byte 160 (cases 402-408, section 3.1); before that: text: automatic leading is verified (400); Exposure (`ADBE Exposure2`, cases 389-397): group start / end parameter types 13 / 14, float slider valid minimum and slider range (section 3.7); before that: text: U+0003 is a paragraph break (386, 387); before that: a stored text Anchor Point is pixels (385, now V); before that: the XML form `.aepx` is read into the same chunk tree (section 1, "The XML form"); the `head` save counter is a `u32` at byte 16; text documents for the importer (stroke colour, automatic leading, the font of each run, the undecoded-slot check, the text-layer Anchor Point, the Source Text record); before that: third round of verified field layouts (explicit-default semantics, type-major bezier ease, exact time stretch and in / out points, Time Remapping state, comp pixel aspect / shutter phase / display start, Point default, Layer Control None, dropdown selection, one `mkif` per mask, polystar and radial gradient records, text styles, camera and light options, marker cue data, audio and image-sequence footage) added to the typed view of `effectcraft-aep` · **Target:** Adobe After Effects 2026
|
||||
> **Last reviewed:** 2026-11-05 · **Last updated:** 2026-11-07 · **Change:** Puppet (`ADBE FreePin3`, 3.7): the property tree from an external scripting listing, **?** until a byte sample exists (#3093); before that: footage: an image sequence without a filename prefix stores only the suffix `Utf8`, and one imported with Force alphabetical order stores its file list in `LIST StVc` / `StVS` (section 3, footage); before that: versions: `svap` is the version that wrote the file, `head` bytes 4 to 7 the version it is written for, and what a Save a Copy As 25.x / 24.x of After Effects 2026 changes (section 1, "Versions"); before that: the stretch numerator is signed (a negative one reverses the layer, 981-983); layer styles (3.12b, 950-980); before that: footage: `sspc@118` of an image sequence is its folder's modification time (860, read-back x1-x3); before that: text: paragraph `/24`, `/35` and style `/68` are neutral for 0 and 1 (732-734, edited in place); before that: keyframes: the ease of mask path keys (599, 700), the spatial speed unit of fractional values (597, 598, 730); before that: text: character and paragraph settings, manual kerning, vertical text, `/nil` is neutral (S17: 538-578, 595, 596); before that: cameras, lights and 3D rotations (S16: the auto Position of a two-node camera is where After Effects renders it, 537; camera and light defaults read back 255, 256; Orientation `otst/otda` 488), Timewarp (529-533), an expression on an effect parameter (534); before that: text: style slot /13 is superscript / subscript (526-528; every scripted text of the corpus is superscript), wrapping box text 517; before that: effects of batch 5 (409-450, 511-516: integer sliders, checkbox defaults in `pard`, arbitrary data of Hue/Saturation and Levels, the parameters of Invert, Fast Box Blur, Gaussian Blur, Drop Shadow, Glow; section 3.7); before that: shape items of batch 5 (451-484, 519: ellipse, fill and stroke opacity, fill rule, group transform, shape layer anchor, trim paths, rectangle roundness, polystar fields, gradient default, nested groups, the defaults of every item; section 3.9); before that: track mattes: mode at `ldta` byte 107 and the matte layer id at byte 160 (cases 402-408, section 3.1); before that: text: automatic leading is verified (400); Exposure (`ADBE Exposure2`, cases 389-397): group start / end parameter types 13 / 14, float slider valid minimum and slider range (section 3.7); before that: text: U+0003 is a paragraph break (386, 387); before that: a stored text Anchor Point is pixels (385, now V); before that: the XML form `.aepx` is read into the same chunk tree (section 1, "The XML form"); the `head` save counter is a `u32` at byte 16; text documents for the importer (stroke colour, automatic leading, the font of each run, the undecoded-slot check, the text-layer Anchor Point, the Source Text record); before that: third round of verified field layouts (explicit-default semantics, type-major bezier ease, exact time stretch and in / out points, Time Remapping state, comp pixel aspect / shutter phase / display start, Point default, Layer Control None, dropdown selection, one `mkif` per mask, polystar and radial gradient records, text styles, camera and light options, marker cue data, audio and image-sequence footage) added to the typed view of `effectcraft-aep` · **Target:** Adobe After Effects 2026
|
||||
|
||||
What `crates/aep` ([`effectcraft-aep`](../crates/aep/README.md)) reads and writes, and the evidence
|
||||
for each statement. Everything here was observed on project files we generated ourselves; no
|
||||
@@ -559,6 +559,36 @@ compositions, the items from one composition per popup item).** Each set value i
|
||||
| `ADBE Offset` | 1 Shift Center To: point, default the layer centre; 2 Blend With Original: fixed, **max 1 (a 0..1 fraction)**, default 0 |
|
||||
| `ADBE Deflicker` (Color Stabilizer) | 1 Stabilize: popup (Brightness, Levels, Curves), **default 2 (Levels)**; 2 Black Point, 3 Mid Point, 4 White Point: points, defaults 0.2 / 0.5 / 0.8 of the width at half the height; 5 Sample Size: fixed, max 50, default 3. The reference frame the Set Frame button picks is not among the parameters |
|
||||
|
||||
**Importer block 2026-11-05, #3112 (`1300-thirdparty.aep`; V for the parameter lists, H for the
|
||||
data layouts, read from default instances only):**
|
||||
|
||||
| Effect (match name, plug-in version) | Parameters (`parT` index: type, valid range, default) |
|
||||
|---|---|
|
||||
| `CS Color Neutralizer` (CC Color Neutralizer, 1.3) | 1 / 7 / 13 Shadows / Midtones / Highlights Unbalance: colours (black, 127 grey, white; pickers: setting one sets the range's sliders, e.g. [0.27, 0.55, 0.85] gives Red 42.94, Green 1.18, Blue -44.12 = (mean - channel) x 150 / 255 on 8-bit values, and leaves no colour record); 2-6, 8-12, 14-18 a group per range (start, Red, Green, Blue, end) with float sliders -100..100 (slider -50..50), default 0; 19 Pinning: float 0..100 (slider 0..50); 20 Blend w. Original: float 0..100; 21-25 the Special group: 22 View popup (Final Result, Correction B to W, Correction Stair), default 1, 23 Black Point float 0..49.9, default 0, 24 White Point float 50.1..100, default 100 |
|
||||
| `EXtractoR` (2.6.6) | 1 Channel Info (`EXtractoR-0013`): arbitrary data, 688 bytes, below; 2-6 the Process group: 3 Black Point and 4 White Point float sliders, valid ±3.4028235e38 (the float32 range; slider ±1 000), default 0 / 1; 5 UnMult: checkbox (empty `pard` name, the label in `pdnm`), default off |
|
||||
| `IDentifier` (2.6.6) | 1 Channel Info (`IDentifier-0005`): arbitrary data, 148 bytes, below; 2 Display: popup (Colors, Luma Matte, Alpha Matte, Raw), default 1; 3 ID: integer slider, max 2 147 483 647, default 0 |
|
||||
|
||||
EXtractoR's Channel Info is the plug-in's own **little-endian** layout: `u32` 1 and 28 bytes, then
|
||||
four 164-byte records (Red, Green, Blue, Alpha), each a kind in byte 0 (1 a channel of the footage by
|
||||
name: `R`, `G`, `B` by default; 2 the input's own channel, named `(copy)`: Alpha by default) and the
|
||||
channel name NUL-terminated from record byte 35. EffectCraft imports kind 2 as its EXtractoR's `(copy)`,
|
||||
the effect input's channel of the same position as earlier effects left it, not as `A` (which names
|
||||
an OpenEXR footage's own alpha plane). The rest is not read: it differs between instances
|
||||
with the same channels (uninitialised-looking values, also in bytes 1..4 of a record: `02 00 00 32`
|
||||
on Alpha in one definition's default, which is why only byte 0 is the kind). **A chosen channel**
|
||||
(`extractor-07-preset-channel-z`, a preset of our own that reads `Z` into Red, Green and Blue) is kind
|
||||
1 with its name (`Z`), and the `u32` at record byte 4 is then 13, which looks like the channel's
|
||||
position in the EXR's sorted channel list of 14 (the defaults hold 0 there: H). IDentifier's data
|
||||
differs between instances with the same settings except for **the chosen channel's name**,
|
||||
NUL-terminated from byte 19, which is `Object ID` when no channel is chosen. After Effects lists
|
||||
only integer (UINT) channels: in 1300's EXR (a FLOAT `ID` channel) it found none ("No ID channels
|
||||
available"), so that block's preset `identifier-09-preset-channel-id` only sets ID 2; in 1310's
|
||||
EXR (UINT `objectId` and `IndexOB.X` added) the preset `identifier-09-preset-channel-objectid-id2`
|
||||
stores `objectId`, with 15 at byte 4 (the channel's position in the sorted list of 16, as for
|
||||
EXtractoR: H). Without a chosen channel After Effects leaves the layer unchanged (1300 and 1310
|
||||
defaults). The other bytes are not read. API: `ExtractorChannels`,
|
||||
`identifier_channel_type`.
|
||||
|
||||
**Curves and Mesh Warp** (961-965, 985; applied from presets, the data is not scriptable): their
|
||||
arbitrary-data parameter (type 11) always has a record (`tdbs` with a 4-byte `cdat`) and a `LIST
|
||||
aRbs` / `aRbp`, also at the default. Curves (`ADBE CurvesCustom-0001`, 1644 bytes): `u16` 1, 1;
|
||||
@@ -669,6 +699,52 @@ presets, and After Effects draws exactly the picked objects as selected (`crypto
|
||||
`crypto-07`: box and disc, the two objects of `mat_paint`). API: `CryptomatteData` (refuses data without `cry1`, a length past the end or
|
||||
a non-zero byte at 112).
|
||||
|
||||
**Puppet (`ADBE FreePin3`; ?: external listing, not the corpus, #3093).** No file of the
|
||||
corpus, the committed fixtures or the samples holds a Puppet. The tree below comes from outside
|
||||
the corpus: a public scripting listing of the effect's properties (a forum post, an After Effects
|
||||
release from before the Advanced and Bend pins and Density). It is not bytes we have seen; that
|
||||
After Effects writes it by the general rule (a `tdmn` and the `LIST tdgp` or `tdbs` it names,
|
||||
nested in the instance's value group `sspc/tdgp`, as masks, shapes and layer styles are) is
|
||||
**H**:
|
||||
|
||||
```text
|
||||
Puppet ADBE FreePin3
|
||||
On Transparent ADBE FreePin3 On Transparent
|
||||
arap ADBE FreePin3 ARAP Group (hidden)
|
||||
Auto-traced Shapes ADBE FreePin3 Outlines
|
||||
Mesh ADBE FreePin3 Mesh Group (hidden)
|
||||
Mesh 1 ADBE FreePin3 Mesh Atom
|
||||
Mesh ADBE FreePin3 Mesh (hidden: the triangulation)
|
||||
Triangles ADBE FreePin3 Mesh Tri Count
|
||||
Expansion ADBE FreePin3 Mesh Expansion
|
||||
Deform ADBE FreePin3 PosPins
|
||||
Puppet Pin 1 ADBE FreePin3 PosPin Atom
|
||||
Vertex Offset ADBE FreePin3 PosPin Vtx Offset (hidden, 2 values)
|
||||
Vertex Index ADBE FreePin3 PosPin Vtx Index (hidden; 4294967295 = none)
|
||||
Position ADBE FreePin3 PosPin Position
|
||||
Overlap ADBE FreePin3 HghtPins (hidden while empty)
|
||||
Stiffness ADBE FreePin3 StarchPins (hidden while empty)
|
||||
```
|
||||
|
||||
A pin's rest place is not a property: it is a vertex of the hidden mesh (Vertex Index) plus an
|
||||
offset, so it cannot be read without decoding the mesh data. The unit of Position (layer pixels,
|
||||
or a fraction of the layer as effect points are) is **?**. The match names of the Overlap and
|
||||
Starch pin atoms and their properties, of the Advanced and Bend pins (Scale, Rotation) and of
|
||||
Density, Mesh Rotation Refinement and the Puppet Engine are **?**, and so is which of them are
|
||||
`parT` parameters; whether After Effects stores some `parT` parameters of a fresh Puppet even at
|
||||
their defaults (the importer would then report them every time) is **?**; whether a Puppet
|
||||
without pins has an (empty) Mesh Group, or no ARAP group at all, is **?**. The importer
|
||||
(`import/puppet.rs`) therefore brings the effect in as EffectCraft's Puppet without meshes or
|
||||
pins and reports, per mesh, Triangles, Expansion and per pin group the pins, how many are keyed
|
||||
or carry an expression, and their atom match names; every entry outside this tree is named in the
|
||||
report. The sample that settles it: a fresh Puppet with no pins in one composition and, in
|
||||
another, a 400 x 800 solid in a larger composition (pixels against fractions) with a Puppet of
|
||||
three Position pins (one keyed, one moved off its rest place without
|
||||
keys), one Advanced, one Bend, one Starch and one Overlap pin, Triangles, Expansion and Density
|
||||
off their defaults, a second mesh, and a scripting read-back of every property's match name and
|
||||
value, the hidden ones included. Pins added by script are reported to come out disabled, so the
|
||||
pins are placed by hand or by a preset.
|
||||
|
||||
### 3.8 Masks and bezier paths (`tdgp[ADBE Mask Parade]`)
|
||||
|
||||
| Field | Chunk path | Offset | Type | Meaning | Evidence | Conf. |
|
||||
@@ -953,6 +1029,7 @@ another value).
|
||||
**Effects**
|
||||
|
||||
- `pard` byte 48 (flags: **?**), 68 / 72 (the point default as a percent pair: **V** in the corpus for 074 and 368, not exposed), 120 (the float slider default again as f32: **V**, not exposed), 124 (display decimals: **H**), 132..147 (fixed slider slider-max, default copy and flags; the low bit of @144 is set on the two percent-displayed sliders and clear on Scatter: **H** "display as percent"), the colour default copy at @60, and the stale memory after the parameter name. The fixed slider valid minimum is not decoded (the float slider one is, 389).
|
||||
- Puppet (`ADBE FreePin3`, 3.7): the hidden mesh data, a pin's Vertex Index and Vertex Offset (its rest place), the unit of a pin's Position, the Overlap, Starch, Advanced and Bend pins, Density, Mesh Rotation Refinement and the Puppet Engine: no sample (**?**).
|
||||
- Effects renamed, or stacked twice on ONE layer (`Gradient Ramp 2`: does the second keep an empty `parT`?); which instance keeps the full `parT` when a second instance is created on a layer below the first; expressions on effect parameters; keyed per-channel Exposure values and a keyed checkbox; Curves / Levels (arrays), Fractal Noise, and whether the `tdpi` of a Layer Control holds an id or an index after the referenced layer is reordered or deleted.
|
||||
|
||||
**Masks, shapes**
|
||||
|
||||
+24
-3
File diff suppressed because one or more lines are too long
@@ -713,6 +713,11 @@ in the Plug-in Library: [publishing-plugins.md](publishing-plugins.md).
|
||||
step (separated X/Y/Z Position; Orientation and X/Y/Z Rotation on 3D layers).
|
||||
* Rename a layer with Enter (or double-click a name): the whole name is selected, Enter or a
|
||||
click elsewhere commits, Escape cancels; `layer.rename {layer, name}` does it directly.
|
||||
A text layer's name follows its text until it is renamed; renaming it to an empty name makes
|
||||
it follow the text again (After Effects). `layer.setText` and typing on canvas rename a text
|
||||
layer whose name still follows its text; `layer.newText {name}` and a name set by
|
||||
`layer.settings` or a script's `layer.name = …` (which runs `layer.rename`) stay, and an empty
|
||||
`layer.settings` name follows the text again too.
|
||||
* Ctrl/Cmd-click on the current-time display (Timeline or Composition panel) toggles the Time
|
||||
Display Style between Timecode and Frames: `file.projectSettings {"timeDisplay": "frames"}`.
|
||||
* `prop.pickWhip {layer, prop, target: {layer, prop, dimension?}}` links a property as its
|
||||
|
||||
+37
-10
@@ -240,16 +240,43 @@ converted on demand with the HDR step and without the exposure; the Info panel s
|
||||
frame's float values. The browser keeps 8-bit frames for now (its frame workers send RGBA8).
|
||||
|
||||
A persistent **disk cache** (`render::disk_cache`, Settings ▸ Media & Disk Cache) backs both
|
||||
the layer cache and the viewer's RAM preview: layer buffers that were slow to render and every
|
||||
preview frame are written (LZ4, atomic rename, checksummed) under 128-bit content keys — the
|
||||
comp's content hash (the comp, what it uses, footage file size and time) plus frame, scale and
|
||||
view for frames; the layer key salted with the footage fingerprint for layers — so entries
|
||||
survive restarts and never go stale. Frame entries are 8-bit RGBA, or for 32 bpc viewer frames
|
||||
half floats with their bytes shuffled into planes before LZ4 (the entry header's format byte
|
||||
tells them apart; the render options in the key keep the two kinds apart). LRU eviction keeps it under the size limit; Edit ▸ Purge
|
||||
empties it, `cache.diskStats` reports it, and the timeline draws disk-only frames in blue. In the
|
||||
browser the frames live in the Origin Private File System: frame workers write them, the page
|
||||
keeps the index (`DiskIndex`) and reads hits ([web.md](web.md#disk-cache)).
|
||||
the layer cache and the viewer's RAM preview: layer buffers that were slow to render, every
|
||||
preview frame and Roto Brush / Object Matte segmentations are written (LZ4, atomic rename,
|
||||
checksummed) and survive restarts. The design (#3184):
|
||||
|
||||
- **Keys from memory.** A frame's key is its comp's content key plus frame, scale, view and
|
||||
render options; the content key hashes the project settings and the items the comp can draw
|
||||
(its layers but those that can't change the picture, nested comps, footage with its settings
|
||||
and paths, solids, Media Replacement footage, proxies: `Project::pixel_reach`). Expressions
|
||||
among them add what they can read: every layer of their comps, the markers, the comps and
|
||||
footage they name with literal names (`comp("Name")`, `footage("Name")`, and which items have
|
||||
those names), or the whole project when they compute a name or reach items another way
|
||||
(`expression_reach`). An edit to anything else keeps the key. A layer buffer's key is the
|
||||
layer cache's content key (which names the footage it uses with its paths) and the renderer
|
||||
version. Nothing here looks at a file, and nothing ever scans the project's files.
|
||||
- **File lists checked on hit.** Every frame and layer entry keeps the source files it was
|
||||
made of, with the size and modification time they were read with (the browser: size and
|
||||
content hash). An entry is used only while they are unchanged: one `metadata` call per listed
|
||||
file when it is read. A changed, missing or unreadable file, a damaged entry or an older
|
||||
format is a miss; the entry is deleted and the frame renders again and replaces it.
|
||||
- **Incomplete lists stay in memory.** A frame or buffer whose files can't all be named (a
|
||||
source that doesn't say what it read, more than 4096 files) is shown but never written.
|
||||
- **Reload Footage drops entries.** File ▸ Reload Footage deletes the frame and layer entries
|
||||
whose lists name the item's files (the writer thread reads each entry's list, not its
|
||||
pixels), so a file replaced by one with the same size and time is read again. A reload while
|
||||
the cache is off is remembered for the session and applied when it is switched on, before it
|
||||
is read. A render already under way offers entries made of the files as they were: each
|
||||
render takes the cache's drop generation before it reads, and an entry listing a file dropped
|
||||
after that is refused (`DiskCache::drop_generation`); the frame is shown, never stored.
|
||||
- **Edits keep what they can't change.** RAM frames outside an edit's dirty spans are kept
|
||||
(`Project::dirty_spans`), and their disk entries are linked to the comp's new key.
|
||||
|
||||
Frame entries are 8-bit RGBA, or for 32 bpc viewer frames half floats with their bytes shuffled
|
||||
into planes before LZ4 (the entry header's format byte tells them apart; the render options in
|
||||
the key keep the two kinds apart). LRU eviction keeps the cache under the size limit; Edit ▸
|
||||
Purge empties it, `cache.diskStats` reports it, and the timeline draws disk-only frames in blue.
|
||||
In the browser the frames live in the Origin Private File System: frame workers write them, the
|
||||
page keeps the index (`DiskIndex`) and reads hits ([web.md](web.md#disk-cache)).
|
||||
|
||||
**Deferred readbacks** (`effectcraft-gpu` `deferred`): where a readback can't be waited for (WebGPU
|
||||
in a browser worker) a frame renders in passes. `Accelerator::frame_begin` / `pass_begin` /
|
||||
|
||||
@@ -8,7 +8,8 @@ the AI models named in `Co-Authored-By` trailers.
|
||||
- Two files, both **compiled into the binary** by the UI crate's `build.rs` (nothing is read from
|
||||
disk or the network at run time; the web build has them too):
|
||||
- [`contributors/contributors.json`](../contributors/contributors.json): commit stats per GitHub
|
||||
username. Never hand-edit.
|
||||
username. Never hand-edit. Release builds regenerate it for the release commit
|
||||
(`.github/workflows/release.yml`, `credits` job); the copy in the repository is not updated.
|
||||
- [`contributors/people.toml`](../contributors/people.toml): the names people chose for
|
||||
themselves. **Each contributor adds only their own entry**, in their own PR.
|
||||
- Each contributor gets one line: GitHub username (always), display name (opt-in, or their synced
|
||||
|
||||
+6
-1
@@ -142,7 +142,12 @@ Commands (CLI, MCP, control channel):
|
||||
it supports it)
|
||||
- `disk.diskCacheEnabled`, `disk.diskCacheMaxGb`, `disk.diskCacheFolder`: the persistent disk
|
||||
cache of processed layers and frames (in the browser: frames in the Origin Private File System,
|
||||
at most half the origin's quota; the folder setting does not apply there). The Disk page also
|
||||
at most half the origin's quota; the folder setting does not apply there). On the desktop the
|
||||
cache never fills its disk: it leaves 5% of the disk free, at least 2 GB and at most 10 GB, and
|
||||
is smaller than `disk.diskCacheMaxGb` when free space requires it. The Disk page shows the limit
|
||||
in effect in MB under Maximum Disk Cache Size, with a note naming the space kept free when free
|
||||
disk space lowers it (with less than 64 MB of room nothing is written, and frames and layers
|
||||
are not compressed for it). The Disk page also
|
||||
shows **Browser Storage** in the web app: usage and quota, persistent storage, Clear buttons
|
||||
(`storage.info` / `storage.persist` / `storage.clear`, see [web.md](web.md))
|
||||
- `disk.mediaCacheFolder`: audio waveform summaries kept between sessions (`Peaks/`)
|
||||
|
||||
+10
-5
@@ -332,9 +332,13 @@ pixels.
|
||||
|
||||
Settings ▸ Disk ▸ Disk Cache works in the browser, backed by the **Origin Private File System**
|
||||
(`src/diskcache.rs`): viewer frames are kept under `effectcraft-cache/v1/frames/<32 hex>.ecc`
|
||||
between visits, in the desktop cache's format (`disk_cache::frame_entry`: 8-bit premultiplied
|
||||
RGBA, LZ4, a checksum), keyed by the same content hash (the comp and everything it uses, frame,
|
||||
scale, view, render options).
|
||||
between visits, in the desktop cache's format (`disk_cache::frame_entry`: the source files the
|
||||
frame read with their size and content hash, then 8-bit premultiplied RGBA, LZ4, a checksum),
|
||||
keyed by the same content hash (from memory: the comp, everything it can draw and what its
|
||||
expressions can read, frame, scale, view, render options; see
|
||||
[architecture.md](architecture.md)). The page reads an entry only while the files it lists are
|
||||
unchanged; a frame whose files can't all be named is not stored. Reload Footage has nothing to
|
||||
drop here: the file table's identities are content hashes, so a replaced file never matches.
|
||||
|
||||
- A render request to a frame worker carries the frame's disk key; the worker posts the frame,
|
||||
then writes the entry with a **synchronous access handle** into a temporary file moved into
|
||||
@@ -352,8 +356,9 @@ scale, view, render options).
|
||||
Cache / `edit.purge {what: "disk"}` clears it. `effectcraft.info().diskCache` has the same.
|
||||
|
||||
**Layer buffers (M13.30).** Slow layer buffers (≥ 20 ms to render) go to the disk cache too
|
||||
(`effectcraft-cache/v1/layers/<32 hex>.ecc`, `disk_cache::layer_entry`, keys salted per project
|
||||
and footage as on the desktop). A layer lookup happens in the middle of a synchronous render,
|
||||
(`effectcraft-cache/v1/layers/<32 hex>.ecc`, `disk_cache::layer_entry`, keyed as on the desktop:
|
||||
`disk_cache::layer_disk_key`; each entry keeps the source files its buffer was made of, with
|
||||
the file table's size and content hash, and is used only while they are unchanged). A layer lookup happens in the middle of a synchronous render,
|
||||
where the browser's file system can't be read, so it is made synchronous by fetching first:
|
||||
|
||||
1. Each frame worker backs its layer cache with a `PrefetchStore` (`effectcraft_render::cache`):
|
||||
|
||||
Reference in New Issue
Block a user