Communitygithub.com

undefine-org/ux-from-use

사용 중 마주친 문제(버그 리포트, 불편함, '이건 왜 여기 있지?')를 제품이 확립해야 할 경험으로 전환하고, 구조적 원인을 찾아 수정한 후, Beam Lisp의 브라우저 네임스페이스로 실제 브라우저에서 직접 테스트하고, 모델의 테이프에 시나리오 영상으로 보관합니다. Othman이 앱 사용 중 발견한 사항을 보고하거나, 수동 테스트를 요청하거나, 기능을 영상으로 문서화하길 원할 때 사용하세요.

ux-from-use란 무엇인가요?

이 스킬은 사용자 경험 중심의 개발 워크플로우를 자동화합니다. 버그 리포트나 불편 사항을 단순히 수정하는 대신, 그 증상 뒤에 숨은 진정한 경험 요구사항을 문장으로 작성하고, 구조적 원인을 찾아 수정한 후, Beam Lisp의 브라우저 네임스페이스를 통해 실제 브라우저에서 직접 테스트합니다. 또한, 모든 과정을 시나리오 테스트로 전환하고 모델의 테이프에 녹화하여 재현 가능한 영상 문서로 만듭니다. Claude Code, Cursor, Codex와 같은 AI 에이전트 플랫폼에서 사용할 수 있으며, 특히 Knowledger 앱 개발에 특화된 'House Taste' 스타일 가이드를 따릅니다. 이 스킬의 핵심은 '경험 문장 쓰기 → 구조적 원인 찾기 → 직접 테스트 → 영상 시나리오로 보관'의 반복 주기를 통해 제품의 사용자 경험을 체계적으로 개선하는 것입니다.

지원 대상~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/undefine-org/enchanted-skills/tree/main/ux-from-use

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

사용에서 경험으로

리포트는 증상을 이름 붙입니다. 작업은 그 뒤에 있는 경험입니다. "대화가 주제로 옮겨가면 클라이언트가 사라진다"는 버그입니다. "대화는 그 주제를 모은다: 주제가 추가되면 클라이언트가 남는다"가 구축하고, 확인하고, 촬영할 내용입니다. 먼저 그 문장을 작성하세요. 증상을 가능하게 한 구조를 수정한 다음, 제품을 직접 사용하여 그 문장을 증명하세요.

반복 주기

  1. 사용 기록 수집. 리포트를 읽고, 실제 사용 흔적(대화, 일지, 로그, 접속 여부, 건드린 파일)을 읽습니다. 그 흔적에는 아무도 문서화하지 않은 기대가 담겨 있습니다("ils en sont où?"는 요약이 아니라 포인트 자체를 기대합니다).
  2. 경험을 작성하세요. 리포트당 한 문장, 현재 시제, 사용자 관점에서, 구현 관련 단어는 쓰지 않습니다. 목록을 유지하세요. 그것이 영상의 내레이션이자 클레임의 메시지가 됩니다.
  3. 구조적 원인을 찾으세요. 왜 제품이 이런 일을 할 수 있었는지 물어보세요. 하나의 원인이 여러 리포트를 설명하는 경우가 많습니다(표시 이름에서 가져온 신원; 단어를 공유하는 두 개의 카운트; 삽입 시 클래스를 버리는 렌더러). 증상을 보여준 화면이 아니라 원인을 수정하세요.
  4. 직접 사용해 보세요. 브라우저 네임스페이스(아래 참조)를 통해 관련된 각 사용자로서 데스크톱 및 휴대폰 너비에서 실제 앱을 구동하세요. 스크린샷을 확인하세요. 코드가 의도한 것이 아니라 페이지가 말하는 것을 세세요.
  5. 보관하세요. 수동 단계를 시나리오로 전환하세요: 액션은 이벤트가 되고, 확인은 클레임이 되며, 경험 문장은 장면의 내레이션이 됩니다. 모델 턴을 테이프에 녹화하여 영상이 비용 없이 몇 초 만에 재생되도록 하세요.
  6. 패치가 아닌 경험을 보고하세요. 요약에서는 사용자가 이제 무엇을 찾을 수 있는지, 그 다음 원인, 그리고 영상 및 재생 방법을 먼저 제시하세요.

