Skip to content

PureGuideline/Pure

Repository files navigation

PURE

Generative Movement Design System for Physical AI

PURE는 Physical AI(물리적 형태를 가진 로봇·사물)의 움직임을 하나의 커뮤니케이션 언어로 설계하는 시스템입니다. 움직임을 다음 흐름으로 다룹니다.

Context(맥락) → State(상태) → Movement(움직임) → Function(기능)

먼저 제품(역할)을 선택하고(아키타입 선택 또는 자사 3D 파일 업로드), 상황이나 감정을 입력하면 — 시스템은 제품을 바꾸지 않고 그 제품이 가져야 할 내부 상태(state) 와 그 상태가 드러나는 구체적인 움직임·인터랙션(interaction) 을 추론합니다. 이로부터 모션 토큰과 3D 움직임 시뮬레이션이 만들어집니다.

라이브 데모: https://pure-omega.vercel.app


주요 기능

  • Guideline (/guideline) — Foundation / Semantic / Components / Patterns로 구성된 디자인 시스템 문서와 상태별 상세 페이지.
  • Lab (/lab) — 실험 워크플로:
    • /lab/archetype — 6가지 아키타입 중 선택 → 프리미티브/세션 형태 설정
    • /lab/custom — GLB/OBJ/STL 업로드 → 바운딩 박스 기반 추상화
    • /lab/studio — 통합 경험: 상태 입력 → 상태 슬라이더 → 모션 토큰 → 실시간 3D 시뮬레이션
    • /lab/report — 세션 기반 리포트 + PDF 출력
  • AI 추론 (/api/analyze) — 이미 선택된 제품(formId) 을 입력으로 받아, OpenAI로 상황/감정 텍스트를 분석해 그 제품의 5차원 상태 벡터(curiosity / attention / confidence / comfort / energy)와 구체적인 움직임(interaction) 을 추론합니다. 제품은 절대 바꾸지 않습니다. API 키가 없거나 요청이 실패하면 로컬 휴리스틱으로 자동 폴백합니다.

기술 스택


시작하기

1. 의존성 설치

npm install

2. 환경 변수 설정

.env.example을 복사해 .env.local을 만들고 OpenAI 키를 입력합니다.

cp .env.example .env.local
# .env.local
OPENAI_API_KEY=sk-...           # 필수: 정밀 추론에 사용
# OPENAI_MODEL=gpt-4o-mini      # 선택: 기본값 gpt-4o-mini

키가 없어도 앱은 로컬 휴리스틱 폴백으로 동작합니다. 키를 추가/변경한 뒤에는 dev 서버를 재시작하세요.

3. 개발 서버 실행

npm run dev

http://localhost:3000 에서 확인합니다. (dev 서버는 Turbopack을 사용합니다.)

4. 프로덕션 빌드

npm run build
npm run start

프로젝트 구조

app/
  api/analyze/route.ts   # OpenAI 추론 엔드포인트 (고정 제품 → 상태 + 움직임)
  guideline/             # 디자인 시스템 문서
  lab/                   # 실험 워크플로 (archetype/custom → studio → report)
    session.tsx          # 세션 상태 (shape + formId + state, localStorage)
components/              # 재사용 UI (StateInput, MotionSimulator, ui 등)
lib/                     # 순수 로직
  ai-analyze.ts          # 분석 타입 · 클라이언트 wrapper · 로컬 폴백
  forms.ts               # 6가지 Physical AI 폼(역할) 정의
  state-generator.ts     # 상태 차원 · 텍스트/픽셀 휴리스틱
  motion-engine.ts       # 상태 → 모션 합성
  motion-tokens.ts       # 모션 토큰
  report.ts              # 리포트 생성

동작 방식 (AI 추론)

  1. Lab에서 제품(역할)을 먼저 선택합니다 — 6가지 아키타입(companion · humanoid · lamp · mobility · animal · ambient) 중 하나를 고르거나, 자사 3D 파일을 업로드해 추상화합니다.
  2. Studio에서 상황·감정을 텍스트로 입력하고 상태 생성을 누릅니다.
  3. /api/analyze선택된 제품(formId)을 입력으로 받아 OpenAI를 호출(JSON schema 구조화 출력)하고 다음을 반환합니다. 제품은 바꾸지 않습니다.
    • state — 그 제품이 맥락에서 가져야 할 5차원 상태 벡터 (각 0~1)
    • interaction — 그 상태가 드러나는 구체적인 움직임 한 문장 (예: "반가워서 제자리를 빠르게 맴돈다.")
    • reasoning — 추론 근거(한국어)
  4. 상태가 세션에 반영되어 3D 시뮬레이터·모션 토큰이 즉시 갱신되고, "추론된 움직임" 패널에 움직임 설명과 근거가 표시됩니다.

사용 예제

1. REST API — POST /api/analyze

