Technical Specification — Studio David Preli — 2026

MilkPEP x NexRender

After Effects template architecture, NexRender integration, data schema, and depth compositing pipeline

Pipeline After Effects → NexRender → Django
Templates 28+ AE project files
Output scope 12,460 combinations
Year 2026
01System overview

Three layers. One contract.

The system is composed of three distinct layers that communicate exclusively through a shared data schema. The web front end collects user input. NexRender carries that input into After Effects. After Effects evaluates it at render time. No layer has any direct knowledge of the others — they share only a vocabulary of keyword strings.

LayerTechnologyResponsibility
Front end Next.js / React Presents user-facing variable selection. Validates input against schema. Submits job request to Django API.
API & render queue Django / NexRender Receives job request. Constructs NexRender job manifest. Queues and executes render. Returns download link on completion.
Render target After Effects (2025) Receives variable values via text layer injection. Evaluates expressions to configure precomp visibility. Composites user label into footage. Renders output file.

The templates were built for After Effects 2025 and are not backwards-compatible with earlier versions. The expression engine behaviour and certain effect parameters differ across versions in ways that affect the depth compositing stack.

Data flow

// Simplified data flow — all values are schema-defined keyword strings User form vessel_type = "JUG" milk_variety = "CHOCOLATE" cap_color = "BROWN" carton_size = "HALF-GALLON" label_asset = "[user uploaded PNG]" ↓ Django API validates & constructs manifest NexRender job manifest composition = "MILK_EXPORT" // reserved comp name assets = [ label_asset → "MILK_LABEL" layer ] actions = [ setText( "VARIETY_VAR", "CHOCOLATE" ), setText( "VESSEL_VAR", "JUG" ), setText( "CAP_VAR", "BROWN" ), setText( "SIZE_VAR", "HALF-GALLON"), ] ↓ NexRender writes values, triggers AE render After Effects VARIETY_VAR text layer = "CHOCOLATE" → expression on chocolate precomp reads layer source text → opacity set to 100; all other variety precomps → 0 MILK_LABEL layer replaced with user PNG, parented to vessel null → depth displacement applied via Displacer Pro → label rendered in-scene with correct perspective
02After Effects template architecture

Identical contract. Unique content.

Every template in the library shares the same structural specification regardless of the recipe it contains. The specification defines reserved layer names, required composition names, the expression pattern for variety switching, and the asset naming conventions that the render pipeline depends on.

2.1 — Composition structure

Each template contains exactly two compositions whose names are reserved and must not be altered.

Composition namePurpose
MILK_EXPORT The render target. NexRender locates this composition by name to initiate the render job. Contains all variable text layers and the final composited output.
MILK_SOURCE The source footage composition. Contains the original recipe video, the vessel precomp hierarchy, and depth map layers. Referenced by MILK_EXPORT.
Critical

NexRender resolves the render target by composition name only. A composition with a corrected or abbreviated name — Milk_Export, MILKEXPORT, export — will not be found. The render job will fail silently or target the wrong composition with no error output.

2.2 — The MILK_LABEL layer

A placeholder layer named MILK_LABEL exists in every template. It is blank in the source file. NexRender replaces this layer with the user-uploaded label asset at job execution time by matching the layer name string exactly.

2.3 — Variable text layers

Four text layers in MILK_EXPORT hold the variable values. Their names are reserved. NexRender's setText action targets them by name and writes the uppercase schema keyword value before rendering begins.

Layer nameWritten byRead by
VARIETY_VAR NexRender setText action Opacity expressions on each milk-variety precomp
VESSEL_VAR NexRender setText action Opacity expressions on vessel-type precomps
CAP_VAR NexRender setText action Opacity expressions on cap-colour layers within active vessel precomp
SIZE_VAR NexRender setText action Scale expression on vessel null; size-specific comp switch expression

2.4 — Expression pattern

All visibility control uses the same expression pattern. An expression on a precomp's Opacity property reads the source text of the relevant variable layer and evaluates it against the keyword value associated with that precomp. The expression returns 100 if the strings match, 0 if they do not.

// Opacity expression — applied to each variety precomp layer // Replace "CHOCOLATE" with the keyword for this precomp // Replace "VARIETY_VAR" with the controlling text layer name var ctrl = thisComp.layer("VARIETY_VAR").sourceText.value; ctrl === "CHOCOLATE" ? 100 : 0;

This pattern is intentionally minimal. The text layer contains the raw uppercase keyword string with no whitespace and no formatting. Any deviation — a trailing space, a capitalisation difference — causes the expression to evaluate to 0 and the precomp to be invisible in the render.

2.5 — Asset naming constraints

Long file names cause decompression failures when NexRender unpacks the project bundle for rendering. This limit was discovered during testing and is not documented by NexRender. All source assets in the templates use the following conventions:

03Data schema

One keyword table. Three systems.

The Milk Dynamic Video Schema defines the canonical keyword string for every variable in the system. The front-end form labels, the backend API field names, the NexRender action targets, and the After Effects expression comparisons all reference the same document. The schema is the only interface between the three layers.

