your personal website on atproto - mirror
0
fork

Configure Feed

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

commit

Florian 8f117a26 e45e8007

+91 -27
src/lib/cards/TetrisCard/SidebarItemTetrisCard.svelte src/lib/cards/GameCards/TetrisCard/SidebarItemTetrisCard.svelte
src/lib/cards/TetrisCard/Tetris8Bit.mp3 src/lib/cards/GameCards/TetrisCard/Tetris8Bit.mp3
+87 -22
src/lib/cards/TetrisCard/TetrisCard.svelte src/lib/cards/GameCards/TetrisCard/TetrisCard.svelte
··· 1 1 <script lang="ts"> 2 - import type { ContentComponentProps } from '../types'; 2 + import type { ContentComponentProps } from '../../types'; 3 3 import { onMount, onDestroy } from 'svelte'; 4 4 import Tetris8BitMusic from './Tetris8Bit.mp3'; 5 5 import { isTyping } from '$lib/helper'; ··· 97 97 98 98 function getColorScheme(): Record<string, string> { 99 99 // Get colors that contrast well with the current background 100 - const excludeColors = isAccentMode && detectedAccentFamily 101 - ? COLOR_FAMILIES[detectedAccentFamily] || [] 102 - : []; 100 + const excludeColors = 101 + isAccentMode && detectedAccentFamily ? COLOR_FAMILIES[detectedAccentFamily] || [] : []; 103 102 104 103 // Pick 7 contrasting vibrant colors for the 7 tetrominos 105 104 const availableColors = Object.entries(VIBRANT_COLORS) ··· 126 125 S: '#34d399', // emerald-400 127 126 Z: '#fb7185', // rose-400 128 127 J: '#60a5fa', // blue-400 129 - L: '#a3e635' // lime-400 128 + L: '#a3e635' // lime-400 130 129 }; 131 130 } 132 131 ··· 151 150 S: '#10b981', // emerald 152 151 Z: '#f43f5e', // rose 153 152 J: '#3b82f6', // blue 154 - L: '#84cc16' // lime 153 + L: '#84cc16' // lime 155 154 }; 156 155 } 157 156 158 157 // Tetromino definitions (each has rotations) 159 158 const TETROMINOES = { 160 159 I: { shape: [[1, 1, 1, 1]] }, 161 - O: { shape: [[1, 1], [1, 1]] }, 162 - T: { shape: [[0, 1, 0], [1, 1, 1]] }, 163 - S: { shape: [[0, 1, 1], [1, 1, 0]] }, 164 - Z: { shape: [[1, 1, 0], [0, 1, 1]] }, 165 - J: { shape: [[1, 0, 0], [1, 1, 1]] }, 166 - L: { shape: [[0, 0, 1], [1, 1, 1]] } 160 + O: { 161 + shape: [ 162 + [1, 1], 163 + [1, 1] 164 + ] 165 + }, 166 + T: { 167 + shape: [ 168 + [0, 1, 0], 169 + [1, 1, 1] 170 + ] 171 + }, 172 + S: { 173 + shape: [ 174 + [0, 1, 1], 175 + [1, 1, 0] 176 + ] 177 + }, 178 + Z: { 179 + shape: [ 180 + [1, 1, 0], 181 + [0, 1, 1] 182 + ] 183 + }, 184 + J: { 185 + shape: [ 186 + [1, 0, 0], 187 + [1, 1, 1] 188 + ] 189 + }, 190 + L: { 191 + shape: [ 192 + [0, 0, 1], 193 + [1, 1, 1] 194 + ] 195 + } 167 196 }; 168 197 169 198 type TetrominoType = keyof typeof TETROMINOES; ··· 202 231 } 203 232 } 204 233 205 - function playTone(frequency: number, duration: number, type: OscillatorType = 'square', volume: number = 0.04) { 234 + function playTone( 235 + frequency: number, 236 + duration: number, 237 + type: OscillatorType = 'square', 238 + volume: number = 0.04 239 + ) { 206 240 if (!audioCtx) return; 207 241 try { 208 242 const oscillator = audioCtx.createOscillator(); ··· 604 638 const elapsed = performance.now() - touchStartTime; 605 639 606 640 // Quick tap (no movement) - rotate 607 - if (!hasMoved && Math.abs(dx) < SWIPE_THRESHOLD && Math.abs(dy) < SWIPE_THRESHOLD && elapsed < 300) { 641 + if ( 642 + !hasMoved && 643 + Math.abs(dx) < SWIPE_THRESHOLD && 644 + Math.abs(dy) < SWIPE_THRESHOLD && 645 + elapsed < 300 646 + ) { 608 647 rotatePiece(); 609 648 return; 610 649 } ··· 683 722 detectTheme(); 684 723 685 724 const colors = getColorScheme(); 686 - const textColor = isAccentMode ? '#000000' : (isDarkMode ? '#ffffff' : '#000000'); 687 - const gridBgColor = isAccentMode ? 'rgba(0, 0, 0, 0.15)' : (isDarkMode ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)'); 688 - const gridLineColor = isAccentMode ? 'rgba(0, 0, 0, 0.1)' : (isDarkMode ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.08)'); 725 + const textColor = isAccentMode ? '#000000' : isDarkMode ? '#ffffff' : '#000000'; 726 + const gridBgColor = isAccentMode 727 + ? 'rgba(0, 0, 0, 0.15)' 728 + : isDarkMode 729 + ? 'rgba(255, 255, 255, 0.05)' 730 + : 'rgba(0, 0, 0, 0.05)'; 731 + const gridLineColor = isAccentMode 732 + ? 'rgba(0, 0, 0, 0.1)' 733 + : isDarkMode 734 + ? 'rgba(255, 255, 255, 0.05)' 735 + : 'rgba(0, 0, 0, 0.08)'; 689 736 690 737 const canvasWidth = canvas.width; 691 738 const canvasHeight = canvas.height; ··· 746 793 // Already swept - show white fading out 747 794 const fadeProgress = Math.min(1, (swooshCol - col - 1) / 2); 748 795 ctx.fillStyle = `rgba(255, 255, 255, ${1 - fadeProgress})`; 749 - ctx.fillRect(offsetX + col * cellSize, offsetY + row * cellSize, cellSize - 1, cellSize - 1); 796 + ctx.fillRect( 797 + offsetX + col * cellSize, 798 + offsetY + row * cellSize, 799 + cellSize - 1, 800 + cellSize - 1 801 + ); 750 802 } else if (col < swooshCol) { 751 803 // Sweep edge - bright white 752 804 ctx.fillStyle = '#ffffff'; 753 - ctx.fillRect(offsetX + col * cellSize, offsetY + row * cellSize, cellSize - 1, cellSize - 1); 805 + ctx.fillRect( 806 + offsetX + col * cellSize, 807 + offsetY + row * cellSize, 808 + cellSize - 1, 809 + cellSize - 1 810 + ); 754 811 } else { 755 812 // Not yet swept - show block 756 813 drawBlock(offsetX + col * cellSize, offsetY + row * cellSize, cellColor); ··· 817 874 const previewY = offsetY; 818 875 819 876 // Semi-transparent background 820 - ctx.fillStyle = isAccentMode ? 'rgba(255, 255, 255, 0.3)' : (isDarkMode ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.5)'); 877 + ctx.fillStyle = isAccentMode 878 + ? 'rgba(255, 255, 255, 0.3)' 879 + : isDarkMode 880 + ? 'rgba(0, 0, 0, 0.4)' 881 + : 'rgba(255, 255, 255, 0.5)'; 821 882 ctx.fillRect(previewX, previewY, previewWidth, previewHeight); 822 883 823 884 // Only show "NEXT" label if there's enough space ··· 850 911 const scorePadding = 4; 851 912 852 913 // Semi-transparent background 853 - ctx.fillStyle = isAccentMode ? 'rgba(255, 255, 255, 0.3)' : (isDarkMode ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.5)'); 914 + ctx.fillStyle = isAccentMode 915 + ? 'rgba(255, 255, 255, 0.3)' 916 + : isDarkMode 917 + ? 'rgba(0, 0, 0, 0.4)' 918 + : 'rgba(255, 255, 255, 0.5)'; 854 919 const scoreBoxWidth = Math.max(40, scoreSize * 4); 855 920 const scoreBoxHeight = cellSize >= 12 ? scoreSize * 2.5 : scoreSize * 1.5; 856 921 ctx.fillRect(offsetX, offsetY, scoreBoxWidth, scoreBoxHeight); ··· 957 1022 {#if gameState === 'idle' || gameState === 'gameover'} 958 1023 <button 959 1024 onclick={startGame} 960 - class="absolute bottom-4 left-1/2 -translate-x-1/2 transform cursor-pointer rounded-lg border-2 border-base-800 bg-base-100/80 px-4 py-2 font-mono text-xs font-bold text-base-800 transition-colors hover:bg-base-800 hover:text-base-100 dark:border-base-200 dark:bg-base-800/80 dark:text-base-200 dark:hover:bg-base-200 dark:hover:text-base-800 accent:border-base-900 accent:bg-white/80 accent:text-base-900 accent:hover:bg-base-900 accent:hover:text-white" 1025 + class="border-base-800 bg-base-100/80 text-base-800 hover:bg-base-800 hover:text-base-100 dark:border-base-200 dark:bg-base-800/80 dark:text-base-200 dark:hover:bg-base-200 dark:hover:text-base-800 accent:border-base-900 accent:bg-white/80 accent:text-base-900 accent:hover:bg-base-900 accent:hover:text-white absolute bottom-4 left-1/2 -translate-x-1/2 transform cursor-pointer rounded-lg border-2 px-4 py-2 font-mono text-xs font-bold transition-colors" 961 1026 > 962 1027 {gameState === 'gameover' ? 'PLAY AGAIN' : 'START'} 963 1028 </button>
+3 -4
src/lib/cards/TetrisCard/index.ts src/lib/cards/GameCards/TetrisCard/index.ts
··· 1 1 //Music by DJARTMUSIC - The Return Of The 8-bit Era 2 2 //https://pixabay.com/de/music/videospiele-the-return-of-the-8-bit-era-301292/ 3 3 4 - 5 - import type { CardDefinition } from '../types'; 4 + import type { CardDefinition } from '../../types'; 6 5 import TetrisCard from './TetrisCard.svelte'; 7 6 import SidebarItemTetrisCard from './SidebarItemTetrisCard.svelte'; 8 7 ··· 15 14 createNew: (card) => { 16 15 card.w = 4; 17 16 card.h = 6; 18 - card.mobileW = 6; 19 - card.mobileH = 8; 17 + card.mobileW = 8; 18 + card.mobileH = 12; 20 19 card.cardData = {}; 21 20 }, 22 21 maxH: 10
+1 -1
src/lib/cards/index.ts
··· 5 5 import { BlueskyPostCardDefinition } from './BlueskyPostCard'; 6 6 import { DinoGameCardDefinition } from './GameCards/DinoGameCard'; 7 7 import { EmbedCardDefinition } from './EmbedCard'; 8 - import { TetrisCardDefinition } from './TetrisCard'; 8 + import { TetrisCardDefinition } from './GameCards/TetrisCard'; 9 9 import { ImageCardDefinition } from './ImageCard'; 10 10 import { LinkCardDefinition } from './LinkCard'; 11 11 import { LivestreamCardDefitition, LivestreamEmbedCardDefitition } from './LivestreamCard';