--- id: game-skia-native-2d title: Skia / Native 2D — Mobile / Cross-platform 그림 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [game, skia, 2d, mobile, vibe-coding] tech_stack: { language: "TS / Dart", applicable_to: ["Mobile", "Frontend"] } applied_in: [] aliases: [Skia, react-native-skia, CanvasKit, Flutter, Path, paint, fast 2D] --- # Skia / Native 2D > Google Skia = Chrome/Flutter/Android/Firefox 의 그림 엔진. **GPU-accelerated 2D**. RN Skia / CanvasKit / Flutter Canvas 가 wrapper. ## 📖 핵심 개념 - Path: 선 + 곡선. - Paint: 색 + style. - Canvas: drawable surface. - Shader / image filter: Path 위 효과. ## 💻 코드 패턴 ### React Native Skia ```bash yarn add @shopify/react-native-skia ``` ```tsx import { Canvas, Circle, Path, Skia, useClockValue, useComputedValue, useValue } from '@shopify/react-native-skia'; function App() { const clock = useClockValue(); const cx = useComputedValue(() => 100 + Math.sin(clock.current / 500) * 50, [clock]); return ( ); } ``` ### Path (복잡 도형) ```tsx const path = Skia.Path.Make(); path.moveTo(50, 50); path.lineTo(150, 50); path.quadTo(200, 100, 150, 150); path.close(); ``` ### Gradient ```tsx import { LinearGradient, vec } from '@shopify/react-native-skia'; ``` ### Image filter (blur, etc) ```tsx import { Blur, ColorMatrix } from '@shopify/react-native-skia'; ``` ### Shader (GPU) ```tsx import { Shader, Skia } from '@shopify/react-native-skia'; const source = Skia.RuntimeEffect.Make(` uniform float2 iResolution; uniform float iTime; half4 main(float2 fragCoord) { float2 uv = fragCoord / iResolution; return half4(uv.x, uv.y, sin(iTime), 1.0); } `); const clock = useClockValue(); const uniforms = useComputedValue(() => ({ iResolution: [width, height], iTime: clock.current / 1000, }), [clock]); ``` → Web 의 Three.js shader 같은 power. ### Animation (declarative) ```tsx import { useSpring, withTiming, withRepeat, withSequence } from '@shopify/react-native-skia'; const x = useSharedValue(0); useEffect(() => { x.value = withRepeat( withSequence( withTiming(200, { duration: 1000 }), withTiming(0, { duration: 1000 }), ), -1 ); }, []); ``` → Reanimated 통합 — UI thread 60fps. ### Text ```tsx import { Text, useFont } from '@shopify/react-native-skia'; const font = useFont(require('./Roboto.ttf'), 24); if (!font) return null; ``` ### CanvasKit (web) ```ts import CanvasKitInit from 'canvaskit-wasm'; const CanvasKit = await CanvasKitInit({ locateFile: f => `/${f}` }); const surface = CanvasKit.MakeWebGLCanvasSurface('canvas')!; const canvas = surface.getCanvas(); const paint = new CanvasKit.Paint(); paint.setColor(CanvasKit.Color4f(0.9, 0.5, 0.2, 1.0)); paint.setStyle(CanvasKit.PaintStyle.Fill); canvas.drawCircle(100, 100, 50, paint); surface.flush(); ``` → Web 에서 Skia 그대로 (Flutter web 이 사용). ### Flutter Canvas ```dart class MyPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue ..style = PaintingStyle.fill; canvas.drawCircle(Offset(size.width / 2, size.height / 2), 50, paint); final path = Path() ..moveTo(0, 0) ..quadraticBezierTo(100, 200, 200, 0); canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant CustomPainter old) => false; } CustomPaint(painter: MyPainter(), size: Size.infinite); ``` ### Game-like usage (RN Skia) ```tsx function Game() { const clock = useClockValue(); const playerY = useComputedValue(() => 200 + Math.sin(clock.current / 500) * 50, [clock]); // Bullets — array of values const bullets = useMemo(() => Array.from({ length: 20 }, () => ({ x: 0, y: 0 })), []); return ( {bullets.map((b, i) => ( ))} ); } ``` ### Performance - Path / shape 재사용 (useMemo). - Reanimated 의 SharedValue 가 UI thread. - `useComputedValue` 가 derive. - 큰 image = `Image` component + cache. - 너무 많은 element = Canvas 가 한 번에 그림. ### Web Canvas API (대안) ```ts const ctx = canvas.getContext('2d')!; ctx.fillStyle = 'red'; ctx.fillRect(10, 10, 100, 100); ctx.beginPath(); ctx.arc(150, 150, 50, 0, Math.PI * 2); ctx.fill(); ``` → Skia 만큼 강력 X. 단순 OK. ### vs WebGL (Three.js) ``` 2D = Skia / Canvas API 3D = WebGL / WebGPU / Three.js Skia 도 GPU 가속 — Canvas API 보다 빠름 (canvaskit). ``` ## 🤔 의사결정 기준 | 상황 | 추천 | |---|---| | RN custom drawing | RN Skia | | Flutter | Canvas / CustomPainter | | Web 2D | Canvas API (간단) / CanvasKit (강력) | | Game UI | Skia / 자체 canvas | | 차트 | Recharts / Visx (위 문서) | | 매우 simple shape | SVG | ## ❌ 안티패턴 - **매 frame Path 새로**: useMemo / 외부. - **JS thread 에 animation**: reanimated SharedValue. - **큰 Bitmap 매번 decode**: cache. - **너무 많은 Element (1000+)**: 한 Canvas 안 묶기. - **Shader 매 frame compile**: useMemo. - **CanvasKit web bundle 인지**: 큰 (~3MB). Lazy. ## 🤖 LLM 활용 힌트 - RN = RN Skia (modern). - Flutter = built-in Canvas. - Web 2D = Canvas API 보통 충분. - Reanimated 통합으로 60fps. ## 🔗 관련 문서 - [[RN_Reanimated_3_Patterns]] - [[Mobile_Flutter_Patterns]] - [[Game_Shader_Patterns]]