The schema was authored before any template was built. Templates were written to satisfy the schema, not the other way around. Introducing a new variable requires a schema revision before any template or API change is made.

Full variable table — v2

VariableAE layer nameAccepted keyword valuesNotes
Milk variety VARIETY_VAR WHOLE / STRAWBERRY / CHOCOLATE / SKIM / 2PERCENT / LACTOSE-FREE Per-recipe availability. Recipes not containing chocolate milk do not include the chocolate precomp set.
Vessel type VESSEL_VAR JUG / CARTON / BOTTLE Determines active vessel precomp hierarchy. Each vessel type has its own depth-scanned label placement null.
Cap colour CAP_VAR RED / BLUE / WHITE / GREEN / YELLOW / ORANGE / PURPLE / BLACK / BROWN / PINK Cap layer visibility is controlled by expression within the active vessel precomp. Not all cap colours are available for all vessel types.
Carton size SIZE_VAR HALF-PINT / PINT / QUART / HALF-GALLON Drives scale expression on vessel null. Non-standard sizes use a size-specific precomp with adjusted depth map.
Label asset MILK_LABEL User-uploaded PNG or JPG. No keyword — the layer is replaced by NexRender directly. Accepted dimensions: minimum 500×500 px. Transparent background supported. Labels with transparency composite against vessel surface colour.

Keyword string rules

04NexRender integration

What NexRender does and does not do.

NexRender is a headless After Effects render automation system. It accepts a job manifest — a JSON object — opens the specified AE project on a render node, makes the modifications described in the manifest, and executes the render queue. It has no awareness of the content it is rendering. It reads strings and writes them to layers.

4.1 — Job manifest structure

// Simplified NexRender job manifest { "template": { "src": "s3://milkpep-vd-assets/templates/[recipe_id].aep", "composition": "MILK_EXPORT" }, "assets": [ { "src": "[user label URL]", "type": "image", "layerName": "MILK_LABEL" } ], "actions": { "prerender": [ { "module": "@nexrender/action-prerender-set-text", "composition": "MILK_EXPORT", "layerName": "VARIETY_VAR", "text": "CHOCOLATE" }, { "module": "@nexrender/action-prerender-set-text", "composition": "MILK_EXPORT", "layerName": "VESSEL_VAR", "text": "JUG" }, { "module": "@nexrender/action-prerender-set-text", "composition": "MILK_EXPORT", "layerName": "CAP_VAR", "text": "BROWN" }, { "module": "@nexrender/action-prerender-set-text", "composition": "MILK_EXPORT", "layerName": "SIZE_VAR", "text": "HALF-GALLON" } ], "postrender": [ { "module": "@nexrender/action-upload", "input": "[output filename]", "dest": "s3://milkpep-vd-outputs/[job_id]/" } ] } }

4.2 — Render node environment

ParameterDetail
AE version After Effects 2025 — required. Expressions and effect parameters are version-specific.
Plugins required Displacer Pro (Jixipix) — must be licensed and installed on the render node. Renders without it will silently omit the depth displacement pass.
Output codec H.264 MP4 via Adobe Media Encoder render queue. Lossless intermediate is not used due to storage constraints.
Asset resolution All templates include a 9:16 (1080×1920) output. Some recipes additionally offer a 4:5 (1080×1350) output. Some recipes additionally offer a 1:1 square output. The available formats per recipe are defined at the template level.

4.3 — Pre-render vs. render-time execution

The setText actions are pre-render actions — they execute before the AE render queue is opened. This is critical: AE evaluates expressions at render time against the layer state in the project file. If text layer values are written after the render begins, expressions have already been evaluated and the variable switch has no effect. All variable injection must complete in the pre-render phase.

The label asset replacement via layerName matching also occurs in the pre-render phase. NexRender locates the layer by name, downloads the asset from the specified URL, and replaces the source footage reference before AE opens the composition.

05Depth compositing pipeline

The label sits in the scene, not on it.

The footage was shot with vessel placement and lighting engineered for a subsequent depth-scanning pass. The depth pipeline produces a per-frame displacement map that allows an incoming label asset to be composited with accurate perspective foreshortening, surface curvature, and lighting response — without any manual tracking or matchmoving.

5.1 — Depth map generation

StageToolOutput
Depth prediction Depth Prediction Transformer (DPT) — monocular depth estimation from RGB footage Per-frame 16-bit depth map — brighter values nearer to camera
Depth refinement Depth Scanner Plugin — analyses surface reflections on vessel to sharpen depth discontinuities at label zone boundary Refined EXR sequence — vessel surface isolated from background
Label displacement Displacer Pro — applies depth map as a displacement field to the MILK_LABEL layer Label warped to follow vessel surface curvature per frame
Label alignment AI alignment algorithm (proprietary) — positions label within the designated safe zone using depth discontinuity as the boundary reference Label locked to vessel surface across all frames

5.2 — Safe zone

