streams 타일 뽑기

Erdos·2026년 2월 1일

노는게 제일좋지

목록 보기
4/5
post-thumbnail

제작

  • 일반적인 보드게임들은 보통 4명이 최적의 인원, 많아봤자 6~8명 안팎으로 플레이가 가능하다.

  • 하지만, 이 스트림스 게임은 다수의 사람들(1~99명)이 동시에 즐길 수 있다는 장점이 있다.

  • 설날 이벤트로 꿀떡 컨셉, antigravity로 딸깍 만들어보았다.

  • 왜 꿀떡 컨셉이냐면,
    꿀떡을 나눠먹고 선물을 교환하고 네트워킹하는 이벤트를 기획했기 때문이다.

  • 사이트: https://erdoslibrary.github.io/streams/

    • GitHub Pages활용
    • 무료, 정적 웹 호스팅 서비스(내 깃허브 저장소에 있는 코드를 실제 웹사이트로 바꿔주는 기능)
    • 완전 무료
    • 자동 배포(CI/CD)
  • 소스코드: https://github.com/erdoslibrary/streams

느낀점

  • 무척 단순한 페이지지만 프론트를 아무것도 모르는 사람이 프롬프트를 입력해서 웹페이지가 나오는 건 내게도 충격이었다.
  • 그럼에도 불구하고, 언어의 구조/설계를 모르는 입장에서 다소 아쉬운 결과물이 나오긴 했다. 바이브 코딩이 대세라지만, 어떻게 사용하는지 어떤 흐름을 가지고 어떻게 만드는지 골격은 알고 만들어야겠다.
  • 이거 잘못하면 저작권 침해.....
  • 웹이지만, 현재 진행하는 그래픽스 과제와 코드 흐름이 꽤 비슷하다는 인상을 받았다.
  • 뭐에서 공통점을 느꼈는가? -> 이벤트 기반 프로그래밍
    • 유저의 클릭, 키보드 입력, 시스템이 보내는 신호(event)에 의해 프로그램의 흐름이 변동됨
    • event loop: 프로그램이 무슨일이 일어났나~ 하면서 계속 확인하는 심장부
    • event queue: 동시다발적으로 발생하는 이벤트(클릭, 마우스 이동 등)를 발생 순서대로 줄을 세워두는 대기열
    • event handler/callback: 특정 이벤트가 발생했을 때 이렇게 행동하세요. 라는 함수들
  • ai 가 알려주는 MLX와 JS의 비교
개념JavaScript (High-level)MLX / C (Low-level)
추상화 (Abstraction)브라우저 엔진이 이벤트 루프와 큐를 내부적으로 관리하여 개발자는 로직에만 집중 가능개발자가 직접 mlx_loop를 실행하고 각 상황에 맞는 Hook 함수를 설계하고 연결해야 함
메모리 (Memory)가비지 컬렉터(GC)가 더 이상 사용되지 않는 변수를 자동으로 정리하여 메모리 누수 방지mlx_new_image 등으로 할당한 메모리는 반드시 mlx_destroy_image 등을 통해 직접 해제해야 함
렌더링 (Rendering)ctx.fillRect나 ctx.arc와 같이 이미 구현된 고수준 API를 호출하여 손쉽게 그래픽 구현이미지 버퍼의 시작 주소를 얻어와 각 픽셀의 메모리 주소(int pointer)에 직접 색상 값을 써넣어야 함

개선점

  • TV를 연결해서 활용할 예정인데, 하나씩 뽑히는 떡 타일이 너무 작은 건 아닐까..
  • 화면 분할을 좌우로 했는데, 핸드폰에서는 겹치는 부분이 일부 있음
  • 복주머니와 뽑힌 떡 숫자를 정중앙에 가장 돋보이게 배치하고, history는 화면 하단에 가로로 최대 20개 배치하는 게 더 적절할 것 같다.
  • 20번째 떡을 뽑은 순간 새로운 창(modal=안내창)이 뜨면서 이전까지 뽑은 떡이 가려진다는 단점

streams란?

  • 오름차순 빙고게임


🛠 stack

  • Languages: Vanilla JavaScript(ES6+), HTML5, CSS3
  • Web APIs: Canvas API (Real-time Physics), Web Audio API (Sound Synthesis)
  • Styling: Modern CSS (Flexbox, CSS Variables, Keyframe Animations)

이번 생에 front는 처음이라..(?)

분명히 꾸글 모임으로 용어를 여러 번 들었는데, 듣기만 한 공부는 흘러가버렸구나..

1. Vanilla JavaScript

  • vinilla: SW에서 아무런 수정이나 추가 기능이 없는 순정 상태. jQuery, React, Vue, Angular와 같은 외부 도구를 전혀 사용하지 않고 브라우저가 기본으로 제공하는 기능만 사용하는 방식

