86 lines
5.5 KiB
JavaScript
86 lines
5.5 KiB
JavaScript
import { chromium } from 'playwright';
|
||
import { mkdir } from 'node:fs/promises';
|
||
|
||
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
|
||
await mkdir('video/raw',{recursive:true});
|
||
const browser=await chromium.launch({headless:true});
|
||
const context=await browser.newContext({
|
||
viewport:{width:405,height:720},
|
||
deviceScaleFactor:1,
|
||
recordVideo:{dir:'video/raw',size:{width:720,height:1280}},
|
||
colorScheme:'light'
|
||
});
|
||
const page=await context.newPage();
|
||
await page.goto('http://127.0.0.1:4173',{waitUntil:'networkidle'});
|
||
const now=Date.now();
|
||
const seed=Array.from({length:7},(_,i)=>({
|
||
id:`demo-${i}`,occurredAt:new Date(now-(7-i)*86400000).toISOString(),
|
||
bristolType:[3,4,4,6,4,3,4][i],color:'brown',urgency:i===3?3:1,discomfort:i===3?2:0,
|
||
note:['Morning','After coffee','Easy','Travel day','Back on track','Morning','Feeling regular'][i],photoDataUrl:'',
|
||
symptoms:{blood:false,blackOrDarkRed:false,severePain:false,vomiting:false,fever:false,cannotPassGas:false}
|
||
}));
|
||
await page.evaluate(data=>localStorage.setItem('timmy-ledger-v1',JSON.stringify(data)),seed);
|
||
await page.reload({waitUntil:'networkidle'});
|
||
await page.addStyleTag({content:`
|
||
#demo-touch{position:fixed;z-index:9999;width:54px;height:54px;border:4px solid rgba(255,255,255,.95);background:rgba(245,201,91,.5);box-shadow:0 0 0 8px rgba(21,125,120,.25);border-radius:50%;pointer-events:none;transform:translate(-50%,-50%)}
|
||
.demo-focus{box-shadow:0 0 0 5px rgba(245,201,91,.95),0 0 0 10px rgba(21,125,120,.3)!important;transition:.2s!important}
|
||
`});
|
||
async function touch(selector,{click=true,after=700}={}){
|
||
const loc=page.locator(selector).first();await loc.scrollIntoViewIfNeeded();const b=await loc.boundingBox();if(!b)throw new Error(`missing ${selector}`);
|
||
await page.evaluate(({x,y})=>{document.querySelector('#demo-touch')?.remove();const d=document.createElement('div');d.id='demo-touch';d.style.left=x+'px';d.style.top=y+'px';document.body.append(d);d.animate([{transform:'translate(-50%,-50%) scale(.55)',opacity:.2},{transform:'translate(-50%,-50%) scale(1)',opacity:1},{transform:'translate(-50%,-50%) scale(.72)',opacity:.8}],{duration:520,easing:'ease-out'});setTimeout(()=>d.remove(),650)},{x:b.x+b.width/2,y:b.y+b.height/2});
|
||
await sleep(300);if(click)await loc.click();await sleep(after);
|
||
}
|
||
async function focus(selector,ms=1500){const loc=page.locator(selector).first();await loc.scrollIntoViewIfNeeded();await loc.evaluate(e=>e.classList.add('demo-focus'));await sleep(ms);await loc.evaluate(e=>e.classList.remove('demo-focus')).catch(()=>{});}
|
||
|
||
// 0–8: Hero and value.
|
||
await sleep(3000);
|
||
await page.evaluate(()=>scrollTo({top:260,behavior:'smooth'}));await sleep(2600);
|
||
await page.evaluate(()=>scrollTo({top:0,behavior:'smooth'}));await sleep(1400);
|
||
// 8–17: form selection.
|
||
await touch('[data-log]');
|
||
await sleep(1500);
|
||
await touch('[data-type="3"]',{after:600});
|
||
await touch('[data-type="4"]',{after:1700});
|
||
await touch('#next',{after:900});
|
||
// 17–29: context and private photo lane.
|
||
await touch('#color',{click:false,after:900});
|
||
await page.locator('#urgency').fill('2');await focus('#urgency',900);
|
||
await page.locator('#discomfort').fill('1');await focus('#discomfort',700);
|
||
await page.locator('#note').fill('After lunch — feeling normal');await focus('#note',1200);
|
||
await focus('.photo-drop',2500);
|
||
await focus('.fine',1300);
|
||
await touch('#next',{after:1400});
|
||
// 29–43: safety boundary.
|
||
await sleep(1700);
|
||
await touch('[data-symptom="blood"]',{after:900});
|
||
await focus('.alert',5200);
|
||
await touch('[data-symptom="blood"]',{after:800});
|
||
await touch('#save',{after:1700});
|
||
// 43–51: pattern view and calendar.
|
||
await focus('.summary-card',2500);
|
||
await touch('[data-view="calendar"]',{after:1500});
|
||
await focus('.calendar',3000);
|
||
// 51–62: Timmy boundary.
|
||
await touch('[data-view="timmy"]',{after:1600});
|
||
await touch('[data-prompt="pattern"]',{after:1400});
|
||
await touch('[data-prompt="food"]',{after:1100});
|
||
await focus('#chat',3600);
|
||
// 62–70: privacy and control.
|
||
await touch('[data-view="privacy"]',{after:1400});
|
||
await focus('.privacy-list',2600);
|
||
await page.evaluate(()=>scrollTo({top:document.body.scrollHeight,behavior:'smooth'}));await sleep(2300);
|
||
await focus('.danger-zone',1400);
|
||
// 70–76: branded close.
|
||
await page.evaluate(()=>{
|
||
const o=document.createElement('div');o.id='outro';o.innerHTML=`<img src="/assets/timmy.svg"><div class="small">YOUR INTELLIGENT POOPING PAL</div><div class="big">Know your gut.<br>Keep your dignity.</div><div class="pill">TIMMY THE TALKING TURD</div>`;
|
||
Object.assign(o.style,{position:'fixed',inset:'0',zIndex:'10000',background:'linear-gradient(145deg,#f7f3ea,#f5c95b)',display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',textAlign:'center',color:'#28211d',fontFamily:'DM Sans,system-ui',opacity:'0'});
|
||
o.querySelector('img').style.cssText='width:190px;height:190px;filter:drop-shadow(0 16px 18px rgba(63,37,30,.18))';
|
||
o.querySelector('.small').style.cssText='font-size:12px;font-weight:800;letter-spacing:.13em;color:#157d78;margin-top:18px';
|
||
o.querySelector('.big').style.cssText='font-size:39px;line-height:1.04;font-weight:800;letter-spacing:-1.5px;margin:12px 0 24px';
|
||
o.querySelector('.pill').style.cssText='background:#28211d;color:white;padding:14px 20px;border-radius:99px;font-size:12px;font-weight:800;letter-spacing:.08em';
|
||
document.body.append(o);o.animate([{opacity:0},{opacity:1}],{duration:700,fill:'forwards'});
|
||
});
|
||
await sleep(6100);
|
||
const video=page.video();await page.close();await video.saveAs('video/timmy-app-demo-raw.webm');await context.close();await browser.close();
|
||
console.log('video/timmy-app-demo-raw.webm');
|