대시보드
Morit Plugin3. 화면과 사용자 경험

기본·커스텀 컴포넌트

UI Runtime v2 node는 공통으로 type, 선택적 id, props, children, visible_when을 가집니다. action은 명확한 탭 영역을 제공하는 surface, card, button, chip에서만 허용됩니다. 구조·표시·입력 node에 action을 붙이면 Host, CLI, MCP 검증이 모두 거부하므로 버튼이나 탭 가능한 surface로 감싸세요. Host가 Material 3 widget으로 렌더링하며 플러그인은 Flutter widget이나 HTML을 전달하지 않습니다.

아래 모든 node는 현재 Android Host에서 지원됩니다. iOS·Desktop도 같은 JSON 계약을 재사용하도록 설계되어 있지만 Host 구현과 실기기 검증 전에는 지원 완료로 표시하지 않습니다. 플랫폼별 상태는 Android, iOS, Desktop 호환을 참고하세요.

레이아웃 컴포넌트

type목적주요 props제약
column세로 읽기 흐름spacing, padding, axis 정렬children 최대 32개
row짧은 항목의 가로 배치spacing, stack_at, axis 정렬좁은 화면 전환을 정의
wrapchip·필터의 자동 줄바꿈spacing, alignment의미 순서는 children 순서
grid같은 중요도의 반복 카드columns, min_item_width, spacing열 수보다 최소 너비 우선
stack겹치는 장식·badge 배치alignment, clippositioned의 직접 부모
positionedstack 안의 위치 지정left, top, right, bottom정확히 한 child, offset 하나 이상
scroll제한된 영역의 스크롤scroll_direction, shrink_wrap정확히 한 child, 중첩 스크롤 자제
padding한 subtree의 내부 여백padding정확히 한 child
center한 subtree 정렬alignment정확히 한 child
expandedrow/column의 남은 공간flexrow/column의 직접 child, child 하나

rowstack_at은 01200이고, 0은 자동 세로 전환을 끕니다. gridmin_item_width는 96600입니다. expanded.flex는 1~24입니다.

Surface와 구조

type목적주요 propschildren
surface안전한 커스텀 시각 surface크기, 여백, 색 token, border, elevation, opacity1개 이상 필수
card독립된 요약·선택 영역title, subtitle, tone, action선택
section제목이 있는 정보 그룹title, subtitle, spacing선택
divider같은 흐름 안의 구분color, margin없음
spacer제한적인 빈 공간size, width, height없음

surface가 Runtime v2의 커스텀 컴포넌트 경계입니다. 허용된 primitive와 Material token을 조합할 수 있지만 실행 코드, HTML, CSS, WebView, native view, 임의 shader는 넣을 수 없습니다. surface props는 spacing, padding, margin, 크기 제약, alignment, 색상, border, elevation, opacity, clip, enabled, tooltip, semantics로 제한됩니다.

json
{
  "type": "surface",
  "props": {
    "padding": {"horizontal": 16, "vertical": 12},
    "background_color": "primary_container",
    "foreground_color": "on_primary_container",
    "border_radius": 20
  },
  "children": [
    {"type": "text", "props": {"text": "오늘 일정 3개", "style": "heading"}}
  ]
}

텍스트와 데이터 표시

type목적주요 props
text제목·본문·라벨text, style, align, max_lines, color
iconHost icon tokenicon, size, color, semantic_label
imagepackage 또는 capability 결과 이미지asset/url, fit, 크기, semantic_label
avatar사람·계정·공간의 작은 이미지asset/url, size, semantic_label
badgechild 위의 짧은 상태 표식child 하나, alignment
metric라벨·큰 값·보조 문구label, value, supporting, tone
progress결정/비결정 진행률label, value
empty빈 데이터와 다음 행동 안내title, supporting, icon

imageavatar는 source를 정확히 하나만 가집니다.

  • asset: package 안의 assets/ GIF/JPEG/PNG/WebP 경로
  • url: {{data.<source>...}} 또는 목록 안의 {{item...}} 전체 binding 하나

literal 외부 URL, data:, file:, javascript:는 사용할 수 없습니다. url binding에는 capability 결과의 이미지 URL만 넣습니다. 이 이미지를 쓰는 package는 Manifest permissionsnetwork를 요청해야 하며 활성 Instance에도 network grant가 있어야 합니다.