선택된 제품(formId)과 상황/감정 입력을 받아, 그 제품의 5차원 상태 벡터와 구체적인 움직임을 반환합니다.

요청 본문

필드 타입 필수 설명
text string text·images하나 상황·감정 텍스트
images string[] text·images하나 data:image/... 형식의 base64 이미지. 여러 장이면 15초 영상의 연속 프레임으로 해석
formId "companion" | "humanoid" | "lamp" | "mobility" | "animal" | "ambient" 선택 제품(역할). 기본값 "companion"

textimages 둘 다 없으면 400, 서버에 OPENAI_API_KEY가 없으면 503을 반환합니다. (클라이언트 헬퍼 analyzeInput/analyzeImages는 이 실패를 잡아 로컬 휴리스틱으로 폴백합니다 — 아래 2번 참고.)

curl

curl -X POST http://localhost:3000/api/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "text": "사용자가 오랜만에 반갑게 인사를 건넨다",
    "formId": "companion"
  }'

응답 (Analysis)

{
  "formId": "companion",
  "role": "Companion",
  "state": {
    "curiosity": 0.82,
    "attention": 0.66,
    "confidence": 0.54,
    "comfort": 0.61,
    "energy": 0.78
  },
  "interaction": "Spins in place quickly out of delight.",
  "reasoning": "반가운 재회 맥락이라 각성도(energy)와 호기심(curiosity)을 높게 잡고...",
  "fallback": false // 로컬 휴리스틱으로 폴백되면 true
}

fetch (브라우저 / 클라이언트 컴포넌트)

const res = await fetch("/api/analyze", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ text: "조용히 집중해서 책을 읽는다", formId: "lamp" }),
});
const analysis = await res.json(); // → Analysis
console.log(analysis.state, analysis.interaction);

이미지/웹캠 프레임으로 추론하려면 imagesdata:image/... 문자열 배열을 보냅니다.

await fetch("/api/analyze", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    images: ["data:image/jpeg;base64,/9j/4AAQ..."], // 여러 장이면 15초 프레임 시퀀스로 처리
    formId: "animal",
  }),
});

2. 라이브러리(lib)로 직접 사용하기

API를 거치지 않고 lib의 순수 함수를 그대로 쓸 수 있습니다. (경로 alias @/ → 저장소 루트)

클라이언트 래퍼 — 자동 폴백 포함

import { analyzeInput } from "@/lib/ai-analyze";

// /api/analyze 호출 → 실패(키 없음/네트워크 오류) 시 로컬 휴리스틱으로 투명하게 폴백
const analysis = await analyzeInput("신나서 방 안을 빠르게 돈다", "mobility");
//    ↳ Analysis: { formId, role, state, interaction, reasoning, fallback }

API 없이 — 텍스트 → 상태 → 모션 토큰 (Node/서버에서도 동작)

import { analyzeText } from "@/lib/state-generator";
import { composeMotion } from "@/lib/motion-engine";
import { localInteraction } from "@/lib/ai-analyze";

const state = analyzeText("calm and focused"); // 키워드 휴리스틱 → StateVector
// 예시 결과: { curiosity: 0.31, attention: 0.49, confidence: 0.45, comfort: 0.83, energy: 0.27 }

const motion = composeMotion(state);
// motion.properties → [{ id: "amplitude", label: "Amplitude", value: 0.43 }, ...]
// motion.tokens     → [{ category: "Direction", token: "Approach" }, { category: "Timing", token: "Pause" }, ...]

const sentence = localInteraction("companion", state);
// → "Companion feels at ease and moves closer calmly."

제품(폼) 정의 조회

import { FORMS, getForm, suggestForm } from "@/lib/forms";

getForm("lamp")?.label;          // → "Lamp"
FORMS.map((form) => form.id);    // → ["companion", "humanoid", "lamp", "mobility", "animal", "ambient"]
suggestForm({ x: 0.3, y: 1.8, z: 0.3 }); // 바운딩 박스 비율 → "humanoid"

3. 리포트·타임라인 데이터 생성

composeMotion 결과를 모션 타임라인과 액추에이터 제약(DOF·각속도·제어 주기 등)으로 변환합니다.

import { composeMotion } from "@/lib/motion-engine";
import { buildTimeline, buildConstraints, periodMs } from "@/lib/report";
import { analyzeText } from "@/lib/state-generator";

const motion = composeMotion(analyzeText("excited and playful"));

periodMs(motion);          // → 한 모션 사이클 길이(ms)
buildTimeline(motion);     // → [{ label: "Move", fromMs, toMs, token, description }, ...]
buildConstraints(motion);  // → [{ label: "Degrees of Freedom (DOF)", value: "1", note: "Yaw (Y, continuous)" }, ...]

본 저장소는 졸업 프로젝트로 제작되었습니다.

About

Movement as the language of Physical AI. A generative motion framework for expressive robot interaction.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages