// =====================================================================
// Recriação da técnica do edit 40 do illdari ("Kanye", 245 mil plays)
// Cada frase num "app" diferente: capa de álbum nas nuvens -> post curvo
// (cilindro com câmera) com whip pan e destaque -> busca do Google que
// explode numa roda de fotos -> pílula de chamada; trocas no tempo forte
// (~89 BPM) e corte seco no fim.
// Gerador ES3 para o After Effects (rodar com eval num envio só, comp fechada).
// Exercício de estilo: texto da tela é exemplo nosso, trocável (bloco T abaixo).
// =====================================================================

// ---------------- TEXTOS TROCÁVEIS ----------------
var T = {
  // textos 100% nossos (revisão 17/10): nada de letra de música nem verso adaptado
  titulo1: "Bom dia",          // nuvens, linha 1 (2 palavras)
  titulo2: "est\u00fadio",     // nuvens, linha 2 (1 palavra)
  palavra2: "Caf\u00e9",       // céu roxo (1 palavra)
  perfil: "@seu.perfil",       // autor do post
  post: "Hoje a timeline sai do papel bem cedo",   // 8 palavras
  destaque: "cedo",            // última palavra, ganha a caixa roxa
  busca: "como deixar anima\u00e7\u00e3o mais lisa no af",   // digitada no Google (corta no meio)
  chamada: "Cliente aprovou a vers\u00e3o",   // pílula, 4 palavras
  tChamada: [8.35, 8.65, 8.88, 9.10]                                // instante de cada palavra
};

// ---------------- CONSTANTES ----------------
var FPS = 30, W = 1080, H = 1080, DUR = 312 / 30;           // 10,4 s como o original
var PASTA = ((typeof RECR_BASE !== "undefined") ? new Folder(RECR_BASE) : File($.fileName).parent.parent).fsName.replace(/\\/g, "/") + "/";   // pasta do projeto (o script fica em ae/)
var ASSETS = PASTA + "assets/";
var F = 1 / FPS;
var COR = {
  creme: [0xFA/255, 0xE6/255, 0xD7/255], selo: [0x69/255, 0xEF/255, 0xF7/255], destaque: [0x84/255, 0x23/255, 0xA6/255],
  laranja: [0xC4/255, 0x6A/255, 0x1E/255], telefone: [0x68/255, 0xFF/255, 0x0C/255]
};
var FONTE_TIT = "Caprasimo-Regular", FONTE_ICO = "SegoeFluentIcons";
var P = app.project;