앱은 binding으로 해석한 URL을 직접 요청하지 않습니다. Host가 인증된 이미지 proxy를 통해 공개 HTTPS URL만 가져오며 DNS/IP SSRF 검사와 redirect 차단을 적용합니다. 응답은 PNG/JPEG/GIF/WebP 중 하나여야 하고 MIME type, magic byte, 실제 이미지 포맷이 일치해야 합니다. 최대 크기는 512 KiB, 가로·세로는 각각 4096 px 이하입니다. 정적 이미지는 1 frame, 애니메이션은 최대 128 frame이며 width × height × frame 수로 계산한 frame 합산 pixel이 16,000,000 이하이어야 합니다. 조건을 통과하지 못하면 해당 이미지에만 오류 fallback을 표시하며 다른 UI와 capability 결과는 유지합니다.

중요한 이미지에는 semantic_label을 쓰고 순수 장식 이미지는 exclude_semantics: true를 사용합니다.

Icon token

icon, App bar action, navigation item의 iconselected_icon은 아래 Host token만 사용합니다. 임의 Material icon 이름이나 code point는 허용하지 않습니다. 목록에 없는 값은 Host, CLI, MCP와 앱 schema parser가 거부하며 다른 아이콘으로 조용히 바꾸지 않습니다. 모든 token은 현재 Android Host에서 같은 의미의 Material 3 아이콘으로 표시되고, iOS·Desktop Host도 이름과 의미를 그대로 유지해야 합니다.

목적지원 token
추가·편집·삭제add, edit, delete, close, check
이동·메뉴arrow_back, arrow_forward, menu, more, home, home_filled
파일·공유file, folder, description, download, upload, share, link
일정·데이터calendar, clock, event, list, analytics
상태·안내info, help, error, favorite, inbox, sparkle
사람·기능person, extension, search, settings, refresh
알림notification, notifications, bell
교육·급식school, education, meal
기존 package 호환 aliasarrow, schedule, school.settings

호환 alias는 각각 arrow_forward, clock, settings와 같은 의미입니다. 새 화면은 의미가 더 명확한 기본 token을 우선 사용하되 기존 서명 package의 alias도 계속 렌더링됩니다. 아이콘만 있는 action에는 반드시 label, 일반 icon node에는 semantic_label을 함께 제공합니다.

행동과 입력

type목적주요 props
button명시적인 주·보조 행동label, icon, style, full_width, enabled
chip필터·짧은 선택label, icon, selected, enabled
field텍스트·숫자·autocomplete 입력state_key, label, placeholder, input_type, suggestions/suggestions_source, persist
select고정·비동기·검색 선택지state_key, label, options/options_source, searchable, persist
switchboolean 설정state_key, label, persist
form관련 입력 묶음spacing, submit_label, children, 선택적 submit action
dialog짧고 집중된 확인·편집title, label, children
sheet모바일 중심의 보조 작업title, label, children

field, select, switchstate_keyinitial_state에 먼저 선언해야 합니다. select options는 1~32개의 { "value": ..., "label": "..." } 객체입니다. 정적과 source 옵션을 둘 다 선언할 수 없습니다. required, 문자열 길이, 숫자 범위와 error_text는 Host form validation에 사용됩니다. enabled: false는 이유를 주변 문구로 설명할 때만 사용합니다.

action은 surface, card, button, chip, form, field, select, switch에만 붙일 수 있습니다. 입력 action 직전에 Host가 IME composition과 controller를 commit하며, validate: true는 잘못된 form의 Tool·navigation 실행을 차단합니다.

반복과 데이터 시각화

type목적주요 props제약
list일반 항목 반복source, empty_text, limit, denseitem template child 정확히 하나
timeline시간 순서 사건source, empty_text, limititem template child 정확히 하나
calendar날짜별 데이터source, date_key, title_key, state_keysource 필수
chart수치 비교·추세·분포source, chart_type, x_key, y_key, show_legendbar, line, donut, scatter
table행·열 구조 데이터source, empty_text, limit, dense최대 6열, 가로 스크롤

반복 template 안에서는 {{item.title}}처럼 item binding을 사용합니다. 큰 목록을 한 번에 렌더링하지 말고 capability에서 페이지나 기간을 나눕니다.