하우스 취향 (Othman이 반복적으로 요청한 사항)

  • 복사를 줄이세요. 상태는 그려집니다: 어조, 무게, 배치, 링, 마크. 화면을 설명하는 문장은 화면이 잘못되었음을 의미합니다.
  • 아이디어당 한 단어. 용어집을 유지하고 지키세요: "critère"(절차에 따라 판단됨)는 절대 "point"(사람이 결정하는 것)가 아닙니다. 두 카운트가 단어를 공유하면 누군가 그것들을 더할 것입니다.
  • 것들은 누적됩니다. 태그는 쌓입니다(종류, 그 다음 클라이언트, 그 다음 주제). 현재 태그는 채워지고 나머지는 윤곽선으로 남습니다. 사용자가 이미 본 컨텍스트를 절대 대체하지 마세요.
  • 텍스트보다 숫자가 먼저 그려집니다. 내역은 차트로 열리며, 각 시리즈마다 하나씩, 값이 레이블로 표시됩니다. 텍스트는 그 아래에 있으며, 이벤트당 한 줄씩, 요청 시 열립니다.
  • 모든 참조는 해당 위치로 연결됩니다. 단락 번호는 해당 단락으로 스크롤되고 강조됩니다. 인용문은 해당 구절을 찾습니다. 스크롤바는 것들의 위치를 색상으로 표시합니다.
  • 기본적으로 라이브. 전체 새로고침 없음. 한 사람이 변경한 내용이 모든 열린 페이지에 즉시 표시됩니다. 느린 페이지에서 반복 탭이 효과를 반복해서는 안 됩니다: 제스처는 멱등적이어야 합니다.
  • 컨트롤은 해당 항목이 있는 곳에, 그리고 그것을 사용할 수 있는 사람에게만 표시됩니다. 읽기 전용 사용자는 컨트롤 없이 상태를 봅니다.
  • 누가 있는지 알 수 있어야 합니다. 신원과 역할이 모든 화면과 모든 에이전트에 도달해야 합니다. 파트너에게 "파트너가 확인해야 합니다"라고 말하지 마세요.
  • 정직한 가장자리. 제품이 아직 하지 못하는 것을 솔직하게 말하세요. 그것을 할 수 없는 화면을 가리키지 마세요.
  • 휴대폰 너비는 일급 독자입니다: 16px 거터, 수평 스크롤 없음(minmax(0,1fr), 1fr 아님), 계정은 항상 접근 가능해야 합니다.
  • 제품 언어로 된 목업과 내레이션 (Knowledger의 경우 프랑스어).

브라우저 네임스페이스로 수동 테스트