// ---------------- AJUDANTES ----------------
function nEases(prop) {
  var t = prop.propertyValueType;
  if (t == PropertyValueType.TwoD_SPATIAL || t == PropertyValueType.ThreeD_SPATIAL) return 1;
  if (t == PropertyValueType.TwoD) return 2;
  if (t == PropertyValueType.ThreeD) return 3;
  return 1;
}
// keys: [[t, v, inflIn, inflOut], ...]; infl 0 = linear naquele lado; "h" = segura
function Q(t) { return Math.round(t * FPS) / FPS; }   // encaixa na grade de quadros
function K(prop, keys) {
  for (var i = 0; i < keys.length; i++) keys[i][0] = Q(keys[i][0]);
  var ehCor = prop.propertyValueType == PropertyValueType.COLOR;
  for (var i = 0; i < keys.length; i++) {
    var v = keys[i][1];
    if (ehCor && v.length == 3) v = [v[0], v[1], v[2], 1];
    try { prop.setValueAtTime(keys[i][0], v); } catch (e) { throw new Error('K em ' + prop.name + ' / ' + prop.parentProperty.name + ' / ' + (prop.propertyGroup(prop.propertyDepth).name) + ': ' + e.toString()); }
  }
  var n = nEases(prop);
  for (var i = 0; i < keys.length; i++) {
    var idx = prop.nearestKeyIndex(keys[i][0]);
    var a = keys[i][2], b = keys[i][3];
    if (a == "h" || b == "h") { prop.setInterpolationTypeAtKey(idx, KeyframeInterpolationType.HOLD, KeyframeInterpolationType.HOLD); continue; }
    if (a === undefined) a = 75; if (b === undefined) b = a;
    var ei = [], eo = [];
    for (var k = 0; k < n; k++) { ei.push(new KeyframeEase(0, Math.max(0.1, a))); eo.push(new KeyframeEase(0, Math.max(0.1, b))); }
    if (a <= 0.1 && b <= 0.1) prop.setInterpolationTypeAtKey(idx, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
    else prop.setTemporalEaseAtKey(idx, ei, eo);
  }
  if (prop.isSpatial) for (var i = 1; i <= prop.numKeys; i++) { try { prop.setSpatialAutoBezierAtKey(i, true); } catch (e) {} }
}
function tr(L) { return L.property("ADBE Transform Group"); }
function pos(L) { return tr(L).property("ADBE Position"); }
function esc(L) { return tr(L).property("ADBE Scale"); }
function opa(L) { return tr(L).property("ADBE Opacity"); }
function rot(L) { return tr(L).property("ADBE Rotate Z"); }
function fx(L, mn) { return L.property("ADBE Effect Parade").addProperty(mn); }
function item(nome) { for (var i = 1; i <= P.numItems; i++) if (P.item(i).name == nome) return P.item(i); return null; }
function importa(arq) {
  var it = item(arq); if (it) return it;
  it = P.importFile(new ImportOptions(File(ASSETS + arq))); it.name = arq; return it;
}
function comp(nome, dur) {
  var c = item(nome); if (c) c.remove();
  c = P.items.addComp(nome, W, H, 1, dur || DUR, FPS);
  c.motionBlur = true; c.shutterAngle = 360; c.shutterPhase = -180; c.motionBlurSamplesPerFrame = 32; c.motionBlurAdaptiveSampleLimit = 256;
  c.bgColor = [0, 0, 0];
  return c;
}
function texto(c, s, fonte, tam, cor, p, just, track) {
  var L = c.layers.addText(s);
  var tp = L.property("ADBE Text Properties").property("ADBE Text Document");
  var d = tp.value; d.resetCharStyle(); d.resetParagraphStyle();
  d.font = fonte; d.fontSize = tam; d.fillColor = cor; d.applyFill = true; d.applyStroke = false; d.tracking = track || 0;
  d.justification = just || ParagraphJustification.LEFT_JUSTIFY;
  tp.setValue(d);
  pos(L).setValue(p);
  return L;
}
// forma: retângulo arredondado (centro, tamanho, raio), preenchimento e traço opcionais
function retangulo(c, nome, centro, tam, raio, cor, traco) {
  var L = c.layers.addShape(); L.name = nome;
  var g = L.property("ADBE Root Vectors Group").addProperty("ADBE Vector Group");
  var v = g.property("ADBE Vectors Group");
  var r = v.addProperty("ADBE Vector Shape - Rect");
  r.property("ADBE Vector Rect Size").setValue(tam); r.property("ADBE Vector Rect Roundness").setValue(raio);
  if (traco) {
    var s = v.addProperty("ADBE Vector Graphic - Stroke");
    s.property("ADBE Vector Stroke Color").setValue(traco[0]); s.property("ADBE Vector Stroke Width").setValue(traco[1]);
    s.property("ADBE Vector Stroke Opacity").setValue(traco[2]);
  }
  if (cor) { var f = v.addProperty("ADBE Vector Graphic - Fill"); f.property("ADBE Vector Fill Color").setValue(cor); }
  pos(L).setValue(centro);
  return L;
}
function elipse(c, nome, centro, diam, cor) {
  var L = c.layers.addShape(); L.name = nome;
  var g = L.property("ADBE Root Vectors Group").addProperty("ADBE Vector Group");
  var v = g.property("ADBE Vectors Group");
  v.addProperty("ADBE Vector Shape - Ellipse").property("ADBE Vector Ellipse Size").setValue([diam, diam]);
  v.addProperty("ADBE Vector Graphic - Fill").property("ADBE Vector Fill Color").setValue(cor);
  pos(L).setValue(centro);
  return L;
}
function cor(L) { // primeira cor de preenchimento de uma forma
  return L.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group").property("ADBE Vector Graphic - Fill").property("ADBE Vector Fill Color");
}
// máscara retângulo arredondado
function mascaraArred(L, x, y, w, h, r) {
  var k = 0.5523 * r, s = new Shape();
  s.vertices = [[x + r, y], [x + w - r, y], [x + w, y + r], [x + w, y + h - r], [x + w - r, y + h], [x + r, y + h], [x, y + h - r], [x, y + r]];
  s.inTangents = [[-k, 0], [0, 0], [0, -k], [0, 0], [k, 0], [0, 0], [0, k], [0, 0]];
  s.outTangents = [[0, 0], [k, 0], [0, 0], [0, k], [0, 0], [-k, 0], [0, 0], [0, -k]];
  s.closed = true;
  var m = L.property("ADBE Mask Parade").addProperty("ADBE Mask Atom");
  m.property("ADBE Mask Shape").setValue(s);
  return m;
}
// formas do SVG oficial (svg_para_ae.py) -> camada de forma
function formaSVG(c, nome, json, idxPath, subIdx, escala, origem, corF) {
  var L = c.layers.addShape(); L.name = nome;
  var g = L.property("ADBE Root Vectors Group").addProperty("ADBE Vector Group");
  var v = g.property("ADBE Vectors Group");
  for (var s = 0; s < subIdx.length; s++) {
    var sp = json[idxPath].paths[subIdx[s]];
    var sh = new Shape(), vv = [], ii = [], oo = [];
    for (var k = 0; k < sp.v.length; k++) {
      vv.push([(sp.v[k][0] - origem[0]) * escala, (sp.v[k][1] - origem[1]) * escala]);
      ii.push([sp.i[k][0] * escala, sp.i[k][1] * escala]); oo.push([sp.o[k][0] * escala, sp.o[k][1] * escala]);
    }
    sh.vertices = vv; sh.inTangents = ii; sh.outTangents = oo; sh.closed = true;
    v.addProperty("ADBE Vector Shape - Group").property("ADBE Vector Shape").setValue(sh);
  }
  v.addProperty("ADBE Vector Graphic - Fill").property("ADBE Vector Fill Color").setValue(corF);
  return L;
}
function lerJSON(arq) { var f = File(arq); f.encoding = "UTF-8"; f.open("r"); var s = f.read(); f.close(); return eval("(" + s + ")"); }
function blur(L, v, solto) { var e = fx(L, "ADBE Gaussian Blur 2"); e.property("ADBE Gaussian Blur 2-0003").setValue(solto ? 0 : 1); if (v !== undefined) e.property("ADBE Gaussian Blur 2-0001").setValue(v); return e.property("ADBE Gaussian Blur 2-0001"); }
function glow(L, raio, inten, limiar) {
  var e = fx(L, "ADBE Glo2"); e.property("ADBE Glo2-0002").setValue(limiar === undefined ? 40 : limiar);
  e.property("ADBE Glo2-0003").setValue(raio); e.property("ADBE Glo2-0004").setValue(inten); return e;
}
// parentesco sem compensação (o .parent = do script converte a rotação do pai em Orientation do filho)
function pai(L, P) { L.setParentWithJump(P); }
function janela(L, a, b) { L.inPoint = Q(a); L.outPoint = Q(b); }
function mb(L) { L.motionBlur = true; }
// deriva lenta (nunca parado): expressão de wiggle bem lento
function vivo(prop, freq, amp) { prop.expression = "wiggle(" + freq + "," + amp + ")"; }

// =====================================================================
// 1) CAPA DE ÁLBUM (0–2,2 s): nuvens + título que cai letra a letra,
//    mascote atravessa colado na câmera, céu roxo + palavra + cabeça do mascote
// =====================================================================
function letrasCaindo(L, t0, t1) {   // animador por caractere: cai de cima, grande e borrado -> 100%
  var an = L.property("ADBE Text Properties").property("ADBE Text Animators");
  var a = an.addProperty("ADBE Text Animator"); a.name = "cai";
  var pr = a.property("ADBE Text Animator Properties");
  pr.addProperty("ADBE Text Position 3D").setValue([0, -90, 0]);
  pr.addProperty("ADBE Text Scale 3D").setValue([180, 180, 100]);
  pr.addProperty("ADBE Text Blur").setValue([22, 22]);
  pr.addProperty("ADBE Text Opacity").setValue(0);
  var s = a.property("ADBE Text Selectors").addProperty("ADBE Text Selector");
  s.property("ADBE Text Range Advanced").property("ADBE Text Selector Smoothness").setValue(100);
  K(s.property("ADBE Text Percent Start"), [[t0, 0, 0, 0], [t1, 100, 0, 30]]);
}
function cenaCapa() {
  var c = comp("C_capa");
  var roxo = c.layers.addSolid([0.42, 0.16, 0.54], "roxo", W, H, 1);
  var nv = c.layers.add(importa("nuvens.png")); nv.name = "nuvens";
  esc(nv).setValue([150, 150]); janela(nv, 0, 1.42);
  K(pos(nv), [[0.0, [540, 470], 0, 0], [1.42, [560, 600], 0, 0]]);
  K(opa(nv), [[0.06, 0, 0, 0], [0.20, 100, 0, 0]]);
  var l1 = texto(c, T.titulo1, FONTE_TIT, 165, COR.creme, [105, 440], ParagraphJustification.LEFT_JUSTIFY);
  var l2 = texto(c, T.titulo2, FONTE_TIT, 165, COR.creme, [105, 570], ParagraphJustification.LEFT_JUSTIFY);
  letrasCaindo(l1, 0.18, 0.52); letrasCaindo(l2, 0.45, 0.74);
  var tts = [l1, l2];
  for (var i = 0; i < 2; i++) { janela(tts[i], 0, 1.42); K(pos(tts[i]), [[0.2, [80, 420 + i * 160], 0, 0], [1.42, [76, 460 + i * 160], 0, 0]]); mb(tts[i]); }
  // mascote voa de baixo à direita, cresce e passa colado na câmera (wipe pelo personagem)
  var m = c.layers.add(importa("mascote-recorte.png")); m.name = "mascote voando"; mb(m); janela(m, 0.76, 1.50);
  K(pos(m), [[0.76, [1080, 1130], 0, 0], [1.02, [640, 600], 0, 0], [1.20, [520, 560], 0, 30], [1.42, [200, 700], 30, 0]]);
  K(esc(m), [[0.76, [30, 30], 0, 0], [1.02, [62, 62], 0, 0], [1.20, [95, 95], 0, 30], [1.42, [480, 480], 30, 0]]);
  K(rot(m), [[0.76, 28, 0, 0], [1.20, -6, 0, 0], [1.42, -30, 0, 0]]);
  // segunda cena: céu roxo, nuvem no alto, palavra cai e a cabeça do mascote sobe
  var ceu = c.layers.addSolid([0, 0, 0], "ceu roxo", W, H, 1); ceu.moveBefore(roxo);
  var gr = fx(ceu, "ADBE Ramp"); gr.property("ADBE Ramp-0001").setValue([540, 0]); gr.property("ADBE Ramp-0002").setValue([0.30, 0.07, 0.40]);
  gr.property("ADBE Ramp-0003").setValue([540, 1080]); gr.property("ADBE Ramp-0004").setValue([0.58, 0.16, 0.66]);
  janela(ceu, 1.38, DUR);
  var nv2 = c.layers.add(importa("nuvens.png")); nv2.name = "nuvem alto"; janela(nv2, 1.38, DUR); nv2.moveBefore(ceu);
  esc(nv2).setValue([260, 260]); K(pos(nv2), [[1.38, [900, 760], 0, 0], [3.0, [880, 790], 0, 0]]);
  var hs = fx(nv2, "ADBE Color Balance (HLS)"); hs.property(1).setValue(-25);
  var leve = texto(c, T.palavra2, FONTE_TIT, 140, COR.creme, [540, 470], ParagraphJustification.CENTER_JUSTIFY);
  janela(leve, 1.50, DUR); letrasCaindo(leve, 1.55, 1.82); mb(leve);
  var cab = c.layers.add(importa("mascote-recorte.png")); cab.name = "cabeca mascote"; janela(cab, 1.55, DUR); mb(cab);
  K(pos(cab), [[1.55, [540, 1500], 0, 80], [1.92, [540, 955], 80, 60], [3.0, [540, 945], 60, 0]]);
  esc(cab).setValue([120, 120]);
  vivo(pos(nv2), 0.4, 8);
  return c;
}

// =====================================================================
// 2) MUNDO PLANO (post + Google + roda de fotos), depois curvado em cilindro
//    Coordenadas do "mundo": cartão do post com 820 u de largura (escala do quadro 2,3 s)
// =====================================================================
var MW = 2400, MH = 2200;
function largura(c, s, fonte, tam) { var L = texto(c, s, fonte, tam, [1, 1, 1], [0, 0]); var w = L.sourceRectAtTime(0, false).width; L.remove(); return w; }
function cenaMundo(capa) {
  var c = P.items.addComp("C_mundo", MW, MH, 1, DUR, FPS); c.motionBlur = true; c.shutterAngle = 360; c.shutterPhase = -180;
  var preto = c.layers.addSolid([0.024, 0.024, 0.024], "fundo post", MW, MH, 1);
  // cartão = capa do álbum (a própria cena 1 continua tocando dentro dele)
  var card = c.layers.add(capa); card.name = "cartao capa"; esc(card).setValue([75.9, 75.9]); pos(card).setValue([1010, 1590]);
  mascaraArred(card, 0, 0, 1080, 1080, 34);
  var vb = fx(card, "ADBE Venetian Blinds"); vb.property("ADBE Venetian Blinds-0001").setValue(14); vb.property("ADBE Venetian Blinds-0002").setValue(90); vb.property("ADBE Venetian Blinds-0003").setValue(5);
  var borda = retangulo(c, "borda cartao", [1010, 1590], [820, 820], 26, null, [[1, 1, 1], 2, 35]);
  // cabeçalho do post: avatar, @, selo
  var av = c.layers.add(importa("avatar.png")); av.name = "avatar"; esc(av).setValue([6.4, 6.4]); pos(av).setValue([584, 1092]);
  var mk = av.property("ADBE Mask Parade").addProperty("ADBE Mask Atom"); var sh = new Shape(), r = 512, k = 0.5523 * r;
  sh.vertices = [[512, 0], [1024, 512], [512, 1024], [0, 512]]; sh.inTangents = [[-k, 0], [0, -k], [k, 0], [0, k]]; sh.outTangents = [[k, 0], [0, k], [-k, 0], [0, -k]]; sh.closed = true;
  mk.property("ADBE Mask Shape").setValue(sh);
  var nome = texto(c, T.perfil, "SegoeUI-Bold", 30, [1, 1, 1], [628, 1103], ParagraphJustification.LEFT_JUSTIFY);
  var wn = nome.sourceRectAtTime(0, false).width;
  var selo = elipse(c, "selo", [628 + wn + 22, 1092], 30, COR.selo);
  var chk = texto(c, "", FONTE_ICO, 18, [1, 1, 1], [628 + wn + 22, 1101], ParagraphJustification.CENTER_JUSTIFY);
  var cab = [av, nome, selo, chk];
  for (var i = 0; i < cab.length; i++) K(opa(cab[i]), [[2.22, 0, 0, 0], [2.32, 100, 0, 0]]);
  // texto do post: letras saltam da linha de base (~1 caractere por quadro), 2,25–3,85
  var xT = 600, yT = 1146;
  var post = texto(c, T.post, "SegoeUI-Semibold", 31, [1, 1, 1], [xT, yT], ParagraphJustification.LEFT_JUSTIFY);
  var an = post.property("ADBE Text Properties").property("ADBE Text Animators");
  var a1 = an.addProperty("ADBE Text Animator"); a1.name = "pulo da base";
  var pr = a1.property("ADBE Text Animator Properties");
  pr.addProperty("ADBE Text Position 3D").setValue([0, 22, 0]); pr.addProperty("ADBE Text Scale 3D").setValue([60, 60, 100]); pr.addProperty("ADBE Text Opacity").setValue(0);
  var s1 = a1.property("ADBE Text Selectors").addProperty("ADBE Text Selector");
  s1.property("ADBE Text Range Advanced").property("ADBE Text Selector Smoothness").setValue(100);
  K(s1.property("ADBE Text Percent Start"), [[2.25, 0, 0, 0], [3.85, 100, 0, 0]]);
  // destaque roxo atrás da última palavra, cresce da esquerda em 3 qd
  var pref = T.post.substring(0, T.post.length - T.destaque.length);
  var x0 = xT + largura(c, pref, "SegoeUI-Semibold", 31), wd = largura(c, T.destaque, "SegoeUI-Semibold", 31);
  var hl = retangulo(c, "destaque", [x0 - 6, yT - 11], [wd + 12, 46], 0, COR.destaque);
  tr(hl).property("ADBE Anchor Point").setValue([-(wd + 12) / 2, 0]); hl.moveAfter(post);
  K(esc(hl), [[4.05, [0, 100], 0, 0], [4.14, [100, 100], 0, 30]]);
  // Google modo escuro: logo oficial (SVG) com o 2º "o" trocado por um quadrado laranja
  var gj = lerJSON(ASSETS + "google-ae.json"), GE = 1.55, GX = 1300, GY = 520;
  for (var p = 0; p < gj.length; p++) {
    if (p == 1) continue;
    var idx = []; for (var q = 0; q < gj[p].paths.length; q++) idx.push(q);
    var hex = gj[p].fill, cc = [parseInt(hex.substr(1, 2), 16) / 255, parseInt(hex.substr(3, 2), 16) / 255, parseInt(hex.substr(5, 2), 16) / 255];
    var g = formaSVG(c, "google " + p, gj, p, idx, GE, [135, 45], cc); pos(g).setValue([GX, GY]);
  }
  var QX = GX + (141.5 - 135) * GE, QY = GY + (47 - 45) * GE;
  var quad = retangulo(c, "quadrado o", [QX, QY], [40 * GE * 0.85, 40 * GE * 0.85], 3, COR.laranja);
  var fundoG = c.layers.addSolid([0.12, 0.118, 0.13], "fundo google", MW, 1000, 1); pos(fundoG).setValue([MW / 2, GY + 150]); fundoG.moveBefore(preto);
  var bar = retangulo(c, "barra busca", [GX, GY + 130], [640, 58], 29, [0.204, 0.208, 0.227]);
  var lupa = texto(c, "", FONTE_ICO, 24, [0.85, 0.85, 0.85], [GX - 292, GY + 140], ParagraphJustification.CENTER_JUSTIFY);
  var busca = texto(c, T.busca, "SFProText-Medium", 26, [0.95, 0.95, 0.95], [GX - 262, GY + 139], ParagraphJustification.LEFT_JUSTIFY);
  var an2 = busca.property("ADBE Text Properties").property("ADBE Text Animators");
  var a2 = an2.addProperty("ADBE Text Animator"); var p2 = a2.property("ADBE Text Animator Properties");
  p2.addProperty("ADBE Text Position 3D").setValue([0, -20, 0]); p2.addProperty("ADBE Text Opacity").setValue(0);
  var s2 = a2.property("ADBE Text Selectors").addProperty("ADBE Text Selector");
  s2.property("ADBE Text Range Advanced").property("ADBE Text Selector Smoothness").setValue(100);
  K(s2.property("ADBE Text Percent Start"), [[5.0, 0, 0, 0], [6.35, 100, 0, 0]]);
  // roda de fotos: a 1ª foto sai do quadrado, as outras nascem em volta (1 qd de stagger) e o anel gira
  var cx = GX, cy = GY + 130, N = 14, RR = 205, LADO = 220;
  var roda = c.layers.addNull(); roda.name = "roda"; tr(roda).property("ADBE Anchor Point").setValue([50, 50]); pos(roda).setValue([cx, cy]);
  K(rot(roda), [[6.38, -40, 0, 30], [7.45, 60, 30, 0]]);
  for (var i = 0; i < N; i++) {
    var f = c.layers.add(importa("fotos/foto-" + (i < 9 ? "0" : "") + (i + 1) + ".png")); f.name = "foto " + (i + 1); mb(f);
    var ang = i * 360 / N, rad = ang * Math.PI / 180;
    pai(f, roda);
    var px = 50 + RR * Math.cos(rad), py = 50 + RR * Math.sin(rad);
    var t0 = (i == 0) ? 6.12 : 6.32 + i * F;
    janela(f, t0, DUR);
    var sc = LADO / 246 * 100;
    if (i == 0) K(pos(f), [[6.12, [50 + (QX - cx) * 1, 50 + (QY - cy)], 0, 60], [6.40, [px, py], 60, 60]]);
    else K(pos(f), [[t0, [50 + RR * 0.6 * Math.cos(rad), 50 + RR * 0.6 * Math.sin(rad)], 0, 70], [t0 + 7 * F, [px, py], 70, 60]]);
    K(esc(f), [[t0, [0, 0], 0, 70], [t0 + 7 * F, [sc * 1.06, sc * 1.06], 70, 70], [t0 + 10 * F, [sc, sc], 70, 70]]);
    rot(f).setValue(ang + 90 + ((i % 3) - 1) * 9);
  }
  roda.moveToBeginning();
  for (var i = 1; i <= c.numLayers; i++) { var L = c.layer(i); if (L.name.indexOf("foto ") == 0) L.moveToBeginning(); }
  return c;
}

// cilindro de eixo vertical feito de tiras do mundo (perspectiva real com a câmera)
var RC = 800, UC = 1010, VC = 1100;
function cenaPost(mundo) {
  var c = comp("C_post");
  // raio do cilindro animado: curvo no post (800) e quase plano no Google (5000), como no original
  var ctrl = c.layers.addNull(); ctrl.name = "CTRL"; ctrl.enabled = false;
  var sl = fx(ctrl, "ADBE Slider Control"); sl.name = "raio";
  K(sl.property(1), [[2.2, RC, 0, 0], [4.80, RC, 0, 60], [5.30, 5000, 60, 0]]);
  var u0 = 300, u1 = 2300, larg = 25;
  for (var u = u0; u < u1; u += larg) {
    var L = c.layers.add(mundo); L.name = "tira " + u; L.threeDLayer = true;
    var m = L.property("ADBE Mask Parade").addProperty("ADBE Mask Atom"); var sh = new Shape();
    sh.vertices = [[u - 1, 0], [u + larg + 1, 0], [u + larg + 1, MH], [u - 1, MH]]; sh.closed = true; m.property("ADBE Mask Shape").setValue(sh);
    var uc = u + larg / 2;
    var R_ = "thisComp.layer('CTRL').effect('raio')(1)";
    tr(L).property("ADBE Anchor Point").expression = "[" + uc + ", " + VC + ", " + R_ + "]";
    pos(L).expression = "[540, 540, " + R_ + "]";
    tr(L).property("ADBE Rotate Y").expression = "-(" + (uc - UC) + " / " + R_ + ") * 180 / Math.PI";
  }
  // câmera: [t, cx, cy, distância, inclinação (câmera abaixo olhando para cima), rolagem]
  var cam = c.layers.addCamera("camera", [540, 540]);
  cam.property("ADBE Camera Options Group").property("ADBE Camera Zoom").setValue(1000);
  var KC = [
    [2.20, 535, 990, 1000, 0, 0, 60], [2.30, 535, 981, 1000, 0, 0, 60], [2.60, 520, 940, 900, 20, 0, 70],
    [2.95, 275, 584, 225, 75, 0, 60], [3.30, 335, 580, 222, 75, 0, 40], [3.55, 520, 574, 215, 70, 0, 50],
    [4.05, 632, 568, 222, 65, 0, 70], [4.75, 640, 568, 202, 65, 0, 30], [5.00, 830, 120, 420, 60, -2, 60],
    [5.20, 830, 79, 500, 40, -3, 70], [6.00, 832, 86, 515, 30, -3, 60], [6.30, 830, 80, 600, 20, -2, 70], [7.45, 830, 78, 650, 20, -1, 0]
  ];
  var kp = [], ka = [], kr = [];
  for (var i = 0; i < KC.length; i++) {
    var z = KC[i]; var poiX = z[1], poiY = z[2];   // já em coordenadas da comp (mundo u -> 540 + u - UC; v -> 540 + v - VC)
    ka.push([z[0], [poiX, poiY, 0], z[6], z[6]]);
    kp.push([z[0], [poiX, poiY + z[4], -z[3]], z[6], z[6]]);
    kr.push([z[0], z[5], z[6], z[6]]);
  }
  K(cam.property("ADBE Transform Group").property("ADBE Anchor Point"), ka);
  K(cam.property("ADBE Transform Group").property("ADBE Position"), kp);
  K(cam.property("ADBE Transform Group").property("ADBE Rotate Z"), kr);
  return c;
}

// =====================================================================
// 3) CHAMADA (pílula estilo ilha dinâmica): palavra por palavra, câmera aproxima
// =====================================================================
function cenaChamada() {
  var c = comp("C_chamada");
  c.layers.addSolid([0.82, 0.82, 0.82], "fundo cinza", W, H, 1);
  var pil = retangulo(c, "pilula", [540, 560], [100, 100], 70, [0.933, 0.933, 0.933]);
  var tx = texto(c, T.chamada, "SFProText-Semibold", 42, [0.07, 0.07, 0.07], [0, 575], ParagraphJustification.LEFT_JUSTIFY);
  var tempos = T.tChamada, ws = T.chamada.split(" ");
  var ex = "var ts=[" + tempos.join(",") + "], w=['" + ws.join("','") + "']; var n=0; for (var i=0;i<ts.length;i++) if (time>=ts[i]) n=i+1; n==0 ? ' ' : w.slice(0,n).join(' ');";
  tx.property("ADBE Text Properties").property("ADBE Text Document").expression = ex;
  janela(tx, 8.2, DUR);
  // a palavra nova cai de cima (3 qd)
  var an = tx.property("ADBE Text Properties").property("ADBE Text Animators");
  var a = an.addProperty("ADBE Text Animator"); var pr = a.property("ADBE Text Animator Properties");
  pr.addProperty("ADBE Text Position 3D").setValue([0, -18, 0]); pr.addProperty("ADBE Text Opacity").setValue(0);
  var sel = a.property("ADBE Text Selectors").addProperty("ADBE Text Expressible Selector");
  sel.property("ADBE Text Range Type2").setValue(3); // palavras
  sel.property("ADBE Text Expressible Amount").expression = "var ts=[" + tempos.join(",") + "]; var n=0; for (var i=0;i<ts.length;i++) if (time>=ts[i]) n=i+1; var v=0; if (textIndex==n){ v=Math.max(0,1-(time-ts[n-1])/0.1)*100; } [v,v,v];";
  // largura da pílula acompanha o texto; o ícone fica na ponta esquerda
  var sz = pil.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group").property("ADBE Vector Shape - Rect").property("ADBE Vector Rect Size");
  K(sz, [[7.80, [0, 0], 0, 70], [7.95, [100, 100], 70, 70], [8.00, [100, 100], 70, 0], [8.10, [470, 136], 0, 70]]);
  sz.expression = "if (time < 8.12) value; else { var r=thisComp.layer('" + tx.name + "').sourceRectAtTime(time,false); var alvo=Math.max(470, r.width+200); [alvo, 136]; }";
  tr(tx).property("ADBE Position").expression = "var w=thisComp.layer('pilula').content(1).content(1).size[0]; [540 - w/2 + 140, 575];";
  var circ = elipse(c, "circulo icone", [540, 600], 96, [1, 1, 1]);
  var ic = texto(c, "", FONTE_ICO, 48, COR.telefone, [540, 618], ParagraphJustification.CENTER_JUSTIFY);
  pai(ic, circ); pos(ic).setValue([0, 18]);
  pos(circ).expression = "var w=thisComp.layer('pilula').content(1).content(1).size[0]; var p=[540,560]; if (time < 7.95) p = [540, 560 + 40*Math.max(0, (7.9-time)/0.45)]; else p=[540 - w/2 + 68, 560]; p;";
  K(esc(circ), [[7.45, [60, 60], 0, 60], [7.80, [80, 80], 60, 60], [7.95, [100, 100], 60, 60]]);
  K(opa(circ), [[7.45, 100, 0, 0]]);
  var gC = cor(circ); K(gC, [[7.70, [0.82, 0.82, 0.82], 60, 60], [7.90, [1, 1, 1], 60, 60]]);
  mb(pil); blur(pil, 0, true);
  K(pil.property("ADBE Effect Parade").property(1).property(1), [[8.0, 0, 0, 0], [8.05, 8, 0, 0], [8.12, 0, 0, 0]]);
  return c;
}

// =====================================================================
// 4) COMP FINAL
// =====================================================================
function montaFinal() {
  var cC = cenaCapa();
  var old = item("C_mundo"); if (old) old.remove();
  var cM = cenaMundo(cC), cP = cenaPost(cM), cH = cenaChamada();
  var c = comp("RECRIACAO");
  c.layers.addSolid([0, 0, 0], "preto", W, H, 1);
  var lC = c.layers.add(cC); lC.name = "capa"; janela(lC, 0, 2.22); mb(lC);
  K(esc(lC), [[2.00, [100, 100], 0, 80], [2.20, [77, 77], 80, 60]]);
  var oc = fx(lC, "ADBE Optics Compensation"); K(oc.property(1), [[2.00, 0, 0, 0], [2.20, 30, 0, 0]]);
  var lP = c.layers.add(cP); lP.name = "post google roda"; janela(lP, 2.20, 7.45);
  // íris branca cresce do furo da roda
  var ir = elipse(c, "iris branca", [540, 560], 100, [0.96, 0.96, 0.96]); blur(ir, 110, true); janela(ir, 7.18, 7.46);
  var irS = ir.property("ADBE Root Vectors Group").property(1).property("ADBE Vectors Group").property("ADBE Vector Shape - Ellipse").property("ADBE Vector Ellipse Size");
  K(irS, [[7.18, [0, 0], 0, 0], [7.40, [720, 720], 40, 0], [7.45, [2400, 2400], 0, 0]]);
  var lH = c.layers.add(cH); lH.name = "chamada"; janela(lH, 7.45, 10.20); mb(lH);
  K(esc(lH), [[8.20, [100, 100], 40, 40], [10.10, [133, 133], 40, 40]]);
  var db = fx(lH, "ADBE Motion Blur"); db.property("ADBE Motion Blur-0001").setValue(90);
  K(db.property("ADBE Motion Blur-0002"), [[10.12, 0, 0, 0], [10.19, 220, 0, 0]]);
  c.workAreaStart = 0; c.workAreaDuration = DUR;
  return c;
}

var compFinal = montaFinal();
"ok " + compFinal.numLayers;
