> ## Content Index
> Fetch the complete content index at: https://blog.sorune.org/llms.txt
> Use this file to discover other available public pages before exploring further.

# AI에게 디자인을 계속 설명하는 대신 실제 React 화면 76개를 HTML로 뽑았다
- URL: https://blog.sorune.org/react-ui-static-export-human-design-surface/
- Published: 2026-09-22T02:26:18.000Z
- Updated: 2026-09-22T02:26:18.000Z
- Description: 반복되는 AI 디자인 피드백 대신 실제 React 앱의 38개 UI 상태를 desktop/mobile 각각 standalone HTML로 추출했다. 새 mock을 만드는 대신 현재 제품을 editable projection으로 바꿔 human visual review 비용을 낮춘 과정을 정리한다.
- Author: Sorune — Engineering, Photography & Lab Notes
- Tags: Engineering, PhotoGram, Frontend, Design Workflow, React, Human-in-the-loop

AI와 화면 디자인을 수정할 때 답답했던 지점이 하나 있었다.

코드 수정 자체는 빠르다.

문제는 내가 실제 화면을 보고 느끼는 이런 판단을 매번 텍스트로 다시 설명해야 한다는 것이었다.

```text
여기가 너무 답답하다
간격이 이상하다
정보 우선순위가 뒤집혔다
모바일에서 이 부분이 무겁다

```

스크린샷을 보내고 수정하고, 다시 앱을 띄우고, 또 캡처하고, 다시 설명하는 루프가 반복됐다.

어느 순간에는 AI에게 디자인을 더 잘 설명하는 방법을 찾는 것보다 내가 직접 실제 화면을 편집할 수 있는 surface를 만드는 편이 더 빠르겠다는 생각이 들었다.

그래서 PhotoGram의 현재 React UI를 static HTML로 뽑았다.

## 새 mock을 만든 것이 아니다

가장 먼저 정한 원칙은 새 디자인을 만들지 않는 것이었다.

```text
NOT a new mock
NOT a new design system
NOT a rewritten static site

```

원하는 것은 현재 실행 중인 React 앱의 projection이었다.

```text
ACTUAL REACT UI
→ browser-rendered DOM
→ applied CSS
→ standalone HTML

```

source를 다른 형태로 다시 구현하는 것이 아니라 브라우저가 실제로 보여준 결과를 편집 가능한 형태로 고정했다.

이 차이가 중요했다.

새 mock을 만들면 실제 제품과 다시 synchronization 문제가 생긴다.

```text
React source
→ product UI

separate mock
→ another UI source

two sources
→ drift

```

반면 rendered snapshot은 authority가 아니다.

```text
React product
= source

static HTML
= editable projection

```

원본을 대체하지 않기 때문에 디자인 작업 surface로만 사용할 수 있다.

## 한 페이지 캡처가 아니라 UI state를 먼저 셌다

처음에는 주요 화면 몇 개만 추출하면 될 것 같았다.

그런데 실제 앱은 route 하나가 곧 화면 하나가 아니었다.

예를 들어 Photo Detail만 해도 상태가 달랐다.

```text
guest
other user
owner
owner + minimal caption
owner + long caption
owner + editing
owner + delete confirm

```

Create도:

```text
step 1 empty
step 1 selected
step 2
step 3

```

가 다르다.

Feed 역시 guest/authenticated/selection pane 상태가 있다.

따라서 페이지 수보다 사용자가 실제로 보는 UI state를 기준으로 inventory를 만들었다.

최종적으로 38개 상태가 나왔다.

## Desktop과 Mobile을 따로 뽑으니 76개가 됐다

같은 DOM이라도 responsive layout은 완전히 다른 디자인 문제를 만든다.

그래서 각 state를 두 viewport에서 추출했다.

```text
desktop: 1280px
mobile:   390px

38 states × 2
= 76 standalone HTML files

```

대상에는 feed, search, photo detail, photo editor, create wizard, story, saved/following, notifications, profile, account, settings, login/register 등이 포함됐다.

단순 happy path만 뽑지 않았다.

```text
empty state
guest state
owner/non-owner
long content
confirmation state
editing state

```

도 같이 남겼다.

디자인 문제는 정상 상태보다 이런 variation에서 더 잘 보이기 때문이다.

## Screenshot이 아니라 DOM을 뽑은 이유

스크린샷도 visual review에는 좋다.

하지만 직접 수정할 수는 없다.

내가 원한 작업은:

```text
눈으로 확인
→ CSS/markup 직접 조정
→ 바로 다시 확인

```

이었다.

그래서 image capture보다 rendered DOM + CSS export가 더 적합했다.

각 HTML에는 실제 적용된 CSS를 standalone 형태로 넣고, 가능한 asset URL도 원래 dev server를 가리키도록 정리했다.

결과적으로 browser에서 파일 하나만 열어도 현재 UI와 거의 같은 상태를 볼 수 있다.

그리고 개발 toolchain을 다시 띄우지 않고도 HTML/CSS를 직접 만질 수 있다.

## 모든 runtime state를 static file로 옮길 수 있는 것은 아니다

