토큰, 크기, 색, 여백, 반응형
Runtime v2는 기본적으로 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가 안전합니다.
반응형 규칙
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이나 색 변화가 없어도 현재 선택과 진행 상태를 알 수 있어야 합니다.