Ergoswarm - 실시간 비트코인 가격 기반 진화형 생태계 시뮬레이션
이름은 거창한데 rust WASM + sveltekit PWA 토이 프로젝트 한번 만들어 봤어요
별것도 아닌데 좀 힘들었네요
rust 게임엔진 macroquad 물리엔진 rapier2d 를 cargo build target wasm32-unknown-unknown 하면 wasm 파일 하나가 나옵니다
이 wasm 파일이 html(sveltekit PWA) 웹화면 전체를 canvas 랜더링 하는건데
프론트엔드 PWA가 백엔드서버에 BTC 가격 1초봉 60개를 1분마다 한번씩 요청하고 데이터를 가져와서 indexedDB에 저장을 합니다
백엔드 서버는 제가 몇주전에 만들어 놓은 N100 16GB ram 미니PC 2대입니다
1번 WAS서버는 cloudflared tunnel - nginx reverse proxy - rust was(프론트엔드 api endpoint 및 binance API에 BTC 가격을 1분에 한번씩 1초봉 60개를 가져와서)
2번 DATA서버는 redis, postgre sql 구동되고 있는데 1초봉 60개를 redis cache에 저장하고 프론트엔드의 api 요청일 있을때 redis streams를 통해서 queue로 순서대로 데이터를 보내줍니다
그리고 프론트엔드에서 indexedDB에 저장된 BTC 가격을 wasm이 가져와서 1초봉 캔들차트를 랜더링 하고
그 1초봉이 상승,보합,하락에 따라서 생태계에 먹이를 다르게 줍니다
게임시뮬레이션을 좀 더 정교하게 다듬어야 되는데 js 와 wasm 간의 데이터 주고 받는 부분에서 너무 헤매다보니까 지쳐서 그냥 요까지만 해야겠습니다 나중에 재미있게 다듬어 봐야죠
SvelteKit PWA와 Rust/Macroquad WASM 연동 아키텍처
================================================================
이 문서는 SvelteKit PWA 환경에서 Rust로 작성된 Macroquad WASM 모듈을 통합하고, miniquad 플러그인 시스템을 통해 양방향 데이터를 교환하는 아키텍처를 정리합니다. 이 방식은 wasm-pack 같은 별도 도구 없이 cargo build와 SvelteKit의 빌드 시스템을 직접 연동하여 단순하고 강력한 구조를 만듭니다.
### 데이터 흐름
1. SvelteKit (JavaScript):
* 백엔드 API에서 실시간 BTC 가격 데이터를 주기적으로 가져와 IndexedDB에 저장합니다.
* 메모리에 가격 큐(Queue)와 차트용 데이터 배열priceHistory)을 유지합니다.
* 1초마다 큐에서 가격을 꺼내 window.current_btc_price와 같은 전역 변수를 업데이트합니다.
2. miniquad 플러그인 (JavaScript Bridge):
* miniquad_add_plugin을 사용하여 Rust 코드가 호출할 JavaScript 함수들을 "등록"합니다.
* 이 함수들get_current_btc_price, get_price_trend 등)은 SvelteKit이 관리하는 전역 변수나 상태 값을 읽어 Rust에 반환합니다.
3. Rust/WASM:
* extern "C" 블록을 통해 JavaScript 함수들을 호출할 것을 선언합니다.
* 매 프레임 unsafe 블록 안에서 이 함수들을 호출하여 최신 데이터를 가져옵니다.
* 가져온 데이터를 기반으로 게임 로직(먹이 생성)을 업데이트하고, 캔들차트와 같은 시각적 요소를 렌더링합니다.
---
### 1. package.json - 통합 빌드 스크립트
npm run build 실행 시, build:wasm 스크립트가 먼저 실행되어 Rust 프로젝트를 컴파일하고, 필수 결과물.wasm, mq_js_bundle.js)을 SvelteKit의 /static 폴더로 복사합니다. 그 후 vite build가 SvelteKit 앱을 빌드합니다.
```json
{
"scripts": {
"dev": "npm run build:wasm && vite dev",
"build": "npm run build:wasm && vite build",
"build:wasm": "cd ergowarm-engine && cargo build --release --target wasm32-unknown-unknown && cp target/wasm32-unknown-unknown/release/ergowarm-engine.wasm ../static/ && cp target/wasm32-unknown-unknown/release/mq_js_bundle.js ../static/"
}
}
```
---
### 2. ergowarm-engine/Cargo.toml - 의존성
특별한 JS 연동 라이브러리 없이 macroquad와 게임 로직에 필요한 의존성만 포함합니다.
```toml
[dependencies]
# Physics Engine
rapier2d = { version = "0.27.0", features = [ "serde-serialize", "dim2" ] }
macroquad = "0.4.14"
nalgebra = "0.33.2"
```
---
### 3. ergowarm-engine/src/main.rs - Rust 핵심 코드
extern "C" 블록으로 JS 함수를 선언하고, main 루프에서 unsafe하게 호출하여 사용합니다.
```rust
// JavaScript가 제공할 함수를 선언합니다.
#[no_mangle]
extern "C" {
fn get_js_counter() -> f64;
}
#[macroquad::main("Ergoswarm")]
async fn main() {
// ... 게임 상태 초기화 ...
loop {
// ... 게임 로직 업데이트 및 그리기 ...
// JS에서 값을 가져옵니다. extern "C" 함수 호출은 unsafe 블록이 필요합니다.
let js_value = unsafe { get_js_counter() };
let text_to_render = format!("JS Counter: {}", js_value as u32);
// ... 텍스트 렌더링 ...
next_frame().await
}
}
```
---
### 4. ergowarm-engine/dist/index.html - JavaScript 로더 및 플러그인
mq_js_bundle.js를 로드한 후, miniquad_add_plugin을 통해 Rust가 호출할 함수를 정의하고 WASM을 실행합니다.
```html
<script src="./mq_js_bundle.js"></script>
<script>
// Rust에서 사용할 카운터 변수를 설정합니다.
window.js_counter = 0;
setInterval(() => window.js_counter++, 1000);
// miniquad 플러그인을 정의합니다.
const ergoswarmPlugin = {
name: "ergoswarm_plugin",
version: "0.1.0",
register_plugin: function(importObject) {
// Rust의 extern "C" { fn get_js_counter() ... } 선언과 연결됩니다.
importObject.env.get_js_counter = () => window.js_counter;
}
};
// 정의한 플러그인을 miniquad 로더에 등록합니다.
miniquad_add_plugin(ergoswarmPlugin);
// WASM 파일을 로드하여 게임을 시작합니다.
load("ergowarm-engine.wasm");
</script>
```
아래는 gemini가 쓴 홍보글(vsc wsl의 gemini cli와 gemini code assist가 코더 열심히 해줬습니다)
Ergoswarm - 실시간 비트코인 가격 기반 진화형 생태계 시뮬레이션
================================================================
태그라인: 실시간 비트코인 가격이 디지털 생태계의 진화를 결정하는 곳.
---
### 개요
Ergoswarm은 실시간 비트코인 가격 데이터에 의해 모든 것이 결정되는 진화형 생태계 시뮬레이션입니다. 이 실험적인 프로젝트에서, 데이터의 흐름은 디지털 유기체의 탄생, 생존, 그리고 소멸을 관장하는 자연의 법칙이 됩니다. 사용자는 예측 불가능한 시장의 변동성 속에서 군집이 어떻게 적응하고 진화하는지를 관찰하며, 혼돈과 질서가 빚어내는 복잡성의 아름다움을 경험하게 됩니다.
---
### ✅ 핵심 특징
* 살아 숨 쉬는 세계: 모든 생명체의 탄생과 자원의 분배는 사전 각본 없이 오직 실시간 BTC 가격 데이터에 의해 결정됩니다. 상승장에서는 풍요로운 자원이, 하락장에서는 생존을 위협하는 요소가 등장하며, 매 순간이 예측 불가능한 새로운 경험을 선사합니다.
* 창발적 전략과 행동: 플레이어는 유닛을 직접 조종하지 않습니다. 대신 환경에 개입하고 우선순위를 설정하며 군집의 진화 방향을 유도합니다. 유닛들은 주어진 규칙과 환경 속에서 스스로 먹이를 찾고, 번식하며, 위협을 회피하는 등 복잡하고 지능적인 행동 패턴을 창발적으로 만들어냅니다.
* 데이터가 그리는 생성 예술 (Generative Art): 화면에 펼쳐지는 유닛들의 움직임, 캔들차트의 시각적 패턴, 자원의 분포는 시장의 변동성을 그대로 비추는 한 폭의 생성 예술입니다. 기술과 예술의 경계에서 데이터가 어떻게 시각적 아름다움으로 변환되는지 직접 목격하세요.
* 웹 브라우저에서의 최상의 성능: Rust의 강력한 성능과 메모리 안전성, 그리고 WebAssembly(WASM)의 네이티브에 가까운 실행 속도를 결합했습니다. 별도의 설치 없이, 어떤 모던 웹 브라우저에서도 복잡한 물리 연산과 AI 시뮬레이션이 부드럽게 구동됩니다.
* 독특한 인지적 도전: Ergoswarm은 단순한 관찰을 넘어, 끊임없이 변화하는 데이터 속에서 최적의 결정을 내려야 하는 고도의 전략적 사고를 요구합니다. 이는 사용자의 멀티태스킹 능력과 상황 판단력을 시험하는 독특한 인지적 도전 과제입니다.
---
### 🎯 타겟 사용자
* 기술 애호가: Rust, WebAssembly, 실시간 데이터 처리 등 최신 웹 기술의 실제 적용 사례에 관심 있는 개발자 및 엔지니어.
* 데이터 시각화 및 생성 예술 팬: 데이터가 어떻게 아름다운 시각적 결과물로 변환되는지에 매력을 느끼는 아티스트와 디자이너.
* 전략/시뮬레이션 게이머: 기존의 틀을 벗어난 새로운 방식의 도전을 원하는 하드코어 게이머.
* 인지 과학 및 AI 연구자: 복잡계, 인공 생명, 창발적 행동에 대한 실험적 플랫폼으로 활용 가능.
---
### 🔧 기술 스택 하이라이트
* 코어 엔진: Rust (고성능, 메모리 안전성)
* 웹 실행: WebAssembly (WASM)
* 물리 엔진: Rapier2D
* 렌더링: Macroquad
* 프론트엔드/PWA: SvelteKit
* 데이터 백엔드: Axum (Rust), Redis
* 데이터 소스: 실시간 Binance API (BTC/USDT)