← back to Wallpaper Paint Antics
series2/episodes/08-service-at-dw.html
215 lines
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo presents — Service at Designer Wallcoverings</title><style>@font-face{font-family:Georgia;src:url('../assets/georgia.ttf')}@font-face{font-family:Verdana;src:url('../assets/verdana.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.preload{position:absolute;opacity:0;pointer-events:none}</style><script src="../assets/gsap.min.js"></script></head><body><div id="root" data-composition-id="main" data-start="0" data-duration="20" data-width="1080" data-height="1920" data-fps="30"><section id="material-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Wallo presenting Service at Designer Wallcoverings"></canvas><span class="preload" style="font-family:Georgia">Wallo</span><span class="preload" style="font-family:Verdana">Designer Wallcoverings</span></section><audio id="narrated-mix" src="../assets/mix-4.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>window.EPISODE={"slug":"08-service-at-dw","title":"A better finish\nstarts with service.","shortTitle":"Service at Designer Wallcoverings","kicker":"05 / SERVICE AT DW","product":"kaya","note":"Samples, product information and quotes at designerwallcoverings.com.","takeaway":"Bring your project to DW.","lines":["Bring your project to Designer Wallcoverings. Start with what you love.","Explore the collection, request samples, and ask for product information.","Share the selected pattern and project details when requesting a quote.","From first shortlist to your order, make each choice an informed one."],"captions":["Start with your project and your ideas.","Products. Samples. Information.","Request a quote with your project details.","Make the next choice an informed one."],"index":4,"audio":{"slug":"08-service-at-dw","provider":"Kokoro local","voice":"am_michael","duration":20,"segments":[{"index":0,"start":0.6,"end":4.825,"text":"Bring your project to Designer Wallcoverings. Start with what you love.","caption":"Start with your project and your ideas.","duration":4.225},{"index":1,"start":5.1,"end":9.333,"text":"Explore the collection, request samples, and ask for product information.","caption":"Products. Samples. Information.","duration":4.233},{"index":2,"start":9.6,"end":13.826,"text":"Share the selected pattern and project details when requesting a quote.","caption":"Request a quote with your project details.","duration":4.226},{"index":3,"start":14.1,"end":18.217,"text":"From first shortlist to your order, make each choice an informed one.","caption":"Make the next choice an informed one.","duration":4.117}],"energy":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0011,0.0961,0.5037,0.9922,0.9758,0.7855,0.7486,0.9046,0.851,0.6868,0.7218,0.8719,0.8068,0.1328,0.023,0.0042,0.2099,0.1055,0.0814,0.6799,0.8387,0.6798,0.6157,0.6494,0.6933,0.6627,0.7698,0.5199,0.3233,0.2107,0.1887,0.5555,0.5551,0.4464,0.6825,0.6174,0.5769,0.4487,0.1957,0.0288,0.0082,0.0023,0.0013,0.2396,0.4031,0.1625,0.4058,0.2598,0.2201,0.1947,0.3378,0.5485,0.5269,0.4267,0.4388,0.4809,0.4284,0.3714,0.5615,0.7101,0.587,0.4203,0.5081,0.5875,0.5487,0.6258,0.6013,0.625,0.5175,0.4616,0.5375,0.4901,0.5221,0.5381,0.5403,0.4622,0.3472,0.3175,0.3063,0.4251,0.7535,0.7515,1,1,1,0.903,0.5636,0.1415,0.0203,0.0031,0.2815,0.1189,0.5535,0.2749,0.1858,0.1537,0.1621,0.2724,0.278,0.224,0.1986,0.1751,0.1418,0.1074,0.0541,0.0832,0.0341,0.0394,0.0157,0.0168,0.0308,0.0884,0.2284,0.3311,0.2441,0.1275,0.0087,0.0059,0.0033,0.0046,0.0045,0.0041,0.0042,0.0045,0.0057,0.0059,0.0076,0.0084,0.0084,0.0082,0.0067,0.0047,0.0027,0.0177,0.187,0.6008,0.8828,0.9224,0.3376,0.0085,1,1,1,1,1,1,1,1,0.861,0.5585,0.303,0.1054,0.0268,0.0131,0.0993,0.2208,0.3879,0.4641,0.3831,0.1547,0.1772,0.1101,0.0158,0.0302,0.2162,0.6315,0.912,0.7881,0.6285,0.298,0.0372,0.0195,0.0454,0.1386,0.1929,0.2578,0.3025,0.3697,0.4179,0.358,0.3465,0.3389,0.302,0.241,0.2961,0.3352,0.4138,0.4818,0.8012,0.6604,0.7945,0.9536,1,1,0.6285,0.4642,0.2849,0.161,0.0579,0.0645,0.0206,0.0309,0.0117,0.0146,0.0258,0.0394,0.0368,0.0214,0.008,0.0018,0.001,0.0002,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0019,0.0017,0.0011,0.0018,0.5634,0.709,0.4269,0.1222,0.1583,0.6329,0.8787,0.699,0.1987,0.019,0.0041,0.1138,0.4519,0.5322,1,1,1,1,1,1,1,0.2657,0.5142,0.8322,0.2769,0.0868,0.1956,0.2964,0.2711,0.5552,0.5245,0.7263,0.6913,0.7836,0.7566,0.7472,0.6632,0.3596,0.0338,0.0764,0.3868,0.5732,0.4759,0.3631,0.2568,0.4309,0.3095,0.162,0.0685,0.0936,0.0744,0.0381,0.0094,0.0044,0.004,0.0032,0.0031,0.0031,0.0025,0.0021,0.0016,0.002,0.0647,0.376,0.7752,0.8437,0.4383,0.1616,0.0242,0.2808,0.1449,0.0761,1,1,1,1,0.854,0.663,0.3114,0.4864,0.488,0.3525,0.3008,0.2698,0.2811,0.2598,0.2391,0.1929,0.6996,0.7168,0.7304,0.7696,0.7965,0.7231,0.574,0.1994,0.0217,0.1007,0.2751,0.2887,0.2808,0.2311,0.1691,0.1445,0.1307,0.135,0.2041,0.1786,0.0441,0.0105,0.0129,0.0161,0.0127,0.0142,0.0125,0.0115,0.0118,0.0128,0.0137,0.0107,0.154,0.4158,0.7403,0.7052,0.7283,0.5309,0.3178,0.0497,0.013,0.6251,0.6628,0.7481,0.8529,0.923,0.9697,1,0.8559,0.4458,0.5726,0.6757,0.2852,0.0319,0.0855,0.109,0.108,0.091,0.6473,0.5931,0.274,0.1121,0.0219,0.1639,0.0977,0.0892,0.4876,0.7883,0.7372,0.6155,0.8095,0.7335,0.8502,0.3447,0.6683,0.6132,0.5105,0.2562,0.0469,0.0051,0.0953,0.4081,0.4964,0.5182,0.5558,0.4736,0.2884,0.155,0.1133,0.1427,0.4684,0.3961,0.4788,0.5382,0.6239,0.4293,0.4968,0.4712,0.4952,0.5566,0.4216,0.2457,0.5089,0.4655,0.4835,0.4515,0.1532,0.2615,0.1422,0.0908,0.0485,0.049,0.0296,0.0193,0.0054,0.002,0.0018,0.0013,0.0012,0.0012,0,0,0,0,0,0,0,0,0,0,0,0,0,0.001,0.0176,0.1335,0.3196,0.5242,0.6617,0.6333,0.6252,1,1,1,1,1,1,0.9683,0.2683,0.2014,0.3731,0.8878,0.5775,0.5034,0.8155,0.6613,0.5339,0.5733,0.3485,0.678,0.4891,0.3674,0.5221,0.5019,0.8717,0.7672,0.7354,0.4802,0.0434,0.007,0.0017,0.0017,0.137,0.5303,0.6329,0.2839,0.243,0.1441,0.0345,0.0048,0.1065,0.2199,0.3849,0.2698,0.2654,0.3932,0.4965,0.7679,0.8316,0.9676,0.8646,0.8374,0.5223,0.3931,0.5669,0.5753,0.5542,0.4722,0.3912,0.3743,0.3833,0.4149,0.4057,0.3935,0.4561,0.4838,0.4453,0.2562,0.0735,0.0097,0.178,0.0819,0.3831,0.6071,0.6511,0.6588,0.5853,0.7425,0.6435,0.5918,0.3112,0.196,0.2676,0.4692,0.3983,0.6763,0.607,0.4722,0.3156,0.1118,0.0338,0.0059,0.0072,0.0294,0.19,0.3837,0.3623,0.2911,0.2873,0.2247,0.1024,0.0827,0.3362,0.2148,0.112,0.4884,0.5742,0.5036,0.5099,0.4333,0.4363,0.3769,0.2931,0.1855,0.1341,0.1054,0.0838,0.0628,0.0682,0.0634,0.1567,0.2792,0.3295,0.1428,0.0207,0.0096,0.0086,0.0103,0.0096,0.0089,0.0091,0.0091,0.0092,0.0118,0.0074,0.0074,0.0065,0.0036,0.0054,0.0759,0.4647,0.5848,0.8059,0.7143,0.709,0.5906,0.4904,0.6383,0.7418,0.5476,0.1494,0.0261,0.0041,0.19,0.1915,0.0782,0.1482,1,1,1,0.8573,0.5762,0.3269,0.7266,0.7295,0.4245,0.1427,0.0299,0.1945,0.5119,0.4364,0.4499,0.4746,0.4601,0.4549,0.4335,0.4069,0.284,0.0496,0.006,0.0046,0.2042,0.1225,0.0795,0.0432,0.0908,0.8781,1,1,1,1,0.7897,0.4142,0.1773,0.0861,0.0311,0.0311,0.0142,0.0101,0.0038,0.0016,0.0036,0.0019,0.0009,0.0007,0,0,0,0,0,0,0,0,0,0,0,0,0,0.001,0.0022,0.012,0.0537,0.0993,0.7228,0.9313,0.5745,0.6818,0.5345,0.3046,0.195,0.1542,0.1727,0.1715,0.1297,0.9073,1,1,1,1,0.893,0.4921,0.444,0.8511,0.6157,0.4911,0.364,0.3983,0.3385,0.3368,0.4294,0.3464,0.6109,0.9116,0.8949,1,1,0.8362,0.7028,0.4254,0.194,0.0635,0.1358,0.1468,0.2899,0.4678,0.544,0.4486,0.3702,0.5324,0.3758,0.0353,0.0023,0.0877,0.267,0.1239,0.3093,0.3106,0.3034,0.3333,0.397,0.4472,0.4991,0.4868,0.5127,0.2119,0.0433,0.0069,0.0419,0.6612,0.7768,0.8615,1,1,1,1,0.8929,0.7756,0.3027,0.2945,0.385,0.2788,0.177,0.115,0.1401,0.0767,0.0764,0.0248,0.0044,0.0042,0.0049,0.0061,0.0068,0.007,0.0067,0.0077,0.0076,0.0093,0.0094,0.0098,0.0086,0.0074,0.0131,0.0087,0.0079,0.1939,0.4091,0.7762,0.759,0.9694,0.7868,0.2621,0.0791,0.0386,0.0098,0.0016,0.0016,0.0024,0.4618,0.6747,0.7207,0.7305,0.6294,0.3927,0.1249,0.0624,0.4291,0.9693,0.6901,0.1991,0.0235,0.05,0.2326,0.5185,0.4737,0.1277,0.554,0.7177,0.7957,0.8991,0.8031,0.6922,0.5238,0.5511,0.566,0.4195,0.3409,0.3879,0.36,0.2806,0.4703,0.4132,0.4809,0.5342,0.5837,0.5359,0.4851,0.5486,0.5609,0.4602,0.2596,0.1275,0.0817,0.0942,0.0981,0.093,0.0886,0.5309,0.7216,0.6655,0.6307,0.7094,0.7424,0.8775,0.73,0.7545,0.6879,0.5274,0.507,0.4707,0.407,0.2623,0.2176,0.2125,0.1821,0.2216,0.2579,0.3535,0.2837,0.1136,0.1449,0.0605,0.0401,0.0572,0.0236,0.0283,0.0134,0.0051,0.0026,0.0019,0.0015,0.0015,0.0014,0.0011,0.0012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"peak":0.6540911197662354}};window.PRODUCTS=[{"id":"fairborn","title":"Fairborn Type 2 | Phillipe Romano","label":"Fairborn Type 2 · Phillipe Romano","url":"https://www.designerwallcoverings.com/products/prw-920735-rif-003","image_url":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/prw-920735-rif-003.jpg?v=1781716604","file":"assets/products/fairborn.jpg","description":"<p>When light rakes across the embossed surface, it reveals an organic grid-like pattern of broken lines. Although extremely durable — as you’d expect from a Type II vinyl wallcovering named for rock fissures — offering a soft, nature-inspired palette of creams, taupes, blues and browns. A small scale and intricate pattern appear almost seamless, and its 12 two-tone colorways resemble artisanal materials like mosaic</p><br><br>A captivating wallcovering featuring intricate detailing and refined textures, offering a sophisticated backdrop that elevates any interior space. The design evokes timeless elegance with a modern touch. \n#luxuryinteriors #modernwallcoverings #elegantdesign\n","retrieved_at":"2026-09-05","local":"../assets/products/fairborn.jpg"},{"id":"waterperry","title":"Waterperry Ivory/Stone | Sanderson","label":"Waterperry / Ivory–Stone · Sanderson","url":"https://www.designerwallcoverings.com/products/waterperry-ivory-stone-sanderson","image_url":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/DWAP216280_5340.jpg?v=1788582264","file":"assets/products/waterperry.jpg","description":"<div class=\"sanderson-product\">\n<p>Waterperry in Ivory/Stone is a Sanderson Wallcovering in a botanical/leaves and trees design. Part of the Sanderson heritage collection, this pattern reads in a palette of Alabaster, Linen, Mist. Supplied by the roll; a memo sample is available. An English design-house classic from Sanderson Design Group.</p>\n</div>","retrieved_at":"2026-09-05","local":"../assets/products/waterperry.jpg"},{"id":"wheaton","title":"Wheaton Type 2 | Phillipe Romano","label":"Wheaton Type 2 · Phillipe Romano","url":"https://www.designerwallcoverings.com/products/prw-920166-coa-004-1","image_url":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/d4639abbf9baa5237707.jpg?v=1785438111","file":"assets/products/wheaton.jpg","description":"<p>Weaving shimmering strands and beguiling texture, emulating the intricacy of our favored grasscloth Tide in the form of a durable Type II vinyl</p>\n","retrieved_at":"2026-09-05","local":"../assets/products/wheaton.jpg"},{"id":"topiary","title":"Topiary View Thyme | Sanderson","label":"Topiary View / Thyme · Sanderson","url":"https://www.designerwallcoverings.com/products/topiary-view-thyme-sanderson","image_url":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/DHIP217511_f500.jpg?v=1788582179","file":"assets/products/topiary.jpg","description":"<div class=\"sanderson-product\">\n<p>Topiary View in Thyme is a Sanderson Wallcovering in a landscapes design. Part of the Sanderson heritage collection, this pattern reads in a palette of Alabaster, Stone, Oatmeal. Supplied by the roll; a memo sample is available. An English design-house classic from Sanderson Design Group.</p>\n</div>","retrieved_at":"2026-09-05","local":"../assets/products/topiary.jpg"},{"id":"kaya","title":"Kaya - Cream Weave Wallcovering | Malibu Wallcovering","label":"Kaya / Cream Weave · Malibu","url":"https://www.designerwallcoverings.com/products/kaya-cream-weave-wallcovering-malibu-wallpaper","image_url":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0086435_kaya-cream-weave_650.jpg?v=1776906632","file":"assets/products/kaya.jpg","description":"<p>Elevate your space with the luxurious Kaya Cream Weave wallcovering. This exquisite nonwoven vinyl design features a warm neutral color palette and stunning texture, perfect for creating an elegant ambiance.</p>","retrieved_at":"2026-09-05","local":"../assets/products/kaya.jpg"}];/* Wallo Material Notes: deterministic articulated character acting and real DW samples. */
(() => {
'use strict';
const canvas=document.getElementById('stage'), c=canvas.getContext('2d');
const E=window.EPISODE, P=window.PRODUCTS, ep=E.index;
const ink='#243a3b', chalk='#eeeae2', teal='#284f4b', clay='#a9634d', brass='#b7924f';
const images={}; let telemetry=[];
const clamp=(x,a=0,b=1)=>Math.max(a,Math.min(b,x));
const mix=(a,b,p)=>a+(b-a)*p;
const smooth=p=>{p=clamp(p);return p*p*(3-2*p);};
const ease=(t,a,b)=>smooth((t-a)/(b-a));
const pulse=(t,a,b,c,d)=>ease(t,a,b)*(1-ease(t,c,d));
const point=(x,y)=>({x,y});
const dist=(a,b)=>Math.hypot(a.x-b.x,a.y-b.y);
function group(x,y,r,s,fn){c.save();c.translate(x,y);c.rotate(r);c.scale(s,s);fn();c.restore();}
function path(fn,fill,stroke=null,w=2){c.beginPath();fn(c);if(fill){c.fillStyle=fill;c.fill();}if(stroke){c.lineWidth=w;c.strokeStyle=stroke;c.lineJoin='round';c.lineCap='round';c.stroke();}}
function line(x,y,u,v,col,w=2){path(q=>{q.moveTo(x,y);q.lineTo(u,v);},null,col,w);}
function rect(x,y,w,h,col){c.fillStyle=col;c.fillRect(x,y,w,h);}
function oval(x,y,rx,ry,col,stroke=null,w=2){path(q=>q.ellipse(x,y,rx,ry,0,0,Math.PI*2),col,stroke,w);}
function rr(x,y,w,h,r,col,stroke=null,lw=2){path(q=>q.roundRect(x,y,w,h,r),col,stroke,lw);}
function text(s,x,y,size=28,color=ink,font='Verdana',align='left'){c.font=`${size}px '${font}'`;c.textAlign=align;c.textBaseline='alphabetic';c.fillStyle=color;c.fillText(s,x,y);}
function wrap(s,x,y,max,size=36,color=ink,font='Verdana',lh=size*1.4){
c.font=`${size}px '${font}'`;let row='',lines=[];
for(const word of s.split(' ')){const test=row?row+' '+word:word;if(c.measureText(test).width>max&&row){lines.push(row);row=word;}else row=test;}
if(row)lines.push(row);lines.forEach((v,i)=>text(v,x,y+i*lh,size,color,font));return lines.length;
}
function imageCover(id,x,y,w,h){const im=images[id];if(!im||!im.complete)return;const k=Math.max(w/im.width,h/im.height);c.save();c.beginPath();c.rect(x,y,w,h);c.clip();c.drawImage(im,x+(w-im.width*k)/2,y+(h-im.height*k)/2,im.width*k,im.height*k);c.restore();}
function sample(id,x,y,w=126,h=164,r=0){group(x,y,r,1,()=>{rr(-w/2+7,-h/2+9,w,h,2,'#203a3a20');rect(-w/2-5,-h/2-5,w+10,h+10,'#f9f7f0');imageCover(id,-w/2,-h/2,w,h);line(-w/2,-h/2,w/2,-h/2,'#ffffff',2);});}
function bone(a,b,width,col,shade){
const angle=Math.atan2(b.y-a.y,b.x-a.x),d=dist(a,b);
group(a.x,a.y,angle,1,()=>{rr(-width*.18,-width/2,d+width*.36,width,width*.46,col);path(q=>{q.moveTo(5,width*.26);q.quadraticCurveTo(d*.5,width*.34,d-3,width*.22);},null,shade||'#00000018',2.3);});
}
function solveIK(root,target,l1,l2,pole){
const dx=target.x-root.x,dy=target.y-root.y,raw=Math.hypot(dx,dy),d=clamp(raw,Math.abs(l1-l2)+.01,l1+l2-.01);
const nx=raw?dx/raw:0,ny=raw?dy/raw:1,a=(l1*l1-l2*l2+d*d)/(2*d),h=Math.sqrt(Math.max(0,l1*l1-a*a));
const end=point(root.x+nx*d,root.y+ny*d),joint=point(root.x+nx*a-ny*h*pole,root.y+ny*a+nx*h*pole);
return {root,joint,end,l1,l2};
}
function rotatePoint(p,angle,origin=point(0,-258)){const x=p.x-origin.x,y=p.y-origin.y;return point(origin.x+x*Math.cos(angle)-y*Math.sin(angle),origin.y+x*Math.sin(angle)+y*Math.cos(angle));}
function key(t,frames){if(t<=frames[0][0])return frames[0].slice(1);for(let i=1;i<frames.length;i++)if(t<=frames[i][0]){const p=ease(t,frames[i-1][0],frames[i][0]);return frames[i].slice(1).map((v,j)=>mix(frames[i-1][j+1],v,p));}return frames.at(-1).slice(1);}
function gait(t,start,end,x0,x1){
const p=clamp((t-start)/(end-start));
const lift=(a,b)=>p>a&&p<b?Math.sin(Math.PI*(p-a)/(b-a))*44:0;
const left=mix(x0-30,(x0+x1)/2-30,smooth((p-.08)/.28))+mix(0,(x1-x0)/2,smooth((p-.65)/.3));
const right=mix(x0+30,x1+30,smooth((p-.35)/.3));
return {x:(left+right)/2,feet:[point(left,-lift(.08,.36)-lift(.65,.95)),point(right,-lift(.35,.65))],walking:p>0&&p<1,phase:p};
}
function voiceEnergy(t){const env=E.audio?.energy||[];return env[Math.min(env.length-1,Math.max(0,Math.floor(t*50)))]||0;}
function hand(x,y,r,pose='open',skin='#c89472',prop=null){
group(x,y,r,1,()=>{
if(prop==='sample')sample(E.product,8,-18,115,148,-.04);
if(prop==='fan')for(let k=0;k<3;k++)sample(['waterperry','topiary','kaya'][k],k*17-15,-43,91,130,(k-1)*.18);
if(prop==='report'){rr(-12,-134,135,176,4,'#f8f5e9',ink,2);rect(1,-117,108,5,teal);text('TEST',4,-87,22,ink);text('REPORT',4,-58,22,ink);for(let k=0;k<3;k++)line(4,-35+k*18,97,-35+k*18,'#a4aaa0',2);}
if(prop==='cloth'){path(q=>{q.moveTo(-28,-15);q.lineTo(30,-26);q.lineTo(43,35);q.lineTo(-21,44);q.closePath();},'#c8c5b5',ink,1);line(-17,-4,28,25,'#efeadb',3);}
if(prop==='roller'){line(0,-8,0,-72,ink,7);line(0,-72,37,-72,ink,7);line(37,-72,37,-108,ink,5);rr(-27,-132,127,38,11,'#8b9c8d',ink,2);rr(-9,-9,18,54,7,brass);}
if(prop==='tablet'){rr(-73,-76,145,170,8,ink);rr(-65,-67,129,151,4,'#f4f0e5');text('DW',-45,-33,27,teal,'Georgia');for(let i=0;i<3;i++)imageCover(['waterperry','fairborn','kaya'][i],-47+i*32,-6,27,60);}
if(pose==='point'){bone(point(-4,3),point(34,-18),13,skin);bone(point(0,9),point(16,15),21,skin);oval(-6,9,13,18,skin);}
else{rr(-14,-9,29,42,12,skin);oval(-15,5,7,13,skin);for(let i=0;i<3;i++)line(-7+i*6,14,-7+i*6,28,'#9e685446',1);}
});
}
function head(kind,x,y,t,look,mouth,tilt){
const male=kind==='wallo',skin=male?'#c89472':'#d5a185',dark=male?'#714f3b':'#834e39';
group(x,y,tilt,.82,()=>{
if(!male){oval(-4,-10,51,70,dark);oval(-39,-50,28,28,dark);path(q=>{q.moveTo(-57,-55);q.quadraticCurveTo(-81,-37,-59,-16);},null,'#a86b4b',7);}
// Tapered jaw, defined brow and modest nose maintain adult proportions.
path(q=>{q.moveTo(-41,-40);q.bezierCurveTo(-43,-77,43,-80,44,-34);q.lineTo(40,31);q.quadraticCurveTo(31,66,5,72);q.quadraticCurveTo(-26,65,-36,34);q.closePath();},skin);
path(q=>{q.moveTo(-38,-31);q.lineTo(-32,34);q.quadraticCurveTo(-24,52,-8,57);q.lineTo(-20,21);q.lineTo(-18,-46);q.closePath();},male?'#b58162':'#c39076');
oval(-40,3,9,16,skin);oval(42,2,8,15,skin);
if(male){path(q=>{q.moveTo(-39,-39);q.lineTo(-33,-18);q.lineTo(-30,-54);q.lineTo(31,-54);q.lineTo(43,-25);q.lineTo(42,-55);q.closePath();},dark);}
else{path(q=>{q.moveTo(-40,-27);q.quadraticCurveTo(-24,-63,2,-56);q.quadraticCurveTo(38,-37,43,-19);q.lineTo(38,-58);q.quadraticCurveTo(-4,-89,-37,-55);q.closePath();},dark);for(let i=0;i<4;i++)path(q=>{q.moveTo(-29+i*17,-56);q.quadraticCurveTo(-26+i*17,-43,-13+i*17,-39);},null,'#ae7150',2);}
const blink=(t+(male?.31:1.93))%4.4<.14;
for(const side of [-1,1]){const ex=side*18+look*3,ey=-8;path(q=>{q.moveTo(ex-10,ey);q.quadraticCurveTo(ex,ey-5,ex+10,ey);},null,ink,2.2);if(!blink){oval(ex+look*3,ey+1,3.5,4.3,ink);oval(ex+look*3+1,ey-.3,1.1,1.2,'#eee8dc');}line(ex-10,ey-15,ex+8,ey-17+(side===1?look*2:0),dark,2.5);}
path(q=>{q.moveTo(3+look*5,-5);q.lineTo(8+look*8,15);q.quadraticCurveTo(4+look*5,20,-1+look*5,17);},null,'#98644f',1.8);
if(male){path(q=>{q.moveTo(-20,29);q.quadraticCurveTo(-6,20,4,27);q.quadraticCurveTo(15,23,26,30);q.quadraticCurveTo(17,39,3,34);q.quadraticCurveTo(-9,37,-20,29);},dark);}
if(mouth>.12){oval(4,44,10+mouth*3,2+mouth*6,'#714735');if(mouth>.4)line(-2,41,11,41,'#efe6d7',2);}
else path(q=>{q.moveTo(-7,43);q.quadraticCurveTo(5,48,17,42);},null,'#714735',1.8);
if(male){path(q=>{q.moveTo(-49,-53);q.quadraticCurveTo(-48,-98,10,-95);q.quadraticCurveTo(47,-89,48,-53);q.closePath();},brass);path(q=>{q.moveTo(-49,-53);q.quadraticCurveTo(12,-64,72,-48);q.quadraticCurveTo(77,-35,39,-41);q.lineTo(-49,-43);q.closePath();},'#97773f');line(-27,-73,12,-84,'#d2b270',3);}
else oval(-39,14,3.5,5.5,brass);
});
}
function character(kind,t,settings={}){
const male=kind==='wallo',skin=male?'#c89472':'#d5a185',shirt=male?'#d6d0bc':clay,cloth=male?teal:'#c8c1af';
const walk=settings.walk||gait(t,0,1,settings.x,settings.x);let x=walk.x,y=settings.y||882;
const crouch=settings.crouch||0,lean=settings.lean||0,breath=Math.sin(t*2.1+(male?0:1.2))*1.7;
const hipY=-275+crouch,origin=point(0,hipY);
const bodyPoint=(u,v)=>rotatePoint(point(u,v+crouch+breath),lean,origin);
const leftShoulder=bodyPoint(-62,-469),rightShoulder=bodyPoint(62,-469);
const arms=[solveIK(leftShoulder,point(...settings.left),118,111,-1),solveIK(rightShoulder,point(...settings.right),118,111,1)];
const legs=walk.feet.map((foot,i)=>solveIK(point(i===0?-32:32,hipY),point(foot.x-x,foot.y-13),134,136,i===0?1:-1));
const mouth=male?voiceEnergy(t)*.88:0;
const joints={kind,x,y,arms,legs,lean,crouch,feet:walk.feet,walking:walk.walking,props:settings.props||[]};
telemetry.push(joints);
oval(x,y+6,94-crouch*.1,15,'#233a3b15');
group(x,y,0,settings.scale||1,()=>{
// Back arm and far leg precede torso so elbow overlaps read spatially.
const armDraw=(i)=>{const b=arms[i];bone(b.root,b.joint,39,shirt);bone(b.joint,b.end,27,skin);oval(b.joint.x,b.joint.y,16,16,skin);const sleeve=point(mix(b.root.x,b.joint.x,.77),mix(b.root.y,b.joint.y,.77));bone(b.root,sleeve,43,shirt);line(sleeve.x-8,sleeve.y,sleeve.x+9,sleeve.y,'#ffffff30',2);};
armDraw(0);
legs.forEach((b,i)=>{bone(b.root,b.joint,58,cloth);bone(b.joint,b.end,43,cloth);oval(b.joint.x,b.joint.y,23,23,cloth);line(b.root.x-8,b.root.y+30,b.joint.x-6,b.joint.y-16,male?'#41635b':'#dfd8c8',2);group(b.end.x,b.end.y+10,walk.walking&&walk.feet[i].y<0?-.12:0,1,()=>{path(q=>{q.moveTo(-24,-20);q.lineTo(20,-20);q.lineTo(27,-9);q.quadraticCurveTo(60,-5,56,14);q.lineTo(-24,14);q.closePath();},male?'#655545':'#626b62');line(-24,14,55,14,'#34413d',5);line(4,-8,25,-7,'#c6b69b',2);});});
group(0,hipY,lean,1,()=>{
const dy=crouch+breath-hipY;
path(q=>{q.moveTo(-63,-478+dy);q.quadraticCurveTo(-82,-460+dy,-71,-417+dy);q.lineTo(-60,-266+dy);q.quadraticCurveTo(0,-235+dy,60,-266+dy);q.lineTo(71,-417+dy);q.quadraticCurveTo(79,-460+dy,58,-479+dy);q.closePath();},shirt);
// Structured overall/apron silhouette, stitched seams, pockets and cloth folds.
path(q=>{q.moveTo(-50,-425+dy);q.lineTo(-46,-350+dy);q.lineTo(-61,-290+dy);q.lineTo(-60,-253+dy);q.lineTo(61,-253+dy);q.lineTo(61,-290+dy);q.lineTo(46,-350+dy);q.lineTo(48,-425+dy);q.closePath();},cloth);
for(const s of [-1,1]){line(s*44,-472+dy,s*38,-405+dy,cloth,17);oval(s*39,-414+dy,4.8,4.8,brass);line(s*49,-328+dy,s*41,-312+dy,male?'#59756b':'#a9a18f',2);}
rr(-27,-401+dy,54,56,4,male?'#254540':'#bab39f');path(q=>{q.moveTo(-23,-388+dy);q.quadraticCurveTo(0,-376+dy,24,-388+dy);},null,male?'#6a8778':'#e5dfd0',1.5);
line(-50,-266+dy,52,-266+dy,male?'#1e403b':'#aca590',3);
if(male){rr(-66,-321+dy,20,67,3,'#8d7452');line(-56,-342+dy,-56,-282+dy,brass,6);}
path(q=>{q.moveTo(-17,-509+dy);q.lineTo(-18,-474+dy);q.quadraticCurveTo(0,-454+dy,21,-474+dy);q.lineTo(18,-509+dy);q.closePath();},skin);
});
const hp=bodyPoint(0,-559);head(kind,hp.x,hp.y,t,settings.look||0,mouth,(settings.headTilt||0)+lean*.28);
armDraw(1);
arms.forEach((b,i)=>hand(b.end.x,b.end.y,(settings.wrists||[0,0])[i],(settings.gestures||['open','open'])[i],skin,(settings.props||[])[i]));
});
return joints;
}
function room(t){
rect(-350,-300,1800,1200,'#dfdbd1');rect(-350,765,1800,450,'#c9c2b1');
rect(20,0,240,706,'#e9e7dc');for(let i=0;i<4;i++)line(22+i*59,0,22+i*59,704,'#f7f4e9',7);
rect(318,26,647,727,'#c7bfae');rect(329,37,624,704,'#efede3');
if(ep===1){const a=ease(t,5.1,8);rect(343,49,596,678,'#aab7a4');c.save();c.beginPath();c.rect(343,49,596*a,678);c.clip();imageCover(E.product,343,49,596,678);c.restore();}
else imageCover(E.product,343,49,596,678);
line(340,743,943,743,'#faf7eb',4);line(-350,765,1450,765,'#a79f8d',2);
for(let i=0;i<6;i++)line(-200,814+i*54,1400,814+i*54,'#b6ad9a',1.4);
line(91,765,-170,1220,'#b6ad9a',1.4);line(880,765,1130,1220,'#b6ad9a',1.4);
// Light and shadow move gently with the camera, not with an arbitrary pulse.
path(q=>{q.moveTo(40,706);q.lineTo(263,706);q.lineTo(672,1120);q.lineTo(412,1120);q.closePath();},'#fcf7df28');
// A sample ledge ties the real products to the working material library.
rect(404,685,479,12,'#b29d7a');for(let i=0;i<3;i++)sample(P[(i+ep)%P.length].id,468+i*115,622,88,116,(i-1)*.045);
}
function documentPanel(t){
if(ep!==0)return;
const a=pulse(t,4.2,4.9,14.3,15.0);if(!a)return;
group(640,177+(1-a)*28,0,.88,()=>{
rr(-239,-168,478,336,2,'#f7f4e9',ink,1.5);text('BEFORE YOU SPECIFY',-210,-126,24,teal);
const labels=['PRODUCT / TEST REPORT','CLASSIFICATION','SUBSTRATE + ADHESIVE'];
labels.forEach((label,i)=>{const done=t>5.0+i*2.8;line(-209,-61+i*77,-182,-61+i*77,done?brass:'#bac0b5',3);text(label,-163,-52+i*77,21,ink);});
});
}
function swatchBoard(t){
if(ep!==3&&ep!==4)return;
const a=pulse(t,6.4,7.1,13.4,14);if(!a)return;
group(560,275+(1-a)*25,0,.95,()=>{
rr(-199,-139,398,278,2,'#f5f0e4',ink,1);sample(E.product,-83,-1,155,220,0);
rect(28,-111,137,83,'#c6bea9');rect(28,-16,137,69,'#8c9985');rect(28,64,137,43,'#b89672');
text(ep===3?'COMPARE YOUR FINISHES':'YOUR PROJECT SHORTLIST',-192,-162,23,ink);
});
}
function actionNotes(t){
if(ep!==2)return;const a=pulse(t,8,8.5,14.2,14.8);if(!a)return;
['ABRASION','CLEANABILITY','CARE'].forEach((s,i)=>{const show=ease(t,8+i*.7,8.4+i*.7);if(show){rect(440,120+i*77,440,58,'#f4f0e6');text(s,468,159+i*77,27,ink);}});
}
function performances(t){
let wwalk=gait(t,.2,2.9,126,253),pwalk=gait(t,.5,3.1,949,801);
const w={walk:wwalk,left:[-85,-279],right:[149,-396],wrists:[-.1,-.36],props:[],gestures:['open','open'],look:.6,lean:Math.sin(t*.8)*.012};
const p={walk:pwalk,left:[-130,-402],right:[86,-275],wrists:[.14,.08],props:['sample'],look:-.6,lean:Math.sin(t*.73+1)*.013};
// Presenter gestures are deliberately different for each spoken clause.
const gesture=key(t,[[0,100,-285],[2.8,145,-411],[4.4,165,-440],[5.2,120,-367],[8.7,161,-441],[9.6,149,-378],[12.8,180,-432],[14,125,-360],[17,152,-419],[19.8,126,-383]]);
w.right=gesture;w.wrists[1]=key(t,[[0,0],[3,-.5],[5.2,-.15],[8,-.42],[11,.1],[14,-.4],[18,-.2]])[0];
w.gestures[1]=t>4.5&&t<8.8?'point':'open';w.headTilt=Math.sin(t*.65)*.022;w.look=t>4&&t<9?1:.1;
if(t<3){w.right=[90-Math.sin(t*4)*40,-277];w.left=[-90+Math.sin(t*4)*40,-277];p.left=[-90+Math.sin(t*4)*24,-280];p.props=[];}
if(ep===0){p.props=['report'];p.left=key(t,[[0,-85,-280],[3,-130,-365],[6,-131,-420],[10,-153,-445],[14,-125,-384],[19,-108,-376]]);p.wrists[0]=-.14;p.right=key(t,[[0,90,-277],[8,98,-320],[11,-10,-377],[14,93,-278]]);}
if(ep===1){
p.props=t<8?['roller']:['sample'];p.left=key(t,[[0,-88,-283],[3,-129,-447],[4.5,-142,-495],[5.2,-143,-411],[6,-146,-495],[7,-145,-397],[8,-100,-367],[11,-139,-436],[15,-103,-361]]);p.wrists[0]=.07;
if(t>9.3){p.walk=gait(t,9.3,11.4,801,870);p.look=-1;p.lean=-.06*ease(t,10,11);}
w.props=['sample'];w.left=key(t,[[0,-87,-282],[4,-98,-291],[6,-39,-389],[8,-30,-433],[12,-59,-386],[17,-78,-320]]);w.wrists[0]=-.08;
}
if(ep===2){
p.crouch=pulse(t,4,5.6,8.8,10.2)*113;p.lean=-pulse(t,4,5.4,9,10.3)*.10;
const wipe=pulse(t,5,5.8,8.2,9);p.props=['cloth'];p.left=[-147-wipe*17,-389+p.crouch+wipe*Math.sin(t*6)*42];p.wrists[0]=-.5;
p.right=[85,-284+p.crouch];p.look=-1;
w.props=['sample'];w.left=[-45,-371];w.wrists[0]=-.18;
}
if(ep===3){
p.props=['sample'];p.left=key(t,[[0,-92,-280],[3,-100,-366],[6,-138,-440],[10,-144,-478],[14,-126,-418],[18,-93,-340]]);p.wrists[0]=key(t,[[0,0],[3,-.08],[7,.22],[10,-.18],[13,.16],[17,0]])[0];
w.props=['fan'];w.left=key(t,[[0,-90,-280],[4,-33,-365],[7,-44,-400],[12,-24,-389],[16,-44,-346]]);w.wrists[0]=-.13;
}
if(ep===4){
w.props=['tablet'];w.left=[-43,-341];w.right=key(t,[[0,101,-280],[3,143,-413],[6,158,-444],[8.5,65,-361],[10,34,-340],[11.6,20,-356],[13,144,-411],[17,160,-444],[19,112,-374]]);w.gestures[1]=t>8&&t<12?'point':'open';
p.props=['fan'];p.left=[-129,-400];p.right=key(t,[[0,89,-280],[6,86,-280],[9,-18,-384],[12,76,-285],[17,100,-382],[19,86,-297]]);
}
// Camera-right actor is drawn first so the presenter remains the visual lead.
character('pippa',t,p);character('wallo',t,w);
}
function overlay(t){
rect(0,0,1080,437,chalk);rect(0,1437,1080,483,chalk);
text('DESIGNER WALLCOVERINGS',72,96,25,ink);text('WALLO PRESENTS',1008,96,21,teal,'Verdana','right');
line(72,124,1008,124,'#b9b6aa',1);text(E.kicker,72,178,24,teal);
E.title.split('\n').forEach((s,i)=>text(s,69,270+i*87,73,ink,'Georgia'));
text('MATERIAL NOTES',73,411,22,teal);text('WITH WALLO & PIPPA',1006,411,20,teal,'Verdana','right');
const product=P.find(p=>p.id===E.product);text(product.label,72,1481,25,ink);
line(72,1505,1008,1505,'#b9b6aa',1);
const segment=(E.audio?.segments||[]).filter(s=>t>=s.start).at(-1);
const caption=segment?E.captions[segment.index]:'A wallcovering presentation with Wallo.';
wrap(caption,72,1570,930,38,ink,'Verdana',55);
if(t>=16.8)text(E.takeaway,72,1738,37,teal,'Georgia');
wrap(E.note,72,1794,926,24,'#58635b','Verdana',34);
text('designerwallcoverings.com',72,1870,25,teal);
text(String(ep+1).padStart(2,'0')+' / 05',1008,1870,22,teal,'Verdana','right');
rect(72,1894,936,3,'#c9c7bb');rect(72,1894,936*clamp(t/20),3,teal);
}
function draw(t){
telemetry=[];rect(0,0,1080,1920,chalk);
c.save();c.beginPath();c.rect(0,437,1080,1000);c.clip();
const zoom=1+ease(t,3.3,5)*.08-ease(t,14.2,16)*.06;
c.translate(540,950);c.scale(zoom,zoom);c.translate(-540,-487);
room(t);documentPanel(t);swatchBoard(t);actionNotes(t);performances(t);
c.restore();overlay(t);window.__rigState=telemetry;
}
const driver={t:0};window.__timelines=window.__timelines||{};
window.__timelines.main=gsap.timeline({paused:true}).to(driver,{t:20,duration:20,ease:'none',onUpdate:()=>draw(driver.t)},0);
window.__draw=draw;
window.__ready=Promise.all(P.map(p=>new Promise((resolve,reject)=>{const im=new Image();images[p.id]=im;im.onload=resolve;im.onerror=()=>reject(new Error('Missing product '+p.id));im.src=p.local;}))).then(()=>document.fonts.ready).then(()=>{draw(driver.t);return true;});
draw(0);
})();
</script></body></html>