공통 UX 프리셋

프리셋은 새 실행 타입이 아니라 검증된 primitive 조합입니다. 그래서 Preview와 Flutter Host가 같은 node를 렌더링하고 기존 플러그인도 별도 migration 없이 사용합니다.

프리셋조합Host가 맡는 상태
목록·검색field + button + list/timelinesource별 loading/error/retry, 빈 목록
상세app_bar + section + card/metricroute back, stale response 차단
form + field/select/switch + submit buttonfocus, keyboard, disabled feedback
설정section + persisted controlsstate 복원, permission/connection 관리 링크
빈 상태empty + 다음 행동 button의미 있는 title/supporting/icon
반응형 dashboardgrid.min_item_width + row.stack_at + adaptive navigationbar/rail/drawer 전환

목록·검색의 최소 tree:

json
{
  "type": "column",
  "props": {"spacing": 12},
  "children": [
    {"type": "field", "props": {"state_key": "query", "label": "검색", "placeholder": "검색어"}},
    {
      "type": "button",
      "props": {"label": "찾기", "icon": "search"},
      "action": {"type": "invoke", "capability": "com.example.search", "query": "{{state.query}}", "arguments": {}, "store": "results"}
    },
    {
      "type": "list",
      "props": {"source": "data.results.data.items", "empty_text": "검색 결과가 없어요.", "limit": 50},
      "children": [
        {"type": "card", "props": {"title": "{{item.title}}", "subtitle": "{{item.summary}}"}}
      ]
    }
  ]
}

권한 요청, 연결 필요, 첫 loading, capability error와 retry는 플러그인이 비슷한 경고 카드를 다시 만들지 않고 Host 공통 상태를 사용합니다. Plugin 상세의 권한/Connection 화면으로 이동한 뒤 같은 route state와 persisted control을 복원합니다. 데이터가 정상적으로 비었을 때만 empty 또는 empty_text를 사용하며 오류를 빈 목록으로 숨기지 않습니다.

모든 프리셋은 light/dark, 320px 폭, tablet/desktop 폭, 큰 글자에서 확인합니다. node별 tooltip, semantic label, 최소 탭 영역과 색 이외의 상태 표시는 Host Material 3 규칙을 따릅니다.

A2UI Response catalog와의 관계

위 node는 Plugin Runtime을 구성하는 primitive입니다. AI가 직접 선택하는 Response catalog는 weather, world_clock, chart, image_gallery, exchange_rate, article_list, article_card, file_result, image_preview, video_preview와 활성 Plugin이 등록한 plugin.<extension-id>로 구성됩니다. 최종 답변 모델은 같은 Registry Skill과 Native Tool에서 출처(builtin/plugin), mode(provider/generated/result), 용도와 Schema를 확인합니다. provider mode는 조회 조건만, generated mode는 답변에 근거한 표시 값만 전달하며 Host가 검증한 뒤 Runtime tree에 주입합니다. 특정 키워드만으로 Tool을 강제하지 않습니다. 구조화 표는 A2UI 전용 컴포넌트 대신 Markdown table을 사용합니다. 위 표의 Runtime table node는 플러그인 화면 호환성을 위한 primitive로 계속 지원합니다. 자세한 등록·fallback 규칙은 Response UI와 Agent Timeline을 참고하세요.

공통 크기·정렬·접근성 props

  • 크기: width, height, min_width, max_width, min_height, max_height
  • 여백: padding, margin, spacing
  • 정렬: alignment, main_axis_alignment, cross_axis_alignment, main_axis_size
  • 시각: color, background_color, foreground_color, border_color, border_width, border_radius, elevation, opacity
  • 이미지: aspect_ratio, fit
  • 접근성: tooltip, semantic_label, exclude_semantics

텍스트 align의 실제 렌더 값은 start, end, left, right, center, justify입니다. 이전 UI v2 package가 사용한 다른 안전한 identifier도 호환을 위해 검증 단계에서는 수용하지만 Host는 기본 정렬로 처리합니다. 새 manifest에는 위 열거 값만 사용하세요.

크기와 색상 범위는 토큰과 반응형에 정리되어 있습니다.

기본·커스텀 컴포넌트 - Developers | Moring Developers