토큰, 크기, 색, 여백, 반응형
Runtime v2와 v3는 기본적으로 Morit의 Material 3 theme를 사용합니다. 플러그인은 전체 앱의 theme를
바꾸지 않고 자신의 extension 범위 안에서만 제한된 theme와 node props를 적용합니다.
Extension theme
{
"theme": {
"radius": 18,
"spacing": 12,
"density": "standard",
"surface": {"elevation": 1},
"border": {"width": 1},
"icon": {"size": 22},
"typography": {"scale": 1.0, "body_weight": 400, "title_weight": 700},
"states": {"disabled_opacity": 0.38},
"light": {
"color_scheme": {
"primary": "#315DA8",
"on_primary": "#FFFFFF",
"surface": "#F9F9FF",
"on_surface": "#1A1B20"
}
},
"dark": {
"color_scheme": {
"primary": "#AFC6FF",
"on_primary": "#002F66",
"surface": "#111318",
"on_surface": "#E2E2E9"
}
}
}
}
radius: 0~64spacing: 0~32density:compact,standard,comfortablecolor_scheme: Material role과#RRGGBB또는#AARRGGBBtypography:scale0.81.4, body/title weight 100900surface:color,container_color,elevation0~24border:color,width08,64radius0icon:color,size12~64states:disabled_opacity0.2~0.8,selected_color,focus_colorlight,dark: 위 필드의 mode별 partial override
최상위 base → 현재 mode variant → Host Material 3 theme 순서로 병합됩니다. 누락한 role은 Host가 채우므로 기존 플러그인은 선언을 추가하지 않아도 앱의 라이트·다크 모드를 따릅니다. 명백히 같은 literal 전경/배경은 validate 오류이며 계산 가능한 4.5:1 미만 조합은 경고입니다. 대비가 확인된 작은 palette만 override하고 모든 role을 임의로 복제하지 않습니다.
색상 token
node의 color, background_color, foreground_color, border_color는 다음 semantic token이나
hex를 사용합니다.
primary, on_primary, primary_container, on_primary_container
secondary, on_secondary, secondary_container, on_secondary_container
tertiary, on_tertiary, tertiary_container, on_tertiary_container
error, on_error, error_container, on_error_container
surface, on_surface, surface_variant, on_surface_variant
outline, outline_variant
inverse_surface, inverse_on_surface, inverse_primary
shadow, scrim, transparent
semantic token을 우선합니다. hex는 브랜드 식별이나 데이터 범례처럼 의미가 명확하고 light/dark 대비를 직접 확인한 경우에만 사용합니다. 상태를 색 하나로만 표현하지 말고 아이콘·문구를 함께 제공합니다.
여백
padding과 margin은 0~128 숫자 하나 또는 다음 세 형태 중 하나입니다.
16
{"all": 16}
{"horizontal": 16, "vertical": 12}
{"left": 16, "top": 8, "right": 16, "bottom": 20}
형태를 섞을 수 없습니다. spacing은 children 사이 간격이며 0~128입니다. 화면 가장자리 여백은
Host가 제공하므로 root에 과도한 padding을 중복하지 않습니다.
크기와 surface
min_width <= max_width, min_height <= max_height여야 합니다. 고정 width와 height는 아이콘,
avatar, 썸네일처럼 크기 의미가 있는 항목에만 쓰고, 본문 카드에는 min/max 제약과 자연 크기를
사용합니다.
정렬
alignment:
top_left, top_center, top_right
center_left, center, center_right
bottom_left, bottom_center, bottom_right
main_axis_alignment은 start, end, center, space_between, space_around,
space_evenly를 사용합니다. cross_axis_alignment은 start, end, center, stretch,
baseline을 사용합니다. main_axis_size는 min 또는 max입니다.
텍스트 align은 start, end, left, right, center, justify입니다. 다국어 화면에는
물리 방향 left/right보다 논리 방향 start/end가 안전합니다.
반응형 규칙
모바일 기본값
모바일에서는 한 화면에 한 가지 주 작업만 두고, 제목·상태·주요 행동 순서로 짧은 세로 흐름을 만듭니다. 장식용 surface 중첩과 별도 색을 줄이고 Host의 typography, semantic color, 기본 여백을 우선합니다. 자주 쓰는 행동은 엄지로 닿는 하단 navigation/action에 두되 파괴적 행동과 붙이지 않습니다. 320px 폭과 큰 글자에서도 가로 스크롤 없이 핵심 문구와 행동이 남아야 합니다.
- 한 화면의 primary action은 하나를 기본으로 합니다.
- 긴 설정 form은 의미 단위 screen이나 section으로 나누고 입력값을 보존합니다.
- 짧은 목록은 card보다 divider와 여백으로 계층을 만들고, card 안에 card를 넣지 않습니다.
- hover에만 정보를 두지 않고 tap, keyboard focus, screen reader에서 같은 의미를 제공합니다.
Row 전환
{
"type": "row",
"props": {"spacing": 12, "stack_at": 480},
"children": []
}
가용 폭이 stack_at보다 작으면 세로로 배치합니다. 입력과 버튼, 두 개 이상의 긴 텍스트가 있는
row에는 480 전후를 시작점으로 사용하고 실제 큰 글자 크기에서 확인합니다.
Grid 열 축소
{
"type": "grid",
"props": {"columns": 3, "min_item_width": 160, "spacing": 12},
"children": []
}
columns는 희망 최대 열 수이고, Host는 min_item_width 96~600을 지키도록 열을 줄입니다. 모바일
가로 폭을 채우기 위해 글자와 숫자를 지나치게 압축하지 않습니다.
Adaptive navigation
navigation.type: "adaptive"는 좁은 화면의 navigation bar와 넓은 화면의 rail/drawer를 Host가
선택하게 합니다. rail_breakpoint는 480~1600이며 꼭 필요한 경우에만 기본값을 조정합니다.
접근성과 동적 크기
- 중요한 텍스트는
max_lines로 잘라 의미를 잃지 않게 합니다. - 버튼은 icon만 두지 말고
label을 제공합니다. - 이미지와 의미 있는 icon에는
semantic_label을 제공합니다. - 작은
dense목록은 스캔 중심 화면에만 사용합니다. - light/dark theme, 시스템 큰 글자, 320px급 폭, tablet/desktop 폭에서 확인합니다.
- animation이나 색 변화가 없어도 현재 선택과 진행 상태를 알 수 있어야 합니다.
SDK 1.7.13: 그라데이션과 가로 카드 목록
아래 속성에는 min_morit_version: "1.7.13" 이상이 필요합니다. 구형 앱은 해당 플러그인의
UI를 로드하지 않으며 호환되지 않는 업데이트로 동작 중인 설치를 덮어쓰지 않습니다.
기존 v1/v2 화면과 세로 목록은 그대로 유지됩니다.
gradient_colors: 2~8개의 기존 색 토큰 또는 HEX 색상. 왼쪽 위에서 오른쪽 아래로 연결합니다.surface와card에서도 클릭 효과 아래에 그려집니다. 콘텐츠의color를 명시해 대비를 확보합니다.list.props.scroll_direction: "horizontal": 자동 재생 없는 가로 카드 목록입니다.height는 기본 280dp,min_item_width는 기본 280dp이며 좁은 화면에서는 다음 카드 일부가 보입니다.list.props.item_key: 결과 항목의 고유한 필드 이름입니다. 서버가 변하지 않는 ID를 제공해야 합니다.- 목록
limit은 최대 100입니다. 기본값은 20이며 대량 데이터는 데이터 소스에서 페이지를 나눕니다.
data.news.data.items를 반환하는 news 데이터 소스가 있는 화면의 예:
{
"type": "list",
"props": {
"source": "data.news.data.items",
"item_key": "id",
"scroll_direction": "horizontal",
"height": 240,
"min_item_width": 280,
"spacing": 12
},
"children": [{
"type": "surface",
"props": {
"gradient_colors": ["#00856A", "#176CB3"],
"border_radius": 18,
"padding": 20
},
"children": [{
"type": "text",
"props": {"text": "{{item.title}}", "color": "#FFFFFF", "style": "title", "max_lines": 4}
}]
}]
}
브랜드 색상·이미지·장식은 정보 계층을 돕는 범위에서 유지합니다. 모든 플러그인을 같은 무채색 카드로 만들 필요는 없습니다. 라이트·다크 테마는 각각 읽기 편한 배경과 글자색을 지정합니다.
글자와 상호작용 표현
text는 font_size(1064), 900, 100 단위), font_weight(100line_height(1~2.5)를
선택적으로 지정합니다. 시스템 글자 확대는 그대로 적용됩니다. 가로 목록의 높이도 글자 확대를 반영합니다.
selected_background_color, selected_foreground_color는 selected: true일 때 적용하며,
disabled_background_color는 비활성 상태에 적용합니다. surface와 card는 pressed_color로
Material 터치 효과를 지정할 수 있습니다. 기본 색·선택 표시·터치 효과는 속성을 생략하면 유지됩니다.
4종 디자인 예제를 참고하세요.