Lesson 233: Spline Embed LCP Fest Landing Receipt on BUILD_RECEIPT (2026)
Direct answer: Before spring fest landing URLs swap, file spline_lcp_fest_receipt_v1.json proving poster-first or click-to-load defer policy, LCP ≤ 2.5 s on mobile throttle lab, zero long tasks overlapping the primary CTA, and a CrUX spot row archived—then promote BUILD_RECEIPT spline_lcp_fest. Distinct from Spline LCP preflight (ninety-second checklist) and R3F self-host preflight (licensing lane).

Why this matters now (May 2027 fest landing traffic spike)
May 2027 teams ship CJK store copy and drop a Spline hero iframe above the fold on the fest hub—Lighthouse mobile LCP 6.2 s, INP red, and Steam in-client browser users never reach the itch demo link. Marketing blames “Spline slow”; the fix is documented embed budget, defer/interaction policy, and a receipt before BUILD_RECEIPT promotion.
The Spline embed LCP preflight is the budget checklist; fest traffic spike preflight is the fest-week URL-swap gate—this lesson is the BUILD_RECEIPT milestone with CI gate verify_spline_lcp_fest_v1.
Beginner path (landing lab smoke)
| Step | Action | Success check |
|---|---|---|
| 1 | Write docs/spline-embed-budget.md row |
Four budget lines filled |
| 2 | Apply poster-first or click-to-load | No autoplay iframe in first viewport |
| 3 | Run Lighthouse mobile (lab) | LCP ≤ 2.5 s |
| 4 | Reserve min-height on iframe container |
CLS stable |
| 5 | Click primary CTA twice | Second click not worse |
| 6 | File spline_lcp_fest_receipt_v1.json |
lcp_fest_pass: true |
| 7 | BUILD_RECEIPT row | spline_lcp_fest GREEN |
Time: ~70 minutes first fest URL; ~20 minutes when defer policy is pinned.
Developer path (gates L1–L6)
| Gate | Check | Fail when |
|---|---|---|
| L1 | Embed budget row in git | Undocumented iframe URL |
| L2 | Defer / interaction policy | Autoplay hero iframe above fold |
| L3 | Single WebGL hero (Rule A) | Spline + Phaser/Three on first paint |
| L4 | Lab LCP + long-task spot | LCP > 2.5 s or long task on CTA |
| L5 | CrUX spot row archived | Lab-only green, no field snapshot |
| L6 | spline_lcp_fest_receipt_v1 + BUILD_RECEIPT |
Fest URL promoted without receipt |
L1 — Embed budget table (copy into receipt)
| Budget line | Measured | Green band |
|---|---|---|
| Iframe weight (above fold) | ___ KB | < 800 KB before first paint |
| GPU memory class | mid-tier phone | One diorama, not two scenes |
| Time to interactive embed | ___ s @ 4× CPU | < 2.5 s if hero |
| Long tasks > 50 ms (first 5 s) | count | 0 overlapping CTA handler |
L2 — Defer / interaction policy (pin in #fest-landing-spline)
Policy A — poster-first (recommended for Steam links):
<div class="spline-hero" style="min-height: 480px; position: relative;">
<img src="/assets/fest-hero-poster.webp" width="960" height="480"
alt="Fest hero still" fetchpriority="high" />
<button type="button" id="load-spline-embed">View 3D scene</button>
<iframe id="spline-embed" hidden loading="lazy"
data-src="https://my.spline.design/SCENE_ID"
title="Fest diorama"></iframe>
</div>
document.getElementById('load-spline-embed')?.addEventListener('click', () => {
const iframe = document.getElementById('spline-embed');
iframe.src = iframe.dataset.src;
iframe.hidden = false;
});
Policy B — click-to-load only: iframe src empty until gesture; poster is LCP element.
Fail closed on autoplay orbit timers in first viewport.
L4 — Lighthouse lab capture
- Chrome DevTools → Lighthouse → Mobile → Performance.
- Throttle: 4× CPU, Slow 4G (or team preset).
- Archive
release-evidence/03-web/lighthouse-fest-landing-mobile.json. - Extract
largest-contentful-paintand long-task count into receipt.
L5 — CrUX spot row (field snapshot)
From PageSpeed Insights or Search Console CrUX export:
| Metric | Spot value | Pass band |
|---|---|---|
| LCP (p75) | ___ s | ≤ 2.5 s (or team waiver documented) |
| INP (p75) | ___ ms | ≤ 200 ms |
| CLS (p75) | ___ | ≤ 0.1 |
Note: Field data lags deploy—file lab L4 even when CrUX is “N/A”; refresh CrUX row after 28 days if fest runs long.
spline_lcp_fest_receipt_v1.json
{
"schema": "spline_lcp_fest_receipt_v1",
"build_label": "spring-fest-2027-rc1",
"landing_url": "https://example.com/fest-hub",
"spline_scene_id": "SCENE_ID",
"embed_policy": "poster_first_click_to_load",
"budget": {
"iframe_kb_above_fold": 620,
"long_tasks_gt_50ms_first_5s": 0,
"lab_lcp_seconds_mobile": 2.1
},
"crux_spot": {
"lcp_p75_seconds": 2.4,
"inp_p75_ms": 180,
"cls_p75": 0.05,
"source": "pagespeed_insights",
"captured_at_utc": "2027-05-12T18:00:00Z"
},
"paired_receipts": {
"store_copy_cjk": "release-evidence/02-store/copy/STORE_COPY_CJK_RECEIPT.json"
},
"gates": {
"L1_embed_budget": "pass",
"L2_defer_policy": "pass",
"L3_single_webgl_hero": "pass",
"L4_lab_lcp": "pass",
"L5_crux_spot": "pass",
"L6_build_receipt": "pass"
},
"lcp_fest_pass": true,
"fest_promotion_allowed": true
}
Pin under release-evidence/03-web/SPLINE_LCP_FEST_RECEIPT.json.
BUILD_RECEIPT row (L6)
| Column | Pass when |
|---|---|
spline_lcp_fest |
Receipt path + lcp_fest_pass: true |
store_copy_cjk |
Lesson 232 independent |
html5_channel_label |
Lesson 201 for itch embed lane |
Relationship to guide vs self-host
| Artifact | Role |
|---|---|
| Spline LCP preflight | L1–L4 checklist |
| Fest traffic spike preflight | Fest-week URL swap + defer under load |
| R3F handoff preflight | Self-host when iframe budget fails |
| This lesson | BUILD_RECEIPT spline_lcp_fest + CrUX spot |
Key takeaways
- Fest traffic hits marketing URLs first—not your game binary.
- Poster-first keeps LCP on still + CTA, not WebGL iframe.
- Rule A: one WebGL hero per viewport.
- Pair with 232—store copy and landing ship same week.
- Steam in-client browser ≈ Deck memory pressure for embed policy.
- Archive lab + CrUX spot—do not claim field green from desktop only.
- Wednesday demo smoke should include landing URL row.
- Q2 capstone 235 wires 233 with 230–234.
- July playtest concurrent load: Lesson 252 —
spline_playtest_lcp_spot_receipt(cousin column, not fest JSON).
Common mistakes
- Measuring desktop only during mobile fest skew.
- Two WebGL heroes (Spline + auto-start Phaser).
- CMS stripping
loading="lazy"—verify View Source. - Promoting fest URL without
min-height→ CLS fails CTA. - Confusing CrUX N/A with permission to skip defer policy.
Troubleshooting
| Symptom | Lane |
|---|---|
| LCP 4–8 s mobile | L2 poster-first; shrink Spline scene |
| CTA frozen on first click | L4 long tasks—defer embed |
| Layout jump on load | min-height + poster dimensions |
| Steam Deck tab reload | L3 remove second WebGL context |
| Lab green, CrUX red | Wait for field; tighten L2 further |
Mini exercise (65 minutes)
- Break L2 on purpose (autoplay iframe)—confirm L4 fails.
- Enable poster-first; pass lab LCP.
- File receipt with
crux_spotrow (orN/A+ waiver note). - Link 232 receipt in
paired_receipts. - Set BUILD_RECEIPT
spline_lcp_festGREEN.
Continuity — Q2 2027 spring fest shipping (230–235)
| Lesson | Receipt focus |
|---|---|
| 230–232 | Art, audio, store copy |
| 233 (this) | Spline fest landing LCP |
| 234 | Micro-trailer stereo embed |
| 235 | Q2 capstone |
Previous: Lesson 232 — Steam CJK short description
Capstone: Lesson 235 — Q2 spring fest shipping — arc 230–235 closed.
FAQ
Same as Spline LCP guide chapter?
Guide = checklist; 233 = BUILD_RECEIPT + CrUX spot + defer policy JSON.
Must we self-host Spline?
Try L2 first; R3F handoff when iframe budget cannot pass.
CrUX still “No data”?
Ship with lab L4 + documented waiver; refresh L5 after traffic accumulates.
Fest landing LCP is a release gate—defer the iframe, measure, file spline_lcp_fest_receipt, then promote the URL.