2. HTML5 (Semantic Markup)

  • 웹 표준을 준수하여 구조화된 문서 설계
  • semantic: 의미론적인, "header"와 같은 태그를 사용하여 구조를 더 정확히 설계
  • 효과음을 위해 사용한 AudioContext나 시각효과를 위한 "canvas" 태그가 HTML5의 핵심 기능.
    -> 멀티미디어 및 웹 앱플랫폼
  • WHATWG

3. CSS3

  • Cascading Style Sheets Level 3
  • 특성: Modern CSS (Flexbox/Grid)
  • flexbox도입으로 정렬을 직관적으로 함
    -> cf) 선(1차원)의 배치에 강함. Grid는 면(2차원) 배치에 강함.

html? css? js?

index.html

Structure: 브라우저가 읽어 들여 화면에 그릴 모든 객체의 목록을 담고 있다

  • 컴포넌트 정의: 게임 제목, 떡의 개수를 표시하는 배지, 복주머니, 결과 창, 히스토리, 그리드 등 HTML 태그로 선언
  • 식별자 부여: 자바스크립트가 접근할 수 있도록 각 요소(ex. currentTile, resetBtn)를 부여하여 '동작의 대상'을 명확하게 한다.
  • 상태 준비: 게임 종료시 나타날 modal 창과 꽃가루가 터질 canvas 공간을 미리 만들어 둔다.
  • 외부 자원 연결: google fonts로부터 폰트를 불러오고, CSS와 JS 파일을 연결하여 하나의 앱으로 묶어 준다.

style.css

Presentation: 정적인 HTML 요소를 예쁘고 생동감 있게 바꾼다

  • 테마 및 변수 관리: ':root'를 통해 브랜드 컬러(떡 색깔, 배경색 등)를 변수로 선언하고 유지보수성을 높임
  • 레이아웃 설계: Flexbox를 활용해 좌측(조작 영역)과 우측(결과 영역)으로 화면 분할, 모바일 환경에서도 최적화되도록 미디어 쿼리(@media) 적용
    - 하지만, 모바일 환경 최적화가 좀 더 필요하다.
  • 애니메이션 구현: 토끼의 숨쉬기(breath), 주머니를 누를 때의 쫄깃한 느낌(squeeze), 모달이 나타나는 효과(popIn) 등을 정의, 일종에 손맛 추가
  • 사용자 정의 커서: 마우스 커서를 당근 모양으로 바꿈

script.js

Behavior: 사용자의 행동에 따라 데이터가 어떻게 변하고 화면이 어떻게 바뀌어야 하는지를 결정

  • 상태 관리(state management): 현재 주머니의 남은 떡의 목록(bag), 진행된 턴 수(turnCount) 등을 변수로 관리
  • suffle: 1~30번 타일과 별 타일을 생성하고(generateTiles) 이를 공정하게 섞음
  • 이벤트 처리: 사용자가 복주머니를 클릭하면 떡을 뽑는다(performDraw). 그리고 화면에 업데이트 (displayTile)하며 히스토리에 기록을 남김(addToHistory)
  • 멀티미디어 제어: AudioContext를 사용하여 동적으로 효과음을 생성, Canvas API를 직접 조작해 물리 연산이 가미된 꽃가루 효과를 렌더링한다.

꽃가루 로직

중력 계산이라니? 갑자기 물리 시간

// 1. 붓(ctx) 준비
const ctx = confettiCanvas.getContext('2d');

function updateConfetti() {
    // 2. 이전 프레임의 그림을 지움
    ctx.clearRect(0, 0, confettiCanvas.width, confettiCanvas.height);

    for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        // 3. 입자의 위치를 옮김 (중력 가속도 등 적용). <-???????????????
        p.x += p.vx; //수평 방향으로는 등속 운동
        p.y += p.vy; // 수직 관련 
        p.vy += 0.5; //<- 여기가 중력 가속도 적용 지점

        // 4. 새로운 위치에 색칠된 사각형을 그람
        ctx.fillStyle = p.color;
        ctx.fillRect(p.x, p.y, p.size, p.size); 
    }

    // 5. 다음 장면을 그리도록 브라우저에 요청
    if (particles.length > 0) requestAnimationFrame(updateConfetti);
}
p.vy += 0.5; //<- 여기가 중력 가속도 적용 지점
  • 0.5 -> 0.1로 줄이면 중력이 줄어들어서 천천히 떨어짐
  • 0.5 -> 1 중력이 늘어나서 빨리 떨어짐. WOW
  • 오일러 적분(Euler Integration)을 활용하였다고..
profile
수학을 사랑하는 애독자📚 Stop dreaming. Start living. - 'The Secret Life of Walter Mitty'

1개의 댓글

comment-user-thumbnail
2026년 2월 12일

재밌는 프로젝트 하셨네요.
짧은 사이에 괴물이 돼버리신 모습에 놀랐습니다.

익숙한 게임이라 생각했는데 컴플레또(Completto)랑 비슷하네요.
잊고 살았는데 감사합니다.

답글 달기