Each vessel precomp defines a label safe zone — a rectangular region on the vessel surface within which any processor's label will be legible and correctly composited regardless of label artwork dimensions. The safe zone was defined during the shoot by marking the vessel with reference tape and is encoded in the vessel null's transform values in the template.

The MILK_LABEL layer is scaled to fill the safe zone by default. Labels with non-standard aspect ratios are letterboxed within the safe zone; the letterbox background matches the vessel colour inferred from the cap colour variable.

5.3 — Lighting response

The depth map drives a secondary luminosity pass on the MILK_LABEL layer. The same practical light used on the original shoot is simulated as a directional gradient, derived from the depth map's surface normal approximation. This gives the label the appearance of being lit by the same source as the surrounding footage rather than pasted flat over it.

Constraint

The lighting simulation is an approximation. Labels with strong internal contrast — e.g. a bright white panel on a dark background — may show visible seaming at the label boundary under certain lighting conditions. The safe zone was positioned during the shoot to keep the vessel in the most favourable lighting angle for all cap colour variants.

06Combinatorics

Where 12,460 comes from.

The 12,460 figure is the total number of distinct renders the system can produce across all recipes, vessel configurations, milk varieties, cap colours, and output formats. It is not a count of renders produced — it is the scope of the system. Each combination is a valid, distinct After Effects render with a unique precomp configuration, label placement, and expression state. All recipes produce a 9:16 output; some also produce 4:5 and 1:1 outputs.

Not all combinations are available for all recipes. A recipe that does not use chocolate milk does not expose the chocolate variety option. The totals below reflect the maximum available per-variable count; actual per-recipe combination counts are lower and vary by recipe.

Variable Count Notes
Recipes (templates) 28 Each recipe is a discrete AE project file with unique footage
Vessel types 3 Jug, carton, bottle — each with independent depth scan and label placement
Carton sizes 4 Half-pint, pint, quart, half-gallon — size-specific precomps for non-standard formats
Milk varieties 6 Whole, strawberry, chocolate, skim, 2%, lactose-free — recipe availability varies
Cap colours 10 Per vessel type; not all colours available for all vessels
Output formats 2 9:16 (all recipes) + 4:5 (select recipes) + 1:1 (select recipes) — format availability is per-recipe, not universal
Total combinations 12,460 28 × 3 × 4 × 6 × 10 × 2, adjusted for per-recipe availability constraints

The complexity implied by this number lives entirely in the template build. Every cap colour that needed to work required a precomp layer, a colour-matched asset, and an expression branch. Every carton size that differed from the default required a size-specific composition with its own depth-adjusted label transform and a corresponding safe zone calibration. Every milk variety required a footage variant — white milk and chocolate milk have visibly different liquid colour — with a separate depth-composited label zone.

At render time, NexRender writes four keyword strings and replaces one layer. The 12,460 combinations are resolved before the render job is ever queued.

07Known failure modes

What breaks and why.

The following failure modes were identified during alpha and beta testing. Most are silent — NexRender does not surface AE expression errors in its job logs, and a render that completes with the wrong variable state is indistinguishable from a correct render at the API level.

FailureCauseSymptomResolution
Wrong precomp visible API passes a lowercase value where the expression expects uppercase, or vice versa — e.g. chocolate instead of CHOCOLATE Render completes. Output shows default (first) precomp regardless of user selection. Schema enforcement at API validation layer. All keyword values uppercased before manifest construction.
Label not replaced MILK_LABEL layer name has been edited, or layer was accidentally renamed during template maintenance Render completes. Output shows blank vessel surface — no label visible. Template naming lock convention: reserved layer names documented and protected via AE script that warns on save if reserved names are absent.
Composition not found MILK_EXPORT composition name altered NexRender job fails with a composition-not-found error. No render produced. Same naming lock convention. This failure is at least visible in the job log.
Decompression failure Asset file name exceeds ~20 characters or contains special characters NexRender fails to unpack the project bundle. Job fails before render begins. Asset naming convention enforced at template authoring time. All names reviewed against convention before template is committed to S3.
Depth displacement missing Displacer Pro not installed or not licensed on render node Render completes. Label appears flat on vessel — no surface curvature or foreshortening. Often not immediately obvious. Plugin license and installation verified on render node environment. Visual QA checklist includes depth displacement verification pass.
Expression evaluates to 0 on all precomps Text layer contains trailing whitespace from API serialisation All variety precomps hidden. Render completes with transparent vessel area. API trims all keyword values before manifest construction. Schema defines no leading or trailing whitespace as valid.
Label scaled incorrectly Uploaded label asset dimensions outside accepted range (<500×500 px) Label visible but undersized relative to safe zone, or pixelated at render resolution. Front-end validation enforces minimum upload dimensions before job submission. API rejects out-of-spec assets before manifest construction.

AE version sensitivity

Templates built in After Effects 2025 use expression engine features and effect parameter names that differ from AE 2023 and earlier. Running a template in an older AE version on a misconfigured render node will cause expression errors that are not surfaced in the NexRender log. The render may complete with all precomps defaulting to 0 opacity. The AE version on the render node is pinned and verified as part of the environment setup.