About drug abuse make a animated video

Asking for Preferences

Animation video video

Running Command

mkdir -p /home/daytona/workspace/drug-abuse-animation

Writing File

~/drug-abuse-animation/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drug Abuse Awareness – Animated Story</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { background: #0a0a1a; font-family: 'Segoe UI', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; }

  h1 { color: #fff; font-size: 1.3rem; letter-spacing: 2px; text-transform: uppercase; margin-bottom: 12px; opacity: 0.7; }

  #stage {
    width: 800px; height: 450px;
    border-radius: 18px;
    overflow: hidden;
    position: relative;
    box-shadow: 0 0 60px rgba(100,60,200,0.5);
    background: #111;
  }

  canvas { display: block; }

  #controls {
    margin-top: 18px;
    display: flex; gap: 14px; align-items: center;
  }
  button {
    padding: 10px 28px; border: none; border-radius: 30px;
    background: linear-gradient(135deg,#7b2ff7,#f107a3);
    color: #fff; font-size: 1rem; cursor: pointer;
    letter-spacing: 1px; transition: opacity .2s;
  }
  button:hover { opacity: .85; }

  #scene-label {
    color: #ccc; font-size: .85rem; letter-spacing: 1px;
    min-width: 180px; text-align: center;
  }

  #progress-bar-wrap {
    width: 800px; height: 6px; background: #222; border-radius: 3px; margin-top: 10px;
  }
  #progress-bar {
    height: 100%; border-radius: 3px;
    background: linear-gradient(90deg,#7b2ff7,#f107a3);
    width: 0%; transition: width .3s;
  }
</style>
</head>
<body>
<h1>🎬 Drug Abuse Awareness</h1>
<div id="stage"><canvas id="c" width="800" height="450"></canvas></div>
<div id="progress-bar-wrap"><div id="progress-bar"></div></div>
<div id="controls">
  <button id="playBtn">▶ Play</button>
  <span id="scene-label">Scene 1 / 8</span>
  <button id="restartBtn">↺ Restart</button>
</div>

<script>
// ─── Canvas & context ────────────────────────────────────────────────────────
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;

// ─── Utility helpers ─────────────────────────────────────────────────────────
function lerp(a,b,t){ return a+(b-a)*t; }
function easeInOut(t){ return t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2; }
function easeOut(t){ return 1-Math.pow(1-t,3); }

// ─── Drawing primitives ──────────────────────────────────────────────────────
function drawSky(y1col, y2col){
  const g=ctx.createLinearGradient(0,0,0,H);
  g.addColorStop(0,y1col); g.addColorStop(1,y2col);
  ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
}

function drawGround(y, col){
  ctx.fillStyle=col; ctx.fillRect(0,y,W,H-y);
}

function drawCloud(x,y,s,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle='#fff';
  [[0,0,s],[s*.6,s*.1,s*.7],[s*1.2,0,s*.8],[s*.3,-s*.4,s*.6],[s*.9,-s*.35,s*.55]].forEach(([dx,dy,r])=>{
    ctx.beginPath(); ctx.arc(x+dx,y+dy,r,0,Math.PI*2); ctx.fill();
  });
  ctx.restore();
}

function drawStar(x,y,r,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle='#fff'; ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI*2); ctx.fill();
  ctx.restore();
}

