DOM이 없는 앱 자동화하기: 좌표만으로 Flutter/Canvas 에디터 제어하기
요약
DOM이 존재하지 않는 Flutter Web이나 Canvas 기반 앱을 자동화하기 위한 좌표 기반 제어 전략을 소개합니다. 뷰포트 안정화, 줌을 통한 텍스트 인식, 시각적 피드백 확인 등 실전적인 4가지 규칙을 다룹니다.
핵심 포인트
- 창 크기와 devicePixelRatio가 안정될 때까지 대기 필수
- Canvas 내 텍스트 추출을 위해 영역 확대(Zoom) 후 스크린샷 활용
- 클릭 후 시각적 변화를 확인하여 동작 성공 여부 검증
- 더블 클릭 구현 시 두 번의 빠른 단일 클릭 방식 권장
지난 포스트에서 저는 일반적인 HTML 페이지의 경우, 요소 기반 자동화(find / read_page)가 좌표 기반 방식보다 항상 우월하다고 말씀드렸습니다. 이번 포스트는 그 조언이 무용지물이 되는 앱들에 관한 이야기입니다.
Flutter Web 앱들. Canvas로 렌더링되는 에디터들. 화면에 보이는 모든 버튼과 패널은 DOM에 존재하지 않습니다. 모든 것이 단일 Canvas 위에 그려진 픽셀일 뿐입니다. find는 아무것도 반환하지 않습니다. read_page의 접근성 트리(accessibility tree)는 사실상 비어 있습니다.
저는 Claude를 사용하여 Rive 에디터(Flutter로 구축된 애니메이션 도구)가 에셋을 선택하고 내보내는 전 과정을 수행하도록 만들었습니다. 여기 실제 상황을 견뎌내며 살아남은 절차를 소개합니다.
0단계: 실제로 이런 상황인지 확인하기
좌표 기반 자동화는 취약하기 때문에, 대안을 배제한 후에만 사용해야 합니다. 테스트는 간단합니다: read_page를 실행하세요. 만약 눈에 보이는 UI에 대응하는 노드가 거의 없다면, 당신은 Canvas로 렌더링된 앱을 보고 있는 것이며, 좌표가 당신이 가질 수 있는 유일한 인터페이스입니다.
네 가지 규칙
1. 다른 무엇보다 창 크기가 안정될 때까지 기다리기
제 이전 포스트와 동일한 실패 사례입니다: 로드 직후에는 뷰포트(viewport)가 최종 너비에 도달하지 않았으며(저는 2~3초에 걸쳐 1664에서 1920으로 변하는 것을 측정했습니다), 초기 스크린샷을 기반으로 한 클릭은 대상의 오른쪽 지점에 떨어지게 됩니다. javascript_tool을 통해 innerWidth를 두 번 읽으세요. 연속된 두 번의 읽기 값이 일치할 때만 진행하십시오. 하지만 innerWidth가 일치하는 것만으로는 충분하지 않습니다. 조작하려는 스크린샷 이후에 devicePixelRatio가 변경되지 않았는지도 확인해야 합니다(제 이전 포스트의 후속 연구에서 이 사실이 드러났습니다: DPI나 스케일링이 변경되면 전체 좌표 공간이 동일하게 재조정되지만, 새로운 값은 즉시 안정화되므로 innerWidth만 체크해서는 이를 잡아낼 수 없습니다). Canvas 앱은 클릭이 빗나갔을 때 요소 기반의 대체 수단이 없기 때문에, 이 부분에서 더욱 철저한 주의(paranoia)가 필요합니다.
2. 텍스트를 추출하는 것이 아니라 줌(zooming)을 통해 읽기
캔버스(canvas)에 그려진 텍스트는 DOM에서 추출할 수 없습니다. 메뉴 항목이나 패널 레이블을 읽으려면 해당 영역을 zoom(확대)하고, 확대된 스크린샷을 이미지로서 읽어야 합니다. 전체 페이지 스크린샷은 작은 텍스트를 잘못 읽기 쉽게 만듭니다. "읽기 전에 확대하라"를 반사적으로 수행해야 합니다.
3. 클릭할 때마다 시각적 증거를 요구할 것
좌표 클릭을 놓쳐도 에러는 발생하지 않습니다. 아무 일도 일어나지 않습니다. 만약 이를 인지하지 못한 채 진행한다면, 이후의 모든 단계는 잘못된 전제 위에서 작동하게 됩니다.
따라서 다음과 같이 수행하십시오: 클릭 → 스크린샷 → 선택의 시각적 증거 확인 (Rive의 경우 파란색 하이라이트, 다른 앱의 경우 선택 테두리나 색상 변화) → 그제서야 계속 진행. 증거가 없다면 진행하지 마십시오. 좌표를 다시 도출하고 재시도하십시오.
4. 두 번의 빠른 단일 클릭으로 더블 클릭 구현하기
double_click 액션은 앱의 더블 클릭 임계값(threshold)을 초과하여 두 번의 단일 클릭으로 전락할 수 있습니다. 캔버스 에디터는 계층 구조로 진입하기 위한 더블 클릭 상호작용을 선호하므로, 이 문제는 진행을 막을 것입니다. 하나의 browser_batch 내에서 동일한 좌표에 두 번의 left_click을 실행하십시오. 간격을 충분히 좁히면 더블 클릭으로 인식됩니다.
실제 실행 사례 (Rive 에디터)
이를 종합하면, "에셋을 선택하고 내보내기(export)" 과정은 다음과 같습니다:
- 에디터 열기 →
innerWidth가 안정될 때까지 대기 - 전체 스크린샷 → 대상 패널 위치 파악
- 객체에 대해 빠르게 두 번 클릭(double-fire) → 스크린샷 → 파란색 하이라이트 확인
- 메뉴 좌표 클릭 → 메뉴 영역 확대(zoom) → 항목 레이블 읽기
- Export 클릭 → 스크린샷 → 대화 상자(dialog)가 나타났는지 확인
모든 단계 뒤에 검증 단계가 끼어 있으므로, 작업 횟수는 사람이 필요로 하는 양의 두 배에 달하기 쉽습니다.
느리지만, 계속해서 움직입니다.
좌표 자동화로 속도를 쫓다 보면 인지하지 못한 실패의 연쇄가 발생하며, 이는 검증 작업에 드는 시간보다 훨씬 더 많은 시간을 낭비하게 만듭니다. 이것이 이 방식을 실제 운영 환경(production)에서 실행하며 얻은 실제 교훈이었습니다.
한계 및 주의사항
이 접근 방식은 화면 레이아웃이 안정적임을 가정합니다. 레이아웃이 끊임없이 재배치되는 페이지(광고, 알림 등)는 좌표의 신뢰성을 더욱 떨어뜨립니다.
특정 앱의 UI 레이아웃은 업데이트에 따라 변경될 수 있으며, Rive도 마찬가지입니다. 전달되는 것은 픽셀(pixels)이 아니라 절차입니다: 안정화 대기(settle-wait) → 확대 및 읽기(zoom-read) → 증거 확인(evidence-check) → 신속한 이중 실행(rapid double-fire).
Windows / 1920×1080 환경에서 검증되었습니다. DPI 스케일링(DPI scaling) 설정이 다를 경우 좌표 동작이 변경될 수 있습니다.
검증 완료: 2026년 6월. 환경: Windows 11 / Chrome + Chrome 확장 프로그램 내 Claude / Rive 에디터 (Flutter/canvas).
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기