static export에도 한계는 있었다.

대표적인 것이 upload preview였다.

React 앱에서는 사용자가 고른 이미지를 browser blob URL로 preview하고 있었다.

이 URL은 해당 tab/session에 묶여 있다.

따라서 standalone HTML로 직렬화해도 나중에 같은 image를 읽을 수 없다.

그래서 create-step1-selected의 thumbnail은 깨졌다.

이 문제를 해결하기 위해 exporter를 크게 다시 만들지는 않았다.

왜냐하면 목적은 완벽한 offline clone이 아니었기 때문이다.

```text
GOAL
= visual editing surface

NOT
= fully functional static reproduction

```

layout과 DOM/CSS가 살아 있으면 이번 목적에는 충분했다.

projection은 source가 가진 모든 capability를 복제할 필요가 없다.

## 이 방식이 유용했던 이유는 human judgment가 병목이었기 때문이다

AI가 잘하는 일과 내가 직접 해야 하는 일이 달랐다.

AI는 component 수정, CSS 반복 적용, route/state 수집, mechanical reflection을 빠르게 할 수 있다.

반대로 최종 visual judgment는 내가 보는 편이 빨랐다.

```text
이 간격이 더 낫다
이 버튼이 너무 튄다
이 정보는 여기 없어야 한다
desktop에서 이 패널은 너무 넓다

```

이런 판단을 매번 자연어 instruction으로 직렬화하는 것은 비효율적이었다.

그래서 workflow를 뒤집었다.

```text
기존:
Human sees UI
→ describes problem to AI
→ AI edits React
→ Human reruns/reviews
→ repeat

변경:
React UI
→ static editable projection
→ Human edits visual surface directly
→ accepted visual delta
→ mechanically reflect into React

```

AI에게 더 많은 visual authority를 주는 대신, human review가 쉬운 representation을 만든 것이다.

## Design artifact를 source of truth로 승격하지 않는다

여기서 중요한 boundary가 하나 있다.

static HTML에서 디자인을 수정한다고 해서 그 파일이 최종 제품 source가 되는 것은 아니다.

```text
STATIC EXPORT
!= PRODUCT SOURCE

```

이 파일은 review/editing artifact다.

최종 반영은 다시 React component/CSS에 들어가야 한다.

그래야 routing, state, interaction, accessibility, responsive logic, tests 같은 실제 product behavior와 함께 유지된다.

즉 flow는:

```text
React source
→ rendered projection
→ human visual change
→ accepted delta
→ React source reflection

```

이다.

중간 projection을 canonical source로 바꾸지 않는다.

## 이 방식은 디자인 도구를 하나 더 만든 것도 아니다

이 문제를 만나면 자동화 tool이나 별도 visual editor를 만들고 싶어질 수 있다.

이번에는 그러지 않았다.

필요한 것은 반복 가능한 거대한 시스템이 아니라 당장 디자인을 직접 만질 수 있는 representation이었다.

그래서 output도 단순했다.

```text
desktop/*.html
mobile/*.html
inventory.md

```

필요할 때 다시 export하면 된다.

이 방식이 반복적으로 핵심 workflow가 된다면 나중에 자동화를 더 붙일 수 있다.

하지만 첫 사용부터 별도 product로 확대하지 않았다.

## Physical source와 useful view는 다를 수 있다

이 작업을 하면서 History retrieval에서 썼던 원칙과 비슷한 패턴을 다시 봤다.

History에서는:

```text
physical files
!= useful retrieval view

```

였고, 그래서 source를 옮기지 않고 catalog/query projection을 추가했다.

디자인에서는:

```text
React component tree
!= useful visual editing view

```

였다.

그래서 React를 버리지 않고 static rendered projection을 추가했다.

둘 다 같은 방향이다.

```text
SOURCE HAS VALUE
+
CURRENT REPRESENTATION IS EXPENSIVE FOR THE TASK
→ ADD A PURPOSE-SPECIFIC PROJECTION

```

source를 새 구조로 다시 만들기 전에 필요한 view를 하나 더 만드는 방식이다.

## AI-assisted workflow에서 representation 선택이 생각보다 중요했다

AI를 많이 쓰면 모델 성능이나 prompt 품질에 먼저 관심이 간다.

하지만 실제 작업에서는 같은 정보를 어떤 형태로 놓느냐가 더 큰 차이를 만들 때가 있다.

React source는 구현에는 좋다.

Screenshot은 관찰에는 좋다.

Static rendered HTML은 visual editing에는 좋다.

```text
SAME PRODUCT
DIFFERENT TASK
→ DIFFERENT USEFUL REPRESENTATION

```

이번에는 더 좋은 디자인 AI가 필요한 게 아니었다.

내가 직접 판단하기 쉬운 surface가 필요했다.

38개 상태, 2개 viewport, 총 76개의 HTML은 그 문제를 꽤 단순하게 해결했다.

그리고 그 결과 디자인 수정의 병목을 AI가 내 말을 얼마나 잘 이해하느냐에서 내가 실제 화면을 보고 무엇을 바꿀 것인가로 다시 옮길 수 있었다.