diff --git a/popdocs/ARCHITECTURE.md b/popdocs/ARCHITECTURE.md
index 1259e9cc..357e5c9b 100644
--- a/popdocs/ARCHITECTURE.md
+++ b/popdocs/ARCHITECTURE.md
@@ -68,12 +68,31 @@ POP 메인 대시보드. 메뉴 그리드, KPI, 공지사항 등을 표시.
- v3/v4 레이아웃 자동 감지 및 렌더링
- 반응형 모드 감지 (태블릿/모바일, 가로/세로)
- 프리뷰 모드 지원 (`?preview=true`)
+- **뷰포트 감지 및 비율 스케일링**
```typescript
+// 뷰포트 너비 감지 (최대 1366px 제한)
+const [viewportWidth, setViewportWidth] = useState(1024);
+
+useEffect(() => {
+ const updateViewportWidth = () => {
+ setViewportWidth(Math.min(window.innerWidth, 1366));
+ };
+ updateViewportWidth();
+ window.addEventListener("resize", updateViewportWidth);
+ return () => window.removeEventListener("resize", updateViewportWidth);
+}, []);
+
// 레이아웃 버전 감지 및 렌더링
if (popLayoutV4) {
- // v4: PopFlexRenderer 사용
-
+ // v4: PopFlexRenderer 사용 (비율 스케일링 적용)
+
} else if (popLayoutV3) {
// v3: PopLayoutRenderer 사용
@@ -228,37 +247,77 @@ type SizeMode = "fixed" | "fill" | "hug";
#### `PopFlexRenderer.tsx` (v4용)
-**역할**: v4 레이아웃을 Flexbox로 렌더링
+**역할**: v4 레이아웃을 Flexbox로 렌더링 + 비율 스케일링
**핵심 기능**:
- 컨테이너 재귀 렌더링
- 반응형 규칙 적용 (breakpoint)
- 크기 제약 → CSS 스타일 변환
- 컴포넌트 숨김 처리 (hideBelow)
+- **비율 스케일링** (뷰어 모드)
-**크기 제약 변환 로직**:
+**비율 스케일링 시스템**:
```typescript
-function calculateSizeStyle(size: PopSizeConstraintV4): React.CSSProperties {
+// 기준 너비 (10인치 태블릿 가로)
+const BASE_VIEWPORT_WIDTH = 1024;
+
+// 스케일 계산 (디자인 모드: 1, 뷰어 모드: 실제 비율)
+const scale = isDesignMode ? 1 : viewportWidth / BASE_VIEWPORT_WIDTH;
+
+// 예시: 12인치(1366px) 화면
+// scale = 1366 / 1024 = 1.33
+// 200px 컴포넌트 → 266px
+```
+
+**크기 제약 변환 로직** (스케일 적용):
+```typescript
+function calculateSizeStyle(
+ size: PopSizeConstraintV4,
+ settings: PopGlobalSettingsV4,
+ scale: number = 1 // 스케일 파라미터 추가
+): React.CSSProperties {
const style: React.CSSProperties = {};
- // 너비
+ // 너비 (스케일 적용)
switch (size.width) {
- case "fixed": style.width = `${size.fixedWidth}px`; style.flexShrink = 0; break;
- case "fill": style.flex = 1; style.minWidth = size.minWidth || 0; break;
- case "hug": style.width = "auto"; style.flexShrink = 0; break;
+ case "fixed":
+ style.width = `${size.fixedWidth * scale}px`;
+ style.flexShrink = 0;
+ break;
+ case "fill":
+ style.flex = 1;
+ style.minWidth = size.minWidth ? `${size.minWidth * scale}px` : 0;
+ break;
+ case "hug":
+ style.width = "auto";
+ style.flexShrink = 0;
+ break;
}
- // 높이
+ // 높이 (스케일 적용)
switch (size.height) {
- case "fixed": style.height = `${size.fixedHeight}px`; break;
- case "fill": style.flexGrow = 1; break;
- case "hug": style.height = "auto"; break;
+ case "fixed":
+ style.height = `${size.fixedHeight * scale}px`;
+ break;
+ case "fill":
+ style.flexGrow = 1;
+ break;
+ case "hug":
+ style.height = "auto";
+ break;
}
return style;
}
```
+**컨테이너 스케일 적용**:
+```typescript
+// gap, padding도 스케일 적용
+const scaledGap = gap * scale;
+const scaledPadding = padding ? padding * scale : undefined;
+```
+
#### `ComponentRenderer.tsx`
**역할**: 개별 컴포넌트 렌더링 (디자인 모드용 플레이스홀더)
diff --git a/popdocs/V4_UNIFIED_DESIGN_SPEC.md b/popdocs/V4_UNIFIED_DESIGN_SPEC.md
index 6f45d014..ade03edd 100644
--- a/popdocs/V4_UNIFIED_DESIGN_SPEC.md
+++ b/popdocs/V4_UNIFIED_DESIGN_SPEC.md
@@ -250,10 +250,49 @@ interface PopComponentDefinitionV4 {
|------|------|------|
| `PopDesigner.tsx` | v3/v4 통합 디자이너 | 완료 |
| `PopCanvasV4.tsx` | v4 캔버스 (4개 프리셋 + 슬라이더) | 완료 |
-| `PopFlexRenderer.tsx` | v4 Flexbox 렌더러 | 완료 |
+| `PopFlexRenderer.tsx` | v4 Flexbox 렌더러 + 비율 스케일링 | 완료 |
| `ComponentPaletteV4.tsx` | v4 컴포넌트 팔레트 | 완료 |
| `ComponentEditorPanelV4.tsx` | v4 속성 편집 패널 | 완료 |
| `pop-layout.ts` | v3/v4 타입 정의 | 완료, Phase 2-3에서 수정 예정 |
+| `page.tsx` (뷰어) | v4 뷰어 + viewportWidth 감지 | 완료 |
+
+---
+
+## 비율 스케일링 시스템
+
+### 업계 표준
+Rockwell Automation HMI의 "Scale with Fixed Aspect Ratio" 방식 적용
+
+### 원리
+10인치(1024px) 기준으로 디자인 → 8~12인치에서 배치 유지, 크기만 비례 조정
+
+### 계산
+```
+scale = viewportWidth / 1024
+scaledWidth = originalWidth * scale
+scaledHeight = originalHeight * scale
+scaledGap = originalGap * scale
+scaledPadding = originalPadding * scale
+```
+
+### 화면별 결과
+
+| 화면 | scale | 200px 컴포넌트 | 8px gap |
+|------|-------|----------------|---------|
+| 8인치 (800px) | 0.78 | 156px | 6px |
+| 10인치 (1024px) | 1.00 | 200px | 8px |
+| 12인치 (1366px) | 1.33 | 266px | 11px |
+| 14인치+ | 1.33 (max) | 266px + 여백 | 11px |
+
+### 적용 위치
+
+| 파일 | 함수/변수 | 역할 |
+|------|----------|------|
+| `PopFlexRenderer.tsx` | `BASE_VIEWPORT_WIDTH` | 기준 너비 상수 (1024) |
+| `PopFlexRenderer.tsx` | `calculateSizeStyle(size, settings, scale)` | 크기 스케일 적용 |
+| `PopFlexRenderer.tsx` | `ContainerRenderer.containerStyle` | gap, padding 스케일 적용 |
+| `page.tsx` | `viewportWidth` state | 뷰포트 너비 감지 |
+| `page.tsx` | `Math.min(window.innerWidth, 1366)` | 최대 너비 제한 |
---