앱 껍데기 data-shell
모든 메뉴 화면은 같은 껍데기 안에 본문(.app__main)만 바뀐다. 메뉴 이동 때 메뉴 · 상단바는 그대로, 본문만 교체 (앱처럼). 아래 두 화면은 같은 마크업을 1920 · 390 폭으로 그린 것.
전체 12미확인 2경고
경고2동 · 고온14:12
온도 30.6℃ — 천창 50% 자동 열림
장애3동 · 센서14:02
온도 센서 T3-2 통신 두절
주의예보13:40
내일 03시 강풍 11m/s 예보
2동 온도 30.6℃ — 천창 50% 자동 열림
모니터 1920 — 왼쪽 메뉴 · 목록 + 상세 나란히
전체 12미확인 2
경고2동 · 고온14:12
온도 30.6℃ — 천창 50% 자동 열림
30℃ 넘은 상태 2분 지속 → 규칙 R2
장애3동 · 센서14:02
온도 센서 T3-2 통신 두절
주의예보13:40
내일 03시 강풍 11m/s 예보
폰 390 — 탭바 · 목록만 (상세는 눌러서)
마크업
<div class="scr app" data-shell="alerts" data-title="알림 센터" data-back="main">
<main class="app__main">
… 화면 내용만 …
</main>
</div>
<!-- spec.js 가 .side(왼쪽 메뉴) · .top(상단바) · .tabbar(폰) 를 넣는다. data-shell = 켜질 메뉴 -->
3D 대시보드 .f3d[data-farm3d]
아래는 실제 3D 엔진이다 — 끌어서 돌리고, 휠로 확대하고, 온도 · 습도 · 히트맵을 바꿔 보세요. 테마를 바꾸면 3D 색도 바뀐다.
3D 불러오는 중…
정상주의경고위험장애히트맵 적정보다 낮음 · 높음
farm3d.js · Three.js r160 — 화면 명세서 A-1 과 같은 장면 (데모 농장 : 연동형 3동 8×50m · 센서 21 · 카메라 4)
규칙
| 무엇 | 규칙 |
| 라벨 양 | 멀리서 = 동 대표값 + 이상 센서 + 카메라. 가까이(확대) = 센서 전부. 폰은 동 이름 · 이상 센서만 |
| 장비 | 실제 상태 그대로 움직임 — 천창 개폐율만큼 열림, 켜진 팬 회전, 카메라는 바닥에 비치는 범위 |
| 색 | 라벨 테두리 = 상태 색. 히트맵 = 적정보다 낮음(파랑) · 적정(회색) · 높음(빨강) — 상태 색과 다른 축 |
| 방향 | 출입구가 남쪽 · 나침반(N)이 시점과 같이 돈다. 바람 화살표는 바람이 흘러가는 쪽 |
| 그리기 | 바뀔 때만 다시 그림 (배터리). 시점 이동 750ms, 사용자가 끌면 멈춤 |
| 누르기 | 라벨 · 카메라 몸체 → 센서 상세 · 카메라 영상 (드로어, 3D 는 뒤에 그대로) |
알림 흐름
알림 하나를 열면 "무엇이 · 왜 · 무엇을 했고 · 결과는 · 누구에게 갔나"가 한 화면에 있어야 한다. 순서: 머리(상태 · 제목 · 메타 · 동작) → 발생 전후 차트 → 타임라인 → 전달 단계.
2동 온도 30.6℃ — 천창 50% 자동 열림
경고2동 · 고온· 14:12 발생 · 8분째· 규칙 R2미확인
알림 전달
앱 푸시 · 김농부, 이반장14:12
위험(35℃↑)으로 오르면 문자5분 미확인
그래도 미확인이면 전화10분
| 등급 | 전달 | 화면 |
| 주의 | 앱 안에만 | 알림 센터 · 3D 라벨 깜빡임 |
| 경고 | 앱 푸시 | + 대시보드 오른쪽 위 · 알림 배지 |
| 위험 | 푸시 + 문자 → 미확인 시 전화 | + 상단 알림 점 |
| 장애 | 푸시 (기기 담당) | 기기 상태 · 3D 점선 라벨 |
장비 제어 .dev
장비 카드 하나에 지금 상태 · 누가 움직이는지(배지) · 왜(한 줄). 사람이 누르면 자동 규칙이 멈춘다는 것을 누르기 전에 확인 창으로 알려준다. 안전 규칙(강풍 · 강우)은 항상 우선.
50%열림 · 14:13 도달
30℃ 넘어 R2가 14:12에 열었어요 · 27℃ 아래면 닫힘
꺼짐15:21 자동 복귀
김농부가 14:21에 껐어요 · 자동 규칙 1시간 멈춤
- 명령 — 버튼을 누르면 확인 창(확인 다이얼로그) : 지금 → 목표 · 걸리는 시간 · 멈추는 규칙과 복귀 시각.
- 결과 확인 — 명령 후 실제 값(개폐율 · 전류)이 바뀌는지 본다. 2분 안에 안 바뀌면 "제어 실패" 위험 알림.
- 복귀 — 1시간 뒤 자동 규칙 복귀. 배지가 수동 → 자동으로 돌아온다.
화면 크기 @container screen
기준은 창(viewport)이 아니라 화면 루트의 폭(컨테이너 쿼리) — 명세서 · 가이드 안의 작은 화면에서도 같은 규칙이 걸린다. 큰 화면은 같은 내용을 키우지 않고 보여주는 양을 늘린다.
폰 세로< 600탭바 · 세로 쌓기 · 드로어 → 바텀시트 · 3D 더 멀리서 · 라벨 줄임 · --u: 1.04px
패드 (세로 · 가로)600 – 1439왼쪽 메뉴 → 아이콘 레일 · 3D + 오른쪽 알림 열 · KPI 4칸 · 알림 목록 + 상세 좁게
모니터 24″1440 – 2199기본 (원본 화면). 대시보드는 스크롤 없이 한 화면
27″ · 32″ 150%≥ 2200+ 카메라 작은 창 · 동별 24시간 차트 · 장비 4열 · --u: 1.12px
32″ 4K 100%≥ 3200배치는 2560 과 같고 글자 · 간격만 --u: 1.6px
/* 크기는 --u(px) × em — 화면 폭이 커지면 --u 만 바꾼다 */
.scr { font-size: calc(var(--u) * 14); }
@container screen (max-width: 599px) { .scr { --u: 1.04px; } }
@container screen (min-width: 3200px) { .scr { --u: 1.6px; } }
/* 보이기 · 숨기기 */
.only-phone · .hide-phone · .only-monitor (≥ 1440) · .only-wide (≥ 2200)
권장폰과 패드에서 버튼 · 토글은 최소 44 × 44px. 장갑 · 젖은 손으로도 누를 수 있게. 마우스 올림(hover)에만 있는 정보를 만들지 않는다.
지양@media (창 폭) 로 화면 규칙 쓰기 — 명세서 · 가이드 안의 작은 화면에서는 걸리지 않는다.
문구
읽는 사람은 농장주 · 현장 관리자. 시스템 말 대신 농장에서 쓰는 말로, 짧게.
| 규칙 | 이렇게 | 이렇게 쓰지 않음 |
| 장소 → 무엇 → 값 | 2동 온도 30.6℃ | TEMP_SENSOR_2 HIGH |
| 자동이 한 일 + 이유 | 천창 50% 자동 열림 (R2) | 제어 명령 전송됨 |
| 다음에 일어날 일 | 33℃ 넘으면 100% + 유동팬 | (없음) |
| 상태 단어는 다섯 개만 | 정상 · 주의 · 경고 · 위험 · 장애 | 심각 · 이상 · 에러 · Critical |
| 시각 | 14:12 · 어제 22:40 · 내일 03시 | 2026-10-13T14:12:00 |
| 말투 — 해요체, 짧게 | 센서 연결이 끊겼어요 | 센서와의 통신이 원활하지 않습니다 |
| 버튼 = 동사 | 확인했어요 · 100% 열기 · 장비 제어 | 확인 · 예 · 실행 |
| 방향 | 북서풍 → 남동쪽으로 (16방위) | 315° |