Skip to content

Latest commit

ย 

History

History
121 lines (110 loc) ยท 9.95 KB

File metadata and controls

121 lines (110 loc) ยท 9.95 KB

์ƒ‰์‹ค ํ’€๊ธฐ (Thread Sort) ์ง„ํ–‰ ์ƒํ™ฉ

์ตœ๊ทผ ์—…๋ฐ์ดํŠธ: 2026-02-28 (6์ฐจ)

์™„๋ฃŒ๋œ ์ž‘์—…

  • [2026-02-27] ๊ฒŒ์ž„ ์ปจ์…‰ ํ™•์ •: ์†ŒํŒ… ํผ์ฆ (Wool Sort / Tangle ๊ณ„์—ด)

  • [2026-02-27] ๊ธฐ์ˆ  ์Šคํƒ ํ™•์ •: React + Vite + HTML5 Canvas

  • [2026-02-27] ์ƒ์„ธ ๊ธฐํš์„œ ์ž‘์„ฑ ์™„๋ฃŒ (v1.0)

  • [2026-02-27] ์‹œ์žฅ ์กฐ์‚ฌ + ๋ ˆํผ๋Ÿฐ์Šค ๋ถ„์„ ์™„๋ฃŒ

  • [2026-02-27] ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ธํŒ… ์™„๋ฃŒ โ€” Frontend Developer

    • React 19 + Vite + Zustand + Howler ์˜์กด์„ฑ ์„ค์น˜
    • ์ „์ฒด ํด๋” ๊ตฌ์กฐ ์ƒ์„ฑ
    • GameLoop, Renderer, InputManager, GameCanvas, HomeScreen, GameplayScreen ๊ตฌํ˜„
    • Zustand ์Šคํ† ์–ด, ๊ฒŒ์ž„ ์ƒ์ˆ˜, utils/math, utils/tween ๊ตฌํ˜„
    • Thread.js, Bobbin.js, Puzzle.js, PuzzleGenerator.js (์—ญ๋ฐฉํ–ฅ ์ƒ์„ฑ + BFS ์†”๋ฒ„) ๊ตฌํ˜„
    • git init + ์ฒซ ์ปค๋ฐ‹ ์™„๋ฃŒ
  • [2026-02-27] ์ฝ”์–ด ๊ฒŒ์ž„ํ”Œ๋ ˆ์ด ๊ตฌํ˜„ ์™„๋ฃŒ โ€” Frontend Developer

    • ์‹ค(Thread) ๋ Œ๋”๋ง: ํ๋น… ๋ฒ ์ง€์–ด ๊ณก์„ , DESIGN.md 8์ƒ‰ ํŒ”๋ ˆํŠธ, ์™ธ๊ณฝ์„ +ํ•˜์ด๋ผ์ดํŠธ ๊ด‘ํƒ ๋ ˆ์ด์–ด
    • ์‹ค ๊ฒน์นจ z-order: zIndex ๊ธฐ๋ฐ˜ ์ •๋ ฌ ๋ Œ๋”๋ง
    • Free End ๋งˆ์ปค: ํŽ„์Šค ์• ๋‹ˆ๋ฉ”์ด์…˜ (1.5์ดˆ ์ฃผ๊ธฐ), ๋„“์€ ํžˆํŠธ ์˜์—ญ (r=28px)
    • ์‹ค ์„ ํƒ ์‹œ๊ฐ ํ”ผ๋“œ๋ฐฑ: ์„ ํƒ ์‹ค ๋ฐœ๊ด‘+๊ตต์–ด์ง, ๋น„์„ ํƒ ์‹ค ๋ฐ˜ํˆฌ๋ช…(opacity 0.4)+blur
    • ๋ณด๋นˆ ๋ Œ๋”๋ง: ๋‚˜๋ฌด ๋ณด๋นˆ (์ƒ/ํ•˜ ํ”Œ๋žœ์ง€+Core), ์‹ค ์ฑ„์›€ ๋‹จ๊ณ„ ์‹œ๊ฐํ™” (์ค„๋ฌด๋Šฌ ์งˆ๊ฐ), ์ƒ‰์ƒ ๋ผ๋ฒจ ์›
    • ํƒญ-ํƒญ ์กฐ์ž‘: ์‹ค ๋ ํƒญ โ†’ ๋ณด๋นˆ ํƒญ ์ด๋™, ์ž˜๋ชป๋œ ๋ณด๋นˆ ๊ฑฐ๋ถ€ ํ”๋“ค๋ฆผ ์• ๋‹ˆ๋ฉ”์ด์…˜
    • ์‹ค ๊ฐ๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜: De Casteljau subdivision์œผ๋กœ ๋ฒ ์ง€์–ด ๊ฒฝ๋กœ ์ ์ง„ ์†Œ๋ฉธ (500ms Tween)
    • ๋ณด๋นˆ ํ•˜์ด๋ผ์ดํŠธ: ์„ ํƒ ์‹ค ์ƒ‰์ƒ์— ๋งž๋Š” ๋ณด๋นˆ๋งŒ ๊ฐ•์กฐ, ํ‹€๋ฆฐ ๋ณด๋นˆ ๋ฐ˜ํˆฌ๋ช…
    • ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ: ๋ณด๋นˆ ์™„์„ฑ ํŒŒํ‹ฐํด 16๊ฐœ fanout, ์Šคํ…Œ์ด์ง€ ํด๋ฆฌ์–ด 60๊ฐœ ํŒŒํ‹ฐํด
    • ํผ์ฆ ๋กœ์ง ์—ฐ๋™: PuzzleGenerator ์—ญ๋ฐฉํ–ฅ ์ƒ์„ฑ, Puzzle.move/undo/isCleared/isFailed/isDeadlocked
    • Undo: ๋ฌด๋ฃŒ ๋˜๋Œ๋ฆฌ๊ธฐ (Move ์†Œ๋ชจ ์—†์Œ)
    • Move ์นด์šดํ„ฐ HUD: ์ž”์—ฌ 5 ์ดํ•˜ ์‹œ ๋นจ๊ฐ„์ƒ‰ pulse ๊ฒฝ๊ณ 
    • ๊ฒŒ์ž„ ํ๋ฆ„: ์Šคํ…Œ์ด์ง€ ์‹œ์ž‘ โ†’ ํผ์ฆ ์ƒ์„ฑ โ†’ ํ”Œ๋ ˆ์ด โ†’ ํด๋ฆฌ์–ด/์‹คํŒจ โ†’ ResultScreen
    • ๋ณ„์  ๊ณ„์‚ฐ: Move 50% ์ด๋‚ด 3์„ฑ, 70% ์ด๋‚ด 2์„ฑ, ์ดˆ๊ณผ 1์„ฑ
    • ๊ฒฐ๊ณผ ํ™”๋ฉด: ๋ณ„ ์ˆœ์ฐจ ๋“ฑ์žฅ ์• ๋‹ˆ๋ฉ”์ด์…˜, ์ฝ”์ธ ๋ณด์ƒ ํ‘œ์‹œ, ๋‹ค์Œ ์Šคํ…Œ์ด์ง€/๋‹ค์‹œํ•˜๊ธฐ/์Šคํ…Œ์ด์ง€ ์„ ํƒ ๋ฒ„ํŠผ
    • ์Šคํ…Œ์ด์ง€ ์„ ํƒ ํ™”๋ฉด: 10์Šคํ…Œ์ด์ง€ ๊ทธ๋ฆฌ๋“œ, ๋ณ„์  ํ‘œ์‹œ, ์–ธ๋ฝ ์‹œ์Šคํ…œ, ์ง„ํ–‰๋ฅ  ๋ฐ”
    • ๋ฉ”์ธ ํ™”๋ฉด: ์ฝ”์ธ ํ‘œ์‹œ, ์‹คํƒ€๋ž˜ SVG ์ผ๋Ÿฌ์ŠคํŠธ, ์Šคํ…Œ์ด์ง€ ์„ ํƒ/๋ฐ”๋กœ ์‹œ์ž‘ ๋ฒ„ํŠผ
    • ์ผ์‹œ์ •์ง€ ๋ชจ๋‹ฌ: ๊ณ„์†ํ•˜๊ธฐ/์žฌ์‹œ์ž‘/์Šคํ…Œ์ด์ง€ ์„ ํƒ/ํ™ˆ์œผ๋กœ ๋ฒ„ํŠผ
    • DESIGN.md ์ปฌ๋Ÿฌ/ํฐํŠธ ์‹œ์Šคํ…œ: CSS Custom Properties ์ „๋ฉด ์ ์šฉ
    • ๋ชจ๋ฐ”์ผ+๋ฐ์Šคํฌํ†ฑ ํ„ฐ์น˜/๋งˆ์šฐ์Šค ์ง€์› (InputManager)
    • ๋ฐ˜์‘ํ˜•: ResizeObserver ๊ธฐ๋ฐ˜, devicePixelRatio ์Šค์ผ€์ผ๋ง
  • [2026-02-27] ๋Ÿฐํƒ€์ž„ ๋ฒ„๊ทธ 5์ข… ์ˆ˜์ • ์™„๋ฃŒ โ€” Frontend Developer

    • [A] CSS @import Google Fonts โ†’ index.html <link> ํƒœ๊ทธ๋กœ ์ด์ „ (๋ Œ๋” ๋ธ”๋กœํ‚น ์ œ๊ฑฐ)
    • [B] Puzzle.isCleared: spare ๋ณด๋นˆ(colorIndex=-1)์„ ํด๋ฆฌ์–ด ์ฒดํฌ์—์„œ ์ œ์™ธ (ํผ์ฆ ํด๋ฆฌ์–ด ๋ถˆ๊ฐ€ ๋ฒ„๊ทธ ์ˆ˜์ •)
    • [C] PuzzleGenerator: THREAD_COLORS[i] (๊ฐ์ฒด ์ˆซ์ž ์ธ๋ฑ์Šค โ†’ undefined) โ†’ THREAD_COLOR_LIST[i] ๋ฐฐ์—ด๋กœ ๊ต์ฒด, import ์ˆ˜์ •
    • [D] Renderer.resize: ctx.scale() ๋ˆ„์  โ†’ ctx.setTransform() ์œผ๋กœ ๊ต์ฒด
    • [E] GameCanvas: ๋งˆ์šดํŠธ ์งํ›„ clientWidth/clientHeight๊ฐ€ 0์ธ ๊ฒฝ์šฐ rAF 1ํ”„๋ ˆ์ž„ ์žฌ์‹œ๋„ ๋กœ์ง ์ถ”๊ฐ€
    • ๋นŒ๋“œ ๋ฐ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ๋™์ž‘ ํ™•์ธ ์™„๋ฃŒ (http://localhost:5176)
  • [2026-02-27] ์กฐ์ž‘ ๋ฐฉ์‹ ๋ณ€๊ฒฝ: 2ํƒญ โ†’ 1ํƒญ ์ž๋™ ๋งค์นญ โ€” Frontend Developer

    • GameController.js: handleTap ๋ฆฌํŒฉํ„ฐ๋ง โ€” Free End ํƒญ ์‹œ ์ฆ‰์‹œ _attemptAutoMove ํ˜ธ์ถœ
    • ์ž๋™ ๋งค์นญ ์šฐ์„ ์ˆœ์œ„: ๊ฐ™์€ ์ƒ‰ ๋ณด๋นˆ(0) โ†’ ์ผ๋ฐ˜ ๋นˆ ๋ณด๋นˆ(1) โ†’ spare ๋นˆ ๋ณด๋นˆ(2) ์ˆœ ์ •๋ ฌ
    • ๊ฑฐ๋ถ€ ํ”ผ๋“œ๋ฐฑ: ์ด๋™ ๊ฐ€๋Šฅ ๋ณด๋นˆ ์—†์„ ์‹œ Free End ์ž์ฒด ์ขŒ์šฐ ํ”๋“ค๋ฆผ + ๋นจ๊ฐ„ flash (_shakeFreeEnd)
    • freeEndShakeState: Controller์—์„œ update(), Renderer์—์„œ ๋ Œ๋”๋ง ๋ถ„๋ฆฌ ๊ด€๋ฆฌ
    • GameRenderer.js: selectedBobbinId ๊ธฐ๋ฐ˜ ํ•˜์ด๋ผ์ดํŠธ/๋”ค/๋ฐœ๊ด‘ ํšจ๊ณผ ์ „๋ฉด ์ œ๊ฑฐ โ€” ๋ชจ๋“  ์‹ค ๋™๋“ฑ ๋ Œ๋”
    • Free End ๋งˆ์ปค: ๊ฑฐ๋ถ€ ์‹œ ๋นจ๊ฐ„ ์™ธ๊ณฝ ์› flash + ๋งˆ์ปค ์ƒ‰์ƒ ์ „ํ™˜ (DANGER ์ƒ‰)
    • GameCanvas.jsx: ๋ Œ๋” ํ˜ธ์ถœ์—์„œ selectedBobbinId ์ œ๊ฑฐ, freeEndShakeState ์ถ”๊ฐ€ ์ „๋‹ฌ
    • selectedBobbinId ์ƒํƒœ ํ•„๋“œ ์™„์ „ ์ œ๊ฑฐ (Undo, ์ด๋™ ์™„๋ฃŒ ํ›„ null ์ฒ˜๋ฆฌ ์ฝ”๋“œ ๋“ฑ)
    • ๋นŒ๋“œ ์—๋Ÿฌ ์—†์Œ ํ™•์ธ (http://localhost:5174)
  • [2026-02-27] ๋น„์ฃผ์–ผ ๋””์ž์ธ ๋ฆฌ์Šคํ‚จ ์™„๋ฃŒ โ€” Frontend Developer

    • ๋””์ž์ธ ํ† ํฐ ๊ต์ฒด: tenqube reward-webview ๋‘๋”์ง€์žก๊ธฐ ์Šคํƒ€์ผ๋กœ ์ „๋ฉด ์ ์šฉ
    • ๋ฐฐ๊ฒฝ: ์ „ ํ™”๋ฉด #FFF9F0/#FFF4E6/#F5EFE6 ์›œํ†ค โ†’ #ffffff ํด๋ฆฐ ํ™”์ดํŠธ
    • ์ฃผ์š” ์ƒ‰์ƒ: terracotta #E8734A ๊ณ„์—ด โ†’ ๋ธ”๋ฃจ #2761FF ๊ณ„์—ด ์ „๋ฉด ๊ต์ฒด
    • ํ…์ŠคํŠธ: #2C1A0E โ†’ #20222E, ๋ณด์กฐ #7A6A5A โ†’ #868686
    • ๋ฒ„ํŠผ: height 52px, border-radius 16px, font-weight 600 ํ†ต์ผ (๊ธฐ์กด 56px/28px pill ํ˜•ํƒœ์—์„œ ๋ณ€๊ฒฝ)
    • ๋น„ํ™œ์„ฑ/๋ณด์กฐ ๋ฒ„ํŠผ: #E8EAED bg ๋˜๋Š” white with border ์Šคํƒ€์ผ
    • ์ง„ํ–‰๋ฐ” fill: #C4845C โ†’ #2761FF
    • ์Šคํ…Œ์ด์ง€ ์นด๋“œ ํ˜„์žฌ ํ•˜์ด๋ผ์ดํŠธ: ์˜ค๋ Œ์ง€ โ†’ #2761FF (glow ring rgba(39,97,255,0.12))
    • HUD/ํˆด๋ฐ”: ๋ฐฐ๊ฒฝ white, ๋ณด๋” #E8EAED
    • ํžŒํŠธ ๋ฒ„ํŠผ: ์˜ค๋ Œ์ง€ FAB โ†’ #2761FF ๋ธ”๋ฃจ pill
    • ์ผ์‹œ์ •์ง€ ๋ชจ๋‹ฌ: ํฐํŠธ Noto Serif KR ์ œ๊ฑฐ โ†’ system font, ๋ฒ„ํŠผ #2761FF primary
    • SVG ์•„์ด์ฝ˜: PauseIcon #7A6A5A โ†’ #868686, UndoIcon โ†’ #20222E
    • ์บ”๋ฒ„์Šค ๋‚ด๋ถ€ ๊ฒŒ์ž„ ์š”์†Œ: ๋ณ€๊ฒฝ ์—†์Œ (์‹ค ์ƒ‰์ƒ, ๋ณด๋นˆ ๋น„์ฃผ์–ผ ์œ ์ง€)
    • ๋Œ€์ƒ ํŒŒ์ผ: App.jsx, HomeScreen.jsx, StageSelectScreen.jsx, GameplayScreen.jsx, ResultScreen.jsx
  • [2026-02-28] ๊ฒŒ์ž„ ์‹œ์Šคํ…œ ์ „๋ฉด ํ”ผ๋ฒ—: ๋ณด๋นˆ ๊ธฐ๋ฐ˜ โ†’ ๊ตฌํ˜• ์‹ค๋ญ‰์น˜(Yarn Ball) โ€” Frontend Developer

    • ์‹ ๊ทœ ํŒŒ์ผ ์ƒ์„ฑ (6๊ฐœ):
      • src/utils/arc.js โ€” ์›ํ˜ธ ์œ ํ‹ธ: normalizeAngle, angleInArc, arcsOverlap, arcMidAngle, arcSpan
      • src/game/entities/WindingThread.js โ€” ์‹ค๋ญ‰์น˜ ์œ„ ์‹ค ํ•˜๋‚˜ (id, colorIndex, color, layer, arcStart, arcEnd, windingLoops, freeEndAngle)
      • src/game/entities/YarnBall.js โ€” ํผ์ฆ ์ƒํƒœ (accessibleThreads, isAccessible, removeThread, undo, isCleared, isFailed)
      • src/game/generators/YarnBallGenerator.js โ€” ๋ ˆ์ด์–ด๋ณ„ arc ๋ฐฐ์น˜ + ํ•ด๊ฒฐ ๊ฐ€๋Šฅ์„ฑ greedy ๊ฒ€์ฆ
      • src/game/systems/YarnBallRenderer.js โ€” ๊ตฌ์ฒด ๋ Œ๋”๋ง (๋“œ๋กญ ์„€๋„, ๋ฐฉ์‚ฌํ˜• ๊ทธ๋ผ๋””์–ธํŠธ, ๋ ˆ์ด์–ด๋ณ„ ์‹ค arc, Free End marker, ๊ตฌ์ฒด ํ•˜์ด๋ผ์ดํŠธ)
      • src/game/systems/YarnBallController.js โ€” ์ƒํƒœ ๋จธ์‹  (idleโ†’unwindingโ†’idle), ํ’€๊ธฐ Tween ์• ๋‹ˆ๋ฉ”์ด์…˜ 600ms
    • ์ˆ˜์ • ํŒŒ์ผ (4๊ฐœ):
      • src/constants/game.js โ€” YARN_BALL ์ƒ์ˆ˜ ๋ธ”๋ก ์ถ”๊ฐ€ (BOBBIN_LAYOUT ๋ณด์กด)
      • src/constants/stages.js โ€” 10๊ฐœ ์Šคํ…Œ์ด์ง€ ์ „๋ฉด ๊ต์ฒด (threadCount/layerCount/arcDensity ํŒŒ๋ผ๋ฏธํ„ฐ)
      • src/ui/components/GameCanvas.jsx โ€” YarnBallRenderer + YarnBallController ๋กœ ๊ต์ฒด, puzzleโ†’yarnBall prop
      • src/ui/screens/GameplayScreen.jsx โ€” generateYarnBall ์‚ฌ์šฉ, ๋ณด๋นˆ UI ์ œ๊ฑฐ
    • ๋นŒ๋“œ ์„ฑ๊ณต ํ™•์ธ (237kB, vite v7.3.1)
    • ๊ตฌ๋ฒ„์ „ ํŒŒ์ผ ๋ณด์กด: Puzzle.js, Bobbin.js, Thread.js, PuzzleGenerator.js, GameController.js, GameRenderer.js, ThreadLayout.js
  • [2026-02-28] ์‹ค๋ญ‰์น˜ ๋ Œ๋”๋ง 3D ๋Œ€์›(great circle) ๋ชจ๋ธ๋กœ ์ „๋ฉด ๊ต์ฒด โ€” Frontend Developer

    • WindingThread.js: tiltAngle + rotOffset + arcStart/arcEnd(๋Œ€์› ํŒŒ๋ผ๋ฏธํ„ฐ) ํ•„๋“œ ์ถ”๊ฐ€, latitude/freeEndAngle ์ œ๊ฑฐ
    • YarnBallGenerator.js: rotOffset ๊ท ๋“ฑ ๋ฐฐ์น˜(์ง€ํ„ฐ ํฌํ•จ), tiltAngle ๋ ˆ์ด์–ด๋ณ„ ๋ฒ”์œ„ ํ• ๋‹น, ํ•ด๊ฒฐ ๊ฐ€๋Šฅ์„ฑ ๊ฒ€์ฆ threadsOverlap ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜
    • YarnBallRenderer.js: _drawThread ์™„์ „ ์žฌ์ž‘์„ฑ โ€” _sampleGreatCircle(๊ธฐ์šธ์–ด์ง„ ๋Œ€์› 3D ์ขŒํ‘œ โ†’ Y์ถ• ํšŒ์ „ โ†’ ์ •์‚ฌ์˜), _splitFrontSegments(์•ž๋ฉด ์„ธ๊ทธ๋จผํŠธ ๋ถ„๋ฆฌ), ๊นŠ์ด ๊ธฐ๋ฐ˜ ๊ตต๊ธฐ/๋ฐ๊ธฐ, ๋ฃจํ”„๋ณ„ tilt ์˜คํ”„์…‹ ๋‹ค์ค‘ ๋ ˆ์ด์–ด ๋ Œ๋”
    • YarnBallRenderer.js: getFreeEndPosition โ€” arcEnd 3D ์ ์—์„œ ๋ฒ•์„  ๋ฐฉํ–ฅ์œผ๋กœ ๋ป—๊ธฐ, ๋’ท๋ฉด์ด๋ฉด arcStart ์‚ฌ์šฉ
    • YarnBallRenderer.js: _drawTextureArcs โ€” ๋ฐฐ๊ฒฝ ํ…์Šค์ฒ˜๋„ ๋Œ€์› ๊ณก์„ ์œผ๋กœ ๊ต์ฒด
    • YarnBall.js: isAccessible โ€” arcsOverlap ๋Œ€์‹  threadsOverlap ์‚ฌ์šฉ
    • arc.js: threadsOverlap ํ•จ์ˆ˜ ์ถ”๊ฐ€ (rotOffset ๊ทผ์ ‘๋„ ๊ธฐ๋ฐ˜, ์ž„๊ณ„๊ฐ’ PI*0.4)
    • game.js: YARN_BALL์— LAYER_DELTA(5), TILT_MIN(0.52), TILT_MAX(1.40) ์ถ”๊ฐ€
    • ๋นŒ๋“œ ์„ฑ๊ณต ํ™•์ธ (238kB)
    • ๊ฒฐ๊ณผ: ์‹ค์ด ๊ตฌ์ฒด๋ฅผ ์‚ฌ์„ ์œผ๋กœ ๊ฐ€๋กœ์ง€๋ฅด๋Š” ๋Œ€์› ํ˜ธ ํ˜•ํƒœ๋กœ ๋ Œ๋”๋ง, ์•ž๋ฉด๋งŒ ํ‘œ์‹œ(back-face culling), ๊นŠ์ด ์Œ์˜ ์ ์šฉ
  • [2026-02-28] JavaScript โ†’ TypeScript ์ „๋ฉด ์ „ํ™˜ + Pretendard ํฐํŠธ ์ ์šฉ โ€” Frontend Developer (ํŒ€)

    • ์ธํ”„๋ผ: tsconfig.json (strict, @/* path alias), vite.config.ts (tsconfigPaths ํ”Œ๋Ÿฌ๊ทธ์ธ), .prettierrc, src/vite-env.d.ts
    • ์˜์กด์„ฑ ์ถ”๊ฐ€: typescript, vite-tsconfig-paths, prettier (devDependencies)
    • ํฐํŠธ ๊ต์ฒด: Google Fonts CDN (Noto Sans KR/Serif KR) โ†’ ๋กœ์ปฌ Pretendard woff2-subset 9์ข… (100~900)
    • ํƒ€์ž… ์ •์˜: src/types/game.ts ์‹ ๊ทœ ์ƒ์„ฑ (ThreadColor, Stage, WindingThreadParams, GameStoreState ๋“ฑ 17+ ์ธํ„ฐํŽ˜์ด์Šค)
    • ์†Œ์Šค ์ „ํ™˜ (31ํŒŒ์ผ): .jsโ†’.ts (24๊ฐœ), .jsxโ†’.tsx (7๊ฐœ), ์ „์ฒด ํด๋ž˜์Šค/ํ•จ์ˆ˜์— ํƒ€์ž… ์ถ”๊ฐ€
    • Zustand v5: create()() ์ด์ค‘ ํ˜ธ์ถœ ํŒจํ„ด ์ ์šฉ
    • ๊ฒ€์ฆ: tsc --noEmit ์—๋Ÿฌ 0๊ฐœ, prettier ํฌ๋งทํŒ…, npm run build ์„ฑ๊ณต (241KB)
    • package.json: "typecheck": "tsc --noEmit", "build": "tsc --noEmit && vite build"

ํ˜„์žฌ ์ง„ํ–‰ ์ค‘

  • (๋‹ค์Œ ์ž‘์—… ๋ฐฐ์ • ๋Œ€๊ธฐ)

์•Œ๋ ค์ง„ ์ด์Šˆ/๋ธ”๋กœ์ปค

  • ์‚ฌ์šด๋“œ ๋ฏธ๊ตฌํ˜„ (Howler.js ์„ค์น˜๋จ, SFX ์—์…‹ ๋ฏธํ™•๋ณด)
  • ํžŒํŠธ ๋ฒ„ํŠผ UI๋งŒ ์žˆ๊ณ  ๊ธฐ๋Šฅ ๋ฏธ๊ตฌํ˜„
  • ๊ด‘๊ณ  SDK ๋ฏธ์—ฐ๋™ (Poki SDK)
  • YarnBallGenerator: ์ƒ์„ฑ ์‹คํŒจ ์‹œ forceSolvable ํด๋ฐฑ์œผ๋กœ ๋А์Šจํ•˜๊ฒŒ ์ƒ์„ฑ (๊ทน๋‹จ์  ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ ๋“œ๋ฌผ๊ฒŒ ๋ฐœ์ƒ ๊ฐ€๋Šฅ)