Beam Lisp의 네이티브 브라우저(beam-lisp 트리의 optional/browser-port`)는 신뢰할 수 있는 입력과 연속 스크린캐스트로 프라이빗 헤드리스 Sway에서 헤드형 Chromium을 실행합니다. 시나리오가 구동하는 것과 동일한 객체이므로, 수동 세션이 다시 작성되지 않고 테스트로 성장합니다. 빠른 확인에는 agent-browser를 사용하세요. 보관할 가치가 있는 것은 브라우저 네임스페이스를 사용하세요.

머신당 한 번

cd ~/projects/beam-lisp/optional/browser-port
nix develop --command cargo build --release --locked --features native-browser
nix build .#runtime-wayland --out-link ~/.local/share/bl-browser/runtime-wayland   # chromium, sway, wayvnc
command -v ffmpeg || nix profile add nixpkgs#ffmpeg

bl run -p ~/projects/beam-lisp/optional/browser-port/bl …(또는 bl test -p …)로 사용하는 모든 것을 실행하세요.

프로브: 파일 하나, 사람 하나, 실제 입력

templates/probe.bl이 시작점입니다. 핵심:

(ns probe (:require [browser.page :as page]))
(def rt (str (System/get_env "HOME") "/.local/share/bl-browser/runtime-wayland/bin/"))
(def p (page/open! {:executable (str (System/get_env "HOME") "/projects/beam-lisp/optional/browser-port/target/release/bl-browser-port")
                    :width 1440 :height 860
                    :launch {"profile" "/tmp/probe/profile" "runtime" "/tmp/probe/runtime"
                             "chromium" (str rt "chromium") "compositor" (str rt "sway") "vnc" (str rt "wayvnc")
                             "width" 1440 "height" 960}}))
(try
  ;; 누가 보고 있는지: 프록시가 추가할 신원(여기서는 Tailscale 헤더); 라이브 소켓에도 도달합니다
  (page/cdp! p "Network.enable" {})
  (page/cdp! p "Network.setExtraHTTPHeaders" {"headers" {"tailscale-user-login" "[email protected]" "tailscale-user-name" "timinou"}})
  (page/record! p "/tmp/probe/take.mp4" {:fps 24})          ; 선택 사항: 전체 세션을 영화로
  (page/navigate! p "http://127.0.0.1:24025/a/sahel-…")
  (page/wait! p "document.documentElement.dataset.live==='1'") ; JS 조건자, 기본 30초 제한
  (page/click! p ".rv-rail a.para[data-goto]")               ; 신뢰할 수 있는 포인터: 이동, 누름, 놓음
  (println (page/evaluate! p "scrollY"))                     ; 사람이 볼 내용을 페이지에 묻기
  (page/screenshot! p "/tmp/probe/after.png")                ; 그런 다음 확인
  (page/stop-recording! p)
  (finally (page/close! p)))

동사는 navigate! wait! click! hover! fill! key! drag! evaluate! screenshot! record! stop-recording! show-cursor! cdp!입니다. cdp!는 Chromium이 제공하는 다른 모든 것(뷰포트, 네트워크, 쿠키, 에뮬레이션(휴대폰용 Emulation.setDeviceMetricsOverride))에 도달합니다.

프로브를 보관할 가치가 있게 만드는 습관

  • 코드가 아닌 페이지에 물어보세요. 모든 확인은 사람이 해당 사항을 볼 때 true를 반환하는 JS 표현식입니다: 행 수, 태그의 텍스트, scrollY, 포인터 아래 요소의 클래스. 해당 표현식은 변경되지 않고 클레임이 됩니다.
  • 의미로 선택하세요. 테스트에 필요한 곳에 안정적인 데이터 속성을 앱에 제공하세요(button.cell[data-person='Karim Saadi'][data-team='Associés']), 절대 "다섯 번째 버튼"이 아닙니다.
  • 각 사람이 되어 보세요. 각 사람의 신원으로 페이지를 하나씩 엽니다. 두 페이지를 나란히 두는 것이 "라이브"를 증명하는 방법입니다: 하나는 액션을 취하고, 다른 하나는 새로고침 없이 변경됩니다.
  • 첫 페인트와 패치된 페이지를 모두 확인하세요. 라이브 앱은 HTML을 한 번 렌더링한 다음 데이터에서 패치합니다. 버그는 차이점에 숨어 있습니다(삽입 시 클래스가 드롭됨, 텍스트로 시작하는 목록이 태그 이름으로 읽힘). 모든 화면에 URL로 한 번, 그리고 탐색으로 한 번씩 도달하세요.
  • 연결뿐만 아니라 페이지가 라이브가 될 때까지 기다리세요. 라이브 클라이언트는 서버에서 렌더링된 페이지를 소켓의 첫 번째 렌더링으로 대체할 수 있습니다. 그 사이에 입력된 텍스트는 테스트와 로드 후 빠르게 입력하는 사람 모두에게 손실됩니다. 앱은 마운트 전에 입력된 내용을 유지하고 라이브 상태임을 알려야 합니다(data-mounted). 테스트는 이 플래그를 기다립니다.
  • 휴대폰 너비를 확인하세요. 390px에서 document.documentElement.scrollWidth === innerWidth를 확인한 다음 스크린샷을 확인하세요.
  • 실제 데이터를 절대 건드리지 말고, 증명하세요. 앱을 데이터의 리플링크 복사본(cp -a --reflink=auto)과 여분의 포트로 지정하세요. 그런 다음 신뢰하기 전에 격리를 증명하세요: 복사본에서 한 가지 이름을 바꾸고(카나리아: 팀 "AssociésX"), 그것에 대해 액션을 취하고, 복사본이 변경되었고 실제 파일의 타임스탬프가 변경되지 않았는지 확인하세요. 쓰는 프로세스 유형(페이지 핸들러, 라이브 소켓, 백그라운드 작업)당 한 번씩 수행하세요. Beam Lisp에서 테스트의 System/put_env는 페이지 핸들러에 도달하지만 라이브 소켓에는 도달하지 않습니다: 구성된 데이터 폴더를 읽지 않는 소켓은 기본값(실제 데이터)으로 폴백됩니다. 앱은 서버가 시작될 때 구성(persistent_term)을 VM 전체에 고정하고 거기에서 읽어야 합니다. 라이브 데이터를 건드려야 하는 경우 파일을 스냅샷하고, 액션을 취하고, 변경 사항만 확인하기 위해 diff를 수행하고, 복원하세요.

프로브에서 영화로

scenario.demo/defdemo는 일반 테스트입니다(bl test). 단계는 일대일로 매핑됩니다:

프로브시나리오
(page/navigate! p url)(s/does :othman [:navigate url])
(page/wait! p js)(s/does :othman [:wait js])
(page/click! p sel) / hover! / fill! / key![:click sel] [:hover sel] [:fill sel text] [:key "Enter"]
눈을 위한 일시 중지[:pause ms]
true여야 하는 (page/evaluate! p js)(s/sees :othman (fn [p _] (= true (page/evaluate! p js))) "the experience")
사람browser.film/owned-worlds의 배우, 열 때 신원을 설정하도록 래핑됨
내레이션 단락(demo/scene :id {:title … :say … :capture :video} events…)

templates/feature-demo.bl은 완전한 파일입니다: 앱 데이터의 격리된 복사본, 테스트 VM의 여분 포트에서 시작된 앱, 신원이 있는 녹화된 월드, 음성 키가 없을 때 무음 트랙, 세 개의 장면이 있는 하나의 데모. 작업 예제: knowledger-interface-review/apps/practice/test/features-demo.bl (다섯 개의 영화: 리뷰, 내역, 조각, 두 사람 간에 라이브로 변경된 팀, 테이프에 녹화된 대화).

장면을 수정이 아닌 경험으로 작성하세요: "§-링크 핸들러 수정"이 아니라 "각 포인트는 해당 위치로 연결됩니다". 내레이션이 문서입니다.

모델 턴을 테이프에 녹화

에이전트가 수행하는 모든 것은 앱 자체의 도구 도어를 통해 이루어져야 하므로, 모델의 선택만 모델의 것입니다. 테이프는 하나의 모델 실행에 대해, 모델, 시스템 프롬프트 및 프롬프트의 해시(시계, 에포크와 같은 숫자 및 16진수 ID는 마스킹됨)로 키가 지정된, 순서대로 도어 호출과 최종 답변을 보관합니다.

  • record: 테이프에 있는 것을 재생하고, 없는 것은 모델을 실행하고, 보관합니다.
  • replay(기본값): 테이프에 없는 실행은 오류 턴입니다. 리플레이는 절대 조용히 모델로 폴백되지 않습니다.
  • 리플레이는 동일한 도어를 통해 동일한 호출을 속도 조절하여 수행하므로, 제품이 다시 작업을 수행하고 화면에 표시되며, 몇 초 만에 무료로 이루어집니다.

프롬프트에 도달하는 모든 것(회사 이름, 날짜가 있는 경우)을 테스트 데이터에 고정하세요. 그렇지 않으면 키가 달라집니다. 테이프를 커밋하세요. 참조 구현: apps/practice/src/practice/cassette.bl 및 conversation.bl의 두 훅(턴 및 도어).

실행 및 렌더링

bl test -p ~/projects/beam-lisp/optional/browser-port/bl app/test/features-demo.bl             # 리플레이, 증명, 캡처
DEMO_RECORD=1 bl test -p …                       # 누락된 모델 턴을 테이프에 넣기 (모델 자격 증명 필요)
BL_DEMO_EXPORT=1 bl test -p …                    # 또한 영화당 MP4 + 자막 + 챕터 렌더링

각 영화는 픽스처에서 마지막 테이크를 지웁니다. 녹화는 절대 덮어쓰지 않기 때문입니다. 각 내레이션을 두 개의 자막 줄(약 130자) 이내로 유지하세요. 그렇지 않으면 렌더러가 거부합니다. 로드된 머신은 스크린캐스트 인코더를 굶길 수 있습니다: frames/recordings.json을 확인하세요. 여기서 encodedFrames는 약 초 × fps여야 하며, 테이크가 짧으면 다시 실행하세요.

렌더링(scenario.film/export!)에는 Python 3과 libass가 있는 FFmpeg가 필요합니다. DEEPGRAM_API_KEY가 설정되면 내레이션이 음성으로 출력됩니다. 그렇지 않으면 각 장면은 자막을 읽는 데 걸리는 시간만큼의 무음 트랙을 얻습니다. 음성 키가 존재한다고 가정하지 마세요. 루프백에서 (scenario.demo/serve! dir {:port 4163})로 영화를 탐색하거나, work serve로 게시하세요.

완료되었다고 말하기 전에

  • 각 보고된 항목에는 경험 문장, 원인, 그리고 실제 브라우저에서 각 관련 사용자로서 이를 증명하는 클레임이 있습니다.
  • 데스크톱 및 휴대폰 너비가 스크린샷에서 확인되었으며, 단언만 한 것이 아닙니다.
  • 터치한 모든 화면에 대해 첫 페인트와 패치된 페이지가 모두 확인되었습니다.
  • 라이브 동작이 중요한 경우 두 사람으로 증명되었습니다.
  • 테스트로 인해 변경된 실제 데이터가 없습니다. 건드린 모든 것은 복원되었으며, diff가 표시됩니다.
  • 영화는 네트워크 없이 테이프에서 재생됩니다. 테이프와 시나리오는 커밋되며, 렌더링은 커밋되지 않습니다.
  • 요약은 사용자가 이제 무엇을 찾을 수 있는지로 시작합니다.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