SOURCE

console 命令行工具 X clear

                    
>
console
const grid = document.querySelector('#grid')
const up = document.querySelector('#up')
const down = document.querySelector('#down')
const left = document.querySelector('#left')
const right = document.querySelector('#right')
let botPos = {x:0, y:0, i:0}
let starPos1 = {x:0, y:0}
let starPos2 = {x:0, y:0}
let starPos3 = {x:0, y:0}
let nStars = 0
let level = 1

for (let row=0; row<10; row++){
  for (let col=0; col<10; col++){
    let dot = document.createElementNS("http://www.w3.org/2000/svg", "circle")
    gsap.set(dot, {attr:{cx:5+col*10, cy:5+row*10, r:1, class:'dot'}})
    grid.appendChild(dot)
  }
}

start()
function start(){
  botPos = {x:0, y:0, i:0}
  
  for (let i=1; i<=3; i++){
    let starPos = eval('starPos'+i)
    starPos.x = gsap.utils.random(1, 9, 1) * 10
    starPos.y = gsap.utils.random(3*(i-1), (i<3)?i*3-1:9, 1) * 10
  }
  gsap.timeline()
    .set('svg', {opacity:1})
    .set('#star1', {...starPos1, transformOrigin:'50%'})
    .set('#star2', {...starPos2, transformOrigin:'50%'})
    .set('#star3', {...starPos3, transformOrigin:'50%'})    
    .to('text', {duration:0.4, opacity:0, scale:2, transformOrigin:'50%', ease:'back.in(3)'}, 0.5)
    .fromTo('.dot', {scale:0.5, rotate:0, opacity:0, svgOrigin:'50 50'}, {scale:1, opacity:1, stagger:{grid:[10,10],from:'center',amount:0.4}, ease:'back.out(3)'}, 1)
    .fromTo('#bot, .stars use', {opacity:0, scale:1},{opacity:1, stagger:0.05, ease:'expo'})
}

function move(t){
  gsap.fromTo(t, {attr:{fill:'#fff'}}, {attr:{fill:'#000'}, duration:0.2, ease:'power2.in', overwrite:'auto'})
  if (gsap.isTweening('#bot')) return;
  if (t == up && botPos.y>0){ botPos.y-=10; botPos.i-=10 }
  if (t == down && botPos.y<90){ botPos.y+=10; botPos.i+=10 }
  if (t == left && botPos.x>0){ botPos.x-=10; botPos.i-=1 }
  if (t == right && botPos.x<90){ botPos.x+=10; botPos.i+=1 }
  gsap.to('#bot', {duration:0.2, ease:'back', x:botPos.x, y:botPos.y})
  
  for (let i=1; i<=3; i++){
    const starPos = eval('starPos'+i)
    if ( botPos.x==starPos.x && botPos.y==starPos.y ){
      starPos.x = -1
      gsap.to('#star'+i, {scale:3, opacity:0})
      nStars++
      gsap.fromTo('.mouth', {attr:{d:'M3,6.8L4,6.8L6,6.8L7,6.8'}},{attr:{d:'M3,6L4,7L6,7L7,6'}, yoyo:true, repeat:1, ease:'expo.inOut', repeatDelay:0.2})
      gsap.to('.markers use', {attr:{fill:(i)=>(i+1<=nStars)?'#fff':'#000'}, onComplete:end})      
    }
  }
}

function end(){
  if (nStars==3){
    nStars = 0
    level++
    gsap.timeline({onComplete:start})
    .to('#bot', {opacity:0, ease:'expo.inOut'})
    .fromTo('.dot', {scale:1, svgOrigin:'50 50', opacity:1, rotate:0}, {rotate:(level%2==0)?-45:45, scale:0.6, opacity:0, stagger:{grid:[10,10],from:'center',amount:0.6}, ease:'back.inOut'}, '-=0.5')
    .to('.markers use', {attr:{fill:'#000'}, ease:'power2.inOut', stagger:-0.1})
    .fromTo('text', {scale:0, opacity:0, textContent:'LEVEL '+level},{scale:1, opacity:1, ease:'back.out(3)'})
    .set('#bot',  {x:0, y:0})
  }
}

up.onpointerup = down.onpointerup = 
left.onpointerup = right.onpointerup = (e)=> move(e.currentTarget)

window.onkeydown = (e)=> {
  if (e.keyCode){
    if (e.keyCode==38) move(up)
    if (e.keyCode==40) move(down)
    if (e.keyCode==37) move(left)
    if (e.keyCode==39) move(right)
  }
}
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/gsap/3.9.1/gsap.min.js"></script>
<svg id="game" viewBox="0 0 100 100" style="opacity:0">
  <g id="grid" fill="#fff"></g>
  <g id="bot" stroke="#fff">
<!--     <path d="M5,2L5,-2"/>
    <circle cx="5" cy="-2" r="0.7"/> -->
    <rect x="-0.5
" y="4" width="11" height="2" rx="0.5"/>
    <rect x="1
" y="1" width="8" height="8" rx="2"/>
    <circle cx="4" cy="4" r="1" />
    <circle cx="6" cy="4" r="1" />
    <path class="mouth" d="M3,6.8L4,6.8L6,6.8L7,6.8" fill="none" />
  </g>
  <g class="stars" stroke="#fff">
    <defs>
      <path id="star" d="M5,2L6,4L8,4.5L6.5,6L7,8L5,7L3,8L3.5,6L2,4.5L4,4z" />
    </defs>
    <use id="star1" href="#star"/>
    <use id="star2" href="#star"/>
    <use id="star3" href="#star"/>
  </g>
  <text fill="#fff" text-anchor="middle" x="50" y="55">LEVEL 1</text>
</svg>
<svg id="controls" viewBox="0 0 100 30" stroke="#fff" stroke-width="0.5">
  <rect id="up" x="65" y="1" width="12" height="12" rx="3"/>
  <rect id="down" x="65" y="17" width="12" height="12" rx="3"/>
  <rect id="left" x="50" y="9" width="12" height="12" rx="3"/>
  <rect id="right" x="80" y="9" width="12" height="12" rx="3"/>
  <g class="markers">
    <use href="#star" x="10" y="9"/>
    <use href="#star" x="20" y="9"/>
    <use href="#star" x="30" y="9"/>
  </g>
</svg>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap');

html, body {
  width:100%;
  height:100%;
  overflow:hidden;
  display: flex;
  flex-direction:column;
  align-items: center;
  justify-content: center;
  background:#000;
  font-family: 'Roboto', sans-serif;
  font-weight:900;
  font-size:12px;
}

#game {
  width:80%;
  height:80%;
  overflow:visible;
}