vod frog, frog with the vods
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix flies: spawn from edges, clamp rotation to ±30deg, flip when moving right

+30 -6
+30 -6
src/lib/FlySpawner.svelte
··· 17 17 targetX: number; // where it's heading (%) 18 18 targetY: number; // where it's heading (%) 19 19 rotation: number; // current rotation (deg) 20 + flipped: boolean; // true when moving right (sprite faces left by default) 20 21 splatted: boolean; // has it been clicked? 21 22 fading: boolean; // is it fading out after splat? 22 23 } ··· 26 27 let spawnTimer: ReturnType<typeof setTimeout> | null = null; 27 28 let moveInterval: ReturnType<typeof setInterval> | null = null; 28 29 30 + /** Random position for fly targets — anywhere on screen */ 29 31 function randomPercent() { 30 - return Math.random() * 80 + 10; // 10–90% to stay away from edges 32 + return Math.random() * 80 + 10; // 10–90% 33 + } 34 + 35 + /** Spawn position — always from a screen edge */ 36 + function edgeSpawnPosition(): { x: number; y: number } { 37 + const edge = Math.floor(Math.random() * 4); 38 + switch (edge) { 39 + case 0: return { x: -5, y: Math.random() * 100 }; // left 40 + case 1: return { x: 105, y: Math.random() * 100 }; // right 41 + case 2: return { x: Math.random() * 100, y: -5 }; // top 42 + default: return { x: Math.random() * 100, y: 105 }; // bottom 43 + } 31 44 } 32 45 33 46 function spawnFly() { ··· 36 49 return; 37 50 } 38 51 52 + const spawn = edgeSpawnPosition(); 39 53 const fly: Fly = { 40 54 id: nextId++, 41 - x: randomPercent(), 42 - y: randomPercent(), 55 + x: spawn.x, 56 + y: spawn.y, 43 57 targetX: randomPercent(), 44 58 targetY: randomPercent(), 45 - rotation: Math.random() * 360, 59 + rotation: (Math.random() - 0.5) * 20, 60 + flipped: false, 46 61 splatted: false, 47 62 fading: false, 48 63 }; ··· 96 111 const speed = 0.4 + Math.random() * 0.3; 97 112 const wobbleX = (Math.random() - 0.5) * 1.5; 98 113 const wobbleY = (Math.random() - 0.5) * 1.5; 114 + 115 + // Sprite faces left by default, so 0° = moving left. 116 + // Only rotate ±30° from the current heading to keep it level. 99 117 const angle = Math.atan2(dy, dx) * (180 / Math.PI); 118 + // Clamp to a gentle wobble: -30° to +30° from horizontal 119 + const clampedAngle = Math.max(-30, Math.min(30, angle > 90 ? angle - 180 : angle < -90 ? angle + 180 : angle)); 120 + 121 + // Flip horizontally when moving right (sprite faces left by default) 122 + const movingRight = dx > 0; 100 123 101 124 return { 102 125 ...f, 103 126 x: f.x + (dx / dist) * speed + wobbleX, 104 127 y: f.y + (dy / dist) * speed + wobbleY, 105 - rotation: angle + (Math.random() - 0.5) * 30, 128 + rotation: clampedAngle + (Math.random() - 0.5) * 10, 129 + flipped: movingRight, 106 130 }; 107 131 }); 108 132 } ··· 125 149 class="fly" 126 150 class:splatted={fly.splatted} 127 151 class:fading={fly.fading} 128 - style="left: {fly.x}%; top: {fly.y}%; transform: rotate({fly.rotation}deg);" 152 + style="left: {fly.x}%; top: {fly.y}%; transform: rotate({fly.rotation}deg) scaleX({fly.flipped ? -1 : 1});" 129 153 onmousedown={() => splatFly(fly.id)} 130 154 ontouchstart={() => splatFly(fly.id)} 131 155 >