У меня есть браузерная игра на js. В ней пользователь рисует мышью горку и по ней запускаются санки. 
Вот её код: 
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>Снежная горка</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
      background: #87CEEB;
    }
    #distance, #recordDistance, #message {
      position: absolute;
      top: 10px;
      left: 10px;
      font-size: 24px;
      color: #fff;
      text-shadow: 1px 1px 2px #000;
    }
    #recordDistance {
      top: 40px;
    }
    #message {
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 36px;
      text-align: center;
      display: none;
      background-color: rgba(0, 0, 0, 0.5);
      padding: 20px;
      border-radius: 10px;
      color: #fff;
    }
    #controls {
      position: absolute;
      top: 10px;
      right: 10px;
    }
    #controls button {
      padding: 10px 20px;
      font-size: 18px;
      margin-left: 10px;
    }
    button.active {
      background-color: #4CAF50;
      color: white;
    }
  </style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="distance">Дистанция: 0 м</div>
<div id="recordDistance">Рекорд: 0 м</div>
<div id="message"></div>
<div id="controls">
  <button id="startButton">Старт</button>
  <button id="resetButton">Новая горка</button>

<button id="pencilButton" class="active">Карандаш</button>
  <button id="eraserButton">Ластик</button>

</div>

<script>
  const canvas = document.getElementById('gameCanvas');
  const ctx = canvas.getContext('2d');
  const distanceDisplay = document.getElementById('distance');
  const recordDistanceDisplay = document.getElementById('recordDistance');
  const messageDisplay = document.getElementById('message');
  const startButton = document.getElementById('startButton');
  const resetButton = document.getElementById('resetButton');

  const pencilButton = document.getElementById('pencilButton');
  const eraserButton = document.getElementById('eraserButton');

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  let isDrawing = false;
  let isErasing = false;
  let hillSegments = [];
  let sled = null;
  let distanceTraveled = 0;
  let recordDistance = 0;
  let animationFrameId = null;
  let currentTool = 'pencil';

  const sledImage = new Image();
  sledImage.src = 'data:image/svg+xml;base64,' + btoa(`
    <svg xmlns="http://www.w3.org/2000/svg" width="60" height="20">
      <path d="M5 15 L55 15 L50 10 L10 10 Z" fill="brown"/>
      <line x1="15" y1="15" x2="20" y2="5" stroke="brown" stroke-width="2"/>
      <line x1="45" y1="15" x2="40" y2="5" stroke="brown" stroke-width="2"/>
      <path d="M5 15 Q0 20 5 20 L55 20 Q60 15 55 15" fill="none" stroke="black" stroke-width="2"/>
    </svg>
  `);

  const characterImage = new Image();
  characterImage.src = 'data:image/svg+xml;base64,' + btoa(`
    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="40">
      <circle cx="10" cy="13" r="7" fill="pink"/>
      <polygon points="10,0 4,10 16,10" fill="red"/>
      <line x1="10" y1="20" x2="10" y2="35" stroke="black" stroke-width="2"/>
      <line x1="10" y1="25" x2="5" y2="30" stroke="black" stroke-width="2"/>
      <line x1="10" y1="25" x2="15" y2="30" stroke="black" stroke-width="2"/>
      <line x1="10" y1="35" x2="5" y2="40" stroke="black" stroke-width="2"/>
      <line x1="10" y1="35" x2="15" y2="40" stroke="black" stroke-width="2"/>
    </svg>
  `);

  pencilButton.addEventListener('click', () => {
    currentTool = 'pencil';
    pencilButton.classList.add('active');
    eraserButton.classList.remove('active');
  });

  eraserButton.addEventListener('click', () => {
    currentTool = 'eraser';
    eraserButton.classList.add('active');
    pencilButton.classList.remove('active');
  });

  canvas.addEventListener('mousedown', (e) => {
    if (currentTool === 'pencil') {
      isDrawing = true;
      hillSegments.push([{ x: e.offsetX, y: e.offsetY }]);
    } else if (currentTool === 'eraser') {
      isErasing = true;
      eraseAt(e.offsetX, e.offsetY);
      draw();
    }
  });

  canvas.addEventListener('mousemove', (e) => {
    if (isDrawing && currentTool === 'pencil') {
      let currentSegment = hillSegments[hillSegments.length - 1];
      currentSegment.push({ x: e.offsetX, y: e.offsetY });
      draw();
    } else if (isErasing && currentTool === 'eraser') {
      eraseAt(e.offsetX, e.offsetY);
      draw();
    }
  });

  canvas.addEventListener('mouseup', () => {
    if (currentTool === 'pencil') {
      isDrawing = false;
      let currentSegment = hillSegments[hillSegments.length - 1];
      if (currentSegment.length >= 2) {
        currentSegment = smoothHill(currentSegment);
        hillSegments[hillSegments.length - 1] = currentSegment;
        draw();
      }
    } else if (currentTool === 'eraser') {
      isErasing = false;
    }
  });

  startButton.addEventListener('click', () => {
    if (hillSegments.length < 1) return;
    if (animationFrameId) {
      cancelAnimationFrame(animationFrameId);
      animationFrameId = null;
    }
    sled = {
      x: hillSegments[0][0].x,
      y: hillSegments[0][0].y,
      vx: 0,
      vy: 0,
      segmentIndex: 0,
      pointIndex: 0,
      crashed: false,
      inAir: false,
      rotation: 0,
      angularVelocity: 0,
      character: {
        x: hillSegments[0][0].x,
        y: hillSegments[0][0].y - 20,
        vx: 0,
        vy: 0,
        inAir: false
      }
    };
    distanceTraveled = 0;
    distanceDisplay.textContent = 'Дистанция: 0 м';
    messageDisplay.style.display = 'none';
    animate();
  });

  resetButton.addEventListener('click', () => {
    if (animationFrameId) {
      cancelAnimationFrame(animationFrameId);
      animationFrameId = null;
    }
    hillSegments = [];
    sled = null;
    distanceTraveled = 0;
    distanceDisplay.textContent = 'Дистанция: 0 м';
    messageDisplay.style.display = 'none';
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  function smoothHill(points) {
    let smoothed = [];
    let windowSize = 5;
    for (let i = 0; i < points.length; i++) {
      let xSum = 0;
      let ySum = 0;
      let count = 0;
      for (let j = Math.max(0, i - Math.floor(windowSize / 2)); j <= Math.min(points.length - 1, i + Math.floor(windowSize / 2)); j++) {
        xSum += points[j].x;
        ySum += points[j].y;
        count++;
      }
      smoothed.push({ x: xSum / count, y: ySum / count });
    }
    return smoothed;
  }

  function drawHill() {
    ctx.strokeStyle = '#f0f0f0'; // Изменено на светло-серый цвет
    ctx.lineWidth = 5;

    ctx.fillStyle = '#fff';
    ctx.beginPath();
    ctx.moveTo(0, canvas.height);
    let lastX = 0;

    for (let segment of hillSegments) {
      if (segment.length > 0) {
        ctx.lineTo(segment[0].x, segment[0].y);
        for (let i = 1; i < segment.length; i++) {
          ctx.lineTo(segment[i].x, segment[i].y);
          lastX = segment[i].x;
        }
      }
    }

    ctx.lineTo(lastX, canvas.height);
    ctx.closePath();
    ctx.fill();

    for (let segment of hillSegments) {
      if (segment.length > 0) {
        ctx.beginPath();
        ctx.moveTo(segment[0].x, segment[0].y);
        for (let i = 1; i < segment.length; i++) {
          ctx.lineTo(segment[i].x, segment[i].y);
        }
        ctx.stroke();
      }
    }
  }

  function drawSled() {
    ctx.save();
    ctx.translate(sled.x, sled.y - 7);
    ctx.rotate(sled.rotation);
    ctx.drawImage(sledImage, -30, -10, 60, 20);
    ctx.restore();
  }

  function drawCharacter() {
    ctx.save();
    if (sled.inAir || sled.crashed) {
      ctx.translate(sled.character.x, sled.character.y);
    } else {
      let segment = hillSegments[sled.segmentIndex];
      let p1 = segment[sled.pointIndex];
      let p2 = segment[sled.pointIndex + 1];
      let angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
      ctx.translate(sled.x, sled.y - 27);
      ctx.rotate(angle);
    }
    ctx.drawImage(characterImage, -10, -20, 20, 40);
    ctx.restore();
  }

  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawHill();
    if (sled) {
      drawSled();
      drawCharacter();
    }
  }

  function isOnHill(x, y) {
    for (let s = 0; s < hillSegments.length; s++) {
      let segment = hillSegments[s];
      for (let i = 0; i < segment.length - 1; i++) {
        let p1 = segment[i];
        let p2 = segment[i + 1];
        if ((x >= p1.x && x <= p2.x) || (x >= p2.x && x <= p1.x)) {
          let t = (x - p1.x) / (p2.x - p1.x);
          let hillY = p1.y + t * (p2.y - p1.y);
          if (Math.abs(y - hillY) < 5) {
            return { onHill: true, hillY: hillY, segmentIndex: s, pointIndex: i };
          }
        }
      }
    }
    return { onHill: false, hillY: null };
  }

  function showMessage(text) {
    messageDisplay.textContent = text;
    messageDisplay.style.display = 'block';
  }

  function updateRecordAndShowMessage(isSuccess) {
    if (isSuccess && distanceTraveled / 10 > recordDistance) {
      recordDistance = distanceTraveled / 10;
      recordDistanceDisplay.textContent = 'Рекорд: ' + Math.floor(recordDistance) + ' м';
    }
    if (isSuccess) {
      showMessage('Игра окончена! Пройдена дистанция: ' + Math.floor(distanceTraveled / 10) + ' м');
    }
  }

  function animate() {
    if (!sled) return;

    const gravity = 0.5;
    const frictionCoefficient = 0.02;
    let hillCheck;
    let speed;

    if (!sled.crashed) {
      hillCheck = isOnHill(sled.x, sled.y);

      if (!hillCheck.onHill) {
        sled.inAir = true;
        sled.character.inAir = true;
      }

      if (sled.inAir) {
        sled.vy += gravity;
        sled.character.vx = sled.vx;
        sled.character.vy = sled.vy;
        sled.x += sled.vx;
        sled.y += sled.vy;
        sled.character.x += sled.character.vx;
        sled.character.y += sled.character.vy;

        hillCheck = isOnHill(sled.x, sled.y);
        if (hillCheck.onHill) {
          sled.inAir = false;
          sled.character.inAir = false;
          sled.segmentIndex = hillCheck.segmentIndex;
          sled.pointIndex = hillCheck.pointIndex;
          sled.y = hillCheck.hillY;
        }
      } else {
        let segment = hillSegments[sled.segmentIndex];

        if (sled.pointIndex >= segment.length - 1) {
          sled.segmentIndex++;
          sled.pointIndex = 0;
          if (sled.segmentIndex >= hillSegments.length) {
            updateRecordAndShowMessage(true);
            sled = null;
            return;
          }
          segment = hillSegments[sled.segmentIndex];
        }

        let p1 = segment[sled.pointIndex];
        let p2 = segment[sled.pointIndex + 1];
        let dx = p2.x - p1.x;
        let dy = p2.y - p1.y;
        let segmentLength = Math.sqrt(dx * dx + dy * dy);
        let tx = dx / segmentLength;
        let ty = dy / segmentLength;

        let v_parallel = sled.vx * tx + sled.vy * ty;

        let a_parallel = gravity * ty;

        let a_friction = -frictionCoefficient * gravity * Math.sign(v_parallel);

        v_parallel += a_parallel + a_friction;

        sled.vx = v_parallel * tx;
        sled.vy = v_parallel * ty;

        sled.x += sled.vx;
        sled.y += sled.vy;

        hillCheck = isOnHill(sled.x, sled.y);
        if (!hillCheck.onHill) {
          sled.inAir = true;
          sled.character.vx = sled.vx;
          sled.character.vy = sled.vy;
          sled.character.inAir = true;
        } else {
          sled.segmentIndex = hillCheck.segmentIndex;
          sled.pointIndex = hillCheck.pointIndex;
          sled.y = hillCheck.hillY;

          if (v_parallel < 0.1 && v_parallel > -0.1) {
            sled.vx = -sled.vx * 0.8;
          }
        }

        distanceTraveled += v_parallel;
        distanceDisplay.textContent = 'Дистанция: ' + Math.max(0, Math.floor(distanceTraveled / 10)) + ' м';

        speed = Math.sqrt(sled.vx * sled.vx + sled.vy * sled.vy);

        if (speed > 25 || (sled.inAir && sled.vy > 5)) {
          sled.crashed = true;
          sled.angularVelocity = sled.vx * 0.05;
          sled.character.vx = sled.vx * 0.8 + Math.sign(sled.vx) * 2;
          sled.character.vy = sled.vy - 5;
        }

        if (!sled.inAir && Math.abs(sled.vx) < 0.01 && Math.abs(sled.vy) < 0.01) {
          updateRecordAndShowMessage(true);
          sled = null;
          return;
        }
      }
    } else {
      sled.angularVelocity += 0.001;
      sled.rotation += sled.angularVelocity;

      sled.vy += gravity;
      sled.x += sled.vx;
      sled.y += sled.vy;

      hillCheck = isOnHill(sled.x, sled.y);
      if (hillCheck.onHill && sled.vy > 0) {
        sled.y = hillCheck.hillY;
        sled.vx *= 0.5;
        sled.vy = 0;
        sled.angularVelocity *= 0.5;
      }

      if (sled.character.inAir) {
        sled.character.vy += gravity;
        sled.character.x += sled.character.vx;
        sled.character.y += sled.character.vy;

        hillCheck = isOnHill(sled.character.x, sled.character.y);
        if (hillCheck.onHill && sled.character.vy > 0) {
          sled.character.y = hillCheck.hillY;
          sled.character.vx *= 0.5;
          sled.character.vy = 0;
          sled.character.inAir = false;
        }
      }
    }

    if (sled && (sled.y > canvas.height || sled.character.y > canvas.height)) {
      showMessage('Человечек упал! Игра окончена. Пройдена дистанция: ' + Math.floor(distanceTraveled / 10) + ' м');
      sled = null;
      return;
    }

    draw();
    animationFrameId = requestAnimationFrame(animate);
  }

  function eraseAt(x, y) {
    let eraseRadius = 20;

    for (let s = hillSegments.length - 1; s >= 0; s--) {
      let segment = hillSegments[s];
      let newSegments = [];
      let currentSegment = [];

      for (let i = 0; i < segment.length; i++) {
        let point = segment[i];
        let dx = point.x - x;
        let dy = point.y - y;
        let distance = Math.sqrt(dx * dx + dy * dy);

        if (distance >= eraseRadius) {
          currentSegment.push(point);
        } else {
          if (currentSegment.length >= 2) {
            newSegments.push(currentSegment);
          }
          currentSegment = [];
        }
      }
      if (currentSegment.length >= 2) {
        newSegments.push(currentSegment);
      }
      if (newSegments.length > 0) {
        hillSegments.splice(s, 1, ...newSegments);
      } else {
        hillSegments.splice(s, 1);
      }
    }
  }

  draw();
</script>
</body>
</html>

Можешь сделать так, чтобы она работала на телефоне? Чтобы пользователь мог рисовать горку пальцем как мышью на компьютере?