// Draw a simple stick-person (x,y = feet center)
function drawPerson(x, y, scale, opts={}){
  const {
    shirtColor='#3498db', pantsColor='#2c3e50', skinColor='#f5cba7',
    happy=true, sweat=false, flipped=false, alpha=1
  } = opts;
  ctx.save();
  ctx.globalAlpha=alpha;
  if(flipped){ ctx.translate(x,y); ctx.scale(-1,1); ctx.translate(-x,-y); }

  const S=scale;
  // Legs
  ctx.strokeStyle=pantsColor; ctx.lineWidth=S*3;
  ctx.beginPath(); ctx.moveTo(x,y-S*30); ctx.lineTo(x-S*12,y); ctx.stroke();
  ctx.beginPath(); ctx.moveTo(x,y-S*30); ctx.lineTo(x+S*12,y); ctx.stroke();
  // Body
  ctx.strokeStyle=shirtColor; ctx.lineWidth=S*4;
  ctx.beginPath(); ctx.moveTo(x,y-S*65); ctx.lineTo(x,y-S*30); ctx.stroke();
  // Arms
  ctx.strokeStyle=shirtColor; ctx.lineWidth=S*3;
  if(happy){
    ctx.beginPath(); ctx.moveTo(x,y-S*55); ctx.lineTo(x-S*20,y-S*40); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(x,y-S*55); ctx.lineTo(x+S*20,y-S*40); ctx.stroke();
  } else {
    ctx.beginPath(); ctx.moveTo(x,y-S*55); ctx.lineTo(x-S*18,y-S*65); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(x,y-S*55); ctx.lineTo(x+S*18,y-S*65); ctx.stroke();
  }
  // Head
  ctx.fillStyle=skinColor; ctx.beginPath(); ctx.arc(x,y-S*80,S*15,0,Math.PI*2); ctx.fill();
  ctx.strokeStyle='#c8a07a'; ctx.lineWidth=1; ctx.stroke();
  // Eyes
  ctx.fillStyle='#222';
  ctx.beginPath(); ctx.arc(x-S*5,y-S*82,S*2.5,0,Math.PI*2); ctx.fill();
  ctx.beginPath(); ctx.arc(x+S*5,y-S*82,S*2.5,0,Math.PI*2); ctx.fill();
  // Mouth
  ctx.strokeStyle='#a0522d'; ctx.lineWidth=S*1.5;
  ctx.beginPath();
  if(happy){
    ctx.arc(x,y-S*76,S*6,0.2,Math.PI-0.2); ctx.stroke();
  } else {
    ctx.arc(x,y-S*70,S*6,Math.PI+0.2,-0.2); ctx.stroke();
  }
  // Sweat drops
  if(sweat){
    ctx.fillStyle='#74b9ff';
    ctx.beginPath(); ctx.arc(x+S*18,y-S*85,S*3,0,Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(x+S*22,y-S*78,S*2,0,Math.PI*2); ctx.fill();
  }
  ctx.restore();
}

function drawBrain(x,y,s,col,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle=col; ctx.strokeStyle='#8e44ad'; ctx.lineWidth=2;
  ctx.beginPath();
  ctx.ellipse(x,y,s*1.1,s*.8,0,0,Math.PI*2); ctx.fill(); ctx.stroke();
  ctx.fillStyle='rgba(0,0,0,.15)';
  // folds
  for(let i=0;i<5;i++){
    ctx.beginPath();
    ctx.arc(x-s*.5+i*s*.25,y,s*.3,0,Math.PI,true);
    ctx.stroke();
  }
  ctx.restore();
}

function drawPill(x,y,w,h,col,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle=col; ctx.strokeStyle='rgba(0,0,0,.2)'; ctx.lineWidth=2;
  ctx.beginPath();
  const r=h/2;
  ctx.moveTo(x+r,y); ctx.lineTo(x+w-r,y);
  ctx.arc(x+w-r,y+r,r,-Math.PI/2,Math.PI/2);
  ctx.lineTo(x+r,y+h);
  ctx.arc(x+r,y+r,r,Math.PI/2,3*Math.PI/2);
  ctx.closePath(); ctx.fill(); ctx.stroke();
  ctx.restore();
}

function drawSyringe(x,y,angle,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.translate(x,y); ctx.rotate(angle);
  ctx.fillStyle='#ecf0f1'; ctx.strokeStyle='#bdc3c7'; ctx.lineWidth=2;
  ctx.fillRect(-40,-8,80,16); ctx.strokeRect(-40,-8,80,16);
  ctx.fillStyle='#c0392b';
  ctx.fillRect(-40,-8,30,16);
  ctx.fillStyle='#7f8c8d';
  ctx.beginPath(); ctx.moveTo(40,-4); ctx.lineTo(60,0); ctx.lineTo(40,4); ctx.closePath(); ctx.fill();
  ctx.restore();
}

function drawCross(x,y,s,col,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle=col;
  ctx.fillRect(x-s*.15,y-s*.5,s*.3,s);
  ctx.fillRect(x-s*.5,y-s*.15,s,s*.3);
  ctx.restore();
}

function drawHeart(x,y,s,col,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle=col;
  ctx.beginPath();
  ctx.moveTo(x,y+s*.4);
  ctx.bezierCurveTo(x,y,x-s,y,x-s,y-s*.4);
  ctx.bezierCurveTo(x-s,y-s,x,y-s*.9,x,y-s*.5);
  ctx.bezierCurveTo(x,y-s*.9,x+s,y-s,x+s,y-s*.4);
  ctx.bezierCurveTo(x+s,y,x,y,x,y+s*.4);
  ctx.closePath(); ctx.fill();
  ctx.restore();
}

function drawTree(x,y,s,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle='#5d4037'; ctx.fillRect(x-s*.08,y-s*.3,s*.16,s*.3);
  ctx.fillStyle='#2e7d32';
  ctx.beginPath(); ctx.arc(x,y-s*.5,s*.35,0,Math.PI*2); ctx.fill();
  ctx.beginPath(); ctx.arc(x-s*.2,y-s*.3,s*.25,0,Math.PI*2); ctx.fill();
  ctx.beginPath(); ctx.arc(x+s*.2,y-s*.3,s*.25,0,Math.PI*2); ctx.fill();
  ctx.restore();
}

function drawBuilding(x,y,w,h,col,a){
  ctx.save(); ctx.globalAlpha=a;
  ctx.fillStyle=col;
  ctx.fillRect(x,y,w,h);
  ctx.fillStyle='rgba(255,255,180,0.6)';
  for(let row=0;row<4;row++) for(let col2=0;col2<3;col2++){
    ctx.fillRect(x+8+col2*(w/3.2), y+10+row*((h-10)/4.5), w/5, h/7);
  }
  ctx.restore();
}

function writeText(text, x, y, size, col, align, bold, alpha){
  ctx.save();
  ctx.globalAlpha = alpha !== undefined ? alpha : 1;
  ctx.fillStyle=col;
  ctx.font = `${bold?'bold ':''}${size}px Segoe UI, Arial`;
  ctx.textAlign=align||'center';
  ctx.fillText(text, x, y);
  ctx.restore();
}

function wrapText(text, x, y, maxW, lineH, size, col, alpha){
  ctx.save();
  ctx.globalAlpha = alpha !== undefined ? alpha : 1;
  ctx.fillStyle=col;
  ctx.font=`${size}px Segoe UI, Arial`;
  ctx.textAlign='center';
  const words=text.split(' '), lines=[];
  let cur='';
  words.forEach(w=>{
    const test=cur?cur+' '+w:w;
    if(ctx.measureText(test).width>maxW){ lines.push(cur); cur=w; }
    else cur=test;
  });
  lines.push(cur);
  lines.forEach((l,i)=>ctx.fillText(l,x,y+i*lineH));
  ctx.restore();
}

function drawSubtitleBox(text, progress){
  if(!text) return;
  ctx.save();
  ctx.fillStyle='rgba(0,0,0,0.6)';
  ctx.beginPath();
  const bw=700, bh=52, bx=(W-bw)/2, by=H-75;
  ctx.roundRect(bx,by,bw,bh,10);
  ctx.fill();
  ctx.fillStyle='#fff';
  ctx.font='bold 18px Segoe UI, Arial';
  ctx.textAlign='center';
  ctx.fillText(text, W/2, by+34);
  ctx.restore();
}

// ─── Stars (for night scenes) ─────────────────────────────────────────────
const stars = Array.from({length:80},()=>({
  x:Math.random()*W, y:Math.random()*H*.5,
  r:Math.random()*1.5+0.3, twinkle:Math.random()*Math.PI*2
}));
function drawStars(t){
  stars.forEach(s=>{
    drawStar(s.x,s.y,s.r,(Math.sin(s.twinkle+t*.02)*.3+.7)*.8);
  });
}

// ─── Particle system ─────────────────────────────────────────────────────────
class Particle {
  constructor(x,y,vx,vy,col,life,r){
    this.x=x;this.y=y;this.vx=vx;this.vy=vy;
    this.col=col;this.life=life;this.maxLife=life;this.r=r;
  }
  update(){
    this.x+=this.vx; this.y+=this.vy;
    this.vy+=.15; this.life--;
  }
  draw(){
    const a=this.life/this.maxLife;
    ctx.save(); ctx.globalAlpha=a;
    ctx.fillStyle=this.col;
    ctx.beginPath(); ctx.arc(this.x,this.y,this.r,0,Math.PI*2); ctx.fill();
    ctx.restore();
  }
}
let particles = [];
function spawnParticles(x,y,col,n,speed,life,r){
  for(let i=0;i<n;i++){
    const angle=Math.random()*Math.PI*2;
    const v=Math.random()*speed+1;
    particles.push(new Particle(x,y,Math.cos(angle)*v,Math.sin(angle)*v-2,col,life,r||4));
  }
}

// ─── Scene definitions ───────────────────────────────────────────────────────
// Each scene: { duration (frames), draw(t, progress 0-1) }
const SCENES = [

  // ── Scene 0: Title ──────────────────────────────────────────────────────
  {
    duration: 180,
    subtitle: 'Drug Abuse: Know the Truth',
    draw(t, p){
      drawSky('#0d1b2a','#1a3a5c');
      drawStars(t);
      // big glowing title
      const pulse = Math.sin(t*.05)*.05+.95;
      ctx.save();
      ctx.shadowColor='#f107a3'; ctx.shadowBlur=30;
      writeText('DRUG ABUSE', W/2, H/2-40, 72*pulse, '#fff', 'center', true, easeOut(p));
      ctx.shadowColor='#7b2ff7'; ctx.shadowBlur=20;
      writeText('KNOW THE TRUTH', W/2, H/2+30, 30, '#f1c40f', 'center', true, easeOut(Math.max(0,p-.3)/.7));
      ctx.restore();
      writeText('An Awareness Story', W/2, H/2+80, 20, '#aaa', 'center', false, easeOut(Math.max(0,p-.6)/.4));
      // floating pills
      for(let i=0;i<4;i++){
        const px=100+i*190, py=60+Math.sin(t*.03+i)*15;
        drawPill(px,py,50,20,['#e74c3c','#3498db','#2ecc71','#f39c12'][i],0.3);
      }
    }
  },

  // ── Scene 1: Happy life ──────────────────────────────────────────────────
  {
    duration: 200,
    subtitle: 'Alex was a happy, healthy student with big dreams.',
    draw(t, p){
      // daytime sky
      drawSky('#87ceeb','#c9e8ff');
      // sun
      ctx.save(); ctx.shadowColor='#ffeb3b'; ctx.shadowBlur=40;
      ctx.fillStyle='#ffeb3b'; ctx.beginPath(); ctx.arc(680,80,45,0,Math.PI*2); ctx.fill();
      ctx.restore();
      drawCloud(80,80,.4,0.85);
      drawCloud(400,60,.5,0.7);
      drawGround(320,'#4caf50');
      // school building
      drawBuilding(120, 180, 180, 140, '#ecf0f1', easeOut(p));
      writeText('SCHOOL', 210, 240, 16, '#34495e', 'center', true, easeOut(p));
      // trees
      drawTree(360, 320, 80, easeOut(p));
      drawTree(420, 320, 60, easeOut(p));
      // happy Alex walking in
      const alexX = lerp(-60, 260, easeInOut(Math.min(1, p*2)));
      drawPerson(alexX, 320, 1.6, {happy:true, shirtColor:'#3498db', alpha:easeOut(p)});
      // school bag (simple rect)
      ctx.save(); ctx.globalAlpha=easeOut(p);
      ctx.fillStyle='#e74c3c';
      ctx.fillRect(alexX+12, 320-85, 20, 28); ctx.restore();
      // birds
      for(let b=0;b<3;b++){
        const bx=(200+b*120+t*.8)%820-20;
        const by=100+b*20+Math.sin(t*.06+b)*8;
        ctx.save(); ctx.strokeStyle='#333'; ctx.lineWidth=2;
        ctx.beginPath(); ctx.moveTo(bx,by); ctx.quadraticCurveTo(bx+8,by-6,bx+16,by); ctx.stroke();
        ctx.restore();
      }
    }
  },

  // ── Scene 2: Peer pressure ──────────────────────────────────────────────
  {
    duration: 220,
    subtitle: 'One day, a friend offered Alex a drug — "Just try it once!"',
    draw(t, p){
      drawSky('#2c3e50','#4a235a');
      drawGround(330,'#1a1a1a');
      drawStars(t);
      // street lamp
      ctx.save(); ctx.strokeStyle='#f39c12'; ctx.lineWidth=4;
      ctx.beginPath(); ctx.moveTo(600,100); ctx.lineTo(600,330); ctx.stroke();
      ctx.fillStyle='#f1c40f'; ctx.beginPath(); ctx.ellipse(600,105,20,8,0,0,Math.PI*2); ctx.fill();
      ctx.save(); ctx.shadowColor='#f1c40f'; ctx.shadowBlur=40;
      ctx.fillStyle='rgba(255,240,100,0.12)';
      ctx.beginPath(); ctx.ellipse(600,220,100,200,0,0,Math.PI*2); ctx.fill();
      ctx.restore(); ctx.restore();
      // Alex (nervous)
      const alexX = 320;
      drawPerson(alexX, 330, 1.6, {happy:false, shirtColor:'#3498db', sweat:true, alpha:easeOut(p)});
      // Bad friend
      const friendX = lerp(800, 500, easeInOut(Math.min(1,p*1.5)));
      drawPerson(friendX, 330, 1.6, {happy:true, shirtColor:'#e74c3c', skinColor:'#f5cba7', flipped:true, alpha:easeOut(p)});
      // pill/offer floating
      if(p > .4){
        const pillA = easeOut((p-.4)/.6);
        drawPill(alexX+80, 280, 50, 20, '#e74c3c', pillA);
        writeText('Try it!', alexX+130, 265, 18, '#f1c40f', 'center', true, pillA);
        // question mark over Alex
        writeText('?', alexX-10, 235, 36, '#fff', 'center', true, pillA*.8);
      }
      // speech bubble from friend
      if(p > .5){
        const bx=friendX-120, by=230;
        ctx.save(); ctx.globalAlpha=easeOut((p-.5)/.5);
        ctx.fillStyle='#fff'; ctx.strokeStyle='#ccc'; ctx.lineWidth=2;
        ctx.beginPath(); ctx.roundRect(bx-70,by-25,150,45,12); ctx.fill(); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(bx+30,by+20); ctx.lineTo(bx+50,by+42); ctx.lineTo(bx+15,by+20); ctx.closePath(); ctx.fill();
        writeText('Just once!', bx+5, by+3, 16, '#c0392b', 'center', true);
        ctx.restore();
      }
    }
  },

  // ── Scene 3: Brain effect ───────────────────────────────────────────────
  {
    duration: 220,
    subtitle: 'Drugs flood the brain with dopamine — creating a false sense of pleasure.',
    draw(t, p){
      drawSky('#1a0033','#330055');
      // Brain center stage
      const bx=W/2, by=H/2-20;
      const bs=90+Math.sin(t*.08)*8;
      // glow
      ctx.save();
      ctx.shadowColor='#9b59b6'; ctx.shadowBlur=50+Math.sin(t*.06)*20;
      drawBrain(bx, by, bs, '#e8b4f8', easeOut(p));
      ctx.restore();
      writeText('BRAIN', bx, by+bs+20, 18, '#ddd', 'center', true, easeOut(p));
      // dopamine particles
      if(p>.3){
        const dp=easeOut((p-.3)/.7);
        for(let i=0;i<8;i++){
          const angle=(i/8)*Math.PI*2+t*.04;
          const r=120+Math.sin(t*.05+i)*15;
          const px2=bx+Math.cos(angle)*r, py2=by+Math.sin(angle)*r;
          ctx.save(); ctx.globalAlpha=dp;
          ctx.fillStyle='#f1c40f';
          ctx.font='bold 22px Arial';
          ctx.textAlign='center';
          ctx.fillText('✦', px2, py2);
          ctx.restore();
        }
        // dopamine label
        writeText('DOPAMINE SURGE', W/2, 60, 24, '#f1c40f', 'center', true, dp);
        // arrows into brain
        for(let i=0;i<5;i++){
          const angle=(i/5)*Math.PI*2+t*.02;
          const x1=bx+Math.cos(angle)*(bs+80);
          const y1=by+Math.sin(angle)*(bs+80);
          const x2=bx+Math.cos(angle)*bs;
          const y2=by+Math.sin(angle)*bs;
          ctx.save(); ctx.globalAlpha=dp*.7;
          ctx.strokeStyle='#9b59b6'; ctx.lineWidth=3;
          ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke();
          ctx.fillStyle='#9b59b6';
          ctx.beginPath(); ctx.arc(x2,y2,5,0,Math.PI*2); ctx.fill();
          ctx.restore();
        }
      }
      // Warning note
      if(p>.6){
        const wa=easeOut((p-.6)/.4);
        ctx.save(); ctx.globalAlpha=wa;
        ctx.fillStyle='rgba(231,76,60,0.2)';
        ctx.beginPath(); ctx.roundRect(30,H-130,W-60,70,10); ctx.fill();
        wrapText('Over time the brain needs MORE drug to feel normal — this is ADDICTION',
          W/2, H-100, 700, 24, 16, '#ff7675', wa);
        ctx.restore();
      }
    }
  },

  // ── Scene 4: Downward spiral ─────────────────────────────────────────────
  {
    duration: 240,
    subtitle: 'Alex started skipping school, losing friends, and falling apart.',
    draw(t, p){
      // gloomy sky
      drawSky('#2d3436','#636e72');
      drawGround(320,'#555');
      // rain
      for(let r=0;r<40;r++){
        const rx=(r*97+t*4)%W;
        const ry=((r*73+t*6))%(H*.8);
        ctx.save(); ctx.globalAlpha=.3;
        ctx.strokeStyle='#74b9ff'; ctx.lineWidth=1;
        ctx.beginPath(); ctx.moveTo(rx,ry); ctx.lineTo(rx-3,ry+15); ctx.stroke();
        ctx.restore();
      }
      // crumbling house
      const cx=130;
      ctx.save(); ctx.globalAlpha=easeOut(p);
      ctx.fillStyle='#795548';
      ctx.fillRect(cx,180,140,140);
      ctx.fillStyle='#5d4037';
      ctx.beginPath(); ctx.moveTo(cx-10,180); ctx.lineTo(cx+70,120); ctx.lineTo(cx+150,180); ctx.closePath(); ctx.fill();
      // cracks
      ctx.strokeStyle='#212121'; ctx.lineWidth=2;
      ctx.beginPath(); ctx.moveTo(cx+40,200); ctx.lineTo(cx+55,240); ctx.lineTo(cx+48,270); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(cx+90,190); ctx.lineTo(cx+80,220); ctx.stroke();
      ctx.restore();
      // Alex sad, hunched
      const alexX = 360;
      // hunched by lowering y and making sad
      drawPerson(alexX, 320 + Math.sin(t*.03)*3, 1.4, {
        happy:false, shirtColor:'#636e72', sweat:false, alpha:easeOut(p)
      });
      // broken items around Alex
      if(p>.3){
        const ia=easeOut((p-.3)/.7);
        // broken phone
        ctx.save(); ctx.globalAlpha=ia;
        ctx.fillStyle='#333'; ctx.fillRect(alexX+25, 285, 22, 36);
        ctx.strokeStyle='#e74c3c'; ctx.lineWidth=1.5;
        ctx.beginPath(); ctx.moveTo(alexX+30,295); ctx.lineTo(alexX+43,315); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(alexX+43,295); ctx.lineTo(alexX+30,315); ctx.stroke();
        ctx.restore();
        // Report card F
        ctx.save(); ctx.globalAlpha=ia;
        ctx.fillStyle='#ecf0f1'; ctx.fillRect(alexX-55, 265, 36, 45);
        writeText('F', alexX-37, 295, 26, '#e74c3c', 'center', true);
        ctx.restore();
      }
      // Crossed-out friends
      if(p>.5){
        const fa=easeOut((p-.5)/.5);
        drawPerson(580, 320, 1.2, {happy:false, shirtColor:'#aaa', alpha:fa*.4});
        drawPerson(650, 320, 1.2, {happy:false, shirtColor:'#aaa', alpha:fa*.4});
        drawCross(580, 270, 40, 'rgba(231,76,60,.7)', fa);
        drawCross(650, 270, 40, 'rgba(231,76,60,.7)', fa);
      }
      // pills on ground
      for(let i=0;i<5;i++){
        drawPill(alexX+50+i*30, 310, 28, 12, ['#e74c3c','#3498db','#9b59b6','#e74c3c','#2ecc71'][i], easeOut(p)*.6);
      }
    }
  },

  // ── Scene 5: Health consequences ────────────────────────────────────────
  {
    duration: 220,
    subtitle: 'Drug abuse destroys your body, mind, and future.',
    draw(t, p){
      drawSky('#1a1a2e','#16213e');
      // Split screen – left: body, right: stats
      // Left side: deteriorating person
      const pulse=Math.sin(t*.1)*.1;
      drawPerson(200, 340, 1.5+pulse, {
        happy:false, shirtColor:'#636e72', skinColor:'#d5a29a', sweat:true,
        alpha:easeOut(p)
      });
      // heartbeat line erratic
      ctx.save(); ctx.globalAlpha=easeOut(p);
      ctx.strokeStyle='#e74c3c'; ctx.lineWidth=2;
      ctx.beginPath();
      const hbStart=60, hbY=H-100;
      ctx.moveTo(hbStart, hbY);
      const hbData=[0,0,0,-30,30,-15,10,0,0,0,0,-5,5,0,-20,25,-10,5,0,0];
      hbData.forEach((dy,i)=>ctx.lineTo(hbStart+i*16, hbY+dy));
      ctx.stroke();
      ctx.restore();
      writeText('♥ Irregular heartbeat', 210, H-55, 14, '#ff7675', 'center', false, easeOut(p));
      // Right side consequences
      const consList = [
        {icon:'🧠', text:'Brain damage', col:'#a29bfe'},
        {icon:'💉', text:'HIV / Hepatitis risk', col:'#fd79a8'},
        {icon:'🫁', text:'Lung & liver failure', col:'#fdcb6e'},
        {icon:'💔', text:'Heart disease', col:'#e74c3c'},
        {icon:'😰', text:'Mental illness', col:'#74b9ff'},
      ];
      consList.forEach((c,i)=>{
        const cy=90+i*62, ca=easeOut(Math.max(0,(p-i*.08-.1)/.5));
        ctx.save(); ctx.globalAlpha=ca;
        ctx.fillStyle='rgba(255,255,255,.08)';
        ctx.beginPath(); ctx.roundRect(420, cy-26, 320, 50, 8); ctx.fill();
        ctx.font='22px Arial'; ctx.textAlign='left'; ctx.fillText(c.icon, 435, cy+8);
        writeText(c.text, 580, cy+8, 18, c.col, 'center', true, 1);
        ctx.restore();
      });
    }
  },

  // ── Scene 6: Help & Recovery ─────────────────────────────────────────────
  {
    duration: 220,
    subtitle: 'It is never too late. Help is available — reach out!',
    draw(t, p){
      drawSky('#0a3d62','#1e3799');
      drawGround(330,'#27ae60');
      // sunrise/hope
      const sunY=80-easeOut(p)*30;
      ctx.save(); ctx.shadowColor='#f1c40f'; ctx.shadowBlur=60;
      ctx.fillStyle='#f1c40f'; ctx.beginPath(); ctx.arc(W/2,sunY+20,50,0,Math.PI*2); ctx.fill();
      ctx.restore();
      // rays
      for(let r=0;r<12;r++){
        const angle=(r/12)*Math.PI*2+t*.01;
        ctx.save(); ctx.globalAlpha=.15*easeOut(p);
        ctx.strokeStyle='#f1c40f'; ctx.lineWidth=3;
        ctx.beginPath();
        ctx.moveTo(W/2+Math.cos(angle)*55, sunY+20+Math.sin(angle)*55);
        ctx.lineTo(W/2+Math.cos(angle)*90, sunY+20+Math.sin(angle)*90);
        ctx.stroke(); ctx.restore();
      }
      // doctor / counselor
      drawPerson(320, 330, 1.6, {happy:true, shirtColor:'#fff', skinColor:'#f5cba7', alpha:easeOut(p)});
      // stethoscope (simple arc)
      ctx.save(); ctx.globalAlpha=easeOut(p);
      ctx.strokeStyle='#3498db'; ctx.lineWidth=3;
      ctx.beginPath(); ctx.arc(320, 330-60, 18, -.5, Math.PI+.5); ctx.stroke();
      ctx.restore();
      writeText('Doctor / Counselor', 320, H-10, 15, '#aaa', 'center', false, easeOut(p));
      // Alex recovering
      const alexX=500;
      const alexY=330-easeOut(Math.max(0,p-.3)/.7)*10;
      drawPerson(alexX, alexY, 1.6, {happy: p>.5, shirtColor:'#2ecc71', alpha:easeOut(Math.max(0,p-.1)/.9)});
      // heart growing
      if(p>.4){
        const ha=easeOut((p-.4)/.6);
        drawHeart(alexX, alexY-130, 20*ha, '#e74c3c', ha);
      }
      // support sign
      if(p>.5){
        const sa=easeOut((p-.5)/.5);
        ctx.save(); ctx.globalAlpha=sa;
        ctx.fillStyle='#2ecc71'; ctx.strokeStyle='#27ae60'; ctx.lineWidth=2;
        ctx.beginPath(); ctx.roundRect(590,140,180,80,10); ctx.fill(); ctx.stroke();
        writeText('REHAB', 680, 178, 20, '#fff', 'center', true);
        writeText('We support you', 680, 205, 14, '#d5f5e3', 'center', false);
        // pole
        ctx.strokeStyle='#795548'; ctx.lineWidth=4;
        ctx.beginPath(); ctx.moveTo(680,220); ctx.lineTo(680,330); ctx.stroke();
        ctx.restore();
      }
      // falling confetti/stars (hope)
      if(p>.6){
        for(let i=0;i<15;i++){
          const cx2=(i*137.5+t*2)%W;
          const cy2=((i*83+t*3)%(H*.7));
          ctx.save(); ctx.globalAlpha=.5;
          ctx.fillStyle=['#f1c40f','#2ecc71','#3498db','#9b59b6','#e74c3c'][i%5];
          ctx.beginPath(); ctx.arc(cx2,cy2,4,0,Math.PI*2); ctx.fill();
          ctx.restore();
        }
      }
    }
  },

  // ── Scene 7: Say NO / CTA ────────────────────────────────────────────────
  {
    duration: 240,
    subtitle: 'Say NO to drugs. Choose life. Choose YOUR future.',
    draw(t, p){
      drawSky('#0d1b2a','#1a3a5c');
      drawStars(t);
      // big NO
      const noScale=easeOut(p)*1+.3;
      ctx.save();
      ctx.translate(W/2, H/2-30);
      ctx.scale(noScale, noScale);
      ctx.shadowColor='#e74c3c'; ctx.shadowBlur=50;
      ctx.fillStyle='#e74c3c';
      ctx.font='bold 110px Segoe UI, Arial';
      ctx.textAlign='center';
      ctx.fillText('SAY NO', 0, 0);
      ctx.restore();
      // to drugs
      writeText('to drugs', W/2, H/2+50, 38, '#f1c40f', 'center', true, easeOut(Math.max(0,p-.2)/.8));
      // three happy people at bottom
      if(p>.4){
        const ga=easeOut((p-.4)/.6);
        drawPerson(W/2-140, H-40, 1.5, {happy:true, shirtColor:'#3498db', alpha:ga});
        drawPerson(W/2, H-40, 1.5, {happy:true, shirtColor:'#2ecc71', alpha:ga});
        drawPerson(W/2+140, H-40, 1.5, {happy:true, shirtColor:'#9b59b6', alpha:ga});
      }
      // hotline box
      if(p>.6){
        const ha=easeOut((p-.6)/.4);
        ctx.save(); ctx.globalAlpha=ha;
        ctx.fillStyle='rgba(255,255,255,.12)';
        ctx.beginPath(); ctx.roundRect(W/2-200,H-175,400,55,10); ctx.fill();
        writeText('📞 Helpline: 1-800-662-4357 (SAMHSA)', W/2, H-142, 16, '#74b9ff', 'center', true);
        ctx.restore();
      }
      // confetti celebration
      particles.forEach(pp=>{ pp.update(); pp.draw(); });
      particles=particles.filter(pp=>pp.life>0);
      if(p>.5 && Math.random()<.4){
        const col=['#f1c40f','#2ecc71','#3498db','#e74c3c','#9b59b6'][Math.floor(Math.random()*5)];
        spawnParticles(Math.random()*W, -10, col, 2, 3, 60, 5);
      }
    }
  }
];

// ─── Animation engine ─────────────────────────────────────────────────────
let currentScene = 0;
let sceneFrame = 0;
let totalFrame = 0;
let running = false;
let animId = null;

const totalFrames = SCENES.reduce((s,sc)=>s+sc.duration, 0);

function render(){
  const scene = SCENES[currentScene];
  const progress = sceneFrame / scene.duration;
  ctx.clearRect(0,0,W,H);
  scene.draw(sceneFrame, Math.min(1, progress));
  drawSubtitleBox(scene.subtitle, progress);
  // scene number overlay
  ctx.save(); ctx.globalAlpha=.5;
  ctx.fillStyle='rgba(0,0,0,.4)';
  ctx.beginPath(); ctx.roundRect(14,14,110,30,8); ctx.fill();
  writeText(`Scene ${currentScene+1} / ${SCENES.length}`, 69, 34, 14, '#ccc', 'center', false);
  ctx.restore();
  // progress bar
  document.getElementById('progress-bar').style.width =
    ((totalFrame/totalFrames)*100)+'%';
  document.getElementById('scene-label').textContent =
    `Scene ${currentScene+1} / ${SCENES.length}`;
}

function tick(){
  sceneFrame++;
  totalFrame++;
  if(sceneFrame > SCENES[currentScene].duration){
    sceneFrame=0;
    currentScene++;
    if(currentScene >= SCENES.length){
      currentScene = SCENES.length-1;
      sceneFrame = SCENES[currentScene].duration;
      running=false;
      document.getElementById('playBtn').textContent='▶ Play';
      render();
      return;
    }
  }
  render();
  if(running) animId=requestAnimationFrame(tick);
}

function play(){
  running=true;
  document.getElementById('playBtn').textContent='⏸ Pause';
  animId=requestAnimationFrame(tick);
}
function pause(){
  running=false;
  cancelAnimationFrame(animId);
  document.getElementById('playBtn').textContent='▶ Play';
}
function restart(){
  pause();
  currentScene=0; sceneFrame=0; totalFrame=0;
  particles=[];
  render();
}

document.getElementById('playBtn').addEventListener('click',()=>{
  if(running) pause(); else play();
});
document.getElementById('restartBtn').addEventListener('click',()=>{
  restart();
});

// initial frame
render();
</script>
</body>
</html>
Running Command

ls -lh /home/daytona/workspace/drug-abuse-animation/

Your animated drug abuse awareness video is ready! Download and open it in any browser:

index

HTML File · HTML


What's inside the animation

The video has 8 fully animated scenes telling a complete story:
SceneTitleWhat happens
1Title ScreenGlowing title with floating pills, intro text
2Happy LifeAlex the stick-figure student walks to school on a sunny day
3Peer PressureA friend offers a drug at night - "Just try it once!"
4Brain EffectAnimated brain with dopamine surge, explains addiction mechanism
5Downward SpiralRain, broken report card, lost friends, pills on the ground
6Health ConsequencesSplit screen - erratic heartbeat + 5 health effects listed
7Help & RecoveryDoctor + recovering Alex, sunrise, rehab sign
8Say NOBold "SAY NO" with confetti celebration, SAMHSA helpline

How to play it

  • Click ▶ Play to start the animation
  • Click ⏸ Pause to stop at any scene
  • Click ↺ Restart to go back to the beginning
  • A progress bar shows how far along you are
This is a shared conversation. Sign in to Orris to start your own chat.