← 모든 글

픽셀 아트의 빛: 낮과 밤, 날씨와 그림자

포켓몬 Crystal은 밤의 마을을 따로 그리지 않습니다. 시계 위에 하루를 세 부분으로 두어 아침 6시간, 낮 8시간, 밤 10시간으로 나누고, 그 시각이 되면 페이드 없이 한 프레임 안에 팔레트를 다시 불러옵니다. 팔레트 파일의 블록에서 일곱 개의 월드 팔레트는 낮 밝기의 0.41~0.68, 평균 0.51을 유지하고(마을이 자기 물과 지붕 색으로 표시하는 상태에서는 맵 그룹별 평균 0.49~0.54) 파랗게 바뀌는 반면, YELLOW라는 팔레트 하나는 가장 밝은 색을 0.90으로 유지하고, 사람들의 팔레트는 화면에서 바뀌지 않습니다.1234 Emerald에는 빛을 위한 시계가 없습니다. 대신 날씨 값이 18개 있고, 비는 1초에 걸쳐 풍경의 팔레트를 원래 값의 약 13/16로 낮추지만 플레이어와 마을 사람의 팔레트는 그려진 그대로 남습니다. Emerald에도 FireRed에도 헤더에 비가 적힌 야외 맵은 하나도 없으며, Emerald의 비는 몇몇 맵의 트리거와 스크립트에서 나오고, 그중 둘은 나흘 주기의 달력을 가진 도로입니다.567 그림자는 어떤 크기에서든 한 톤에 높이 다섯 픽셀 행이고, 어둠은 플래시 없이 반지름 1.5셀, 플래시를 쓰면 4.5셀인 밝은 원입니다.85 제 마을인 Kiradex World는 이미 자기만의 네 시간대를 갖고 있으며, Mac에서 소스로 읽으면(여기서 iPhone으로 측정한 것은 하나도 없습니다) 밤은 아틀라스 낮 밝기의 0.588을 남기고, 불 켜진 창은 틴트를 입은 가장 밝은 픽셀 0.562에 맞서 0.901에 있으며, 바뀜은 1분에 한 번 읽는 컷입니다.9 날씨는 없고, 걷는 이들은 땅과 함께 어두워지며, 어떤 건물도 땅에 그림자를 드리우지 않습니다. 그래서 브리프는 오마주 글이 정한 네 시간대를 유지하고, 빛을 30분에 걸쳐 바꾸며, 걷는 이들을 흰색 쪽으로 절반 끌어올리고, 구역마다 하루에 한 번 날씨를 굴리되 비는 Emerald의 밀도와 어둡기로 하며, 건물 그림자 33셀을 땅에 그려 넣고, 실제 현지 날씨, 해를 따라 움직이는 그림자, 번개 섬광은 모두 거부합니다. 그리고 각 항목에 단위 테스트, UI 테스트, 포지 검사, 스크립트, 캡처 중 하나로 실행할 수 있는 검사를 붙이며, 앱에 지금 있는 것이나 브리프가 추가를 제안하는 것만 이름으로 가리킵니다.101112

TL;DR

  • 하루는 팔레트 세트이지 두 번째 마을이 아닙니다. Crystal은 하루를 4:00, 10:00, 18:00에서 6시간, 8시간, 10시간으로 나누고, 배경 팔레트 블록 다섯 개(아침, 낮, 밤, 어둠, 실내)를 둡니다. 밤에는 그 블록들 안에서 각 월드 팔레트가 낮 밝기의 평균 0.511을 유지하고(마을이 자기 물과 지붕 색으로 표시하는 상태에서는 0.509), 파랑은 5비트 단위로 6.44 올라갑니다(표시되는 상태에서는 7.27). 아침이 바꾸는 것은 32색 중 5색뿐이고, 모두 가장 밝은 색입니다.12134
  • 불 켜진 것은 어둠을 거부하고, 사람은 제 색을 지킵니다. Crystal의 YELLOW는 다른 모든 월드 색이 0.6 아래로 떨어지는 밤과 어둠에도 가장 밝은 색을 루마 0.90으로 유지합니다. 다섯 개의 사람 팔레트는 투명색만 바꿉니다. Emerald의 비는 16개 배경 팔레트 중 14개를 어둡게 하고, 플레이어와 다섯 마을 사람 슬롯의 팔레트만 정확히 항등 맵에 남겨 둡니다.114515
  • 시각은 컷하고, 날씨는 페이드합니다. Crystal은 시각이 바뀌는 프레임에 팔레트를 바꾸고, 8프레임짜리 흰색 페이드는 문, 워프, 공중날기, 메뉴가 여는 화면, 일부 스크립트 장면을 위해 남겨 둡니다(검은색 페이드를 부르는 것은 맵 스크립트 열한 개뿐이고, 흰색 페이드는 맵 스크립트 16개도 부릅니다). Emerald는 20프레임씩 3단계, 1.00초에 걸쳐 비로 페이드합니다. Stardew Valley의 밤은 “gradually becomes darker over time”(시간이 지나며 점점 어두워집니다).1516
  • 날씨는 장소와 날에 속합니다. Emerald(68개 맵)에서도 FireRed(76개)에서도 헤더가 비인 야외 맵은 없습니다. Emerald의 비는 몇몇 맵의 트리거와 스크립트에서 나오고(5개 맵에 있는 좌표 날씨 이벤트 86개 중 4개가 RAIN이고 24개가 두 도로 주기를 시작합니다. 스크립트 날씨 호출 24개 중 1개가 RAIN, 2개가 호우입니다), Route 119와 123은 하루에 한 단계씩 나흘 주기를 밟습니다. Stardew는 계절에 따라 하루에 한 번 날씨를 굴리고 전날 예보합니다.571718
  • 비는 성기고 빠르며, 번개는 짧고 드뭅니다. 한 화면에 빗방울 10개, 초당 868픽셀, 수직에서 26.6도, 방울당 18프레임에 7프레임짜리 물보라입니다. 번개는 6~8프레임 유지되고, 최소 61프레임의 어두운 간격을 두며, 주기와 주기 사이는 6~12초입니다. 플레이 도중 비로 바뀌면 빗방울은 바뀐 뒤 약 2초 만에 다 자리를 잡고, 팔레트는 그보다 1초쯤 먼저 자리를 잡습니다.54
  • Kiradex의 하루는 작동하지만 컷합니다. 네 시간대(3, 8, 3, 10시간)는 밤의 아틀라스를 낮 밝기의 0.588로 만들고, 틴트를 입지 않는 불빛 메시는 0.901에 있으며, 가산 블렌딩 웅덩이는 결코 어둡게 하지 않고 빛을 더합니다. 하지만 빛은 60초마다 읽는 컷이고, 걷는 이들은 밤 틴트를 받으며, Air의 어디에서도 Reduce Motion(동작 줄이기)을 읽지 않고, 건물은 땅에 그림자를 드리우지 않습니다. 모두 Mac에서 소스와 내보낸 이미지로 읽은 것이지 iPhone에서 측정한 것이 아닙니다.91920
  • 이것이 Kiradex에 주는 것. 브리프입니다. 오마주 글의 네 시간대 유지, 시계로 계산하는 30분 램프(0.108의 컷 대신 0.0036의 단계), 흰색 쪽으로 절반 끌어올린 걷는 이(밤 루마가 장소의 0.593에 맞서 0.796), 구역마다 하루 한 번 굴리는 다섯 가지 날씨 상태, 뷰당 15방울에 13/16로 어둡게 하고 1초 동안 페이드하는 비, 초당 한 타일로 움직이는 구름 그림자, 구워 넣은 건물 그림자 33셀, 창이 바깥 시간대를 보여 주는 방, Reduce Motion 모드, 번개 섬광 없음, 그리고 검사 열한 개입니다. Kiradex의 수치는 Mac에서 앱의 소스와 내보낸 그림으로 계산한 것이지 iPhone에서 측정한 것이 아닙니다.101112

Kiradex는 제가 만든 iPhone용 카드 수집 앱이고, Kiradex World는 그 안에 있는 작은 픽셀 마을로, 수집가들이 그곳을 걷고 만나고 카드를 보여 줍니다. 마을은 이미 하루를 갖고 있습니다. Daylight.swift가 휴대폰에서 시각을 읽어 네 시간대에 이름을 붙이고, 리그는 빛을 받지 않는 모든 것에 그 시간대의 틴트를 곱합니다. 불 켜진 창과 홀의 벽등은 틴트 없이 그리는 두 번째 메시입니다. 그리고 빌드 29부터는 가로등과 창이 땅에 가산 블렌딩 웅덩이를 드리우고, 낮에는 구름 시트가 마을 위를 흘러가며, 아침에는 공원에 안개가 고이고, 가을에는 잎이 지고, 밤에는 반딧불이가 떠돕니다. 굴뚝 여섯 개에서는 연기도 오르는데, 디자인 계획은 이것을 빌드 28에 둡니다.212022239 공기를 맡은 파일은 자기가 무엇을 위한 것인지 한 줄로 말합니다. “none of it takes the day’s tint: light is light.”(그 어느 것도 하루의 틴트를 받지 않는다. 빛은 빛이다)22

마을에 없는 것은 날씨, 누구나 점진적이라고 부를 만한 빛의 변화, 사람들이 밤에도 알아볼 수 있게 남아 있을 이유, 그리고 땅에 떨어지는 건물 그림자 하나입니다. 건물을 조립하는 포지는 그 마지막 것을 자기 docstring에서 미뤄 두었습니다. “The ground shadow stays off the building: it belongs to the ground layer.”(땅 그림자는 건물에 붙이지 않는다. 그것은 땅 레이어에 속한다)24 그래서 이 글은 이 시리즈의 앞선 글들이 건물과 움직임에 대해 한 일을 빛, 날씨, 시간에 대해 합니다. Crystal이 하루를 어떻게 유지하는지(시각, 팔레트, 변화를 보여 주는 방식, 어느 맵에서 일어나는지), Emerald가 날씨를 어떻게 다루는지(상수, 어둡게 하는 처리, 비, 안개, 모래, 구름, 천둥, 각각이 어디서 일어나는지), 둘이 어둠과 그림자를 어떻게 다루는지, Stardew Valley 위키가 그 하루와 날씨에 대해 무엇을 기록하는지, 그리고 현대의 조명이 들어간 픽셀 게임을 만든 이들이 자기 빛에 대해 무엇을 말하는지 측정합니다. 그런 다음 Kiradex 자신의 빛을 소스에서 읽고, 출시된 것과의 차이로 브리프를 씁니다.

측정 방법

포켓몬의 수치는 pret 디컴파일의 얕은 클론에서 나옵니다. 각 게임을 상수에 이름을 붙인 C와 어셈블리로 다시 만드는 커뮤니티 프로젝트로, pokecrystal은 5beda23(2026년 9월 29일 커밋), pokeemerald는 731ad5b(10월 1일), pokefirered는 037335f(9월 26일), pokered는 d2704a6(9월 22일)입니다.25 파이썬 스크립트 네 개가 이것들과 Kiradex를 측정하고, 다섯 번째가 정전의 수치를 Kiradex의 단위로 옮기며, 여섯 번째가 저장한 Apple 문서 페이지를 읽습니다. 각각은 출력과 함께 이 글을 위한 저자의 증거 폴더에 저장되어 있고, 모두 몇 초 만에 다시 실행됩니다. 게시 전에 전부 다시 실행했습니다. 둘은 저장된 출력을 바이트 단위로 그대로 돌려주었고, 넷은 도중에 고쳤으며, 각각의 이전 버전과 출력은 옆에 남겨 두었습니다. 제안 스크립트는 건물 그림자를 행별로 놓기 위해, 날씨의 젖은 기간을 10절이 정의하는 대로 세기 위해, 그리고 Kiradex의 걷기를 초당 4타일로 이어받지 않고 앱의 Motion.swift에서 읽기 위해 고쳤습니다(소스로 읽으면 앱의 걷기는 초당 60픽셀이고, 2절, 7절, 10절이 그것을 씁니다). Emerald 스크립트는 비 라벨이 생성 카운터의 한도를 생성 주기로 출력했기 때문에 고쳤습니다(2절은 고친 수치를 씁니다). Crystal 스크립트에는 네 가지 페이드 각각을 무엇이 부르는지에 대한 전수 조사를 더했고, 맵 헤더 파서가 한 단어짜리 필드만 받아들여서 음악 필드가 식으로 되어 있는 라디오 타워의 다섯 층을 빠뜨렸기에 고쳤으며(헤더는 383개가 아니라 388개이고, 1절은 바뀐 모든 수를 씁니다), 이제 environment_colors.asm과 지붕 표로부터 맵이 표시하는 팔레트 세트를 풀어내고, 어느 화면이 메뉴 페이드를 거치는지와 어느 실내 맵이 자기만의 팔레트 표를 받는지도 셉니다. Kiradex 스크립트는 구름 줄이 같은 초당 4타일을 라벨로 이어받고 있었기에 고쳤습니다. 다른 섹션들은 전과 같이 출력됩니다.1215891126 일곱 번째는 브리프의 캡처 두 개에서 카메라가 어디에 자리 잡는지를 종이 위에서 재생하고, 여덟 번째인 arith.py는 프레임 시간부터 밤과 낮의 비까지 본문이 쓰는 모든 파생 수치를 출력하며, 아홉 번째는 앱의 색 상수를 Crystal의 팔레트와 비교하고, 열 번째는 Emerald의 비 준비와 천둥 주기를 소스의 상태 기계에서 호출 단위로 재생하며, 열한 번째는 수집가의 프레임 중 수집가 자신이 얼마나 덮는지를 세고, 브리프의 검사 3을 위해 서 있는 그림마다, 그리고 렌더러가 틴트를 다룰 수 있는 방식마다 밤의 비를 계산합니다. 일곱 번째, 아홉 번째, 열 번째도 저장된 출력대로 다시 실행되었습니다.274282930

여기서 밝기는 루마입니다. 저장된 채널 값을 0~1로 스케일하고 Rec. 601 가중치(빨강 0.299, 초록 0.587, 파랑 0.114)를 적용한 것으로, 감마도 화면 모델도 없습니다. 팔레트를 비교하기 위한 읽기 도구이지 측색이 아니며, 게임보이 컬러의 색은 LCD가 보여 준 대로가 아니라 저장된 그대로입니다.121 셀은 휴대용 게임기의 16×16픽셀 맵 칸이고 타일은 Kiradex의 한 변 16텍셀 칸이므로, 둘은 일대일로 비교됩니다. 휴대용 게임기의 속도로 센 초는 초당 59.7275프레임을 씁니다. 게임보이 어드밴스에서는 2^24 ÷ 280,896, 게임보이 컬러에서는 2^22 ÷ 70,224로, 같은 속도입니다.124

글 전체에 걸쳐 한 가지 한계가 있습니다. 이 글의 어떤 것도 iPhone에서 측정하지 않았습니다. Kiradex의 모든 수치는 앱의 소스를 텍스트로 읽었거나, Mac에서 내보낸 그림으로 계산한 것입니다. 출시된 마을 아틀라스에 스크립트로 틴트를 적용한 것, 구름 그림의 알파, 마을의 내보내기입니다. 본문이 Kiradex의 밝기를 말할 때 그것은 이 계산이며, SpriteSheet.material이 UnlitMaterial의 tint를 쓰는 것처럼 리그의 곱셈 틴트가 텍스처에 채널별로 작용한다고 가정합니다. 기기에서의 비용이 문제가 되는 곳은 측정하지 않았다고 표시했습니다.129

1. 소스에서 측정한 Crystal의 하루

Gold, Silver, Crystal은 실시간 시계로 시간을 재고, 이 글이 읽는 것은 그중 Crystal입니다.2 이 절의 내용은 모두 measure_gen2_daylight.py에서 나옵니다. 이 스크립트는 시계의 상수와 표, 시각에 따라 바뀌는 팔레트 파일 세 개, 그것을 적용하는 루틴, 각 환경의 맵이 파일의 어느 팔레트를 표시하는지 알려 주는 표, 그리고 어느 맵이 시계를 따르는지 알려 주는 맵 헤더 388개를 읽습니다.1

하루는 세 부분

상수는 MORN_HOUR 4, DAY_HOUR 10, NITE_HOUR 18이고, 시각을 하루의 부분으로 바꾸는 TimesOfDay 표는 자기 요약을 주석으로 달고 있습니다. “0400-0959 morn | 1000-1759 day | 1800-0359 nite”입니다.21 아침 6시간, 낮 8시간, 밤 10시간이므로 밤이 가장 길어 하루의 41.7%를 차지합니다.14 이 시리즈의 오마주 글도 같은 상수와 같은 주석을 읽었고, 둘은 일치합니다.10

하늘이 없는 곳을 위한 네 번째 상태가 있습니다. 하루의 시간대를 담는 변수 wTimeOfDay는 MORN, DAY, NITE, DARKNESS를 가지며, 배경 팔레트 파일 bg_tiles.pal은 팔레트 여덟 개짜리 블록 다섯 개를 아침, 낮, 밤, 어둠, 실내에 하나씩 두고, 야외 물을 위한 한 쌍을 더 둡니다.31131 한 블록의 팔레트 여덟 개는 성도의 모든 타일이 받는 이름 붙은 여덟 팔레트, GRAY, RED, GREEN, WATER, YELLOW, BROWN, ROOF, TEXT입니다.132

띠 세 개가 있는 24시간 차트. Crystal: 아침은 04:00부터 10:00, 낮은 10:00부터 18:00, 밤은 18:00부터 04:00. Kiradex: 아침은 06:00부터 09:00, 낮은 09:00부터 17:00, 저녁은 17:00부터 20:00, 밤은 20:00부터 06:00이며, 가로등은 17:00부터 06:00까지 13시간 켜진다. Stardew Valley: 하루는 06:00부터 02:00까지로 실제 14분 길이이며, 해 질 녘이 겨울 18:00, 가을 19:00, 봄과 여름 20:00으로 표시되어 있다.

한 시계 위의 세 가지 하루. Crystal의 상수, Kiradex의 Daylight.swift, Stardew Valley 위키에서 가져와 figures/make_figures.py로 그렸습니다.

밤은 빛이 절반, 그리고 파랑

Crystal의 배경 팔레트 여덟 개(팔레트 파일의 기본 블록)의 아침, 낮, 밤, 어둠의 평균 루마를 묶은 막대 그래프. 마을이 표시하는 물은 파일의 야외 쌍, Kiradex의 마을 아틀라스는 아침, 낮, 밤 틴트 아래의 값. 기본 블록에서 YELLOW를 뺀 모든 월드 팔레트가 밤에 0.206~0.321, 어둠에 0.009로 떨어진다. 마을의 물은 낮 0.528, 밤 0.248. YELLOW는 밤에 0.460, 어둠에 0.224로 떨어진다. TEXT는 모든 시간에 0.549를 유지한다. Kiradex의 아틀라스는 0.432, 0.449, 0.264.

색이 아니라 밝기입니다. 각 팔레트의 네 색의 평균 루마를 시간대별로 보인 것으로, 파일의 기본 블록과 그 옆에 마을이 표시하는 물을 gen2_daylight.txt에서, Kiradex의 아틀라스를 kiradex_light.txt에서 가져왔습니다. 후자는 Mac에서 출시된 아틀라스로 계산한 것이지 iPhone에서 측정한 것이 아닙니다. 팔레트 색은 하나도 재현하지 않았습니다.

팔레트 파일의 블록 다섯 개에서 각 팔레트의 네 색의 평균 루마로 재면, 밤 블록은 낮 블록 밝기 중 RED의 0.406부터 YELLOW의 0.684까지를 유지하고, 일곱 월드 팔레트의 평균은 0.511입니다. 인터페이스 팔레트인 TEXT는 모든 시각에 똑같습니다.1 어둠 블록에서 월드 팔레트는 루마 0.009로 떨어지고, YELLOW만 0.224입니다.1

이것은 파일이 담고 있는 그대로의 블록이며, 마을이 그것을 그대로 표시하지는 않습니다. environment_colors.asm은 환경과 시간대마다 파일의 팔레트 42개 중 어느 여덟 개를 불러올지 지정합니다. TOWN이나 ROUTE는 블록 자신의 팔레트를 받지만 WATER만은 파일의 야외 쌍에서 오는데, 아침과 낮에 하나, 밤에 하나입니다. 그다음 LoadMapPals가 맵 그룹의 지붕 색 두 개를 ROOF의 가운데 두 색 위에 씁니다. INDOOR나 GATE 맵은 아침과 낮에는 파일의 실내 블록을 받지만, 타일셋이 자기만의 표를 불러오는 경우는 예외입니다(아래). CAVE나 DUNGEON은 블록을 그대로 받습니다.33341 그렇게 풀면 마을 물의 평균 루마는 낮 0.528, 밤 0.248로 낮의 0.470이고(기본 블록은 0.448), ROOF는 마을이나 도로를 가진 맵 그룹 25개에 걸쳐 낮의 0.369(Blackthorn의 것)에서 0.688을 유지합니다. 마을이 표시하는 일곱 월드 팔레트는 그룹별로 낮 밝기의 평균 0.494~0.539, 25개 전체로 0.509를 유지하며, 블록의 0.511에 대응합니다.14 그림은 블록과 그 옆에 표시되는 물을 그리며, 아래 수치는 어느 세트의 것인지 밝힙니다.

밤은 색상도 바꿉니다. YELLOW와 TEXT를 뺀 월드 색에서 파랑에서 빨강과 초록의 평균을 뺀 값은 기본 블록에서 낮 −0.73, 밤 +5.71로, 게임보이 컬러의 5비트 단위로 6.44 오르며, 전체 눈금 31의 약 5분의 1입니다. 블록의 물 대신 마을의 물을 넣으면 −1.17과 +6.10으로 7.27 오릅니다.14 그 원리는 파일에 그대로 드러납니다. 밤 블록에서는 YELLOW를 뺀 모든 월드 팔레트의 가장 밝은 색이 똑같이 (15, 14, 24), 루마 0.498의 푸른 회색이고, 낮에는 대부분 (27, 31, 27), 루마 0.947입니다. 마을이 표시하는 상태에서는 일곱 개 중 다섯, GRAY, RED, GREEN, BROWN, ROOF(지붕 표는 가장 밝은 색에는 손대지 않습니다)가 그 색을 공유합니다. 물의 밤 가장 밝은 색은 야외 쌍 자신의 것인 (15, 13, 27), 루마 0.490으로, 초록에서 한 단계, 파랑에서 세 단계 어긋납니다.14 제가 읽기에는, 가장 밝은 색을 공유하고 물이 거기서 한 단계 떨어져 있기 때문에 밤의 Crystal 마을이 팔레트 여섯 개가 제각기 어두워진 것이 아니라 하나의 하늘 아래 하나의 장소로 읽힙니다.

아침은 더 따뜻한 흰색

아침은 독립된 장면이 아닙니다. 낮과 다른 것은 월드 색 32개 중 5개, 15.6%이고, 다섯 모두 GRAY, RED, YELLOW, BROWN, ROOF의 색 0, 즉 가장 밝은 색입니다. 아침에는 (28, 31, 16), 낮에는 (27, 31, 27)로, 파랑 채널이 11 내려갑니다.14 각 팔레트에서 그보다 어두운 색은 모두 낮의 것입니다. 정전의 아침은 흰색을 데운 낮빛이고, 그 밖에는 아무것도 움직이지 않습니다.

어둠을 거부하는 팔레트 하나

밤과 어둠에서 YELLOW의 색 0은 (30, 30, 11), 루마 0.90입니다. 어느 블록에서도, 마을이 표시하는 세트에서도 루마 0.6을 넘는 월드 색은 이것뿐입니다. 다른 팔레트의 가장 밝은 색은 밤에 0.498(마을의 물은 0.490)이고 어둠에서는 검정에 가깝습니다.14 성도 타일셋에서 johto_palette_map.asm은 YELLOW를 타일 192개 중 3개, 1.6%에 줍니다. 뱅크 0의 타일 38, 55, 56입니다. GRAY는 36, BROWN은 99, RED는 26, GREEN은 12, ROOF는 9, WATER는 7입니다.3514

그 세 타일이 무엇인지 보려고 스크립트는 그것들을 네 배 크기로 렌더링합니다. 이 렌더는 저작권이 있는 그림에서 파생한 것이라 분석용으로만 보관하고 공개하지 않습니다.1 제 눈에 타일 38은 유리가 두 장인 창으로 보입니다. 그것은 그림에 대한 제 해석이지, 팔레트만 지정하는 소스의 라벨이 아닙니다. 그 해석이 맞다면 Crystal의 가로등은 빛이 아니라 색입니다. 게임은 밤에 빛나야 할 몇몇 타일에 가장 밝은 색이 떨어지지 않는 유일한 팔레트를 주어 표시하고, 주변 마을이 파래지는 동안에도 창은 켜진 채로 남습니다.

밤의 루마를 보인 가로 막대 그래프. Crystal: GRAY, RED, GREEN, BROWN, ROOF가 공유하는 밤의 가장 밝은 색 0.498, 마을이 표시하는 WATER의 밤 가장 밝은 색 0.490, YELLOW의 가장 밝은 색 0.898. Kiradex: 낮의 아틀라스 평균 0.449, 밤 틴트 아래 0.264, 밤 틴트 아래 가장 밝은 아틀라스 픽셀 0.562, 가로등 웅덩이의 중심을 밤 평균에 더하고 그림의 최댓값으로 가중한 값 0.785, 틴트 없이 그리는 불 켜진 창과 벽등 픽셀 0.901.

불 켜진 것은 밝게 남습니다. Crystal의 YELLOW와 다른 밤 색, 그리고 Kiradex의 불빛 셀과 웅덩이와 틴트를 입은 마을을 gen2_daylight.txt, kiradex_light.txt, arith.txt에서 가져왔습니다. Kiradex의 값은 Mac에서 내보낸 그림으로 계산한 것이지 iPhone에서 측정한 것이 아닙니다.

사람은 어두워지지 않는다

npc_sprites.pal의 오브젝트 팔레트도 시간대를 따르지만, 배경과는 다른 방식입니다. 다섯 개의 사람 팔레트(빨강, 파랑, 초록, 갈색, 분홍)는 낮과 밤, 낮과 어둠 사이에 색 0만 바꾸며, 오브젝트 팔레트의 색 0은 게임보이 컬러에서 투명이므로 화면에서는 전혀 바뀌지 않습니다. SILVER는 어떤 색도 바꾸지 않습니다. 네 색을 모두 바꾸는 것은 풍경에 속하는 오브젝트의 팔레트인 TREE와 ROCK뿐입니다.141 Crystal의 밤에 마을은 파래지고, 그 안을 걷는 사람들은 정오와 똑같이 그려집니다.

지붕은 자기만의 밤을 가진다

지붕에는 전용 표가 있습니다. roofs.pal은 맵 그룹마다 하나씩 27개 항목을 두며 첫 항목은 쓰이지 않고, 각 항목은 아침과 낮을 위한 색 한 쌍과 밤을 위한 한 쌍을 가집니다. 그룹 전체에서 밤 쌍의 루마를 낮 쌍의 루마로 나눈 값은 0.247부터 1.000까지, 평균 0.556입니다.361 이 시리즈의 구조물 편 글은 같은 표와, 타일셋 하나로 어떻게 성도의 모든 마을에 저마다의 색을 주는지를 설명했습니다.23

다시 불러오기가 불러오는 것

LoadMapPals는 맵을 불러올 때나 시간이 바뀔 때 그 모두를 적용합니다. 시간대에 맞는 8바이트짜리 배경 팔레트 여덟 개, 즉 environment_colors.asm이 그 맵의 환경에 지정한 여덟 개를 복사합니다. 다만 실내와 동굴 타일셋 여섯 개(TILESET_POKECOM_CENTER, TILESET_BATTLE_TOWER_INSIDE, 명예의 전당 밖의 TILESET_ICE_PATH, TILESET_HOUSE, TILESET_RADIO_TOWER, TILESET_MANSION)는 예외로, 그 배경 팔레트는 LoadSpecialMapPalette가 먼저 자기만의 표에서 불러오므로 이 복사는 건너뜁니다. 다음으로 모든 맵에서 시간대에 맞는 오브젝트 팔레트 여덟 개를 복사합니다. 그리고 TOWN이나 ROUTE에서만 맵 그룹의 지붕 색 두 개, 4바이트를 ROOF 팔레트에 넣습니다.341 TOWN이나 ROUTE 맵 중 여섯 타일셋을 쓰는 것은 없습니다(쓰는 것은 INDOOR 맵 75개와 CAVE 맵 5개이고, 그 INDOOR 맵 가운데 TILESET_ICE_PATH 위의 명예의 전당을 뺀 74개 모두가 자기만의 표를 받습니다). 따라서 야외에서는 배경 팔레트 64바이트, 오브젝트 팔레트 64바이트, 지붕 4바이트로 모두 132바이트입니다.14

이것은 이 시리즈의 한 문장을 바로잡습니다. 세계를 다룬 첫 글은 “time of day in Johto is a 64-byte palette reload”(성도의 시간대는 64바이트 팔레트 다시 불러오기다)라고 썼습니다.32 배경 팔레트에 대해서는 맞는 말입니다. LoadMapPals와 대조하면, 다시 불러오기는 오브젝트 팔레트 64바이트도 복사하고 야외에서는 지붕 색 4바이트도 복사합니다. 사람 팔레트는 투명색만 바뀌므로 겉보기에는 같지만, 바이트는 다시 불러와집니다.341 이것은 이 글의 발견입니다. 앞선 글은 고치지 않았습니다.

변화는 컷이다

필드 루프는 맵 이벤트가 켜져 있는 동안 매번 UpdateTime, GetJoypad, TimeOfDayPals를 부릅니다. HandleMapTimeAndJoypad는 wMapEventStatus가 MAPEVENTS_OFF이면 맨 처음에 돌아갑니다.371 _TimeOfDayPals는 강제된 팔레트 세트가 적용 중이거나(FORCED_PALSET_F) 시간대가 바뀌지 않았으면 바로 돌아갑니다. 바뀌었으면 팔레트 세트를 바꾸고, _UpdateTimePals를 한 번 부르고(이것은 ld c, $9 ; normal 다음에 DmgToCgbTimePals가 오는 것입니다), 한 프레임 기다립니다. 아침과 낮, 낮과 밤, 밤과 아침 사이에 단계적인 페이드는 없으며, 팔레트 세트는 한 프레임에 바뀝니다.31

게임에는 페이드가 있고, 그것을 다른 일에 아껴 둡니다. FadeInFromBlack, FadeOutToBlack, FadeInFromWhite, FadeOutToWhite는 각각 팔레트 4개를 한 단계에 2프레임씩 밟아 8프레임, 134밀리초입니다.314 맵 준비 스크립트가 쓰는 것은 흰색 쌍입니다. 플레이어가 밟는 워프, 즉 문이나 동굴 입구는 Door 스크립트로 맵을 불러오는데, 이것은 흰색으로 페이드아웃했다가 Train 스크립트로 이어져 흰색에서 페이드인합니다. 스크립트 워프가 실행하는 Warp 스크립트는 끝나기 두 명령 전에 흰색에서 페이드인합니다. 공중날기 스크립트는 흰색으로 페이드아웃하고 Warp 스크립트로 이어집니다. 그리고 FadeToMenu를 거쳐 열리고 FinishExitMenu를 거쳐 돌아오는 화면은 흰색으로 페이드아웃했다가 돌아옵니다. 시작 메뉴 항목 중 여섯 개(StartMenu_Pokedex, StartMenu_Pokemon, StartMenu_Pack, StartMenu_Status, StartMenu_Option, StartMenu_Pokegear)가 그렇고, 다른 일곱 파일에 15개의 호출이 더 있으며, 그중에는 상점, PC, 셀렉트 버튼 도구의 것이 있습니다. 시작 메뉴 자체에는 페이드가 없습니다. StartMenu는 맵 위에 그리고, 열릴 때와 닫힐 때 현재 시각의 팔레트를 적용하는 UpdateTimePals를 부릅니다. 검은색 쌍을 지정하는 준비 스크립트는 없습니다. 검은색 쌍에 닿는 것은 맵 스크립트 열한 개의 special뿐이며, 각각 페이드아웃과 페이드백을 한 번씩 갖고, 그중에는 Sprout Tower 3층, Route 24, 로켓단 아지트 지하 2층이 있습니다.381 맵 스크립트는 흰색 쌍도 부르고, 더 자주 부릅니다. 맵 스크립트 16개에서 special로 흰색 페이드아웃 27번, 페이드인 12번이 있고, 그중에는 아무도 어디로 가지 않는 장면, Blue의 집에서 Daisy가 포켓몬의 털을 손질하는 장면과 등대 6층의 장면들이 있습니다. 그리고 검은색 쌍의 열한 개 중 하나인 Route 26의 휴게소는 이동이 아니라 휴식과 회복입니다.1 그러니 전수 조사가 보여 주는 정전의 문법은 이렇습니다. 페이드는 장면의 전환, 이동, 메뉴, 스크립트의 순간을 표시하며, 시각은 그 어느 것도 아닙니다.

플레이어가 컷을 보았는지는 4:00, 10:00, 18:00에 어디 있었느냐에 달려 있었습니다. 시계를 따르는 맵의 야외에 있었다면 그것은 그 프레임에 화면에 나왔습니다. 필드 루프가 플레이어가 걷는 동안 팔레트를 적용하기 때문입니다. 실내에서는 바뀐 팔레트가 표시 중인 것이 아니었습니다. FadeToMenu를 거쳐 열리는 화면에서는 돌아올 때 흰색에서 페이드인하기 전에 시간대 팔레트를 다시 불러오므로 새 세트가 페이드 아래에서 도착했고, 시작 메뉴 자체에서는 메뉴가 닫힐 때 UpdateTimePals가 그것을 적용했습니다.37381 각각이 얼마나 자주 일어났는지는 소스가 말해 줄 수 없습니다. 누군가 광장에 열어 둔 휴대폰은 다른 경우이며, 7절에서 다시 다룹니다.

시간을 따르는 것은 야외뿐

각 맵 헤더는 환경과 팔레트 모드를 지정합니다. 헤더 388개 중 TOWN 맵 23개와 ROUTE 맵 54개는 모두 시계를 따르는 모드인 PALETTE_AUTO이고, CAVE 맵 하나도 그렇습니다. 388개 중 78개, 20.1%입니다.3914 실내에서는 시계가 멈춥니다. INDOOR 맵 208개 중 207개와 GATE 맵 25개 중 24개는 PALETTE_DAY로, 몇 시든 낮빛에 고정되어 있습니다. 그 INDOOR 맵 중 133개가 보여 주는 낮빛은 파일의 실내 블록이고, 나머지 74개는 HOUSE, RADIO_TOWER, MANSION, BATTLE_TOWER_INSIDE, POKECOM_CENTER 타일셋 위에 있어 LoadSpecialMapPalette가 그 타일셋을 위해 불러오는 표를 보여 줍니다(위의 “다시 불러오기가 불러오는 것”).13334 13개 맵이 PALETTE_DARK입니다. Whirl Islands의 맵 여덟 개, Silver Cave의 첫 방, Dark Cave의 입구 두 개, Rock Tunnel의 두 층입니다. 27개는 PALETTE_NITE, 영원한 밤입니다. 그중 24개가 CAVE 맵이며 Ilex Forest와 Tohjo Falls가 포함되고, 나머지 셋은 Burned Tower 1층(DUNGEON 맵), Dragon Shrine(INDOOR), Underground Path(GATE)입니다.1394

그러니 Crystal에서 시간대는 바깥 공기의 속성입니다. 22:00의 집은 정오의 집처럼 밝고, 수관 아래의 숲은 늘 밤이며, 어둠은 또 다른 세 번째 것입니다.1

플래시는 팔레트, Red의 어둠은 오프셋

Crystal의 플래시는 원을 그리지 않습니다. PALETTE_DARK 맵에서 ReplaceTimeOfDayPals는 DARKNESS 세트를 쓰지만, 상태 플래그 STATUSFLAGS_FLASH_F가 설정되어 있으면 모든 시간대에 NITE 세트를 씁니다.3 플래시로 동굴을 밝히면 동굴은 검정에서 밤으로, 18:00 이후 마을이 입는 것과 같은 파란 팔레트로 바뀝니다.

한 세대 전의 Red에는 어두운 곳이 하나 있고, 그것을 한 줄로 처리합니다. 워프 목적지가 ROCK_TUNNEL_1F이면 워프 코드는 wMapPalOffset을 6으로 설정하고, LoadGBPal은 그 오프셋을 FadePal4에서 빼서 FadePal2에 닿습니다. 그 배경 항목은 dc 3,3,3,2로 거의 새까맣습니다.4041 야외 맵에서 오는 그 워프는 pokered가 오프셋을 0이나 전투가 저장했다가 되돌리는 값이 아닌 다른 값으로 설정하는 유일한 곳입니다. 두 실내 맵 사이의 워프는 오프셋을 그대로 두고, 아래층인 ROCK_TUNNEL_B1F에는 워프가 네 개 있는데 모두 1층으로 이어지므로, 그곳에는 1층에서만 갈 수 있고 똑같이 어둡게 남습니다. 플래시, 기절, 공중날기나 던전 워프, 바깥으로 돌아가는 워프는 모두 오프셋을 0으로 만듭니다.4042 Red에는 시계가 없고, Rock Tunnel의 두 층이 유일한 어두운 곳입니다.

2. 소스에서 측정한 Emerald의 날씨

빛을 위한 시계는 없다

게임보이 어드밴스 작품들은 반대 방향으로 갔습니다. Emerald에도 FireRed에도 빛을 위한 시간대 시스템이 없습니다. 두 디컴파일 모두 src/*.c나 include/**/*.h의 어떤 파일도 “timeofday”나 “time_of_day”와 일치하지 않습니다.5 Emerald에는 실시간 시계가 있고, 오마주 글은 그것이 움직이는 것을 측정했습니다. 실제 시간으로 자라는 나무열매와, 날짜가 바뀔 때 실행되는 하루 단위 갱신 열한 가지이며, 날씨도 그중 하나입니다(살아 있는 마을 글이 그 함수 UpdateWeatherPerDay를 지목합니다).1043 그 어느 것도 시각에 따라 팔레트에 손대지 않습니다. Crystal이 색을 시간에 쓴 자리에서 Emerald는 색을 하늘에 썼습니다.

날씨 열여덟 가지, 세 종류

include/constants/weather.h는 WEATHER_* 값 18개를 지정합니다. NONE, SUNNY_CLOUDS, SUNNY, RAIN, SNOW, RAIN_THUNDERSTORM, FOG_HORIZONTAL, VOLCANIC_ASH, SANDSTORM, FOG_DIAGONAL, UNDERWATER, SHADE, DROUGHT, DOWNPOUR, UNDERWATER_BUBBLES, ABNORMAL, 그리고 두 도로 주기입니다. 헤더는 그중 셋(SNOW, FOG_DIAGONAL, UNDERWATER)에 “// Unused”(쓰지 않음)라고 표시하고, SHADE에는 따로 “Original name was closer to WEATHER_CLOUDY/OVERCAST”(원래 이름은 WEATHER_CLOUDY/OVERCAST에 가까웠다)라는 주석이 붙어 있습니다. 맵 트리거를 위한 COORD_EVENT_WEATHER_* 값도 13개 더 있습니다.445

화면에 무엇을 하는지로 묶으면 세 종류로 나뉩니다.57

  • 팔레트를 어둡게 하는 날씨. 쓰이는 네 가지, RAIN, RAIN_THUNDERSTORM, DOWNPOUR, SHADE는 팔레트를 컬러 맵 3으로 보냅니다. 쓰이지 않는 SNOW도 그렇습니다. 모두 자기 InitVars에서 targetColorMapIndex를 3으로, colorMapStepDelay를 20프레임으로 설정합니다.5
  • 자기만의 표를 가진 날씨. DROUGHT는 src/field_weather.c에서 음수 맵 인덱스(페이드인 뒤에는 −6)로 닿는, 미리 계산한 자기만의 색 표를 씁니다.612
  • 팔레트를 건드리지 않는 날씨. SUNNY_CLOUDS, FOG_HORIZONTAL, FOG_DIAGONAL, VOLCANIC_ASH, SANDSTORM은 컬러 맵 0을 유지하고, 대신 스프라이트 레이어를 하드웨어 알파 블렌딩, 채널별 (eva × target1 + evb × target2) / 16으로 장면 위에 섞습니다. 구름은 12와 8로, 가로 안개는 12와 8로 갔다가 나중에 4와 16으로, 재와 모래는 16과 0입니다.5

비는 장소를 13/16로 어둡게 한다

어둡게 하는 처리는 BuildColorMaps에서 나오며, 스크립트는 그것을 파이썬으로 재생합니다. 맵 19개를 만드는데, 각각 5비트 채널 값을 다른 값으로 바꾸는 표입니다. 처음 세 개는 값을 16으로 나눈 것을 한 단계씩 빼므로, 비와 그늘이 쓰는 맵 3은 채널 값 v를 약 0.81 v로 보냅니다. 31은 25가, 16은 13이, 8은 6이 됩니다. 1~31의 값에서 출력을 입력으로 나눈 값은 0.8125를 넘지 않으며, 16에서 그 값에 이릅니다.65 비는 20프레임씩 3단계, 60프레임, 1.00초에 걸쳐 거기에 이릅니다.54

그래서 13/16, 즉 0.8125가 정전의 비 수치가 됩니다. 어두워지는 모든 팔레트의 모든 채널이 약 5분의 4입니다. 빛을 절반 남기는 Crystal의 밤에 비하면 부드러운 어두워짐입니다.14

5비트 채널(0~31)의 출력을 입력에 대해 그린 차트. 점선은 항등선. 비의 맵(맵 3)은 그 아래를 지나며 입력의 약 0.81로, 31에서 25, 16에서 13, 8에서 6. 번개의 맵(맵 19)은 12 미만의 입력에서는 항등선을 따르고(0에서 1, 8에서 8, 11에서 10), 12 이상의 모든 입력에서 31로 뛴다.

Emerald의 비와 번개 맵을 BuildColorMaps에서 figures/make_figures.py로 재생한 것으로, measure_gen3_weather.py가 출력한 점들을 검증합니다. 그림이 아니라 곡선입니다.

비는 사람을 건드리지 않는다

어느 팔레트가 어두운 맵을 받는지도 표로 정해져 있으며, sBasePaletteColorMapTypes는 하드웨어 팔레트마다 하나씩 32개 항목입니다.6 배경 팔레트 0~13은 어두운 맵을 받고, 인터페이스인 14와 15는 아무것도 받지 않습니다. 오브젝트 팔레트 16개 중 10개는 어두운 맵을 받고, 6개는 평범한 “contrast” 맵을 받는데, 그 맵 3은 항등 맵이라 그려진 것이 정확히 그려진 그대로 남습니다.5

include/event_object_movement.h에 이름 붙은 팔레트 슬롯과 대조하면 그 여섯은 오브젝트 팔레트 0, 2, 3, 4, 5, 10으로, PALSLOT_PLAYER, PALSLOT_NPC_1~PALSLOT_NPC_4, PALSLOT_NPC_SPECIAL, 즉 플레이어와 다섯 마을 사람 슬롯입니다. 반사 슬롯은 플레이어의 것도 마을 사람 각각의 것도 모두 어두운 맵을 받습니다.155 비 속에서 Emerald의 땅, 건물, 물, 그리고 그 물에 비친 반사까지 13/16가 되고, 그 사이를 걷는 사람들은 제 색을 지킵니다.

두 세대, 두 메커니즘, 그리고 하나의 규칙입니다. Crystal의 사람 팔레트는 밤에 투명색만 바꾸고, Emerald의 사람 팔레트는 비 속에서 항등 맵 위에 있습니다. 빛은 장소에 속하고, 인물은 그 안에서 읽히는 채로 남습니다.15 소스는 대응만 말하고 이유는 말하지 않습니다. 제가 읽기에 그것은 작고 어두운 화면에서의 가독성으로, 그런 화면에서는 어두워진 스프라이트가 가장 먼저 윤곽을 잃습니다. 어느 쪽이든 결과는, 사람이 눈을 찡그리고 봐야 하는 대상이 되는 일은 결코 없다는 것입니다.

번개는 같은 표의 반대쪽 끝

같은 표의 반대쪽 끝이 섬광입니다. 마지막 맵인 맵 19는 12 이상의 모든 채널 값을 31로 보내고, 12 미만의 값은 원래 자리 가까이에 둡니다. 0은 1이 되고, 4는 4로, 8은 8로 남고, 11은 10이 됩니다.56 하얀 화면이 아니라 고대비 섬광입니다. 모든 팔레트의 밝은 절반이 하얘지고, 어두운 절반은 어둡게 남습니다.

비를 측정하다

비는 빗방울 스프라이트 10개이고, 뇌우는 16개, 호우는 24개이며 이것이 상한이기도 합니다. 각 빗방울은 16×32 스프라이트입니다. UpdateVisibleRainSprites는 ++rainSpriteVisibleCounter > rainSpriteVisibleDelay일 때 빗방울 하나를 활성화합니다. 지연 다음 프레임에 발화하는 카운터로, 지연이 비는 8, 무거운 두 종류는 4이므로 새 빗방울은 비에서는 9프레임마다, 뇌우나 호우에서는 5프레임마다 더해지며, 개수가 찰 때까지 이어집니다. 활성화 단계만 해도, 활성 빗방울 0개부터 세어 비는 90프레임, 1.51초, 뇌우는 80프레임, 1.34초, 호우는 120프레임, 2.01초입니다.754 그것이 변화의 전부는 아닙니다. 상태 기계에서 호출 단위로 재생하면, 맑은 하늘(마무리 처리가 바로 돌아가는 SUNNY)에서 플레이 도중 날씨가 바뀌는 일은 Task_WeatherMain이 날씨를 바꾸는 프레임에 시작합니다. 그다음 프레임부터 Rain_Main은 첫 호출에서 빗방울 시트를 불러오고, 이어지는 24번의 호출에서 한 번에 하나씩 빗방울 스프라이트 24개를 모두 만든 뒤에야 활성화를 시작합니다. 그래서 비의 마지막 빗방울은 교체 후 115프레임, 1.93초에 활성화되고, 뇌우는 105프레임, 1.76초, 호우는 145프레임, 2.43초입니다. 팔레트가 먼저 끝납니다. 20프레임씩 세 단계로 프레임 59에 맵 3에 닿아, 어느 종류의 마지막 빗방울보다도 앞서며, 뇌우의 첫 번개는 프레임 109에 칠 수 있습니다. 두 비 종류 사이에서는 스프라이트를 유지한 채 개수만 바뀌며, 5프레임이나 9프레임마다 한 방울씩입니다. 비에서 뇌우로 가면 32번째 호출까지 여섯 방울을 더 활성화합니다. 이미 비가 오는 상태로 맵이 불러와지면 Rain_InitAll이 같은 단계를 한 프레임 안의 루프로 실행하고(비에서 호출 116번), 화면은 가득 찬 채로 시작합니다. 비가 그칠 때는 같은 호출이 9프레임이나 5프레임마다 한 방울씩 거둬들입니다.29764

각 빗방울은 16이 1픽셀인 Q28.4 고정소수점으로 저장된 일정한 속도로 움직입니다. 비는 프레임당 (−6.5, +13.0)픽셀, 14.5픽셀, 초당 868픽셀, 수직에서 26.6도로 18프레임, 262픽셀을 떨어진 뒤 물보라가 됩니다. 호우의 빗방울은 프레임당 (−10, +20)픽셀, 22.4픽셀, 초당 1,336픽셀로 같은 각도에서 12프레임, 268픽셀을 떨어집니다.57 둘 다 땅에 닿기 전까지 셀 약 16개만큼의 거리를 0.301초와 0.201초에 떨어집니다.4 물보라 애니메이션은 3 + 2 + 2 = 7프레임, 0.117초이고, 무거운 물보라는 3 + 3 + 4 = 10프레임, 0.167초입니다.54

그러니 정전의 비는 성기고 빠릅니다. 240×160 화면에 줄기 열 개가 약 5분의 1초 만에 화면을 가로지르고, 각각 맨 위에서 물보라 끝까지 25프레임, 0.42초를 삽니다.4 그것이 비로 읽히는 것은 밀도가 아니라 각도, 속도, 물보라 덕분입니다.

안개, 모래, 구름

어둡게 하지 않는 날씨는 대신 레이어를 움직입니다.57

  • 가로 안개는 4프레임마다 1픽셀, 초당 14.9픽셀, 걷는 속도의 4분의 1로 스크롤하며, 8/16 위에 12/16로 섞입니다.54
  • 대각선 안개는 쓰이지 않으며, 가로로 3프레임마다, 아래로 5프레임마다 1픽셀 움직입니다. 초당 19.9픽셀과 11.9픽셀입니다.5
  • 모래바람은 레이어를 프레임당 gSineTable[index] × 4 / 256픽셀 움직이며, 인덱스는 6프레임마다 0x20부터 0x5F까지 나아갑니다. src/trig.c의 사인 표로 6,000프레임을 재생하면 프레임당 2.83~4.00픽셀, 평균적으로 왼쪽으로 3.59(초당 215픽셀), 위로 0.90입니다. 걷는 속도의 3.6배로, 플레이어보다 빠른 유일한 날씨 레이어입니다.454
  • SUNNY_CLOUDS는 64×64 구름 스프라이트 세 개로, 소스가 “for the lower half of Route 120”(Route 120의 아래쪽 절반을 위한)이라고 말하는 맵 셀에 놓이고, 12와 8로 섞이며, UpdateCloudSprite가 움직입니다. 그 주석은 “Move 1 pixel left every 2 frames.”(2프레임마다 왼쪽으로 1픽셀 이동)입니다. 초당 29.9픽셀, 걷기 59.7의 절반입니다.7511

공기의 각 레이어가 얼마나 빨리 움직이는지를 각 게임의 걷는 속도에 대한 비율로 보인 가로 막대 그래프. 걷기를 1로 둔다. Emerald: 모래바람 3.60, 구름 0.50, 가로 안개 0.25. Kiradex(오늘의 초당 60픽셀 걷기, 즉 초당 60번 뛰는 시계의 16틱에 16픽셀에 대해): 제안하는 구름 시트는 초당 16픽셀로 0.27, 오늘의 구름 시트는 0.027.

걷기에 대한 공기. Emerald의 레이어는 gen3_weather.txt에서, Kiradex의 오늘과 제안된 구름은 kiradex_proposals.txt와 arith.txt에서, Kiradex의 걷기는 그 Motion.swift에서 읽었습니다. Kiradex의 속도는 Mac에서 소스로 읽은 것이지 iPhone에서 측정한 것이 아닙니다.

천둥: 짧고, 드물고, 섬광과 함께 혹은 그 뒤에 들린다

뇌우는 작은 상태 기계를 돌리며, 소스는 그것을 하나의 패턴으로 요약합니다. “(SHORT_BOLT){1,2}(LONG_BOLT)?”입니다.7 측정한 결과는 이렇습니다.54

  • 첫 주기 이후의 각 주기는 360~719프레임의 타이머를 기다리고, 그것이 끝난 2프레임 뒤에 칩니다(다음 호출이 번개를 준비하고, 그다음 호출이 칩니다). 주기 시작부터 361~720프레임, 6.04~12.05초입니다. 첫 주기는 기다리지 않습니다. 폭풍으로의 페이드가 끝나면 THUNDER_STATE_WAIT_CHANGE가 기다림을 건너뛰고 THUNDER_STATE_INIT_CYCLE_1로 갑니다.5297
  • 짧은 번개가 1번이나 2번 치며, 각각 맵 19를 6~8프레임, 0.10~0.13초 유지한 뒤 비의 맵으로 돌아갑니다.57
  • 번개 사이의 타이머는 60~75프레임이고, 한 번개가 끝나고 다음 번개가 칠 때까지의 어두운 간격은 그보다 한 프레임 길어 61~76프레임, 1.02~1.27초입니다. 긴 번개의 간격도 같습니다.5294
  • 주기의 절반에서는 긴 번개가 뒤따르며 30~45프레임, 0.50~0.75초 유지되고, 그다음 컷이 아니라 서서히 비의 맵으로 페이드해 돌아갑니다.57
  • 천둥소리는 주기의 마지막 번개가 치는 프레임에 대기열에 들어갑니다. 긴 번개가 뒤따르지 않으면 마지막 짧은 번개가 칠 때 EnqueueThunder(20), 긴 번개가 칠 때 EnqueueThunder(100)입니다. EnqueueThunder는 타이머를 Random() % waitFrames로 설정하고, 매 프레임 Thunderstorm_Main 맨 앞에서 불리는 UpdateThunderSound가 그것을 세어 내려가다가 0에 닿고 다른 효과음이 재생 중이지 않으면 소리를 냅니다. 타이머가 끝날 때 다른 소리가 나지 않으면 번개 후 1~20프레임, 최대 0.33초, 긴 번개는 1~100프레임, 최대 1.67초입니다. 그때 다른 효과음이 재생 중이면 UpdateThunderSound는 돌아갔다가 다음 프레임에 다시 시도하므로, 천둥은 그 소리가 끝나기를 기다리며, 이 범위들은 상한이 아닙니다. 짧은 번개는 6~8프레임 유지되므로 번개가 아직 켜져 있는 동안 소리가 시작될 수 있습니다. 소스는 “Thunder only plays on the final bolt of the cycle.”(천둥은 주기의 마지막 번개에서만 울린다)라고 적고 있습니다.74

Emerald 뇌우 주기를 상태 기계에서 재생한 타임라인. 첫 주기 이후의 주기이며 모든 타이머를 최솟값으로 두고 프레임 단위 축척으로 그렸다. 주기 시작부터 361프레임의 기다림, 6프레임 켜지는 짧은 번개, 61프레임의 어둠, 6프레임의 두 번째 짧은 번개, 61프레임의 어둠, 그리고 페이드가 시작되기 전 30프레임 켜지는 긴 번개. 짧은 번개 하나만도 허용되므로, 이것은 가장 짧은 주기가 아니라 가장 긴 패턴을 가장 촘촘하게 한 것이다. 첫 간격 아래의 자는 1초, 59.73프레임을 표시하며, 두 번째 번개가 시작되기 전에 끝난다.

첫 주기(기다림을 건너뜁니다) 이후의, 기다림이 최소인 번개 세 개짜리 주기를 gen3_replay.txt의 상태 전이에서 재생한 것입니다. 각 간격은 그 타이머에 다음 상태가 움직이는 데 걸리는 한 프레임을 더한 것입니다. 1초 자는 arith.py의 것입니다.

이것을 따라 하려는 사람에게는 이 산수가 중요합니다. 두 번개 사이의 어두운 간격은 최소 61프레임이고, 초당 59.7275프레임에서는 1.0213초로 1초보다 깁니다. 그러니 Emerald 폭풍의 어떤 1초 창에도 한 번개의 끝과 다른 번개의 시작이 함께 들어가지 않으며, 어느 1초에든 섬광은 많아야 한 번입니다.4 이는 W3C의 성공 기준 2.3.1 안에 듭니다. 레벨 A 요구 사항으로, 콘텐츠가 “anything that flashes more than three times in any one second period”(어떤 1초 동안이든 세 번보다 많이 번쩍이는 것)를 담지 않을 것을 요구합니다.46 그래도 10절은 Kiradex를 위해 섬광을 거부하며, 그 이유는 거기서 말합니다.

3. 날씨가 있는 곳: 맵, 트리거, 달력

날씨는 맵의 속성

3세대의 모든 맵의 map.json은 헤더에서 날씨 하나를 지정합니다. 스크립트는 Emerald의 518개, FireRed의 425개를 모두 읽고 맵 종류별로 묶습니다.547

Emerald의 야외 맵 68개(시티 9, 타운 7, 도로 41, 바다 도로 11)는 SUNNY를 51번, NONE을 13번, SHADE를 2번, FOG_HORIZONTAL을 1번, VOLCANIC_ASH를 1번 갖습니다. FireRed의 야외 맵 76개는 SUNNY 66, NONE 8, SHADE 2입니다.54 두 게임 모두 야외 맵의 4분의 3 이상이 기본으로 맑고(75.0%와 86.8%), 헤더가 비인 야외 맵은 없습니다.4

모든 야외 맵의 헤더 날씨를 보인 누적 막대 두 개. Emerald 68개 맵: 맑음 51, 없음 13, 그늘 2, 가로 안개 1, 화산재 1. FireRed 76개 맵: 맑음 66, 없음 8, 그늘 2. 두 게임 모두 헤더가 비인 야외 맵은 없다. 메모: Emerald의 비는 트리거에서 온다. 5개 맵에 있는 좌표 날씨 이벤트 86개 중 4개가 RAIN, 24개가 Route 119와 123의 주기이고, 스크립트 setweather 호출 24개 중 1개가 RAIN, 2개가 DOWNPOUR다. FireRed에는 좌표 날씨 이벤트가 없다.

맵별 헤더 날씨. gen3_weather.txt 섹션 G에서.

비는 트리거, 스크립트, 달력에서 온다

Emerald의 비는 굴려서 정하는 것이 아니라 놓여 있습니다. 맵에는 좌표 날씨 이벤트, 즉 플레이어가 밟으면 날씨를 바꾸는 셀이 86개 있고, Jagged Pass와 Route 113, 119, 120, 123의 5개 맵에 있습니다. 종류별로는 SUNNY 34, SUNNY_CLOUDS 12, VOLCANIC_ASH 12, RAIN 4, 두 도로 주기가 각각 12입니다.54 스크립트는 setweather 호출 24개를 더합니다. NONE 5, SUNNY 4, ABNORMAL 3, DOWNPOUR 2, SANDSTORM 2(둘 다 Route 111), SUNNY_CLOUDS 2, VOLCANIC_ASH 2, FOG_HORIZONTAL 2, RAIN 1번(Route 120), DROUGHT 1번입니다.5 FireRed에는 좌표 날씨 이벤트가 전혀 없습니다.5

두 도로가 달력을 가집니다. Route 119는 SUNNY, RAIN, RAIN_THUNDERSTORM, RAIN을, Route 123은 SUNNY, SUNNY, RAIN, SUNNY를 하루에 한 단계씩 돌며, UpdateWeatherPerDay가 진행시킵니다.75 Route 119에서는 나흘 중 사흘이 젖고, Route 123에서는 하루입니다.4 단계가 하루에 한 번만 움직이므로 같은 날 Route 119를 두 번 걷는 플레이어는 같은 날씨를 두 번 만나고, 어느 날의 날씨는 누가 도착하기 전에 정해져 있습니다.

실내도 날씨다

헤더 필드는 하늘만을 위한 것이 아닙니다. Emerald는 실내 맵 2개에 가로 안개를, 실내 맵 1개에 그늘을 주고, 지하에서는 11개 맵이 그늘, 7개가 안개입니다. FireRed는 실내 맵 5개에 안개를, 4개에 그늘을 주고, 지하 맵 14개에 안개를, 1개에 그늘을 줍니다. Emerald의 수중 맵 14개는 모두 UNDERWATER_BUBBLES를 갖습니다.548 원래 이름이 흐림이나 잔뜩 찌푸린 날씨를 뜻했다고 주석이 말하는 SHADE는, 방이나 동굴이 어둑하다고 말하는 정전의 방식입니다.

이것이 날씨에 대해 말하는 것

모아 보면 측정은 날씨를 세계의 예정된 상태로 그려 냅니다. 날씨는 장소(도로, 동굴, 방)에 속하고, 한 걸음이나 하루에 바뀌며, 그 도로를 전에 걸어 본 사람이라면 미리 알고, 그곳에 있는 모두에게 같습니다.5 5절은 Stardew Valley가 다른 장치로 같은 일을 하는 것을 보여 줍니다. 골짜기 전체에 매일 한 번 굴리고, 전날 알려 주는 것입니다.17 어느 게임도 플레이어의 실제 날씨를 보여 주지 않으며, 제가 읽기에 그것은 하드웨어의 한계가 아니라 설계입니다. 세계의 날씨는 세계가 가진 것이지, 플레이어가 들고 들어오는 것이 아닙니다.

4. 3세대의 어둠과 그림자

어두운 동굴은 밝은 원

Emerald는 어둠을 기하로 그립니다. src/field_screen_effect.c의 sFlashLevelToRadius는 {200, 72, 64, 56, 48, 40, 32, 24, 0}픽셀로, 완전히 밝은 상태부터 완전히 검은 상태까지 아홉 단계입니다.495 맵 헤더가 requires_flash를 설정하면(맵 도구는 이것을 C 코드가 gMapHeader.cave로 읽는 헤더 바이트에 씁니다) SetDefaultFlashLevel은 레벨 7, gMaxFlashLevel - 1, 반지름 24픽셀, 1.5셀에서 시작합니다. 플래시를 쓴 뒤에는 레벨 1, 72픽셀, 4.5셀에서 시작합니다. 다른 모든 맵은 동굴이든 아니든 레벨 0, 완전히 밝은 상태에서 시작합니다.505 밝은 영역은 게임보이 어드밴스의 창으로, 그 가로 경계는 DMA로 주사선마다 다시 쓰이며, 플레이어가 아니라 화면 너비와 높이의 절반, 즉 화면 중앙에 놓입니다.5

240×160 화면에서 플래시 없는 원은 화면의 4.7%를, 플래시가 있는 원은 42.4%를 덮어 면적이 아홉 배입니다.4 레벨 1부터 레벨 7까지 각 레벨은 반지름을 8픽셀, 반 셀씩 줄이고, 레벨 8은 검정입니다.4

16픽셀 격자 위의 240×160픽셀 화면 도식. 어둡고, 가운데에 원 두 개가 있다. 안쪽은 반지름 24픽셀, 1.5셀로 플래시 없는 동굴. 바깥쪽은 반지름 72픽셀, 4.5셀로 플래시를 쓴 경우. 옆에 반지름 표 200, 72, 64, 56, 48, 40, 32, 24, 0픽셀과 화면에서 차지하는 비율 4.7%와 42.4%가 적혀 있다.

셀 단위 반지름으로서의 어둠. gen3_weather.txt에 출력된 sFlashLevelToRadius로 만든 도식입니다. 맵은 그리지 않았습니다.

Emerald의 맵 7개가 requires_flash를 설정하므로 518개 중 7개가 어둡게 시작합니다. 그중 셋은 Ruby와 Sapphire에서 남은 쓰이지 않는 맵(CaveOfOrigin_UnusedRubySapphireMap1~3)이고, 나머지는 Granite Cave의 아래 두 층과 Victory Road의 두 층입니다. FireRed에는 둘, Rock Tunnel의 층들이 있습니다.5 Crystal과 나란히 놓으면 세 세대는 어두운 곳을 세 가지로 그립니다. Red는 팔레트 오프셋으로, Crystal은 플래시가 밤과 바꿔 주는 팔레트 세트로, Emerald는 플래시가 반지름을 세 배로 늘리는 빛의 원으로 그립니다.4035

그림자는 한 톤에 높이 다섯 행

Emerald는 그림자를 필드 이펙트 스프라이트 네 개로 그리며, measure_shadows.py가 그것을 읽습니다. 소형은 8×8픽셀, 중형은 16×8, 대형은 32×8, 특대형은 64×32입니다. 각각 색 인덱스 하나이고, 각각 프레임 아래쪽 다섯 행에 있는 납작한 타원입니다. 불투명 픽셀은 소형이 64개 중 24개, 중형이 128개 중 64개, 대형이 256개 중 144개, 특대형이 2,048개 중 304개입니다.8514 걷는 이의 크기가 어떻든 그림자는 높이 다섯 행에 한 톤입니다. 이 시리즈의 높이 글은 규칙의 나머지 절반을 측정했습니다. 걷는 이가 턱을 뛰어넘을 때 그림자는 땅에 남습니다.52

Kiradex의 걷는 이 그림자 shadow.png도 같은 설계를 따릅니다. 12×4픽셀, 한 톤, (18, 17, 23)에 알파 153, 48픽셀 중 40개가 불투명하며, Mac에서 출시된 그림으로 읽은 것이지 iPhone에서 측정한 것이 아닙니다.89 알파 153은 60% 덮음이고, 톤은 루마 0.071로 파랑 쪽으로 기운 검정에 가까운 색입니다.4

5. Stardew Valley의 하루와 날씨

Stardew Valley는 달력으로 돌아가는 마을을 찾아 이 시리즈가 거듭 돌아오는 현대 게임이며, 그 위키는 하루와 날씨를 자세히 기록합니다. 여기 있는 것은 2026년 10월 5일에 저장한 위키의 말과 수치입니다. 이 글을 위해 게임 코드는 읽지 않았으므로, 읽은 페이지가 알려 주지 않는 밤 틴트 값과 어두워지는 속도는 여기 없습니다.12

멈추지 않으면 14분인 하루

하루는 오전 6시부터 오전 2시까지, 게임 속 20시간이며, “Time passes at 0.7 real seconds per in-game minute”(게임 속 1분마다 실제 0.7초가 흐른다)이므로 하루 전체는 실제 840초, 14분입니다. 다만 위키 자신의 두 조건 아래에서입니다. 하나는 1분이 0.9초 걸리는 해골 동굴 밖일 것(“except the Skull Cavern where it’s 0.9”), 다른 하나는 “Ignoring pauses”(일시 정지를 빼고)로, 싱글 플레이에서는 컷신, 메뉴, 대화 중에 시계가 멈추기 때문입니다.164 해 질 녘은 계절에 따라 움직입니다. “In Spring and Summer , it is 8pm, while in Fall it is at 7pm and Winter is 6pm.”(봄과 여름에는 오후 8시, 가을에는 오후 7시, 겨울에는 오후 6시)라고 되어 있습니다(쉼표 앞의 공백은 위키의 것입니다). 해 질 녘이 되면 “indoors the windows turn dark and lamps and sconces light up”(실내에서는 창이 어두워지고 램프와 벽등이 켜진다), 야외에서는 “it does not immediately become full dark, but gradually becomes darker over time.”(곧바로 완전히 어두워지지 않고, 시간이 지나며 점점 어두워진다)16 오전 6시부터 세면 해 질 녘은 봄날에는 실제 약 9.8분 뒤, 겨울날에는 8.4분 뒤에 옵니다.4

그러니 Stardew는 Crystal이 하지 않는 일을 합니다. 어둠은 그러데이션으로 오고, 시작하는 시각은 계절을 따릅니다. 실내도 어둡게 합니다. Crystal은 실내 맵 208개 중 207개를 낮에 고정하지만, Stardew에는 위키가 기록하는 예외가 하나 있습니다. “if nightfall happens while you are indoors it stays light until you exit and re-enter.”(실내에 있는 동안 해가 지면, 나갔다가 다시 들어올 때까지 밝게 남는다)161

불빛은 맵의 속성

위키의 맵 모딩 페이지는 조명을 맵이 가진 속성으로 나열합니다.53

  • AmbientLight는 “Sets the RGB color that is subtracted from white (255,255,255)”(흰색 (255,255,255)에서 빼는 RGB 색을 설정한다)이므로, 맵의 어둠은 곱하는 색이 아니라 덜어 내는 색입니다.53
  • Light는 아홉 가지 빛 종류 중 하나를 놓습니다. 랜턴, 창, 벽등, 가마솥, 실내 창, 프로젝터, 수조, 겨울 마을 나무 조명, 핀포인트입니다.53
  • WindowLight는 “only lit during the day when it is not raining”(비가 오지 않는 낮에만 켜지는) 빛을 더합니다. 바깥에서 창을 통해 들어오는 빛입니다.53
  • NightTiles는 “Changes the tile after 7pm”(오후 7시 이후 타일을 바꾼다)이고, 페이지는 그것이 “is mostly used for lamps in the game.”(게임에서는 주로 가로등에 쓰인다)라고 덧붙입니다.53

구조물 편 글은 Kiradex의 불 켜진 창의 본보기로 NightTiles를 썼습니다.23 WindowLight는 나머지 절반이며, Kiradex에 아직 없는 쪽입니다. 창이 바깥의 빛을 보여 주는 방입니다.

날씨는 날마다, 전날 알린다

Stardew의 날씨는 하루에 한 번 굴리고 알립니다. 위키의 날씨 페이지는 “Weather changes daily and with the seasons”(날씨는 매일, 그리고 계절에 따라 바뀐다)라고 하고, 다음 날 날씨는 “can be checked by viewing the TV screen”(TV 화면을 보면 확인할 수 있다), 곧 TV의 일기 예보에서 볼 수 있다고 합니다.17 날씨가 강제되지 않는 날짜에 대한 모딩 페이지의 확률은 이렇습니다.18

  • 봄: “an 18.3% base chance of rain”(비의 기본 확률 18.3%), 그리고 “in spring there’s a 66.4% chance of sunny weather.”(봄에는 66.4% 확률로 맑다)18
  • 여름: “The chance of sunny weather diminishes steadily per day from 87.4% on summer 1 to 79.9% on summer 28”(맑을 확률은 여름 1일의 87.4%에서 여름 28일의 79.9%까지 날마다 꾸준히 줄어든다), 그리고 “There’s an 85% chance that rain becomes storms.”(비가 폭풍이 될 확률은 85%)18
  • 겨울: “a 63% chance of precipitation”(강수 확률 63%), 그리고 비 자체에 대해서는 “Winter: never rains.”(겨울: 비가 오지 않는다)18
  • 날림(바람): 봄에는 “approximately 16.6% chance of debris weather”(날림 날씨 확률 약 16.6%), 가을에는 “approximately 49.8%”(약 49.8%)입니다.18

폭풍 중에는 “There is a chance for a lightning strike to occur every 10 minutes”(10분마다 벼락이 칠 가능성이 있다)이고, 게임은 플레이어가 눈을 약하게 할 수 있게 해 줍니다. “Snow transparency can be changed in the Options Menu”(눈의 투명도는 옵션 메뉴에서 바꿀 수 있다)17 이 마지막 줄은 날씨에 관한 작은 접근성 설정이며, 10절은 그 힌트를 받아들입니다.

6. 현대의 조명이 들어간 픽셀 게임, 만든 이들의 말로

이 시리즈의 첫 글은 픽셀 아트 조명의 단계표를 제시했습니다. 여기 요약하면, 맨 아래에 Moonlighter의 겹친 스프라이트, Celeste의 라이트 마스크, Eastward의 손으로 그린 범프 맵, 그리고 맨 위에 Sea of Stars와 HD-2D의 조명이 들어간 3D 장면이 있으며, Animal Well과 Dead Cells도 자리를 잡습니다.32 이 절은 만든 이들에게 돌아가 각자가 자기 빛이 무엇을 위한 것이라고 말하는지 확인합니다. 낮밤 주기나 날씨의 수치를 주는 이는 아무도 없습니다. 수치라고는 Celeste의 텍스처와 빛 예산뿐이고, 조명 수치가 담긴 Eastward나 Sea of Stars의 발언은 찾지 못했습니다.12

Moonlighter: 조명이 전혀 없다

Digital Sun은 80.lv에 “There is no dynamic lighting”(동적 조명은 없다)이라고 말했고, “we use the superposition of sprites to give the impression of light (for example in Rynoka during the night).”(스프라이트를 겹쳐 빛의 인상을 준다. 예를 들어 밤의 Rynoka에서)라고 했습니다.54 그 마을의 밤은 계산되는 것이 아니라 그려진 것입니다.

Celeste: 벽에 닿는 빛

2017년 9월 25일에 Noel Berry가 남긴 Celeste 조명 재작업 기록은 하나의 요구 사항에서 시작합니다. 단순한 스포트라이트로는 “wouldn’t cut it”(어림없었다), 왜냐하면 “the lights needed to actually hit walls.”(빛이 실제로 벽에 닿아야 했다) 때문입니다. 그의 방법은 먼저 각 빛의 스포트라이트를 마스크에 그리고, 그다음 모든 벽 면이 “their shadow projection (each just a single quad)”(그림자 투영, 각각 사각형 하나뿐)를 위에 그려 스포트라이트에서 그림자를 도려내는 것입니다. 각 빛은 2048×2048 텍스처를 256×256 슬롯으로 나눈 것의 색 채널 하나를 차지하고, 네 채널짜리 슬롯이 64개이므로 “we can have a total of 256 lights on a single, big texture.”(큰 텍스처 하나에 모두 256개의 빛을 둘 수 있다)554

Eastward: 2D처럼 보이는 3D 게임

Pixpil의 Tommo Zhou는 2021년 10월 11일 Game Developer에 말했습니다. “Interestingly Eastward is a 3D game with a 2D perspective!”(흥미롭게도 Eastward는 2D 시점을 가진 3D 게임이다!) 스튜디오는 “shader textures and lighting systems in our custom engine (Maoi) to help convey atmosphere, and things like the weather and the time”(분위기, 그리고 날씨와 시간 같은 것을 전하기 위해 자체 엔진(Maoi)의 셰이더 텍스처와 조명 시스템)을 쓰며, “intricate fog layers and sunlight beams breaking through the landscape during dawn and dusk”(새벽과 해 질 녘에 풍경을 뚫고 들어오는 정교한 안개 레이어와 햇살)가 있고, 에셋은 3D로 다시 만들어 “hand painted in the bump map one by one”(하나하나 범프 맵에 손으로 칠한다)고 합니다.56

Octopath Traveler와 HD-2D: 그림자가 떨어지는 곳

Nintendo Everything이 2018년 11월 3일 번역한 Nintendo Dream 인터뷰에서 Octopath Traveler의 Shizuka Morimoto는 이렇게 말했습니다. “At first, I started using some techniques to add dramatic lighting to the 2D art, but Asano told me that wasn’t enough.”(처음에는 2D 그림에 극적인 조명을 더하는 기법을 쓰기 시작했지만, Asano가 그걸로는 부족하다고 했다) Tomoya Asano는 이렇습니다. “I wanted to make use of lighting mixed with pixels in a way that emphasized how light shines on objects and how shadows fall.”(빛이 사물에 어떻게 비치고 그림자가 어떻게 떨어지는지를 강조하는 방식으로, 픽셀과 섞인 조명을 살리고 싶었다)57 2차 자료인 Wikipedia는 이 시리즈가 알려지게 된 기법 HD-2D를 이렇게 설명합니다. “Typically, a point light source is placed into the scene to make characters and objects cast shadows”(보통 캐릭터와 사물이 그림자를 드리우도록 장면에 점광원을 둔다), 그 위에 틸트 시프트, 피사계 심도, 블룸, 볼류메트릭 조명, 안개가 더해집니다.58 비용에 대한 Asano 자신의 평가는, 2022년 5월 Nintendo Life가 보도한 4Gamer 인터뷰에서 기사 제목 아래의 한 줄입니다. “It costs more than you’d think”(생각보다 비용이 든다)59 Unreal Engine의 Octopath Traveler 페이지 두 개는 가져오기 도구에도 curl에도 HTTP 403을 돌려주었으므로, Nintendo Dream 번역이 그것을 대신합니다.12

Sea of Stars: 기능으로서의 조명, 그리고 플레이 속의 시계

Sabotage의 Sea of Stars 보도 자료는 “Full-on dynamic lighting. Our custom-made render pipeline allows the creation of a breathtaking world coming to life by pushing the limits of 2D pixel-art games.”(본격적인 동적 조명. 자체 제작한 렌더 파이프라인이 2D 픽셀 아트 게임의 한계를 밀어붙여 숨 막히는 세계에 생명을 불어넣는다)를 내세웁니다.60 게임플레이 영상에 대한 TechRaptor의 기사는 낮과 밤의 변화가 플레이를 움직인다는 것을 보여 줍니다. 그것은 “influences gameplay as well, specifically some interesting little puzzles that materialize bridges at the right time of day.”(게임플레이에도 영향을 주며, 특히 하루의 알맞은 시간에 다리가 나타나는 재미있는 작은 퍼즐들이 있다)61 Sabotage Studio의 Thierry Boulanger는 2023년 8월 Screen Rant에, 이 시리즈의 높이 글이 인용하듯, 레벨이 “to all read well with different levels of height, with the light and everything”(높이가 다른 곳에서도 빛과 모든 것과 함께 잘 읽히도록) 해야 했다고 말했습니다.52

손으로 그린 그림자

두 화가가 엔진이 전혀 필요 없는 그림자 규칙을 줍니다. 한 사람은 글 세 편으로, 다른 한 사람은 한 줄로.

Raymond Schlitter는 탑다운 오브젝트에 관한 Pixelblog에서 드리운 그림자에 대해 이렇게 씁니다. “It’s best to keep them subtle and not cast out long in any particular direction”(은은하게 두고 어느 방향으로도 길게 드리우지 않는 것이 가장 좋다), 그리고 “in most cases I make the shadows on separate tiles and place them on a different layer than the sprites.”(대부분은 그림자를 별도 타일로 만들어 스프라이트와 다른 레이어에 둔다)62 탑다운 타일 글의 2부에서는 벽 아래의 드롭 섀도에 대해 이렇습니다. “it’s best to limit them to one or two wall faces, minding light source, and they should not exceed a tile in length. No matter how tall the rock wall all shadows are the same length.”(광원을 염두에 두고 벽면 한두 개로 제한하는 것이 가장 좋으며, 길이는 한 타일을 넘지 않아야 한다. 바위벽이 아무리 높아도 그림자는 모두 같은 길이다)63 그리고 탑다운 나무 글에서는 나무의 그림자를 어디에 둘지에 대해 이렇습니다. “It’s most practical for game design to center the shadow directly under the tree, so that it doesn’t run into other assets”(다른 에셋과 부딪치지 않도록 그림자를 나무 바로 아래 가운데에 두는 것이 게임 디자인상 가장 실용적이다)64

Koichi Ishii는 성검전설 3에 대해, Shmuplations의 번역에서 이렇게 말합니다. “for shadows and the like, we’re using deep blues and purples instead of shades of black, to impart a sense of softness.”(그림자 같은 데에는 부드러운 느낌을 주려고 검은 계열 대신 깊은 파랑과 보라를 쓰고 있다)65

단계표를 휴대폰을 위해 읽다

만든 이들의 말은 단계표에 한 가지를 더합니다. Moonlighter보다 위의 모든 단계는 빛이 무언가와 상호작용하게 하려고 있습니다. Celeste의 빛은 벽에 닿고, Eastward의 빛은 범프 맵 표면에 떨어지며, Octopath는 “how shadows fall.”(그림자가 어떻게 떨어지는지)을 보여 줍니다.555657 더하기만 하는 빛, 막히지도 않고 닿은 곳에 의해 모양이 잡히지도 않는 빛은 어떻게 블렌딩되든 Moonlighter의 단계입니다.

Kiradex의 웅덩이가 바로 그것입니다. 진짜 가산 블렌딩으로 땅에 더한 빛이며, 아무것과도 상호작용하지 않습니다(7절).6622 제가 읽기에 그것은 결함이 아닙니다. 휴대폰 마을이 감당할 수 있는 단계이며, 위의 손 그림 규칙들은 엔진 없이 그것을 어디까지 끌고 갈 수 있는지 알려 줍니다. 그림자는 자기 레이어에, 짧게, 한두 면에, 높이와 상관없이 같은 길이로, 검정이 아니라 파랑 쪽으로 기운 색으로.626365

7. Kiradex의 오늘 빛, Mac에서 소스로 읽다

이 절의 모든 내용은 2026년 10월 5일 16:51부터 18:19 사이에 Kiradex 저장소의 작업 트리에서, 커밋 cf3beb1e부터 66c116b0 시점에 읽은 것입니다. 트리는 그날 편집 중이었고, git도 포지도 실행하지 않았으며, 각 주석이 어느 읽기인지 밝힙니다. 읽은 것 가운데에는 Kiradex/World/Daylight.swift, Motion.swift, Air.swift, Glow.metal, PlazaStage.swift, PlazaRig.swift, HallView.swift, 포지의 scripts/forge/air.py, town.py, buildings.py, 그리고 내보낸 마을 Kiradex/Resources/World/town.json(40×30타일, 파일 날짜 2026년 10월 3일 21:34)과 그 아틀라스와 공기 그림이 있습니다.912 measure_kiradex_light.py는 Swift와 Python을 텍스트로 읽고, Pillow로 출시된 그림에 틴트를 적용합니다. 그 어느 것도 iPhone에서 실행하지 않았고, 여기 있는 어떤 수치도 캡처가 아닙니다. 본문이 마을의 밤은 낮의 0.588이라고 말할 때, 그것은 출시된 아틀라스에 출시된 틴트를 Mac에서 곱한 것입니다.9

휴대폰 달력 위의 네 시간대

Daylight.Phase는 시각을 6시부터 9시는 아침, 9시부터 17시는 낮, 17시부터 20시는 저녁, 나머지는 밤으로 대응시킵니다. 3, 8, 3, 10시간입니다.219 가로등은 저녁과 밤에 켜지며, lampsOn은 self == .evening || self == .night로 하루 13시간, 54.2%입니다.214 이것은 Crystal의 시각이 아니며, 일부러 그렇습니다. 오마주 글은 Kiradex의 시간대를 Crystal의 4, 10, 18과 나란히 놓고 Kiradex 고유의 것으로 남기기로 했으며, 이 글은 그 결정을 지킵니다.10

각 시간대는 틴트, 즉 “a multiplier on the art’s own colours”(그림 자신의 색에 곱하는 값)이고, 파일은 넷을 그림의 표면, “four fixed lights for a pixel world”(픽셀 세계를 위한 네 개의 고정된 빛)로 선언합니다.21 루마와 함께 보이면 이렇습니다.9

시간대 틴트(빨강, 초록, 파랑) 루마 파랑에서 빨강과 초록의 평균을 뺀 값
아침 1, 0.96, 0.86 0.961 −0.12
낮 1, 1, 1 1.000 0.00
저녁 1, 0.78, 0.6 0.825 −0.29
밤 0.5, 0.58, 0.9 0.593 +0.36

계절은 거기에 곱하는 색조를 더합니다. 봄 (0.97, 1, 0.95), 루마 0.985. 여름은 흰색, 1.000. 가을 (1, 0.93, 0.84), 0.941. 겨울 (0.9, 0.94, 1), 0.935입니다. 시간대와 계절의 조합 16가지 중 가장 어두운 빛은 가을 밤 (0.5, 0.539, 0.756), 루마 0.552이고, 가장 밝은 것은 여름 낮 1.000입니다.921 계절은 달로 고르며, 파일 자신의 말로는 “in the north; the south is a setting for later”(북반구 기준. 남반구는 나중에 설정으로)입니다.21

모양은 정전과 맞습니다. 밤은 Crystal에서도 Kiradex에서도 가장 긴 시간대로 24시간 중 10시간입니다. Kiradex의 아침은 데운 낮빛으로 모든 색에 루마 0.961의 틴트를 곱하는데, Crystal은 흰색만 데웁니다. 그리고 Kiradex의 밤은 Crystal처럼 파랑 쪽으로 기웁니다.194 Kiradex는 Crystal에 없는, 따뜻하고 가로등이 켜진 저녁을 더합니다.

틴트가 마을에 하는 일

출시된 아틀라스 town.png(256×352픽셀, 그중 81,926픽셀이 불투명)에 적용하면 네 틴트는 평균 루마를 아침 0.432, 낮 0.449, 저녁 0.372, 밤 0.264로 만듭니다. 낮의 0.962, 1.000, 0.829, 0.588입니다.94 Kiradex의 밤은 Crystal의 평균보다 빛을 조금 더 남기고(0.511에 맞서 0.588), 밤 틴트 자신의 루마 0.593보다 조금 덜 남깁니다. 아틀라스의 색이 밤 틴트가 깎는 따뜻한 채널 쪽으로 기울어 있기 때문입니다.4 제가 읽기에, 팔을 뻗어 든 휴대폰이라면 틀리더라도 이쪽으로 틀리는 것이 맞습니다.

불 켜진 것은 틴트를 거부한다

Kiradex는 다른 길을 거쳐 Crystal의 답에 닿았습니다. 불 켜진 창과 홀의 벽등은 머티리얼을 light: .white로, 틴트 없이 그리는 두 번째 메시이고, 가로등이 켜질 때 활성화됩니다. 포지는 불빛 셀마다 켜졌을 때 바뀌는 픽셀만 내보냅니다.2023 내보내기에서 그것은 아틀라스 인덱스 세 개에 있는 셀 24개입니다. 창 20개(인덱스 200, 각각 불투명 픽셀 54개), 박공 창 2개(인덱스 201, 역시 54개. buildings.py가 박공 삼각형 한가운데에 두는 창으로, house-mine과 홀에 있습니다. 도머는 불빛 변형이 없는 지붕 조각입니다), 그리고 홀의 벽등 2개(인덱스 257, 12픽셀, 셀 (21, 5)와 (23, 5))입니다.9

그것들의 가장 밝은 픽셀은 틴트 없이 그려져 루마 0.901입니다. 밤 틴트 아래에서는 아틀라스 어디에서든 가장 밝은 픽셀이 0.562입니다. 불빛 셀은 밤 틴트를 입은 아틀라스에서 가장 밝은 픽셀의 1.60배입니다. 여기에는 가산 블렌딩 웅덩이를 넣지 않았으며, 웅덩이의 가로등 중심은 0.785~0.806에 이릅니다(아래).94 Crystal의 YELLOW가 다른 팔레트의 밤 가장 밝은 색 0.498(마을의 물은 거기서 한 단계 떨어진 0.490)에 맞서 0.90에 있는 것은 같은 생각을 팔레트로 나타낸 것입니다. 불 켜진 것은 밝기를 지키고, 그 둘레의 마을이 떨어집니다.14

그 개수는 이 시리즈의 다른 글을 바로잡습니다. 구조물 편 글은 “nineteen windows and the hall’s two sconces”(창 열아홉 개와 홀의 벽등 두 개)라고 쓰고, “21 lit cells dedupe to two”(불빛 셀 21개는 중복을 없애면 둘이 된다)라고 말합니다.23 10월 3일 21:34의 내보내기에는 아틀라스 인덱스 세 개에 불빛 셀 24개, 창 20개, 박공 창 2개, 벽등 2개가 있습니다.94 그 글을 쓴 뒤 마을이 바뀌었거나, 그 글이 다르게 셌거나 둘 중 하나입니다. 출시된 내보내기에 비추면 셀 세 개와 아틀라스 인덱스 하나만큼 낡았습니다. 이것은 이 글의 발견이고, 앞선 글은 고치지 않았습니다.

더하기만 하는 빛 웅덩이

빌드 29부터 가로등과 불 켜진 창은 밤에 땅에 빛 웅덩이를 드리웁니다. Glow.metal은 RealityKit 서피스 셰이더로, 그림의 색에 틴트를 곱한 것을 기본 색과 발광 색 둘 다로 불투명도 1로 쓰며, 머티리얼은 더하기로 블렌딩합니다. 주석이 그 이유를 말합니다. “black adds nothing, and a pool of light never darkens what it lies on, which an alpha halo did.”(검정은 아무것도 더하지 않고, 빛 웅덩이는 자기가 놓인 것을 결코 어둡게 하지 않는다. 알파 헤일로는 그렇게 했다)6622 Air.swift에서는 프로그램의 디스크립터가 blendMode = .add를 설정합니다.22

웅덩이는 코드와 그림으로 측정합니다.922

  • 가로등 웅덩이. 56×56픽셀, 3.5타일로, 마을의 빛 7개(가로등 머리와 키오스크) 각각의 아래에 있으며, 틴트는 (0.7, 0.52, 0.24)입니다.922
  • 창 웅덩이. 40×28픽셀, 2.5×1.75타일로, 불 켜진 1층 창이나 벽등 앞에 있으며, 틴트는 (0.5, 0.38, 0.17)입니다. 건물의 기단 행이나 그 바로 위 행에 있는 불빛 셀만 하나를 드리우므로, 불빛 셀 24개 중 17개가 그렇고, 웅덩이는 모두 24개입니다.4
  • 그림. glow.png는 64×64의 방사형 웅덩이로, 중심이 0.961이고 픽셀의 0.713에서 0보다 큽니다.967

웅덩이가 땅에 하는 일은 계산할 수 있습니다. 밤 아틀라스의 평균 색은 (0.228, 0.264, 0.358), 루마 0.264입니다. 중심에서 가로등의 틴트를 통째로 더하면 (0.928, 0.784, 0.598), 루마 0.806으로 올라가 낮의 0.449를 넘습니다.9 스크립트는 틴트를 통째로 더합니다. 그림 자신의 최댓값 0.961로 가중하면 중심은 0.785가 됩니다.4 어느 쪽이든 밤의 가로등은 그 아래 땅을 정오보다 밝게 만들며, 그것이 가로등이 그 아래 땅에 하는 일입니다.

걷는 이들은 밤을 받는다

걷는 이들은 제 색을 지키지 않습니다. PlazaRig.light(_:lampsOn:)은 새 빛을 땅, 주변, 오브젝트에 설정하고, 모든 걷는 이에게 “redrawn in the new light on the next frame”(다음 프레임에 새 빛으로 다시 그린다)이라고 표시합니다. 각 걷는 이 프레임의 머티리얼은 같은 light를 쓰는 sheet.material(column:row:light:), 곧 땅과 같은 곱셈입니다.20 밤에 걷는 이들은 밤 틴트, 세 채널 곱셈값 (0.5, 0.58, 0.9)로 그려지며, 그 틴트 자신의 루마는 0.593이고, 저장된 값에서는 수집가 인물의 루마(idle_a로 고정했을 때의 마스크)의 0.575를 남깁니다.30 바로 Crystal과 Emerald가 사람을 건드리지 않는 곳입니다.915

예외 하나는 수집가가 들고 있는 카드입니다. 리그는 “For the card alone: nothing else in the world is lit.”(카드만을 위해. 세계의 다른 어떤 것도 빛을 받지 않는다)라는 주석과 함께 DirectionalLight를 더합니다.20

이것이 두 번째 정정입니다. 세계 글의 체크리스트에는 이렇게 있습니다. “Dusk and night as one multiply tint over the world plus hand-drawn emissive variants for lamps, windows and the kiosk sign.”(해 질 녘과 밤은 세계 전체에 곱셈 틴트 하나로, 가로등, 창, 키오스크 간판에는 손으로 그린 발광 변형을 더해서)32 코드는 그대로 하고 있고, 코드에 대한 기술로서는 정확합니다. 이 글의 브리프는 그것을 걷는 이들에 대해 바꿉니다. 걷는 이들은 틴트를 통째로 받아서는 안 됩니다(10절, 항목 2). 정전과 대조하면, 걷는 이를 포함해 모든 것에 곱셈 하나를 거는 것은 Crystal과 Emerald가 둘 다 택하지 않는 규칙입니다. 이것은 이 글의 발견이고, 세계 글은 고치지 않았습니다.

컷, 1분에 한 번

빛은 clock, 즉 스테이지가 가진 날짜의 함수입니다. 태스크가 60초마다 그것을 다시 읽으며, 그 주석은 “The light follows the clock, a minute at a time.”(빛은 시계를 1분씩 따른다)입니다. 그리고 onChange(of: clock)이 relight()를 불러 시간대와 계절을 계산하고 새 머티리얼을 한꺼번에 할당합니다.199 빛과 빛 사이에 애니메이션은 없고, World/ 어디에도 significantTimeChangeNotification의 옵저버는 없습니다. 시각은 휴대폰 자신의 시간대인 Calendar.current에서 Daylight.now를 거쳐 오며, 실행 인자 -plazaHour가 시각 하나를 강제하고, UI 테스트는 그것으로 밤의 광장을 봅니다.92168 스테이지는 TimelineView(.animation(minimumInterval: 0.1))를 돌리지만, 그것은 bubbles(of:in:)에 있는 말풍선의 시계로, 방금 한 말을 말한 사람의 머리 위에 몇 초 동안 띄워 두기 위한 것입니다. 빛의 시계도 아니고 걷기의 시계도 아니며, 걷기는 rig.update가 장면의 업데이트 이벤트에서 진행시킵니다.199

그러니 시간대 변화는 컷이고, 경계보다 최대 60초 늦게 올 수 있습니다. 아틀라스 평균 루마에서 컷은 arith.py에 따르면 이렇습니다.411

  • 06:00, 밤에서 아침: 0.168의 단차로, 하루 중 가장 큽니다.4
  • 09:00, 아침에서 낮: 0.017입니다.4
  • 17:00, 낮에서 저녁: 0.077입니다.11
  • 20:00, 저녁에서 밤: 0.108입니다.11

Crystal도 컷했고, 18:00에 야외에 있던 플레이어는 그것이 일어난 프레임에 보았습니다(1절). 누가 얼마나 자주 보고 있었는지는 소스가 말해 줄 수 없습니다.1 제가 읽기에 Kiradex의 광장은 늘 열려 있는 화면입니다. 누군가 책상 위에 열어 둔 채 20:00에 고개를 들면, 마을의 평균 루마가 한 프레임 만에 0.372에서 0.264로, 밝기의 4분의 1 이상 떨어지는 것을 볼 수 있습니다. 누군가 보고 있는 화면 위의 컷은 하나의 사건이며, 정전은 그것을 해결할 필요가 없었습니다.

방과 홀은 휴대폰의 시계를 지킨다

PlazaStage.swift의 RoomView는 자기만의 PlazaStage를 만들고, HallView도 하나 만듭니다. 그래서 방과 홀은 광장과 같은 코드로, 같은 시계, 곧 휴대폰의 시계에서, 가로등까지 포함해 다시 비춰집니다.1969 둘 다 검은 베일을 지나 들어가며, 각자의 주석에서는 “A room is entered through the veil”(방에는 베일을 지나 들어간다), “The show is entered through the veil”(쇼에는 베일을 지나 들어간다)이고, 둘 다 광장을 대신하지 않고 광장 위에 겹쳐집니다.1969 이것은 코드에 대한 제 해석이지 캡처가 아닙니다. 이것은 Crystal이 아니라 Stardew의 선택입니다. Stardew는 해 질 녘에 실내를 어둡게 하고 램프를 켜며, Crystal은 실내 맵 208개 중 207개를 낮에 고정합니다.161 둘 다 정전입니다. Kiradex는 이미 하나를 골랐고, 거기서 한 걸음 더 나아갑니다. Stardew는 해 질 녘에 플레이어가 있는 방을 나갔다 돌아올 때까지 밝게 두지만, Kiradex의 방은 플레이어가 안에 있어도 1분마다 다시 비춰지며, 이것은 정전이 아니라 Kiradex 자신의 선택입니다.1619

공기

Air.swift는 디자인 계획의 4절을 따르는 빌드 29의 “Light and air over a place”(장소 위의 빛과 공기) 레이어입니다.2270 코드와 포지의 그림으로 측정하면 이렇습니다.9

  • 구름 그림자. 어떤 뷰보다 넓은 시트가 카메라를 따르며, 그 그림 cloud.png(256×256)는 월드 384픽셀마다 반복됩니다. 텍스처 오프셋은 초당 (0.004, 0.0015) 나아가고, 384픽셀에 걸치면 초당 (1.536, 0.576)픽셀, 합쳐서 초당 1.64픽셀입니다.229 이 환산은 RealityKit이 오프셋을 스케일 뒤에 더해 오프셋 1이 그림의 온전한 한 번 반복이 된다고 가정합니다. 이 글을 위해 저장한 Apple 페이지는 이 속성이 “A two-dimensional transformation to apply to the entity’s primary texture coordinates”(엔티티의 주 텍스처 좌표에 적용할 2차원 변환)라고만 할 뿐, 순서는 말하지 않습니다.71 앱 자신의 스프라이트 시트도 같은 순서에 기댑니다. SpriteSheet.swift는 열을 열 수로 나눈 오프셋과 1을 열 수로 나눈 스케일로 프레임을 고르는데, 이것은 오프셋이 스케일 뒤에 올 때만 프레임에 맞고, 그 주석은 시뮬레이터에서 오프셋의 규약을 측정했다고 기록합니다.72 그러니 1.64와, 2절 차트의 구름 막대는 그 순서에 기대고 있습니다. 오프셋에는 매 프레임 카메라 위치를 384로 나눈 값도 더해지므로, 화면에서 시트의 움직임은 흐름에 더해 뷰가 움직일 때 그 항이 하는 일이 됩니다. 저는 그것을 캡처하지 않았습니다.229 구름은 밤을 뺀 모든 시간대에 보입니다.
  • 구름 그늘. cloud.png는 “a tileable mask of cloud shadow: alpha where a cloud passes”(타일로 이어 붙일 수 있는 구름 그림자 마스크. 구름이 지나는 곳에 알파)로, 면적의 0.499를 덮고, 알파는 최대 110이며, 머티리얼 불투명도 0.55로 그려집니다. 가장 짙은 그늘은 땅에 0.763을 곱하고, 그림의 평균은 0.950을 곱합니다.679
  • 안개. 공원 연못 위, 셀 (5, 24), (9, 26), (4, 27)에 덩어리 세 개가 있고, 각각 128×64픽셀, 알파 최대 93에 불투명도 0.7이며, 아침에만 있습니다.922
  • 잎과 반딧불이. 가을에는 밤을 뺀 모든 시간대에 잎 14장, 밤에는 공원의 직사각형 안에 반딧불이 10마리입니다.922
  • 연기. 포지가 기록한 굴뚝 6개 각각 위에 연기 덩어리 세 개. UI 테스트는 공기의 보고가 smoke 18이라고 말하기를 기다립니다.2268

정전과 비교하면 구름은 느리고 그늘은 부드럽습니다. 초당 1.64픽셀이면 Kiradex 걷기의 0.027이고 한 타일을 가로지르는 데 9.8초가 걸립니다. Emerald의 구름은 걷기의 절반으로 움직입니다. 휴대폰에서는, 제가 읽기에, 멈춰 있는 것으로 읽힐 만큼 느립니다.114 비교 대상인 걷기는 초당 60픽셀입니다. Motion.swift의 틱 시계는 초당 60틱으로 돌고, Stride.ticks는 16픽셀짜리 곧은 걷기 한 걸음에 16틱을 주며, PlazaRig.update(_:)는 틱을 tick()에 통과시키고, 그것이 플레이어를 나아가게 합니다.732011 구름의 가장 짙은 그늘 0.763은 Emerald의 비 맵(모든 채널의 약 0.81)보다 어둡지만, 그림의 절반만 덮습니다.95

그림자

그림자 셋은 규칙으로 그려지고(포장석 위의 가로등 기둥도 자기 그림자를 가집니다), 하나가 빠져 있습니다.9874

  • 걷는 이의 그림자. shadow.png, 4절의 12×4 한 톤 덩어리로, 모든 걷는 이 아래에 12×4로 그려집니다.98
  • 벽의 그림자. 포지는 벽 셀의 발치에 있는 것의 위쪽 4픽셀 행을 그 자신의 램프로 한 단계 어둡게 합니다. 주석이 참고한 곳을 밝힙니다. “the way the light falls at Leene.”(Leene에서 빛이 떨어지는 방식)74
  • 처마의 그림자. 지붕 아래 건물 벽에 있는 3픽셀 행의 그림자로, buildings.py가 건물을 마무리할 때 그립니다.24
  • 땅의 그림자, 빠져 있는 것. 어느 건물에서도 땅으로 그림자가 떨어지지 않습니다. 그것을 미루는 docstring은 이 글 맨 앞에 인용한 대로이고, 포지의 paint는 그것을 결코 그리지 않습니다.249

벽의 그림자는 이미 Schlitter의 규칙(한 면, 한 타일보다 짧게, 위에 무엇이 있든 같은 길이)을 따르고, 걷는 이의 그림자는 Emerald의 규칙(한 톤, 몇 행)을 따릅니다.638 빈자리는 건물입니다.

움직임과 시스템 설정

accessibilityReduceMotion은 World/에서 정확히 한 파일, FigurePreview.swift에서만 읽힙니다. Air.swift는 그것을 읽지 않으므로 구름의 흐름, 안개, 잎, 반딧불이, 연기는 모두 설정과 상관없이 움직입니다.975 스테이지는 renderingEffects.depthOfField = .disabled를 설정합니다. 디자인 계획의 빌드 29는 “a vignette and tilt-shift depth of field as the camera’s rendering effects”(카메라의 렌더링 효과로서 비네트와 틸트 시프트 피사계 심도)를 요구했지만, 비네트는 만들어졌고 피사계 심도는 꺼져 있습니다.1970

시리즈 각 글의 말을 확인하다

이 시리즈 앞선 글들의 세 가지 진술이 이 글이 측정한 것과 맞지 않으며, 각각 위에서 측정과 함께 말했습니다. 구조물 편 글의 불빛 셀 21개 대 내보내기의 24개, 세계 글의 64바이트 다시 불러오기 대 야외에서 LoadMapPals의 132바이트, 그리고 세계 글의 세계 전체에 곱셈 틴트 하나로, 이 브리프는 그것을 걷는 이들에 대해 바꿉니다.2332934 맞았던 것은 이렇습니다. 오마주 글의 Crystal과 Kiradex 시각. 살아 있는 마을 글의 오늘 시계에 대한 설명, 곧 휴대폰의 달력과 시간대를 지정하지 않는 서버, 그리고 그와 나란한, 방의 시간대와 시계를 실어 나르는 welcome과 조용한 광장 응답의 계약. 10절은 이것을 바탕으로 하며, 클라이언트는 10월 5일 시점에 그것을 읽지 않았습니다. 구조물 편 글의 NightTiles와 roofs.pal에 대한 설명. 그리고 높이 글의, 점프 아래 땅에 남는 그림자입니다.1043762352 캐릭터 글, 모션 글, 방 글, 경로 글은 이 글이 반박하는 것을 아무것도 말하지 않으며, 모션 글의 초당 60틱에서 타일당 16틱인 걷기는 앱이 지금 실행하는 것입니다.127773

8. 기법을 수치가 있는 규칙으로

아래의 각 규칙은 1~7절에서 측정한 사실에 제가 거기서 얻는 디자인상의 해석을 붙인 것입니다. 수치는 정전과 앱의 것입니다. Kiradex의 모든 수치는 Mac에서 소스로 읽었거나 내보낸 그림으로 계산한 것이지 iPhone에서 측정한 것이 아니며, 해석은 제 것입니다.

요소 규칙 출처
하루의 부분 하루는 서너 부분이고, 밤이 가장 길다. Crystal: 6 + 8 + 10시간. Kiradex: 3 + 8 + 3 + 10. 1절과 7절19
밤 밤은 빛이 약 절반이고 더 파랗다. Crystal의 월드 팔레트는 팔레트 파일 블록에서 낮 루마의 0.41~0.68, 평균 0.51을 유지하고(마을이 자기 물과 지붕 색으로 표시하는 상태에서는 맵 그룹별 0.49~0.54), 파랑 치우침은 5비트 단위로 약 6~7 오른다. Kiradex의 밤은 아틀라스 루마의 0.59를 유지한다(Mac에서 읽은 것). 1절과 7절19
아침 아침은 더 따뜻한 흰색이지 다른 장면이 아니다. Crystal의 월드 색 32개 중 아침에 바뀌는 것은 5개이고, 모두 가장 밝은 색. 1절1
불 켜진 것 불 켜진 것은 틴트를 거부한다. Crystal의 YELLOW는 밤에도 루마 0.90. Kiradex의 불빛 셀은 틴트 없이 0.901로, 가장 밝은 픽셀이 0.562인 밤의 마을에 맞선다(Mac에서 읽은 것). 1절과 7절19
사람 장소는 어두워지고 사람은 어두워지지 않는다. Crystal의 사람 팔레트와 Emerald의 플레이어와 마을 사람 팔레트는 밤에도 비에도 손대지 않는다. 1절과 2절15
변화 시각은 컷하고 날씨는 페이드한다. Crystal: 정각에 한 프레임, 그리고 8프레임짜리 흰색 페이드는 문, 워프, 공중날기, 메뉴가 여는 화면, 일부 스크립트 장면을 위한 것. Emerald의 비: 20프레임씩 3단계, 1.00초, 빗방울은 그 약 1초 뒤에 자리를 잡는다. 마을 위에 열어 둔 휴대폰은 컷하는 동안에도 보이므로 Kiradex는 램프를 쓴다(10절). 1절, 2절, 7절15
비의 빛 비는 장소를 13/16로 만든다. Emerald의 맵 3, 모든 채널의 약 0.81. 2절5
빗방울 비는 성기고 빠르다. 240×160 화면에 10방울, 수직에서 26.6도로 초당 868픽셀, 방울당 18프레임과 7프레임 물보라. 호우는 24방울에 초당 1,336픽셀. 2절5
공기 구름과 안개는 걷는 것보다 느리게 움직인다. Emerald의 구름은 걷기의 0.50, 안개는 0.25. 그보다 빠른 것은 3.6의 모래바람뿐. 2절511
날씨의 일정 날씨는 장소와 날로 정해지고 미리 알려진다. Emerald에도 FireRed에도 헤더가 비인 야외 맵은 없다. Route 119와 123은 나흘 주기를 가진다. Stardew는 하루에 한 번 굴리고 다음 날을 예보한다. 3절과 5절517
번개 번개는 짧고 드물다. 번개당 6~8프레임, 짧은 번개는 많아야 둘이고 최소 61프레임의 어둠을 사이에 두며, 주기와 주기 사이는 6~12초. 번개 둘을 담는 1초는 없으며, W3C의 초당 세 번 섬광보다 아래다. 2절5446
실내 실내는 낮을 유지하거나 낮을 따른다. 하나를 고른다. Crystal은 실내 맵 208개 중 207개를 낮에 고정한다. Stardew는 해 질 녘에 실내를 어둡게 하고 램프를 켜지만, 해 질 녘에 플레이어가 있는 방은 나갔다 돌아올 때까지 밝게 남는다. Kiradex는 이미 Stardew를 따르며, 플레이어가 안에 있는 방도 다시 비춘다. 1절, 5절, 7절11619
어둠 어둠은 셀 단위 반지름이다. Emerald: 플래시 없이 1.5셀, 플래시로 4.5셀. 4절5
드리운 그림자 드리운 그림자는 한 톤이고, 한 타일보다 짧으며, 한두 면에 놓이고, 높이와 상관없이 같은 길이다. Emerald의 그림자 스프라이트, Schlitter의 규칙, Kiradex의 벽. 4절, 6절, 7절86374
가산 빛 가산 빛은 결코 어둡게 하지 않는다. 그림자에는 알파나 그림이 필요하다. RealityKit 프로그램의 블렌드 모드는 add와 alpha이고, unlit 머티리얼은 투명도로 블렌딩한다. 7절과 9절7866

9. Apple의 방식: 블렌드 모드, 건너뛰는 시계, Reduce Motion

Kiradex World 아래의 엔진은 이 시리즈의 첫 글이 제시한 것입니다. 2D 렌더러로 쓰는 RealityKit 장면, 텍셀당 정수 개의 기기 픽셀에 맞춘 직교 카메라, 그리고 모두 unlit인 스프라이트 머티리얼입니다.32 빛, 날씨, 시간에는 새 프레임워크가 필요 없습니다. 필요한 것은 가산 블렌딩과 알파 블렌딩인데, 앱은 이미 둘 다 씁니다(앞의 것은 웅덩이의 BlendMode.add로, 뒤의 것은 UnlitMaterial의 투명 블렌딩으로). 그리고 아직 관찰하지 않는 알림 두 개와, 한 파일에서만 읽는 환경 값 하나입니다. 아래의 지원 정보는 2026년 10월 5일에 각 문서 페이지가 나열한 것으로, 저장한 페이지에서 parse_apple.py가 읽었습니다.26

블렌드 모드 둘, 그리고 각각이 그릴 수 있는 것

MaterialParameterTypes.BlendMode는 “Modes that describe how materials should be blended with content behind them”(머티리얼을 뒤에 있는 콘텐츠와 어떻게 블렌딩할지 기술하는 모드)으로 문서화되어 있고, 그 페이지는 정확히 두 개의 열거 케이스 add와 alpha를 나열합니다.784 add에 대해 Apple은 이렇게 씁니다. “Blend by adding the material’s color to the background color, ignoring alpha”(알파를 무시하고 머티리얼의 색을 배경 색에 더해 블렌딩한다), “also known as additive blending or linear dodge.”(가산 블렌딩 또는 리니어 닷지라고도 한다)79 둘 다 iOS 18.0 이상, iPadOS 18.0, Mac Catalyst 18.0, macOS 15.0, tvOS 26.0, visionOS 2.0으로 나열되어 있습니다.7879

블렌드 모드는 머티리얼의 프로그램에 속하고, 그 프로그램은 CustomMaterial, “A material that works with custom Metal shader functions”(사용자 정의 Metal 셰이더 함수와 함께 작동하는 머티리얼)로, iOS 15.0과 macOS 12.0부터 쓸 수 있습니다.80 마을의 다른 모든 것은 UnlitMaterial, “A material that doesn’t respond to lights in the scene”(장면의 빛에 반응하지 않는 머티리얼)로, iOS 13.0과 macOS 10.15부터입니다.71 Kiradex는 둘을 정확히 그렇게 씁니다. 웅덩이는 프로그램의 디스크립터가 blendMode = .add를 설정하는 CustomMaterial이고(간직할 만한 주석이 붙어 있습니다. “The program says how to blend; the material says that it blends at all.”(어떻게 블렌딩할지는 프로그램이 말하고, 블렌딩을 하는지 자체는 머티리얼이 말한다)), 구름 시트와 안개는 불투명도 0.55와 0.7에서 .transparent 블렌딩을 쓰는 UnlitMaterial입니다.229

그림자에 대한 결론은 이 목록에서 나옵니다. 가산 빛은 밝게 할 수만 있습니다. Glow.metal의 말로는 “black adds nothing”(검정은 아무것도 더하지 않는다)입니다.66 프로그램의 블렌드 모드가 나열하는 케이스가 add와 alpha뿐이고 unlit 머티리얼이 투명도로 블렌딩하는 이상, 이 엔진에서 그림자를 그리는 방법은 둘 중 하나입니다. 뒤에 있는 것 위에 어두운 색을 알파 블렌딩하는 것으로, 구름 시트가 이미 하는 일입니다. 아니면 그림에 구워 넣는 것으로, 벽의 그림자가 하는 일입니다.782274 그림자의 색으로 어둡게 하는 곱셈 블렌드는 없습니다. 그러므로 움직이는 그림자는 알파 시트이고, 고정된 그림자는 아틀라스에 속합니다.

어느 쪽이든 휴대폰에서의 비용은 측정하지 않았습니다. 구조물 편 글은 그 두 새 메시의 GPU 비용을 프로파일하지 않았다고 적었고, 그 뒤 더해진 가산 웅덩이 24개, 구름 시트, 안개도 프로파일하지 않았습니다.2312 브리프는 비 스프라이트, 물보라, 눈, 구름을 위한 두 번째 알파 세기를 더합니다. 그 비용도 측정하지 않았습니다. 항목 4가 비에 대해 그렇게 말하고, 항목 5와 6의 눈, 흐림, 구름의 새 속도도 프로파일하지 않았습니다.

시계, 그리고 그것이 건너뛸 때

스테이지는 잠드는 태스크로 60초마다 시계를 다시 읽습니다.19 SwiftUI에는 시간에 따라 바뀌는 뷰를 위한 문서화된 대안이 있습니다. TimelineView, “A view that updates according to a schedule that you provide”(제공한 일정에 따라 갱신되는 뷰)이고, 일정 everyMinute는 “A schedule for updating a timeline view at the start of every minute”(매분 시작 시점에 타임라인 뷰를 갱신하는 일정)로 문서화되어 있으며, 둘 다 iOS 15.0부터 쓸 수 있습니다.8182 제가 읽기에 스테이지의 태스크가 시계가 건너뛰었다는 것(자정을 지남, 일광 절약 시간 진입, 다른 시간대로 이동)을 아는 것은 다음에 깨어날 때, 최대 1분 뒤입니다. 시각이 건너뛸 때는 시스템이 알려 줍니다.

UIApplication.significantTimeChangeNotification은 Apple의 말로 “when, for example, there’s a change to a new day (midnight), a carrier time update, or a change to, or from, daylight savings time.”(예를 들어 새로운 날로의 변화(자정), 이동통신사 시간 갱신, 일광 절약 시간으로의 또는 그로부터의 변화가 있을 때) 게시됩니다. 그 페이지는 iOS, iPadOS, Mac Catalyst, tvOS, visionOS를 버전 없이 나열합니다.8326 NSSystemTimeZoneDidChange는 “A notification posted when the time zone changes”(시간대가 바뀔 때 게시되는 알림)로, iOS 2.0부터 쓸 수 있습니다.84 EnvironmentValues.timeZone은 “The current time zone that views should use when handling dates”(뷰가 날짜를 다룰 때 써야 할 현재 시간대)로 iOS 13.0부터이며, 뷰 트리에 시간대를 실어 나르는 SwiftUI의 방식입니다.85

이 시리즈의 살아 있는 마을 글은 방마다의 시계에 대한 계약을 정합니다. 모든 방은 UTC의 서버 시각으로 돌아가되 방 자신의 시간대로 읽고, 서버는 welcome과 조용한 광장의 응답에서 그 둘을 zone과 clock으로 보내므로, 방 안의 모두가 휴대폰 시계가 뭐라고 하든 같은 시간대를 봅니다.43 광장이 열려 있는 동안 빛은 휴대폰의 시계가 아니라 그 시계를 따라야 하며, 위의 알림들이 다루는 것은 방의 달력이 아니라 휴대폰의 달력입니다. Apple의 페이지는 첫 번째 알림이 게시되는 때로 기기에서의 새로운 날을 들지만, 다른 시간대의 자정에 대해서는 아무 말도 하지 않습니다. 브리프의 항목 1이 둘을 어떻게 맞출지 말합니다. 10월 5일에는 방의 시계도 시각 건너뜀의 옵저버도 앱에 없었습니다. 10절은 그 뒤 바뀐 것으로 시작합니다.983

Reduce Motion

accessibilityReduceMotion은 “Whether the system preference for Reduce Motion is enabled”(Reduce Motion 시스템 설정이 켜져 있는지)를 나타내는 환경 값으로, iOS 13.0부터 쓸 수 있습니다. 그 페이지의 설명은 직설적입니다. “If this property’s value is true, UI should avoid large animations, especially those that simulate the third dimension.”(이 속성의 값이 true이면, UI는 큰 애니메이션, 특히 3차원을 흉내 내는 애니메이션을 피해야 한다)86 Kiradex는 그것을 FigurePreview.swift에서 읽고, 세계의 코드 다른 곳에서는 읽지 않습니다.9 전부가 움직임인 공기는 오늘 그것을 읽지 않습니다.

실제 날씨, 그리고 섬광

Apple은 플레이어의 실제 날씨를 위한 프레임워크를 제공합니다. WeatherKit은 “Deliver weather conditions and alerts to your users”(사용자에게 기상 상황과 경보를 전달한다)로 문서화되어 있으며, iOS 16.0부터 쓸 수 있습니다.87 10절은 그것을 거부하고, 그 이유를 거기서 말합니다.

섬광에는 공표된 문턱이 있습니다. WCAG 2.2 성공 기준 2.3.1 “Three Flashes or Below Threshold”(세 번의 섬광 또는 문턱 이하), 레벨 A 기준에 대한 W3C의 Understanding 페이지는 웹 페이지가 “do not contain anything that flashes more than three times in any one second period, or the flash is below the general flash and red flash thresholds”(어떤 1초 동안이든 세 번보다 많이 번쩍이는 것을 담지 않거나, 섬광이 일반 섬광 및 적색 섬광 문턱 아래에 있다)라고 말하고, 그 이유를 듭니다. “Flashing content can cause migraines, dizziness, nausea, and seizures.”(번쩍이는 콘텐츠는 편두통, 어지럼증, 메스꺼움, 발작을 일으킬 수 있다)46 Kiradex는 웹 페이지가 아니라 앱이며, 저는 이 기준을 가장 가까운 공표된 기준으로 쓰는 것이지 법적으로 적용된다고 주장하는 것이 아닙니다.

10. 브리프: Kiradex가 만드는 것과 통과해야 할 검사

저자의 종합. 아래는 제 제안이며, 1~9절에서 이끌어 내어 2026년 10월 5일 16:51부터 18:19 사이, 커밋 cf3beb1e부터 66c116b0 시점에 트리가 편집되는 중에 읽은 앱과의 차이로 썼습니다. 각 주석이 기대는 읽기를 밝히며, 읽은 것 가운데에는 Daylight.swift, Motion.swift, Air.swift, Glow.metal, PlazaStage.swift, PlazaRig.swift, PlazaClient.swift, HallView.swift, CollectorComposer.swift, 포지의 air.py, town.py, buildings.py, interiors.py, 10월 3일의 town.json, 그리고 인물 시트와 그 characters.json이 있습니다.1297388 어떤 포켓몬 게임에서도 이름을 붙이지 않고 아무것도 그리지 않습니다. 그 팔레트, 스프라이트, 날씨 이름, 소리는 하나도 쓰지 않습니다. 메커니즘을 빌리는 곳에서는 8절의 규칙이 어디서 왔는지 말하고, 모습은 포지의 것입니다. 오마주 글의 결정은 그대로입니다. Kiradex는 자기만의 네 시간대와 자기만의 시각을 지킵니다.10 아직 아무것도 만들지 않았고, 어떤 수치도 iPhone에서 측정하지 않았습니다. Kiradex의 모든 수치는 Mac에서 소스로 읽었거나 내보낸 그림으로 계산한 것이며, 기기에서의 비용은 전체에 걸쳐 측정하지 않았고, 검사는 빌드가 그것을 잴 수 있도록 썼습니다. 검사가 지목하는 모든 타입, 메서드, 파일, 실행 인자는 오늘 존재해서 여기서는 그 심볼로, 주석에서는 그 줄로 인용하거나, 항목 안에서 제안하는 추가로 나열합니다. 검사 2~8, 10, 11은 조사 자료의 것을 제가 고친 것입니다. 처음 쓰인 그대로는, 앱 자신의 프로세스만 할 수 있는 일을 UI 테스트에 요구하거나, 앱이 실행 중일 때 실행 인자를 바꾸거나, 값을 실어 나르지 않는 곳에서 값을 읽거나, 앱에 없는 목록에 기대는 것들이 있었습니다. UI 테스트는 자기 프로세스에서 돌며 앱을 접근성 값, 레이블, 스크린숏으로 봅니다. -plazaHour는 실행 인자에서 읽으므로 실행하는 동안 고정됩니다. 그리고 스테이지가 테스트에 주는 유일한 값인 접근성 값은 플레이어의 마지막 걸음이나, -airProbe 아래에서는 공기의 보고를 실어 나르며, UI 테스트는 그것을 읽습니다. 스테이지 자신의 주석으로는 “since nothing else the simulator logs reaches them”(시뮬레이터가 기록하는 다른 어떤 것도 그것들에 닿지 않으므로)입니다.192168 고친 각 검사는 무엇이 필요한지 말합니다.

앱은 10월 5일 이후 바뀌었습니다. 2026년 10월 15일 23:53에, 저장소의 main이 가리키는 커밋 fc9d4876(그날 17:45 커밋)에서 다시 읽었습니다. git을 실행하지 않고 저장소 자신의 객체에서 각 파일을 꺼냈으며, 작업 트리의 각 사본도 같은 바이트였습니다. 서버는 이제 모든 welcome에서 zone과 clock을 보냅니다. 세계 전체에 시간대 하나이며, 설정하지 않으면 UTC입니다. 그리고 PlazaClient가 그것을 간직하며, 항목 1이 제안하듯 서버의 밀리초를 휴대폰의 가동 시간과 짝지어 방의 시각을 roomDate로 줍니다.89 빛은 아직 그것을 읽지 않습니다. PlazaStage는 여전히 매분 휴대폰에서 다시 읽는 clock을 간직하고 거기서 하루를 가져오며, 조용한 광장은 여전히 어떤 방에도 들어가지 않습니다. 그리고 작업 트리의 Swift를 검색해도 시각 건너뜀의 옵저버는 없습니다. 거부 목록이 이제 존재합니다. scripts/forge/protected_names.txt이며, server/tests/test_names.py가 그것을 세계의 구역 이름, 프리셋 대사, 마을 사람의 핸들에 비추어 읽습니다.89 아래는 모두 10월 5일의 읽기에 맞춰 쓴 것이고, 그 “오늘”은 그날입니다. 항목 1과 검사 2는 이제 클라이언트의 방 시계에서, 항목 10과 검사 11은 그 목록에서 시작하게 됩니다.

1. 하루의 시계: 시각은 지키고, 빛은 램프로, 방의 시계를 읽는다

  • 시각은 그대로. 6시부터 9시는 아침, 9시부터 17시는 낮, 17시부터 20시는 저녁, 나머지는 밤입니다(8절, 하루의 부분).1021
  • 시계로 계산하는 램프. 새 Daylight.light(at:calendar:)는 Daylight.now(_:calendar:)가 이미 그러듯 날짜와, 기본값이 Calendar.current인 달력을 받아, 각 경계 뒤 처음 30분에 걸쳐 앞 시간대의 틴트에서 새 틴트로 선형 보간한 틴트에 계절의 색조를 곱한 것을 돌려줍니다. 스테이지는 이미 매분 다시 비추므로 램프는 30단계입니다. 아틀라스 평균 루마로 보면 저녁의 변화는 0.077짜리 한 단계 대신 0.0026짜리 30단계가, 밤의 변화는 0.108짜리 한 단계 대신 0.0036짜리 30단계가 됩니다.11 오늘 가장 큰 컷인 0.168의 아침 변화는 최대 0.0056짜리 30단계가, 낮의 0.017은 최대 0.0006짜리 단계가 됩니다.4
  • 램프에는 애니메이션도 새 타이머도 필요 없다. 하루의 빛은 시각의 순수 함수이므로, 같은 시계를 읽는 휴대폰 두 대는 같은 빛을 보여 주고, 17:12에 깨어난 휴대폰은 램프를 지켜보지 않았어도 17:12의 빛을 보여 줍니다. Crystal의 컷은 테스트가 시간대를 직접 보려고 쓰는 강제된 -plazaHour에서만 남으며, 그 아래에서 relight()는 오늘의 Daylight.light(phase:season:)를 계속 부릅니다(8절, 변화).2168 날씨의 1초 페이드(항목 4)가 애니메이션하는 유일한 변화이며, 자기만의 타이머가 아니라 리그의 기존 프레임별 갱신에 올라탑니다.
  • 방의 시계. 다음 항목에서 제안하는 작은 타입 LightClock이 빛이 읽는 유일한 시계이며, 광장에서는 살아 있는 마을 글의 계약이 정한 대로 방의 시각으로 돌아갑니다. UTC의 서버 시각을 방 자신의 시간대로 읽고, 둘 다 welcome과 조용한 광장의 응답에서 zone과 clock으로 보내는 것입니다. 조용한 광장의 응답은 그 글이 멀티플레이가 제한된 플레이어, 곧 WebSocket을 열지 않는 플레이어에게 주는 유일한 요청입니다. 둘 중 도착한 쪽이 그것을 LightClock에 넘깁니다. welcome에서는 PlazaClient가, 응답에서는 조용한 광장의 요청이 넘깁니다. 시계는 서버의 타임스탬프를 그것이 도착한 순간의 휴대폰 단조 가동 시간과 짝지어 간직하므로, 그 now는 서버 시각에 그 뒤의 가동 시간을 더한 것을 방의 달력으로 나타낸 것이 됩니다. 벽시계가 몇 시간이나 틀린 휴대폰도 방 안의 다른 모든 휴대폰과 같은 빛을 보여 주며, Daylight.light(at:calendar:)와 Weather.today(zone:date:)(항목 3)는 시계의 달력과 시간대를 받습니다. 휴대폰 자신의 벽시계와 시간대는 광장의 첫 welcome이나 조용한 응답이 도착하기 전, 그리고 광장 밖, 곧 방이나 홀에서만 읽습니다. 그곳에서는 살아 있는 마을 글이 수집가를 자기 시계에 그대로 둡니다(항목 8이 그 문간에서 그것이 무엇을 뜻하는지 말합니다). LightClock은 다음 응답이 올 때까지 마지막 응답의 시간대와 타임스탬프를 간직하고, 그 상태는 어느 것으로 돌아가는지 밝힙니다. welcome에 의한 방의 시계, 조용한 응답에 의한 방의 시계, 또는 휴대폰의 시계입니다. 10월 5일에는 서버의 welcome이 시간대도 시계도 실어 나르지 않았고, PlazaClient의 핸들러도 어느 것도 읽지 않았습니다(그 뒤 바뀐 것은 이 절의 첫머리가 말합니다). 조용한 광장의 응답은 그 글의 제안입니다. 응답이 그것을 실어 나를 때까지 LightClock은 휴대폰의 시계로 돌아가며, 상태에서 그렇게 말합니다.432176
  • 1분 늦게가 아니라 경계에서 바꾼다. 새 Kiradex/World/LightClock.swift에 있는 LightClock은 시각의 공급원(단조 가동 시간과 벽시계, 둘 다 교체 가능), NotificationCenter, 그리고 스테이지의 다시 비추기를 받습니다. 그 달력으로부터 빛이 바뀌어야 할 다음 순간, 곧 다음 시간대 경계와 그 경계의 항목 1 30분 램프의 끝, 그리고 항목 3의 그 시간대에서의 다음 자정을 계산하고, 램프에 필요한 1분 1회 깨어남과는 별도로 각각에 대해 명시적으로 깨어남을 예약합니다. 깨어남은 읽은 시각으로 다시 비추기를 부릅니다. 또 자기 센터에서 UIApplication.significantTimeChangeNotification과 NSSystemTimeZoneDidChange를 관찰하고, 둘 중 어느 것에서든 다시 비춥니다. Apple의 페이지가 드는 것, 곧 휴대폰 자신의 시계에서의 새로운 날, 이동통신사 시간 갱신, 일광 절약 시간으로의 또는 그로부터의 변화, 그리고 휴대폰 시간대의 변화를 위해서입니다. 그것들이 다루는 것은 휴대폰의 달력이고, 페이지는 첫 번째 알림이 다른 시간대의 자정에 게시된다고 말하지 않으므로, 방의 경계를 그것에 맡기는 일은 결코 없습니다. PlazaStage는 자기의 clock 상태와 그것을 매분 다시 읽는 잠드는 태스크 대신, 시스템의 시각 공급원과 NotificationCenter.default로 만든 하나를 가집니다. 그러면 방 시간대의 자정, 시간대 경계, 일광 절약 시간 변화, 시간대 변화가 최대 60초를 기다리지 않습니다. 시계, 센터, 시각 공급원은 매개변수이므로 테스트가 그것들을 움직일 수 있습니다. 이 설계는 제 것입니다.838419
  • 강제한 시각은 실행 인자로 남는다. Daylight.forcedHour는 프로세스의 실행 인자에서 -plazaHour를 읽으므로 실행 전체에 걸쳐 유지되고, 앱이 실행 중일 때는 바꿀 수 없습니다. 아래의 어떤 검사도 그것을 요구하지 않습니다.21
  • 비용. 오늘과 마찬가지로 땅, 주변, 오브젝트, 각 걷는 이에 1분에 한 번 머티리얼을 할당하며, 이것은 프로파일하지 않았습니다. 램프는 두 색의 블렌드를 계산하는 것 말고는 일을 더하지 않습니다.20

마을 아틀라스의 평균 루마를 24시간에 걸쳐 그린 꺾은선 그래프. 오늘은 점선 계단: 밤 동안 0.264, 06:00에 0.432로 컷, 09:00에 0.449로, 17:00에 0.372로 내려가고 20:00에 0.264로. 제안은 실선으로, 같은 수준을 따르지만 각 경계 뒤 30분 동안 계단 대신 비탈을 이룬다.

제안 대 오늘. 매분의 빛 아래 아틀라스 평균 루마를, 출시된 town.png와 Daylight.swift의 틴트로 figures/make_figures.py가 계산한 것입니다. Mac에서 읽은 것이지 휴대폰에서 캡처한 것이 아닙니다.

인수 검사 1, 램프. Daylight.light(at:calendar:)의 단위 테스트로, 고정된 시간대의 달력을 주고 16:59, 17:00, 17:15, 17:29, 17:30, 그리고 20:00부터 20:30까지 매분을 살핍니다. 표본으로 뽑은 시각들에 걸쳐 루마가 단조로울 것, 1분 떨어진 어느 두 표본 사이(16:59와 17:00, 17:29와 17:30, 그리고 20:00부터 20:30까지 각 분)에서도 아틀라스 평균으로 0.004를 넘는 단차가 없을 것(스크립트의 값은 0.0036이며, 테스트는 앱 번들에서 town.png의 불투명 픽셀 평균을 구합니다), 그리고 :30 이후로는 오늘의 틴트와 같을 것을 확인합니다.1211 06:00부터 06:30까지의 같은 테스트는 0.006의 한계를 씁니다. 아침의 램프는 분당 최대 0.0056씩 나아가기 때문입니다.4

인수 검사 2, 방의 시계와 시각의 건너뜀. 프로세스 안에서, 새 KiradexTests/LightClockTests.swift로 합니다. UI 테스트는 앱 안에서 알림을 게시할 수 없고, 휴대폰의 시계를 설정할 수 없으며, -plazaHour는 앱이 실행 중일 때 바꿀 수 없기 때문입니다. 각 테스트는 자기만의 NotificationCenter, 스스로 통제하는 시각 공급원(손으로 진행시키는 가동 시간과 벽시계), 그리고 호출을 기록하는 다시 비추기로 LightClock을 만들며, 진짜 타이머는 쓰지 않습니다. 테스트가 직접 가동 시간을 진행시키고, 그 순간까지 예약된 것을 실행하라고 시계에 요청합니다. (a) 어긋난 휴대폰: 방의 시간대로 clock이 20:35:00인 welcome을 공급원의 가동 시간으로 타임스탬프를 찍어 시계에 주고, 벽시계는 세 시간 틀리게 해 둡니다. 다시 비추기는 방의 달력으로 20:35를 받아 불리고, Daylight.now(_:calendar:)는 그것을 night로 읽으며, Daylight.light(at:calendar:)는 밤의 빛을 줍니다. 항목 1의 램프는 20:30에 끝났기 때문입니다(램프 안의 시각, 예를 들어 20:05라면 저녁의 빛에서 밤의 빛으로 6분의 1 나아간 빛이 되어, 올바른 빌드라도 그것을 밤의 빛과 맞출 수 없습니다). 그리고 벽시계를 다시 움직여도 아무것도 바뀌지 않습니다. (b) 두 시간대: 휴대폰의 달력을 방보다 10시간 앞선 시간대에 두고, 둘 다 고정 오프셋으로 해서 일광 절약 시간 변화가 어느 것도 움직이지 않게 합니다. 방의 시간대로 20:35인 서버 순간은 휴대폰에서는 다음 날 06:35로, Daylight.Phase(hour:)는 그것을 아침, 항목 1의 램프를 지난 것으로 읽습니다. 반면 방의 20:35는 밤으로, 저녁의 램프를 지났습니다. 다시 비추기는 휴대폰의 빛, 곧 아침 틴트에 계절 색조를 곱한 것(여름에 0.961)이 아니라 방의 빛, 곧 밤 틴트에 계절 색조를 곱한 것(여름에 루마 0.593)을 받습니다. 그리고 Weather.today(zone:date:)는 방의 시간대와 방의 날짜, 곧 휴대폰 날짜의 전날로 질의됩니다. 휴대폰의 시계를 읽는 빌드는 빛에서도 날짜에서도 실패합니다. (c) 경계, 알림을 전혀 게시하지 않고: 방의 시계로 19:59:30에서 테스트는 가동 시간을 60초 진행시키고, 예약된 깨어남 하나가 그 분의 끝이 아니라 방의 달력으로 20:00:00에 실행되었음을 검증합니다. 23:59:30에서 60초를 진행시키고, 방의 시간대로 다음 날 00:00:00에 깨어남이 있으며 그 시각의 Weather.today(zone:date:)가 새 날의 굴림임을 검증합니다. (d) 옵저버, 배선으로만: 방의 시계를 주지 않은 채 테스트의 센터에 significantTimeChangeNotification을 게시하면 벽시계의 시각으로 다시 비추고, NSSystemTimeZoneDidChange도 마찬가지입니다. 테스트가 검증하는 것은 호출이지, 시스템이 그것을 게시한다는 것이 아닙니다. 그것은 어떤 테스트도 할 수 없습니다. (e) 게시도, 기한이 된 깨어남도, welcome도 없으면 다시 비추기는 불리지 않습니다. (f) 조용한 광장, 프로세스 안에서: welcome 대신 조용한 광장의 응답을 같은 20:35:00과 세 시간 틀린 벽시계로 시계에 주면, 다시 비추기는 (a)처럼 방의 달력으로 20:35와 밤의 빛을 받고, 그 상태는 조용한 응답을 밝힙니다. 그리고 앱에서는, 살아 있는 마을 글의 첫 안전 검사가 하듯 멀티플레이 제한을 스텁으로 켜고, -airProbe를 붙이고, 조용한 광장의 요청에 고정된 zone과 시뮬레이터보다 세 시간 어긋난 clock으로 답하는 로컬 테스트 서버와 함께 UI 테스트를 실행합니다. 서버에는 앱의 기존 -plazaServer 인자(PlazaClient.endpoint로, 그 주석은 로컬 서버용으로 -plazaServer ws://127.0.0.1:8300/v1/plaza를 듭니다)를 통해 닿습니다. 조용한 요청은 WebSocket을 열지 않으므로 그 URL을 HTTP 형태, 곧 ws를 http로, wss를 https로 바꾸고 조용한 경로 자신의 패스를 붙여 받으며, 이 대응은 제 제안입니다. 스테이지의 값은 LightClock의 상태를 프로브의 보고에 더해 조용한 응답을 밝히고, 테스트는 그 글의 검사처럼 WebSocket이 열리지 않음을 검증합니다. 이를 위해서는 서버 픽스처와 프로브 줄이 필요하며, 둘 다 제 제안입니다. 파일: LightClock.swift(새 파일), LightClock을 가지는 PlazaStage.swift, welcome 핸들러가 zone과 clock을 그것에 넘기게 될 PlazaClient.swift(서버는 10월 5일에 그것을 보내지 않았습니다), 답으로 같은 일을 할 조용한 광장의 요청, 그리고 새 테스트 파일입니다.7643 테스트가 볼 수 없는 것은 PlazaStage가 NotificationCenter.default와 진짜 시각 공급원을 넘긴다는 점이며, 그것은 소스에서 읽을 두 줄입니다. 처음 쓰인 그대로는 검사가 -plazaHour를 바꾼 뒤 UI 테스트에 알림을 게시하게 했는데, 그것은 어떤 UI 테스트도 할 수 없습니다. 휴대폰의 벽시계 위에 만들고 손으로 게시한 자정 알림을 방의 것 대신 쓰는 시계도 소용없습니다. 살아 있는 마을 글의 계약이 앞의 것을 배제하고, Apple의 페이지는 뒤의 것을 약속하지 않기 때문입니다. 그래서 검사는 서버의 타임스탬프, 명시적으로 예약한 경계, 그리고 두 시간대의 경우에 기댑니다.1221194383

2. 사람은 제 색을 지킨다

  • 끌어올림. 걷는 이들은 흰색 쪽으로 절반 끌어올린 빛, 채널별 (1 + tint) / 2를 받습니다. 밤에는 (0.75, 0.79, 0.95), 루마 0.796으로, 장소의 0.593에 맞서 1.34배 밝습니다. 저녁은 0.913, 아침은 0.980입니다.114
  • 어디에 두는가. 새 Kiradex/World/PlaceLight.swift에 있는 새 값 타입 PlaceLight가 하루의 빛(항목 1에서)과 날씨 계수(항목 4)를 가지고 두 색을 줍니다. place는 하루의 빛에 계수를 곱한 것이고, walkers는 하루의 빛을 흰색 쪽으로 절반 끌어올린 것으로 날씨 계수를 받지 않습니다. PlazaRig는 자기의 light 하나 대신 이것을 하나 가집니다. 장소 머티리얼은 place를 받습니다. build(tiles:collector:arrival:)가 처음 만드는 땅, 주변, 오브젝트로, light(_:lampsOn:) 안과 물결의 프레임 갱신 안에서, 그리고 showDoor(at:sheet:column:)의 문 그림입니다. 걷는 이들은 walkers를 받습니다. add(other:figure:tile:facing:)에서의 도착 머티리얼과 animate(_:)에서의 각 프레임 머티리얼입니다.20 순수한 값이므로 단위 테스트가 RealityKit 없이 움직일 수 있습니다. 이 타입은 제 제안입니다.
  • 왜 절반인가. 8절의 규칙은 손대지 않는다고 말합니다. 절반을 제안하는 것은 Kiradex의 걷는 이들이 하드웨어 팔레트 위가 아니라 가산 웅덩이와 비네트가 있는 블렌딩된 장면에 서 있기 때문이며, 틴트를 전혀 입지 않은 인물은, 제가 읽기에, 밤 위에 붙여 넣은 것처럼 보일 것입니다. 그것은 기기에서 내려야 할 판단이고, 아래 검사는 그 판단을 내릴 여지를 남깁니다.1219
  • 들고 있는 카드. 이미 자기만의 빛, 카드만을 위한 DirectionalLight가 있습니다. 바꾸지 않습니다.20
  • 프로브 위의 수집가 프레임, 인물, 그림. -airProbe 아래에서 스테이지의 값은 플레이어 스프라이트의 네 모서리에 PlazaRig.viewPoint(of:in:displayScale:)를 적용한, 뷰의 포인트 단위 수집가 프레임과, 수집가의 인물 마스크도 실어 나릅니다. 마스크는 32×40 셀의 픽셀 중 서 있는 수집가가 보여 주는 모든 그림, 곧 숨 쉬는 대기, 눈 깜박임, PlazaRig.animate(_:)가 고르는 대기 이모트(틱, 둘러보기, 어깨 으쓱, 생각하기, 졸기)에서 모두 불투명한 것입니다. 인물의 합성된 인덱스 평면 CollectorComposer.indexPlane(for:)에서 가져오며, 픽셀이 투명도 지우개도 아니면 불투명으로 보고, 각 행을 따라 연속 구간으로 씁니다. 둘 다 공기가 준비된 뒤 스테이지의 .task가 오늘 그곳에 쓰는 보고에 더합니다. 매니페스트의 기본 인물이 아래를 볼 때 마스크는 셀의 1,280픽셀 중 290입니다.20198830 값은 또 수집가의 머티리얼이 보여 주는 프레임, 곧 걷는 이의 shown(방향의 행에 시트의 43열을 곱하고 그림의 열을 더한 것이므로, 0은 아래를 보는 idle_a)을 바뀔 때마다 다시 써서 실어 나르고, 뷰에 온전히 들어온 불빛 셀들의 뷰 프레임을 town.json에서의 셀별로 실어 나릅니다. 디버그 인자 -plazaHoldStill(제가 붙인 이름)은 -plazaHour처럼 실행 인자에서 읽어 실행하는 동안 고정되며, 서 있는 수집가를 idle_a에 붙들어 둡니다. 숨도, 깜박임도, 대기 이모트도 없습니다. animate(_:)는 그렇지 않으면 그것들을 6~14초 간격으로 무작위로 시작하며, 플레이어의 첫 이모트는 7초, 첫 깜박임은 2.5초입니다.20 같은 인자 아래에서 Air.set(phase:season:)은 걷는 이들 위로 움직이는 레이어들, 곧 구름, 안개(아침에만, 2.41), 잎, 반딧불이, 굴뚝 연기를 그리지 않습니다. 모두 걷는 이들의 1~1.5보다 위인 깊이 2.4~2.45에 그려집니다. 가로등 웅덩이는 밤의 빛이므로 남습니다. 프로브의 값은 어느 웅덩이의 평면이 수집가 프레임과 겹치는지도 말하며, -airProbe 아래에서 스테이지는 검사 3의 파이프라인 견본을 그리고 그 프레임을 보고합니다.2230 이것들은 모두 검사 3을 위해 제안하는 추가입니다.

Kiradex 자신의 네 빛을 보인 견본. 위 줄은 장소: 아침 (1, 0.96, 0.86), 루마 0.961. 낮 (1, 1, 1), 1.000. 저녁 (1, 0.78, 0.6), 0.825. 밤 (0.5, 0.58, 0.9), 0.593. 아래 줄은 제안하는 걷는 이들로, 각각 흰색 쪽으로 절반 끌어올린 것: 아침 루마 0.980. 낮 1.000. 저녁 (1, 0.89, 0.8), 0.913. 밤 (0.75, 0.79, 0.95), 0.796.

Daylight.swift의 Kiradex 틴트와 제안하는 걷는 이의 빛. 견본은 figures/make_figures.py로 그렸습니다. 이것은 앱 자신의 값으로, Mac에서 소스로 읽은 것입니다. 루마는 거기서 계산한 것이지 iPhone에서 측정한 것이 아닙니다.

인수 검사 3, 사람. iPhone 18 Pro Max 시뮬레이터에서 캡처 두 개를 각각 따로 실행해 찍습니다. 하나는 -plazaHour 12, 다른 하나는 -plazaHour 22이며, 둘 다 -plazaWeather clear(항목 3)를 붙여 그날의 굴림이 빛을 바꾸지 못하게 하고, -plazaHoldStill(항목 2)을 붙여 둘 다 같은 그림을 보여 주고 그 위에 아무것도 그려지지 않게 하며, -airProbe를 붙이고, UI 테스트의 save로 저장합니다. 스테이지의 값은 수집가 프레임, 인물 마스크, 그림, 그리고 불빛 셀들의 프레임(항목 2에서 제안하는 추가)을 실어 나르므로, 테스트는 어느 픽셀이 수집가이고 어느 것이 불 켜진 창인지 압니다. 각 캡처 직전과 직후에 그림을 읽어 네 번 모두 프레임 0, 곧 아래를 보는 idle_a일 것을 요구합니다. 네 번의 읽기 중 하나라도 프레임 0이 아니면 고정이 깨진 것이고 검사는 실패합니다. 또 밤 캡처에서 수집가 프레임 위에 웅덩이가 없다고 프로브가 보고할 것을 요구합니다. 픽스처는 어떤 캡처를 판정하기 전에 동결합니다. 실행 인자 세트 네 개, 견본의 그림, 틴트, 위치, 캡처의 대상이 되는 마을 내보내기(10월 3일의 town.json을 해시로 지정하고 그 아틀라스와 함께), 잘라 내는 영역(프로브에서 받은 수집가 마스크로, 그 각 픽셀을 프레임 안 해당 칸의 중심에서 표본으로 뽑음. 땅은 뷰에서 수집가 프레임과 상태 줄을 뺀 것. 불빛 픽셀은 아래), 파이프라인, 그리고 아래의 허용 오차는 테스트 안의 상수이며, 그 어느 것을 바꾸는 것도 검사를 바꾸는 일로, 공개적으로 하며 결코 캡처에서 얻은 읽기로 하지 않습니다.12206819

루마는 캡처의 저장된 색 값으로 잽니다. RealityKit이 틴트와 그림을 어떻게 그 값으로 바꾸는지는 이 글을 위해 저장한 Apple 페이지에 나와 있지 않습니다. UnlitMaterial 페이지는 init(applyPostProcessToneMap:), “Creates an UnlitMaterial with the given tone mapping setting”(주어진 톤 매핑 설정으로 UnlitMaterial을 만든다)을 나열하지만, SpriteSheet.material(light:)가 만드는 평범한 UnlitMaterial()이 무엇을 하는지도, 틴트와 .color 시맨틱으로 만든 텍스처가 각각 어떻게 변환되는지도 말하지 않습니다.7172 그래서 대역은 파이프라인마다, 모두 어떤 캡처보다 앞서, 덮음 계산의 섹션 E에서 정합니다.30

  • 보정. 불 켜진 창과 벽등은 틴트 없이 그려지므로, 밤 캡처는 자기만의 고정된 기준을 갖습니다. 아래의 각 파이프라인에서 틴트 없는 색은 저장된 그대로 나옵니다. 불빛 셀 24개 중 7개는 검사 8의 종이 위 재생에서 도착 뷰에 온전히 들어오고, 불빛 픽셀은 294개이며, 모두 어느 웅덩이의 평면에서도 벗어나 있고 뷰 중심에서 450포인트 안, 곧 비네트의 900포인트 반지름 중 맑은 안쪽 절반에 있습니다. 각각을 주사선 행이 덮지 않는 칸의 점에서 표본으로 뽑고, 그 픽셀들에 걸쳐 아틀라스의 저장된 값과의 채널별 차이 중 최댓값의 중앙값이 0.02 이하, 255단계로 5단계 이하여야 합니다. 그렇지 않으면 톤 맵이나 색 변환이 경로에 있는 것이고, 아래의 어떤 파이프라인도 맞지 않습니다. 검사는 대역을 읽기 전에 거기서 실패하며, 창이 보여 주는 것의 대역을 이것들처럼 아틀라스에서 계산해 테스트에 적어 넣은 뒤에야 쌍을 다시 판정합니다.201930
  • 틴트를 저장된 그대로 곱하거나, 틴트와 그림 모두 선형으로. 땅의 밤 대 낮은 저장된 그대로 0.588, 그림과 틴트를 sRGB에서 디코딩해 곱하고 다시 인코딩하면 0.562입니다. 채널별로 빨강, 초록, 파랑은 (0.500, 0.580, 0.900)과 (0.469, 0.554, 0.892)입니다. 대역은 0.46~0.69입니다. idle_a로 고정한 수집가 마스크는 끌어올림 아래에서 0.788과 0.764, 밤 틴트를 통째로 받으면 0.575와 0.531이며, 0.67에 이르러야 합니다. 두 올바른 값 중 낮은 쪽과 두 망가진 값 중 높은 쪽의 한가운데입니다.
  • 틴트의 숫자를 선형으로 취급. 그림은 디코딩하고 틴트는 디코딩하지 않으면 땅은 0.774, 채널별로 (0.719, 0.772, 0.951)이고, 대역은 0.67~0.87입니다. 마스크는 끌어올림 아래에서 0.889, 틴트를 통째로 받으면 0.756이며, 그 한가운데인 0.82에 이르러야 합니다.
  • 어느 것인가. 파이프라인을 밝히는 것은 땅이 아니라 견본입니다. -airProbe 아래에서 스테이지는 저장값 51과 102(255 중)인 회색 두 개의 고정된 그림을, 모든 채널에 0.25인 고정된 틴트 아래에서 그립니다. 이것은 SpriteSheet.material(light:)에 직접 주며 결코 PlaceLight나 하루의 빛을 거치지 않고, 웅덩이 위의 사각형에, 뷰의 고정된 위치에, Pro Max의 440×956포인트에서 x 24~56, y 462~478에 16포인트짜리 패치 두 개를 나란히 그립니다. 왼쪽 가장자리의 높이 한가운데이며, 가장 먼 모서리는 중심에서 197포인트이므로 비네트의 맑은 절반 안에 있습니다. 프로브가 그 프레임을 보고하고, 땅의 잘라 내기는 그것을 빼며, 위치는 다른 픽스처와 함께 동결합니다. 프로브의 프레임으로 테스트는 그것이 수집가 프레임과도, 기준 창 일곱 개 중 어느 것과도 겹치지 않음을 검증합니다. 도착 시점 계산으로 겹침은 0이며, 가장 가까운 창과 267포인트 떨어져 있습니다. 창처럼 주사선 행을 피해 표본으로 뽑으며, 그 저장된 값은 두 시각에서 같습니다. 저장된 그대로 곱하면 13과 26, 그림과 틴트를 선형으로 하면 6과 20, 틴트의 숫자를 선형으로 취급하면 22와 51이 되며, 어느 패치에서도 두 파이프라인이 6단계보다 가까워지지 않습니다. 각 캡처의 견본은 한 파이프라인의 두 값에서 2단계 안에 있어야 하고, 모든 캡처에서 같은 파이프라인이어야 하며, 그 파이프라인의 대역과 문턱이 적용됩니다. 파이프라인을 밝히는 것이 땅이 아니라 견본이므로, 우연히 다른 파이프라인의 대역에 맞는 땅이 그 아래에서 통과할 수는 없습니다. 테스트는 밝혀진 파이프라인을 그것을 밝힌 SDK와 함께 기록하기도 하며, 나중의 실행이 다른 것을 밝히면 그 기록을 공개적으로 바꿀 때까지 실패합니다. 견본과 그 그림은 제 제안입니다.30

  • 통과 조건. 보정이 성립할 것. 땅의 밤 대 낮이 밝혀진 파이프라인의 대역 안에 있을 것. 견본이 모든 캡처에서 한 파이프라인, 곧 테스트가 기록한 것을 밝힐 것. 마스크의 비가 그 파이프라인의 문턱에 이르고 땅의 비보다 위에 있을 것(이것이 항목 2의 끌어올림이 드러나는 것입니다). 땅의 채널 비가 아래의 두 검증을 통과할 것. 두 대조군이 모두 실패할 것. 그림의 네 번 읽기가 모두 프레임 0일 것. 그리고 밤 캡처가 수집가 위에 웅덩이가 없다고 보고할 것. 그 밖의 것은 모두 검사 실패입니다.

  • 대역. 각 대역은 그 파이프라인의 계산된 비 앞뒤로 0.1을 잡아 반올림한 것이며, 계산에서 정한 목표이지 측정이 아닙니다. 계산된 비는 아틀라스만의 것입니다. 캡처에는 가로등 웅덩이도 들어 있는데, 그것은 밤을 밝게 할 수만 있고, 0.1은 그것을 위해 남겨 둔 여지로, 첫 캡처 전에 고른 것입니다. 주사선과 비네트는 두 시각에서 똑같이 그려지므로, 제가 읽기에는 두 캡처를 똑같이 줄입니다.1291922
  • 왜 같은 그림인가. 문턱은 두 캡처에서 같은 그림일 때, 그리고 그때만 성립합니다. 저장된 그대로 곱하면 끌어올림의 가장 작은 채널은 0.75이므로, 그 아래에서 어떤 색도 낮 루마의 0.75 미만을 남기지 않고, 같은 그림이라면 마스크의 평균도 그럴 수 없습니다. 두 그림에 걸치면 그럴 수 있습니다. 마스크가 고정하는 것은 어느 픽셀을 뽑는지이지 그 픽셀이 가진 색이 아니기 때문입니다. 마스크의 낮 루마는 doze_b의 0.2989부터 think의 0.3161까지이고, 낮에는 think, 밤에는 doze_b로 찍힌 올바른 빌드는 0.746이 되며, 그림 11개의 순서쌍 121개에 걸쳐 걷는 이들에게 틴트를 입히는 빌드는 0.610에 이릅니다. 그래서 고정합니다. 선형에서는 sRGB 곡선의 곧은 발치 때문에 가장 어두운 색이 0.75 미만을 남길 수 있으며, 그래서 각 문턱은 그 하한이 아니라 계산된 평균입니다.3011
  • 공기가 할 일. 공기가 그리는 모든 것은 모든 걷는 이보다 위에 있습니다. 구름은 깊이 2.4, 안개(아침에만)는 2.41, 잎, 반딧불이, 연기는 2.45, 웅덩이는 2.5로, 걷는 이들의 1~1.5에 맞섭니다. 그리고 구름은 밤을 뺀 모든 시간대에 보입니다. 그 가장 짙은 그늘은 그 아래 것에 0.763을 곱하며, 낮의 마스크 위에서는 걷는 이들에게 틴트를 입히는 빌드를, 그늘이 인코딩된 값을 어둡게 한다면, 저장된 그대로 0.754, 선형으로 0.696, 틴트의 숫자를 선형으로 취급하면 0.991로 끌어올립니다. 인코딩 전에 선형 빛에서 어둡게 한다면 선형으로 0.608, 틴트의 숫자를 선형으로 취급하면 0.865입니다. 렌더러가 어느 쪽을 하는지는 저장한 페이지에 나와 있지 않으며, 0.608인 경우를 뺀 모든 경우에 망가진 빌드가 문턱을 통과하게 됩니다.2230
  • 왜 고정인가. 고정은 공기를 수집가에게서 떼어 놓으며, 이 검사는 그것 없이는 성립하지 않습니다. 수집가가 그늘에서 벗어날 때까지 다시 찍는 프로브 플래그로도 될 수는 있지만, 구름은 가로로 초당 1.536픽셀, 위나 아래로 0.576픽셀 흐릅니다(각 축에서 어느 쪽으로 가는지는 코드가 정하지 않습니다. 스프라이트 시트의 측정된 규약, 곧 텍스처 왼쪽 위부터 세는 오프셋은 그것들 자신이 손으로 만든 사각형을 위한 것이고, 구름은 생성된 평면입니다). 그래서 수집가 프레임을 가로지르는 그늘은 흐름이 그것을 프레임 너비인 32픽셀 옮기는 데 걸리는 21초(20.8초) 동안 그 일부에 머물고, 그늘이 넓을수록 더 오래 머무르며, 그림은 약 절반이 덮여 있습니다. 반면 고정은 모든 캡처에서 그것을 해결합니다. 저는 고정을 골랐습니다. 웅덩이는 떼어 놓을 수 없습니다. 시험 중인 빛 그 자체이기 때문입니다. 그리고 웅덩이는 움직이지 않습니다. 도착 시점에 수집가의 32×40픽셀 프레임은 가장 가까운 웅덩이 평면에서 52픽셀 떨어져 있으므로, 프로브의 웅덩이 플래그는 그 계산의 감시자이며, 그것이 서면 검사는 다시 찍지 않고 실패합니다.22930
  • 왜 프레임 전체가 아닌가. 수집가 프레임 전체는 잘라 내는 영역으로 쓸 수 없습니다. 대부분이 땅이기 때문입니다. 기본 인물은 첫 서 있는 그림에서 1,280픽셀 중 408을 덮고(몸 시트만으로 377, 내보내기의 모든 인물 시트를 한꺼번에 겹치면 581), 나머지를 아틀라스 평균 색으로 두고 저장된 그대로 곱하면 올바른 빌드의 프레임 전체는 0.638이 됩니다. 마스크가 이르러야 할 0.67보다 낮고 땅보다 겨우 0.049 위이며, 걷는 이들에게 틴트를 통째로 입히는 빌드는 0.584가 됩니다.30
  • 검증 두 개 더. 쌍이 서로 닮아서 통과하는 것을 막습니다. 땅의 밤 대 낮 비를 채널별로 구하면, 밤 틴트 (0.5, 0.58, 0.9)가 늘어놓는 대로 파랑이 초록보다, 초록이 빨강보다 위에 오고, 각각이 밝혀진 파이프라인의 계산된 채널에서 0.15 안에 있어야 합니다(첫 번째는 어느 세트든 됩니다).
  • 대조군. -plazaHour 22에 제안하는 디버그 인자 -plazaNoTint를 붙인 세 번째 실행은 -plazaHour처럼 실행하는 동안 고정되며, 그 아래에서 PlaceLight.place는 모든 시각에 하루의 빛을 돌려줍니다. 이것은 대역에서 실패해야 하며, 그 땅의 비는 1 근처에 옵니다. 이는 대역이 틴트 없는 출력을 거부한다는 것을 보여 줍니다. PlaceLight를 무시하는 렌더러는 두 시각에서 같은 그림을 내놓으며, 이 검사에 대해서는 땅의 비가 약 1이라 어느 대역에서도 실패하고, 평평한 채널 비가 순서에서 실패합니다. 두 번째 대조군, -plazaHour 22에 또 다른 제안 디버그 인자 -plazaLiftAgain(제가 붙인 이름)을 붙인 네 번째 실행에서는 SpriteSheet.material(light:)가 받은 모든 틴트를 다시 흰색 쪽으로 절반 끌어올리며, 이것도 실패해야 합니다. 이것은 PlaceLight는 올바른 값을 주는데 머티리얼은 그렇지 않은 빌드입니다. 저장된 그대로 곱하면 그 땅은 낮의 0.794, 채널은 (0.750, 0.790, 0.950), 마스크는 0.894가 되고, 흰 창은 바뀌지 않으며, 틴트 없는 대조값은 여전히 1입니다. 땅만 보면 0.794에 빨강 비 0.750으로, 틴트의 숫자를 선형으로 취급하는 경우의 대역 0.67~0.87 안에 들어 땅에 대해 하는 모든 검증을 통과해 버립니다. 그래서 견본이 결정합니다. 견본은 그것을 실패시킵니다. 그 틴트는 0.625에 이르고 32와 64로 읽혀, 가장 가까운 파이프라인의 값에서 13단계 떨어져 있습니다.30
  • 대역은 옮기지 않는다. 첫 진짜 쌍이 그 파이프라인의 대역 밖으로 떨어지면 검사는 실패하고, 원인을 렌더러나 계산 안에서 찾습니다. 그것에 맞추려고 대역을 옮기지는 않습니다. 첫 쌍에서 대역을 잡으면 틴트를 끈 렌더러를 통과시키게 되며, 그래서 픽스처와 대역은 미리 고정되고, 첫 쌍은 이미 적힌 대역 가운데 하나를 고를 뿐입니다.
  • 단위 테스트. PlaceLight의 단위 테스트가 정확한 부분을 더합니다. 밤 틴트에서, 여름의 맑은 날씨일 때 walkers는 (0.75, 0.79, 0.95)이고 place는 틴트 그 자체입니다.11
  • 처음 쓰인 그대로. 검사는 밤 캡처 하나를 두고, 땅이 0.55~0.65 사이일 때 수집가의 평균 루마가 낮 캡처의 최소 0.75일 것을 요구했으며, 잘라 내는 영역도, 픽스처도, 그림도, 파이프라인도, 대조군도 지정하지 않았습니다. 위의 모든 것은 제 수정입니다.12

3. 날씨: 상태 다섯 가지, 하루 한 번 굴림

  • 상태. clear, overcast, rain, heavy rain, 그리고 겨울에만 있는 snow입니다. 아침 안개, 가을 잎, 밤 반딧불이는 지금 그대로 위에 겹쳐집니다. 날씨는 야외에만 있습니다. Air가 하늘을 찾지 못하는 곳(그 outdoors), 곧 방과 홀은 빗방울도 날씨 계수도 받지 않으며, 이 선택은 제 것입니다.1222
  • 하루 한 번 굴림, 한 구역의 모두에게 같게. Weather.today(zone:date:)는 시간대 식별자와 그 시간대에서의 날짜 "zone|yyyy-mm-dd"의 SHA-256을 구하고, 다이제스트의 처음 4바이트를 부호 없는 빅 엔디언 수 하나로 읽어 100으로 나눈 나머지를 취합니다. 그 굴림 값을 계절의 표에 누적으로 맞춥니다. 상태를 나열한 순서대로 취해 각 상태의 가중치를 누계에 더해 나가고, 누계가 굴림 값을 처음 넘는 상태가 그날의 상태입니다. 봄이라면 굴림 값 0~54가 맑음, 55~79가 흐림, 80~99가 비입니다.11 표는 제 것입니다. 봄 맑음 55, 흐림 25, 비 20. 여름 맑음 65, 흐림 20, 비 10, 폭우 5. 가을 맑음 45, 흐림 30, 비 20, 폭우 5. 겨울 맑음 40, 흐림 30, 눈 30입니다.12 그 모양은 Stardew의 계절별 확률을 따르고(비가 많은 봄, 비가 거세지는 건조한 여름, 비 없는 겨울), 수치는 Kiradex의 것입니다(8절, 날씨의 일정).18
  • 1년치. 한 구역에서 2027년에 대해 돌리면 굴림은 이렇게 나옵니다. 봄 92일, 맑음 53(58%), 흐림 22(24%), 비 17(18%). 여름 92일, 맑음 61(66%), 비 13(14%), 흐림 12(13%), 폭우 6(7%). 가을 91일, 맑음 40(44%), 흐림 30(33%), 비 17(19%), 폭우 4(4%). 겨울 90일, 맑음 36(40%), 흐림 29(32%), 눈 25(28%). 1년 중 젖은 날 82일, 곧 비, 폭우, 눈의 날 가운데, 여기서 젖은 기간이란 셋을 어떻게 섞든 연속된 젖은 날의 이어짐으로, 비 온 날 다음에 폭우 온 날이 오면 이틀짜리 기간 하나입니다. 젖은 기간은 65개이고, 하루짜리가 50, 이틀짜리가 13, 사흘짜리가 2이며, 가장 긴 것은 3일입니다. 두 구역은 1월 30일 중 8일이 일치합니다. 각 구역이 따로 굴리기 때문입니다. 그리고 같은 구역과 날짜는 언제나 같은 상태를 줍니다.114 봄의 비 18%는 Stardew의 기본 확률 18.3%에 들어맞습니다.184
  • 변화가 스테이지에 닿을 때. 굴림의 날짜는 방의 시간대로 읽으므로, 그날의 상태는 그 시간대의 자정에 바뀝니다. 스테이지는 다시 비출 때마다 그것을 읽고, 항목 1의 LightClock은 자기 달력에서 방의 자정에 깨어남을 예약하므로, 새 날의 상태는 최대 1분 늦게가 아니라 제때 도착하며, Apple의 페이지가 휴대폰 자신의 날에 대해서만 약속하는 시스템 알림에도 기대지 않습니다. 나타나는 스테이지는 첫 다시 비추기에서 그날의 상태를 읽고 페이드 없이 보여 줍니다. 그러니 항목 4의 페이드를 보는 것은 방의 자정에 광장을 열어 둔 사람뿐이며, 그것은 Kiradex의 밤에 옵니다.832143
  • 미리 알려진다. Stardew의 TV가 그러듯, 퀘스트 게시판이 내일의 날씨를 Kiradex 자신의 말로 한 줄에 싣습니다.17
  • 파일. 상태, 각 상태의 빛 계수와 상태 문구, 굴림, 게시판 줄(Weather.boardLine(zone:date:), 같은 구역의 다음 날 상태를 밝힘), 구름의 속도(항목 6), 강제 상태를 위한 새 Kiradex/World/Weather.swift. 비, 물보라, 눈, 흐림을 위한 Air.swift(항목 4). rain.png, splash.png, snow.png를 8×8~8×16 셀로 그리는 포지의 air.py. relight()가 상태를 읽어 계수를 리그에, 상태를 Air에 넘기고, PlazaView.words가 상태 문구를 상태 줄에 더하는 PlazaStage.swift. 그리고 게시판 줄을 위한 QuestBoardView.swift로, 광장 뷰(PlazaView)와 Me 탭이 시트로 띄웁니다.129019 Daylight.swift는 날씨를 받지 않습니다. 그 빛은 시각만의 함수로 남고, 날씨 계수는 PlaceLight에서 적용합니다. 조사 자료는 날씨 계수를 Daylight에, 게시판 줄을 PlazaStage.swift에 두었습니다. 페이드는 시각의 함수 안에 살 수 없고 게시판은 자기만의 뷰이므로, 두 정정 모두 제 것입니다.
  • 테스트를 위한 강제 날씨. 상태 이름을 붙인 -plazaWeather는 한 번 실행하는 동안 그날의 상태를 강제합니다. 실행 인자에서 읽고, -plazaHour처럼 실행하는 동안 고정됩니다. 아래의 검사들이 이것을 씁니다. 이것은 제 추가입니다.

한 구역에서 2027년 제안 날씨 굴림 1년치를 계절마다 하나씩 보인 누적 막대 네 개. 봄 92일: 맑음 53, 흐림 22, 비 17. 여름 92일: 맑음 61, 흐림 12, 비 13, 폭우 6. 가을 91일: 맑음 40, 흐림 30, 비 17, 폭우 4. 겨울 90일: 맑음 36, 흐림 29, 눈 25.

제안: 매일 굴림의 1년치. kiradex_proposals.txt 섹션 6에서, Mac에서 계산했습니다.

인수 검사 4, 굴림. 단위 테스트가 시간대 America/Los_Angeles에서 2027년 365일에 대해 Weather.today를 계산하고, measure_kiradex_proposals.py 섹션 6이 출력하는 것과 맞춥니다. 각 계절의 각 상태 개수, 위에서 정의한 젖은 기간 65개에 든 젖은 날 82일, 가장 긴 3일, 그리고 Europe/London이 일치하는 1월 30일 중 8일입니다.1211 또 테스트가 기기의 시간대로 무엇을 설정하든 같은 구역과 날짜가 같은 상태를 준다는 것을 검증합니다. 날짜는 지정한 시간대로 읽기 때문입니다. 게시판 줄은 제 것입니다. 같은 테스트가 Weather.boardLine(zone:date:)가 같은 구역의 다음 날에 대해 Weather.today가 돌려주는 상태를 밝힌다는 것, 그리고 다섯 상태의 상태 문구가 서로 다르고 어느 것도 비어 있지 않다는 것을 검증합니다. 처음 쓰인 그대로는 검사가 1년을 날마다 스크립트 출력과 비교했는데, 스크립트가 출력하는 것은 날이 아니라 개수입니다. 그리고 서버 테스트에 서버가 하지 않는 굴림을 확인하게 했습니다. 또 조사 자료의 젖은 이어짐(그 섹션 4.3)은 한 상태의 이어짐을 셌으므로 비 다음의 폭우가 둘이 되어 67이라는 수가 나왔는데, 스크립트는 더는 그 수를 출력하지 않습니다.

4. 비

  • 빗방울. iPhone 18 Pro Max 뷰에 15방울입니다. 이 뷰는 월드 165×358픽셀을 보여 줍니다(캐릭터 글의 수치로, 여기서 다시 재지 않았습니다). Emerald의 10,000제곱픽셀당 2.60방울이라는 밀도를 가져온 것입니다. 폭우는 37방울입니다.1191
  • 낙하. 빗방울은 포지가 그리는 Kiradex 고유 모양의 줄기로, 초당 약 868픽셀, 수직에서 26.6도로 0.301초(Emerald의 18프레임) 떨어진 뒤 땅에서 0.117초(그 7프레임)의 물보라가 됩니다.11 위치는 정수 픽셀입니다(8절, 빗방울). 초당 120프레임에서는 프레임당 7.2픽셀이고, 줄기의 길이가 그 틈을 메웁니다.114
  • 빗방울이 사는 곳. Air에 RainField를 더합니다. 뷰의 크기와 그날의 상태에 대한 빗방울 위치를 담고, 프레임의 시간만큼 나아가 정수 픽셀로 반올림하는 값입니다. Air.update(_:camera:view:)가 그것을 나아가게 하고 빗방울마다 엔티티 하나를 놓으며, Air.set(phase:season:weather:reduceMotion:)이 오늘의 set(phase:season:)을 대신해 빗방울, 눈송이, 흐림 시트를 켜고 끕니다. 빗방울은 Air의 것이고, 그 헤더의 말로 Air의 어느 것도 하루의 틴트를 받지 않으므로, 밤의 빗방울은 포지가 그린 그대로 그려집니다. 그것이 밤에 잘 어울리는지는 기기에서의 판단입니다. Air는 빗방울 개수도 보고에 담으며, -airProbe 아래에서 스테이지는 공기를 준비하는 .task 안에서 플레이어의 첫 걸음까지 보고를 한 번이 아니라 초당 한 번 자기 값에 복사합니다. 그 뒤로는 오늘처럼 rig.onStep이 걸음 기록을 거기에 씁니다. 걷기 테스트들이 거기서 그것을 읽기 때문입니다. 보고를 읽는 검사 5와 10은 한 걸음도 내딛지 않습니다. 이것은 모두 제안입니다.2219
  • 빛. 장소의 빛에 13/16를 곱합니다(8절, 비의 빛). 아틀라스의 낮 루마는 0.449에서 0.365로, 비 오는 밤은 0.214가 됩니다.11 걷는 이들은 항목 2의 끌어올림을 유지하고 날씨 계수를 받지 않습니다. 불빛 셀과 웅덩이는 바뀌지 않습니다.
  • 1초 페이드, 그리고 누가 그것을 돌리는가. 비로 들어가고 나올 때 장소의 빛은 1초에 걸쳐 페이드합니다(8절, 변화).12 PlaceLight(항목 2)는 날씨 계수, 페이드해 가는 목표 계수, 변화 이후의 시간을 담습니다. 페이드와 함께 새 계수를 전달받으면, 진행되는 시간의 1.0초에 걸쳐 가지고 있던 계수에서 새 계수로 선형으로 움직입니다. 이미 세계의 틱(걷는 이들, 카메라, 카드)을 돌리고, 그다음 매 프레임 진열장을 돌리고 물결을 진행시키고 공기를 갱신하는 PlazaRig.update(_:)가 그것을 진행시키며, place가 바뀐 프레임에서는 다시 비출 때 light(_:lampsOn:)가 하듯 장소 머티리얼 세 개를 할당하고, 문이 보이는 동안에는 문의 것도 할당합니다. 스테이지의 relight()는 각 상태의 계수(맑음 1, 흐림 0.9, 비 13/16, 폭우 0.75, 눈 1)를 페이드와 함께 넘기되, 스테이지의 첫 다시 비추기만은 예외로 곧바로 설정합니다. 그 밖에 빛을 애니메이션하는 것은 없고, 타이머도 더하지 않습니다.2019
  • 가정. 가져온 수치는 60헤르츠를 가정합니다. 휴대용 게임기와 다른 프레임 속도는 프레임당 진행을 바꿀 뿐 속도는 바꾸지 않습니다.12
  • 비용. 스프라이트 엔티티 15~37개와 그 물보라로, 프로파일하지 않았습니다.11 페이드 동안 리그는 1초 내내 매 프레임 장소 머티리얼 세 개를 할당하고, 문이 보이면 그것도 할당합니다. 60헤르츠에서 180번, 120헤르츠에서 360번(문이 있으면 240번과 480번)이며, 다시 비추기가 1분에 3번(문이 보이는 동안 4번), 물이 있는 곳에서 물결이 초당 12번인 것과 비교됩니다. 이것은 코드에서 센 것이고, 기기에서의 비용은 측정하지 않았습니다.420

인수 검사 5, 비. 두 부분으로 나뉩니다. 앱에서는, Pro Max 시뮬레이터에서 -plazaHour 12, -plazaWeather rain, -airProbe로 실행한 UI 테스트가, testTheChimneysSmoke가 smoke 18을 기다리듯, 스테이지 값에 있는 공기의 보고가 15 ± 1의 빗방울 개수를 읽기를 기다립니다. 이를 위해서는 항목 4에서 제안하는 보고와 그 초당 한 번 복사가 필요하며, 테스트는 한 걸음도 내딛지 않으므로 복사가 값을 지킵니다.6819 프로세스 안에서는, 단위 테스트가 Pro Max 뷰의 RainField를 초당 120프레임으로 시뮬레이션한 비 10초 동안 진행시키며 모든 빗방울 위치가 정수이고 개수가 15임을 검증합니다. 하루의 빛에 있는 PlaceLight를 페이드와 함께 비를 전달받게 하여 진행시키며, place가 1.0초 표시 한 프레임 전에는 아직 하루 빛의 13/16보다 위에 있고 그 한 프레임 뒤 안에 13/16에 있음을 검증합니다. 그리고 walkers가 날씨 계수가 있든 없든 같음을 검증합니다. 배선, 곧 PlazaRig.update가 자기 PlaceLight를 진행시키고 place가 바뀔 때 머티리얼을 할당하는 것은 소스에서 읽을 몇 줄입니다. 처음 쓰인 그대로는 검사가 넷을 모두 리그 로그에서 읽었는데, 그 로그가 닿는 곳은 Mac의 콘솔이지 테스트가 아닙니다.12

5. 흐림, 눈, 번개 없는 폭우

  • 흐림. 구름 시트의 불투명도는 0.55에서 0.8로 오르고, 빛은 0.9의 회색을 받습니다.12 출시된 cloud.png로는 가장 짙은 그늘이 0.763에서 0.655로, 그림의 평균이 0.950에서 0.927로, 그 회색 아래 아틀라스의 낮 루마가 0.404가 됩니다.4 회색은 비처럼 PlaceLight를 거쳐 페이드합니다. 시트의 불투명도는 Air.set(phase:season:weather:reduceMotion:)이 곧바로 설정합니다. 상태가 바뀌는 것은 자정뿐이고, 그때 시트는 숨겨져 있기 때문입니다(Air.set은 밤에 구름을 숨깁니다).22
  • 눈. 겨울에만 있고, 포지가 그립니다. 잎의 흔들림을 가진 느린 눈송이로, Air가 잎처럼 간직하며, 땅은 겨울 색조를 유지합니다. 눈은 날씨 계수를 받지 않으며, 이것은 제 선택입니다.1222
  • 폭우. 빛은 더 어두워져 0.75가 됩니다. 아틀라스의 낮 루마 0.337, 폭우의 밤 0.198입니다.124 RainField는 37방울을 담습니다.11
  • 번개 섬광 없음. 폭우는 섬광을 만들지 않습니다. 2절에서 측정한 Emerald의 폭풍은 어느 1초에든 번개를 많아야 하나만 담아 W3C의 초당 세 번 섬광 한도 아래에 있으므로, 정전은 그 기준을 통과할 것입니다.446 거부는 통과하느냐의 문제가 아닙니다. W3C의 말로 번쩍이는 콘텐츠는 “can cause migraines, dizziness, nausea, and seizures”(편두통, 어지럼증, 메스꺼움, 발작을 일으킬 수 있다)이고, 제 전제는 아이들이 이 마을을 오래 쓸 수 있다는 것입니다. 그렇게 쓰이는 세계에는 그것이 필요 없습니다.4612

인수 검사 6, 섬광 없음. 프로세스 안에서, 단위 테스트가 하루의 빛에 있는 PlaceLight를 초당 120프레임으로 시뮬레이션한 10초 동안 진행시키며, 2초에 페이드와 함께 폭우를, 6초에 맑음을 전달하고, place가 아틀라스 평균의 루마로 한 프레임에서 다음 프레임으로 0.02보다 크게 바뀌는 일이 결코 없으며, 하루 빛의 0.75에 이르렀다가 돌아온다는 것을 검증합니다. 폭우로의 페이드는 낮의 0.449를 1초에 걸쳐 0.337로 만들며, 60헤르츠에서 프레임당 0.0019, 120헤르츠에서 0.0009이므로 한계는 넉넉히 성립합니다. 컷이라면 0.112의 단차가 됩니다.4 PlaceLight는 Reduce Motion 입력을 받지 않으므로, 페이드는 구조상 설정이 켜져 있든 꺼져 있든 같습니다(항목 9). 설정이 무엇을 바꾸는지는 검사 10이 검증합니다. Mac에서 하는 시뮬레이터 화면 녹화로 교차 확인할 수는 있지만, 녹화가 앱이 그리는 모든 프레임을 담는다는 보장이 없고, 빗방울 자체의 움직임도 프레임의 평균을 움직이므로, 검사는 단위 테스트입니다. 처음 쓰인 그대로는 검사가 모든 프레임의 캡처를 요구했는데, UI 테스트는 그것을 찍을 수 없습니다.12

6. 움직이는 구름 그림자

  • 속도. 구름은 초당 1.64픽셀 대신 고정된 초당 16픽셀, 초당 한 타일로 흐릅니다. 오늘 걷기, 초당 60픽셀의 0.27이며, 앱의 틱 시계는 모션 글의 브리프가 정한 대로 이 걷기를 줍니다(틱당 1픽셀, 타일당 16틱, 초당 60틱). 고정된 수치가 제안이며, 2절의 차트는 그것을 그 걷기와 나란히 놓습니다. Emerald의 안개 비 0.25에 가깝고 그 구름의 0.50보다 느립니다(8절, 공기). 그 속도로 구름은 Pro Max 뷰의 높이 358픽셀과 같은 거리를 22.4초에 갑니다. 뷰를 가로지르는 데 걸리는 시간은 아래에 나오는 그날의 방향에 달려 있습니다. 2027년 1월 1일에는 동쪽에서 215.16도를 향하고, 수직 성분이 초당 9.21픽셀, 수평 성분이 13.08픽셀이므로 뷰의 높이를 38.9초에, 너비를 12.6초에 가로지릅니다.1147773 이것은 오늘 흐름의 9.75배입니다.4
  • 그늘. 시트의 가장 짙은 그늘 0.763과, 그림의 약 절반이라는 덮음은 그대로 둡니다.9
  • 방향. 그날의 방향은 다이제스트의 다섯 번째 바이트, 곧 굴림이 읽지 않는 첫 바이트로 고정하며, 그 바이트에 360/256도를 곱한 각도를 동쪽에서 반시계 방향으로 잡습니다. 그러면 한 구역의 모두가 구름이 같은 쪽으로 가는 것을 봅니다. 2027년 1월 30일에 대해 스크립트는 서로 다른 방향 30개를 찾습니다.11 조사 자료는 굴림의 “second byte”(두 번째 바이트)라고 했는데, 그것은 굴림이 읽는 4바이트 중 하나입니다. 다섯 번째는 제 정정입니다.12
  • 파일. Weather.swift의 Weather.cloudVelocity(zone:date:)가 그날의 속도를 초당 픽셀로 줍니다. Air.update는 오늘의 고정된 초당 SIMD2(0.004, 0.0015) 대신 그것을 384로 나누어 구름 오프셋에 더하고, 흐름을 초당 픽셀로 보고에 담습니다. 둘 다 제안입니다.22

인수 검사 7, 구름. 프로세스 안에서, 단위 테스트가 Weather.cloudVelocity(zone:date:)의 크기가 초당 16픽셀이고, 같은 구역과 날짜에서 같으며, 주어진 날짜 다음 29일 중 적어도 하루는 다르다는 것을 검증합니다(스크립트는 2027년 1월 2일부터 30일까지 29일 모두가 1월 1일과 다름을 찾습니다). 화면에서는, -plazaHour 12, -plazaWeather clear, 수집가가 가만히 선 상태로 5초 간격을 두고 찍은 두 캡처를, 구름 그늘을 가장 잘 맞추는 이동량으로 겹쳐 80 ± 3 월드 픽셀의 흐름을 보여 줍니다. 이것은 동시에 7절이 가정하듯 RealityKit이 오프셋을 스케일 뒤에 적용하는지, 그리고 항목 6이 말하듯 Air.update가 속도를 더하는지도 잽니다. 처음 쓰인 그대로는 검사가 리그 로그를 읽고, 시뮬레이터 두 대에 날짜를 공유하게 했는데, 실행으로는 그것을 설정할 수 없습니다.122211

7. 땅에 떨어지는 건물 그림자

  • 패스. town.py의 paint 안에서 벽의 그림자 다음에 두는 포지 패스입니다. 각 건물에 대해 맨 위 행부터 기단 행까지 한 행씩, 그 행에서 가장 동쪽에 있는 건물 셀의 바로 동쪽 셀이 벽 발치와 같은 처리, 곧 건물에 가장 가까운 4픽셀 열에서 그 자신의 램프로 한 단계 어두워지는 처리를 받습니다. 셀은 마을의 문자로 땅, 잔디, 길, 포장석일 때만 그림자를 받습니다. 소품, 나무, 키오스크, 다른 건물, 울타리, 물이 있으면 그 행은 그림자를 받지 않으며, 패스는 그것을 지나 더 동쪽 셀로 넘어가는 일이 결코 없습니다. 그러니 모든 띠는 자기 벽에 닿아 있습니다. 빛은 왼쪽 위에서 옵니다. 그림자는 한 면에 놓이고, 한 타일보다 짧으며, 1층 건물이든 2층 건물이든 같은 폭입니다(8절, 드리운 그림자).126311 행과 소품에 대한 규칙은 제 것입니다. 조사 자료는 패스를 각 건물의 열로 정의했고, 그 스크립트는 열을 건물의 경계 상자에서 가져왔으므로, 지붕이나 기단 행이 좁으면 띠가 벽에서 셀 세 개 떨어져 있었습니다.
  • 어디에 떨어지는가. 건물 일곱 채에는 모두 39개 행이 있습니다. 33개 행에서는 동쪽 셀이 땅으로, 잔디 28, 길 5이며, 그림자를 받습니다. 6개 행에서는 소품이 있고(길을 막는 것 5개와 house-mine의 기단 행 옆에 있는 꽃밭 1개), 자기 그림을 유지합니다.11 셀당 16행씩 4열이므로 그림자 픽셀은 2,112개입니다.4
  • 기단 아래에는 두지 않는다. 각 열에서 가장 아래 건물 셀 밑의 셀은 40개를 더하게 되며, 그중 35개가 땅입니다(길 22, 잔디 8, 포장석 5). 브리프는 그것들에 그림자를 두지 않습니다.114 정면은 뷰의 빛 쪽을 향하고 있고, Schlitter의 “one or two wall faces”(벽면 한두 개)에 대한 제 해석으로는 그곳에 띠가 있으면 건물이 떠 있는 것처럼 읽힐 것입니다.1163
  • 실행 시에 그리지 않고 구워 넣는다. 그림자는 땅 아틀라스에 들어갑니다. 시각에 따라 움직이지 않고(여기서 측정한 어느 게임도 그림자를 움직이지 않습니다), 밤에는 아무 비용도 들지 않습니다.12
  • docstring이 사실이 된다. buildings.py의 줄 “The ground shadow stays off the building: it belongs to the ground layer.”(땅 그림자는 건물에 붙이지 않는다. 그것은 땅 레이어에 속한다)는 그때 존재하는 것을 설명하게 됩니다.24

내보낸 문자 격자로 그린 Kiradex의 40×30 마을 도식. 건물은 보라색, 막힌 셀과 소품은 회색, 연못은 파란색, 걸을 수 있는 땅은 무지. 그림자를 받는 셀 33개, 곧 건물 행 가운데 그 행의 마지막 건물 셀 동쪽 셀이 땅인 것이 행마다 하나씩 주황색 테두리로 표시되어 있고, 각각 16픽셀 열 중 건물에 가장 가까운 4열에 주황색 띠가 칠해져 있다. 모든 띠는 자기 벽에 닿아 있고, 동쪽 셀에 소품이 있는 행에는 띠가 없다.

제안: 건물 그림자가 떨어지는 곳. town.json과 kiradex_proposals.txt 섹션 3에서. 렌더가 아니라 계획입니다.

인수 검사 8, 그림자. 포지 검사가 그림자 셀 33개를 세고, 서쪽 이웃이 같은 행의 같은 건물 셀이 아닌 그림자 셀, 잔디, 길, 포장석이 아닌 셀 위의 그림자, 그리고 4픽셀보다 넓은 띠를 거부합니다.1211 Pro Max 시뮬레이터에서 도착 시점, 어떤 탭보다도 먼저, -plazaHour 12, -plazaWeather clear, -airProbe로 실행한 캡처는 house-dawn의 다섯 행 모두 동쪽, 열 18의 길 위의 띠와, house-moss의 행 3과 4의 띠를 보여 주고, 소품이 서 있는 그 행 5의 동쪽에는 아무것도 보여 주지 않습니다. 그 프레임은 리그 자신의 기하로 카메라를 종이 위에서 재생한 데서 나옵니다. 수집가는 (19, 13)에 도착하고, 카메라는 월드 픽셀로 (312, 278)에 자리 잡으며, 뷰는 가로로 229.5부터 394.5까지 걸치므로, 그 띠들은 모두 25픽셀 이상의 여유를 두고 프레임에 들어옵니다. 프로브의 뷰와 월드 크기가 캡처를 판정하기 전에 재생의 165×358을 확인하고, 프로브의 프레임이 -airProbe 아래에서 그려지는 검사 3의 파이프라인 견본이 여기서 지목한 띠 어느 것과도 겹치지 않음을 확인합니다. 도착 시점에 띠들은 견본에서 144포인트 이상 떨어져 있습니다.276830 대신 testTheChimneysSmoke의 걷기를 따라 house-mine으로 가는 것은 되지 않습니다. 같은 방식으로 재생하면 그 걷기의 탭은 내보내기가 소품으로 표시한 셀에 떨어져 수집가가 움직이지 않으며, 도착 프레임에서 테스트가 할 수 있는 어떤 탭도 house-mine의 띠 전부를 너비 10.3타일인 뷰에 넣지 못합니다. 인접 규칙과 도착 프레임은 조사 자료의 검사를 제가 고친 것입니다.

8. 실내

Kiradex는 이미 Stardew를 따릅니다. 방과 홀은 광장과 같은 코드로, 같은 시계에서, 램프와 함께 다시 비춰지며, 그 시계는 오늘은 휴대폰의 것입니다(7절). 그것을 유지합니다(8절, 실내). 다만 7절이 밝힌 차이가 있습니다. Stardew는 플레이어가 있는 방의 빛을 플레이어가 나갔다 돌아올 때까지 붙들어 두고, Kiradex는 그것을 1분마다 다시 비추며, 이것은 Kiradex의 선택입니다.16 광장이 방의 시계로 옮겨 가도(항목 1) 방과 홀은 휴대폰의 시계에 남습니다. 광장 밖에서는 살아 있는 마을 글의 계약대로 수집가의 시계가 그 사람 자신의 것이고, 홀은 그 주석으로 “off the plaza”(광장 밖)의 장소이며 클라이언트 없이 만들어집니다. 휴대폰의 시간대와 방의 시간대가 다른 곳에서는 빛이 문간에서 바뀔 수 있으며, 코드는 이미 두 넘나듦 모두를 검은 베일 아래에 둡니다. 방과 홀에는 그것을 지나 들어가고, 광장은 “out of the door gone in by, the veil lifting”(들어간 문으로 나오며, 베일이 걷힌다)으로 돌아옵니다. 광장은 그 위에 겹쳐진 장소 아래에 머물고 그 LightClock도 함께이므로, 돌아오는 길에도 마지막 welcome이나 조용한 응답의 시간대와 타임스탬프를 간직하고 있습니다. 이 규칙은 제 것입니다.436919 그런 다음 Stardew의 다듬기 하나, 그 WindowLight를 더합니다. 방의 창이 바깥 시간대를 보여 주므로, 밤의 방은 창이 어둡기 때문에 어둡습니다.125369 포지의 interiors.py는 오늘 방의 창을 둘 그립니다. 평범한 창과 커튼 달린 창(window와 curtained_window로, 방 격자의 문자 N과 K로 놓입니다)입니다. 각 창유리에 대해 낮, 저녁, 밤 변형을 그리고, 각 창의 셀을 방과 함께 내보내게 됩니다. 리그는 선반과 책상을 그 셀 위에 겹치듯(addQuad) 시간대 변형을 각 창 셀 위에 겹치고, 스테이지의 relight()가 그것에 시간대를 넘깁니다. 이것은 모두 제안입니다.9220

인수 검사 9, 방. 포지 검사가 방 아틀라스에서 각 창유리의 세 변형을 찾고, 방 격자의 모든 N과 K에 대해 창 셀을 찾습니다. Pro Max 시뮬레이터에서 각각 따로 실행해 -plazaHour 22와 -plazaHour 12로 찍는 두 캡처가, 서버가 필요 없는 Me 탭의 me-room 버튼으로 플레이어 자신의 방에 들어가, 1층 셀 (3, 1)의 커튼 달린 창에 밤 유리와 낮 유리를 보여 줍니다. 같은 종이 위 재생에서, 방의 도착 지점 (7, 10)에서 뷰는 가로로 타일 2.34부터 12.66까지와 방의 높이 전체에 걸치므로, 그 창은 프레임에 들어오고 (12, 1)의 평범한 창은 가장자리에서 잘립니다.9227 이 검사는 제 것으로, 모든 항목이 검사를 갖도록 더했습니다.

9. Reduce Motion

PlazaStage는 환경에서 accessibilityReduceMotion을 읽고, -plazaHour처럼 실행하는 동안 고정되는 디버그 실행 인자 -plazaReduceMotion과 논리합을 취해, 그 결과를 다시 비출 때마다와 환경 값이 바뀔 때마다 Air.set(phase:season:weather:reduceMotion:)에 넘깁니다. 인자와 매개변수 모두 제안입니다. 켜져 있으면 비와 눈은 개수가 3분의 1로 줄고 절반 속도로 떨어지며(뷰 안에 비는 5방울, 폭우는 12방울, 초당 434픽셀), 잎, 반딧불이, 안개, 연기는 멈추고, 구름은 속도를 0으로 하여 멈춥니다. 빛은 컷하지 않습니다. 틴트는 30분 램프를 유지하고, 날씨는 1초 페이드를 유지하며, PlaceLight는 Reduce Motion 입력 없이 그것을 돌립니다. 제가 읽기에 밝기의 느린 변화는 이 설정이 겨냥하는 움직임이 아니며, 그것을 컷하면 느린 변화를 갑작스러운 변화와 맞바꾸게 됩니다. 비로의 페이드는 아틀라스의 낮 평균을 0.449에서 0.365로 만들며 60헤르츠에서 프레임당 0.0014인데, 컷은 0.084짜리 한 단계로 검사 6의 프레임당 한계 0.02의 네 배가 넘습니다.12864 조사 자료는 Reduce Motion 아래에서 날씨를 페이드 대신 컷하게 했고, 비, 눈, 잎, 반딧불이, 구름만 지목했습니다. 이 항목과 검사 6이 맞도록 페이드를 유지한 것, 그리고 7절이 설정과 상관없이 움직인다고 찾은 안개와 연기를 멈춘 것이 제 변경입니다. Stardew의 눈 투명도 설정이 플레이어에게 날씨를 약하게 할 수 있게 하는 선례입니다.17

인수 검사 10, Reduce Motion. SwiftUI의 환경 값은 읽기 전용으로 var accessibilityReduceMotion: Bool { get }이라고 선언되어 있으므로, 앱도 테스트도 그것을 설정할 수 없습니다. 바꿀 수 있는 것은 시스템 설정뿐입니다.86 그래서 항목 9는 -plazaReduceMotion을 더합니다. -plazaHour 12, -plazaWeather rain, -plazaReduceMotion, -airProbe로 실행한 UI 테스트가, 빗방울 개수(항목 4)와 구름의 흐름(항목 6)을 실어 나르는 공기의 보고가 빗방울 5 ± 1개와 흐름 0을 읽기를 기다립니다. 검사 6의 단위 테스트가 페이드가 그 한계 아래로 유지됨을 보여 줍니다. 페이드에는 그것을 바꿀 Reduce Motion 입력이 없기 때문입니다. 한 번은 손으로, 시뮬레이터의 설정에서 Reduce Motion을 켜면 같은 보고가 인자 없이 같은 개수를 보여 줍니다. 처음 쓰인 그대로는 검사가 비 로그를 읽었는데, 테스트 안의 어느 것도 설정을 켜지 않습니다.1219

10. 이름과 그림

10월 5일 시점에 앱에는 거부 목록이 없었습니다. 이 항목의 조사 자료 판은 날씨 그림이 “the deny list”(거부 목록)를 통과한다고 말하며, 그것을 요구하는 경로 글은 “The deny list does not exist yet”(거부 목록은 아직 존재하지 않는다)라고 말하고 그것을 만드는 일을 자기 브리프의 일부로 삼습니다. 10월 5일에 Kiradex 저장소를 검색해도 그런 목록은 없었습니다.1293 그래서 이 항목은 10월 5일에 할 수 있었던 것과 그 목록을 기다리던 것을 말합니다. 목록은 그 뒤 추가되었습니다(이 절의 첫머리).

  • 문자열. 새 문자열은 다섯 상태의 상태 문구와 게시판 줄입니다. 그것들은 경로 브리프가 요구하는 거부 목록을 통과합니다. 그 목록은 10월 5일에 없었고, 지금은 저장소가 scripts/forge/protected_names.txt로 가지고 있습니다. 또 공개된 유일한 목록, 오마주 글의 “Never” 목록과도 대조하며, 그 두 번째 항목은 어떤 기능도 써서는 안 되는 프랜차이즈 어휘를 지목합니다.10
  • 그림. rain.png, splash.png, snow.png, 그리고 창유리는 포지가 그리며, 같은 목록의 첫 항목에 비추어 검토합니다. 그것은 “taken, traced or redrawn from any Pokémon game”(어떤 포켓몬 게임에서든 가져오거나, 따라 그리거나, 다시 그린) 타일, 스프라이트, 팔레트를 거부합니다.10
  • 팔레트. Daylight나 Weather의 어떤 색 값도 0~1로 스케일한 pokecrystal 팔레트 색과 같지 않습니다. 순수한 흰색만은 예외입니다. 흰색은 그림을 그려진 그대로 두는 곱셈이지 누군가에게서 가져온 색이 아닙니다. 오늘의 낮 틴트와 여름 색조는 흰색이고(Daylight.swift 안), 흰색은 Crystal의 배경과 사람 팔레트에도 있으므로, 조사 자료가 쓴 그대로의 규칙으로는 출시된 그대로의 앱이 실패하게 됩니다. 예외는 제 정정입니다.122821

인수 검사 11, 이름과 그림. 새 단위 테스트 KiradexTests/NamesTests.swift가 오마주 글 “Never” 항목 2의 용어를 테스트 타깃 안의 목록으로 가지고, 어느 상태의 상태 문구에도, 어느 게시판 줄에도 대소문자를 무시하고 그것이 들어 있지 않음을 검증합니다. 그 항목이 “Poké-anything”(Poké로 시작하는 무엇이든)을 거부하듯, “Poké”로 시작하는 모든 단어를 거부합니다. 같은 테스트는 10월 5일에는 존재하지 않던 저장소의 거부 목록도 읽습니다. 그날은 실행할 수 없었던 검사의 절반이며, 지금은 scripts/forge/protected_names.txt입니다. 파일은 KiradexTests에 테스트 리소스로 번들하고, 그 항목들(한 줄에 하나, # 줄은 건너뜀)을 파일 헤더가 말하는 대로(“matched without regard to case as a whole word or phrase”(대소문자와 상관없이 단어나 구 전체로 맞춘다)) 대소문자와 상관없이 단어나 구 전체로 맞춥니다. 번들은 제 제안입니다.89 스크립트가 Daylight.swift와 Weather.swift의 모든 색 상수를 0~1로 스케일한 bg_tiles.pal, npc_sprites.pal, roofs.pal의 모든 색과 비교해, 순수한 흰색 말고는 일치가 없음을 찾습니다. 스크립트는 저자의 증거 폴더에서 디컴파일 클론 옆에서 돌므로, 같은 “Never” 목록의 네 번째 항목이 요구하듯 디컴파일 데이터는 앱에도 포지에도 들어가지 않습니다. 10월 5일에 출시된 Daylight.swift에 대해 돌리면, 그 색 상수 8개와 세 파일의 404색 사이에서 일치 두 개를 찾습니다. 둘 다 순수한 흰색으로 낮 틴트와 여름 색조이며, 다른 것은 없습니다. 그 밖에 가장 가까운 쌍은 한 채널에서 5비트로 꼭 한 단계 떨어져 있습니다. 그림의 검토는 각각의 캡처와 함께 기록합니다.121028 처음 쓰인 그대로는 검사가 그림에, 10월 5일에는 앱에 없던 거부 목록을 통과하게 했습니다.

이 브리프에 넣지 않는 것

  • 플레이어의 실제 날씨. WeatherKit은 광장을 날씨 앱으로 만들고, 플레이어의 위치를 필요로 합니다. 정전의 날씨는 세계의 것이며, 예정되고 공유됩니다(8절, 날씨의 일정).8712
  • 해를 따라 움직이는 그림자, 스프라이트에 비추는 점광원, 피사계 심도. HD-2D 단계는 그 프로듀서 자신의 말로 “costs more than you’d think”(생각보다 비용이 든다)이고, 세계 글이 기록했듯 그 플레이어들은 흐림 효과를 끕니다.5932 여기서 측정한 어느 게임도 시각에 따라 그림자를 움직이지 않으며, 스테이지는 이미 피사계 심도를 꺼 두었습니다.19
  • 번개 섬광(항목 5)과 모든 가로등의 깜박임. 다만 깜박임이 검사 6을 통과하고 Reduce Motion 아래에서 멈춘다면 예외입니다.12
  • Crystal의 팔레트, Emerald의 비, 안개, 물보라 스프라이트, 그리고 그 날씨 이름. 메커니즘만 가져옵니다.1210
  • 정각의 컷. 강제된 -plazaHour 아래에서만 예외입니다.12

핵심 요약

그림을 그린다면

  • 밤은 두 번째 타일 세트가 아니라 팔레트로 그리십시오. Crystal은 빛을 약 절반 남기고(팔레트 블록에서는 각 팔레트 낮 루마의 0.41~0.68, 마을이 표시하는 상태에서는 맵 그룹별 평균 0.49~0.54), 밤에는 일곱 월드 팔레트 중 다섯에서 푸른 회색의 가장 밝은 색 하나를 공유하며, 마을의 물은 거기서 한 단계 떨어져 있습니다.1
  • 아침은 더 따뜻한 흰색으로 하고 그 이상은 하지 마십시오. Crystal이 아침을 위해 바꾸는 것은 32색 중 5색이며, 모두 가장 밝은 색입니다.1
  • 불 켜진 것에는 어둠을 거부하는 색을 주십시오. Crystal의 YELLOW는 다른 모든 것이 0.6 아래로 떨어질 때도 0.90에 머뭅니다. Kiradex의 불빛 셀은 틴트를 입은 가장 밝은 픽셀 0.562에 맞서 0.901에 있습니다(Mac에서 읽은 것이지 iPhone에서 측정한 것이 아닙니다).19
  • 드리운 그림자는 짧게, 한 톤으로, 한두 면에, 높이와 상관없이 같은 길이로 두고, 검정이 아니라 파랑 쪽으로 기울이십시오.86365

엔진을 만든다면

  • 사람을 틴트에서 빼거나, 거의 빼십시오. Crystal과 Emerald 둘 다 그렇게 하며, 서로 다른 두 메커니즘으로 합니다.15
  • 빛을 시계로 계산해 램프로 만들고, 사람들이 열어 두는 화면 위에서 컷하지 마십시오. 30분 램프는 Kiradex의 0.108짜리 컷을 0.0036의 단계로 바꿉니다(아틀라스 평균 루마로, Mac에서 읽은 것).11
  • 빛을 방의 시계로 돌리고, 자기 경계를 스스로 예약하며, 휴대폰의 경계를 위해서는 시스템의 시각 건너뜀 알림을 관찰하십시오. 다음 1분을 기다리지 마십시오.438384
  • 가산 빛은 어둡게 할 수 없습니다. RealityKit의 두 블렌드 모드에서 움직이는 그림자는 알파 시트이고, 고정된 그림자는 아틀라스에 속합니다.7866
  • 공기를 움직이는 모든 파일에서 Reduce Motion을 읽으십시오.869

루프를 설계한다면

  • 날씨를 플레이어의 실제 하늘이 아니라 세계의 예정된 속성으로 만들고, 하루 한 번 굴려 미리 알리십시오. Emerald에도 FireRed에도 비로 태어나는 야외 맵은 없습니다.517
  • 날씨는 약 1초에 걸쳐 페이드인하고, 부드럽게 유지하십시오. Emerald의 비는 빛의 13/16입니다.5
  • 번개 섬광은 빼십시오. 정전의 폭풍은 W3C의 문턱을 통과합니다. 아이들이 이 마을에서 오랜 시간을 보낼 수 있다는 제 전제에서는, 그것을 시험해 볼 필요가 없습니다.446
  • 실내가 하루를 따를지 정하십시오. Crystal은 208개 중 207개에서 아니라고 하고, Stardew는 그렇다고 합니다. 하나를 골라 지키십시오.116

자주 묻는 질문

포켓몬 Gold, Silver, Crystal의 낮밤 주기는 어떻게 작동합니까?

이 글이 읽는 세 작품 중 Crystal에서는 실시간 시계가 하루를 4:00부터의 아침, 10:00부터의 낮, 18:00부터의 밤, 6시간, 8시간, 10시간으로 나눕니다. 각 부분은 배경 팔레트 여덟 개, 오브젝트 팔레트 여덟 개, 그리고 야외에서는 지붕 색으로 된 자기만의 세트를 가지며, 부분이 바뀌면 게임은 그것들을 페이드 없이 한 프레임 안에 다시 불러옵니다. 시계를 따르는 것은 마을, 도로, 동굴 하나뿐입니다. 실내 맵 208개 중 207개는 낮에 고정되고, 27개 맵(그중 24개가 CAVE 맵)은 영원한 밤입니다.2134

포켓몬 Emerald에는 낮밤 주기가 있었습니까?

빛에 대해서는 없습니다. Emerald에도 FireRed에도 소스에 시간대 시스템이 없으며, Emerald의 시계는 나무열매와 매일의 이벤트를 움직입니다. Emerald에 있는 것은 날씨 값 18개로, 맵마다, 그리고 트리거로 설정됩니다. 비, 뇌우, 호우, 그늘, 안개, 재, 모래바람, 가뭄 등이 있고, 비는 풍경을 약 13/16로 어둡게 하며 사람들은 제 색을 지킵니다.510

포켓몬 Emerald의 비는 어떻게 작동합니까?

비는 빗방울 스프라이트 10개, 뇌우는 16개이며, 각각 초당 868픽셀, 수직에서 26.6도로 18프레임 떨어진 뒤 7프레임 물보라가 됩니다. 호우의 24방울은 초당 1,336픽셀로 12프레임 떨어진 뒤 10프레임 물보라가 됩니다. 팔레트는 1.00초에 걸쳐 원래 값의 약 0.81인 컬러 맵으로 페이드하지만, 플레이어와 마을 사람의 것은 예외입니다. 맑은 하늘에서 플레이 도중 비로 들어가면, 시트와 빗방울 스프라이트 24개를 준비하고 빗방울을 9프레임마다 하나씩 활성화한 뒤, 비의 경우 변화 후 115프레임, 1.9초에 빗방울이 모두 자리를 잡습니다. 헤더가 비인 야외 맵은 없습니다. 비는 5개 맵의 좌표 트리거, 몇몇 스크립트, 그리고 Route 119와 123의 나흘 주기에서 옵니다.57

타일을 다시 그리지 않고 픽셀 아트 게임에서 낮과 밤을 만들려면 어떻게 합니까?

하루의 부분마다 장면에 틴트를 곱하거나 팔레트를 바꾸고, 불 켜진 것은 거기서 빼십시오. Crystal의 밤은 빛을 약 절반 남기고 파래집니다. Kiradex는 틴트 네 개를 곱하고, 불 켜진 창을 틴트 없는 두 번째 메시로 그리며, 땅에는 가산 빛 웅덩이를 둡니다. 틴트 사이는 컷하지 말고 램프로 잇고, 캐릭터를 장소보다 밝게 남기십시오.196611

탑다운 픽셀 아트에서 그림자는 어떻게 그립니까?

짧게, 한 톤으로, 자기 레이어에 그립니다. Emerald의 그림자 스프라이트는 어떤 크기에서든 다섯 행의 단색입니다. Raymond Schlitter는 드리운 그림자를 은은하게, 별도 타일에, 한두 면에, 벽이 아무리 높아도 같은 길이로 둡니다. Koichi Ishii는 검정 대신 깊은 파랑과 보라를 썼습니다. 가산과 알파 블렌딩만 있는 엔진에서 고정된 그림자는 그림에 속합니다.862636578

픽셀 아트 게임은 플레이어의 실제 날씨를 써야 합니까?

정전의 답은 아니라는 것입니다. Emerald의 날씨는 그 맵과 날들에 속하고, Stardew는 골짜기 전체에 하루 한 가지 날씨를 굴려 전날 텔레비전으로 알립니다. 실제 날씨는 플레이어의 위치를 필요로 하고, 공유된 세계를 개인의 일기 예보로 바꿉니다. 구역과 날짜를 열쇠로 하는 매일의 굴림은 한 장소의 모두에게 같은 하늘을, 미리 알 수 있게 줍니다.5178711

게임 속 번개는 발작 위험이 있습니까?

섬광은 그럴 수 있습니다. W3C의 성공 기준 2.3.1은 섬광이 일반 섬광과 적색 섬광 문턱 아래에 있는 경우가 아니라면 어느 1초에든 세 번 이하라는 기준을 정하고, 번쩍이는 콘텐츠가 편두통, 어지럼증, 메스꺼움, 발작을 일으킬 수 있다고 말합니다. 측정한 Emerald의 폭풍은 1초 안에 번개 둘을 담는 일이 결코 없습니다. Kiradex의 브리프는 섬광을 아예 뺍니다.464


이 글을 만든 방법. 바탕이 된 조사 자료는 2026년 10월 5일에 정리했습니다. pret 디컴파일 네 개의 얕은 클론을 출력과 함께 저장한 파이썬 스크립트 다섯 개로 측정했고, 그 밖에 저장한 Stardew Valley 위키의 하루, 날씨, 맵 페이지, 현대의 조명이 들어간 픽셀 게임에 관한 페이지 여덟 개(인터뷰, 개발자의 글, 보도 자료, 뉴스 기사, Wikipedia의 HD-2D 문서), Pixelblog 세 편, 성검전설 3에 관한 번역 인터뷰 한 편, 섬광에 관한 W3C의 페이지, 그리고 여섯 번째 스크립트로 읽은 Apple 문서 페이지 열한 개를 썼습니다. 게시 전에 전부 다시 실행했습니다. 둘은 저장된 출력을 바뀌지 않은 채 돌려주었습니다. 제안 스크립트는 건물 그림자를 행별로 놓기 위해, 젖은 기간을 10절이 정의하는 대로 세기 위해, 그리고 Kiradex의 걷기를 초당 4타일로 이어받지 않고 앱의 소스에서 읽기 위해 고쳤습니다. Emerald 스크립트의 비 라벨은 생성 카운터의 한도를 주기로 출력했기에 고쳤습니다. Crystal 스크립트에는 페이드 루틴 호출부의 전수 조사를 더했고, 맵 헤더 파서는 음악 필드가 식인 헤더 다섯 개를 빠뜨렸기에 고쳤으며, 이제 각 환경이 표시하는 팔레트 세트도 풀어냅니다. 그리고 Kiradex 스크립트의 구름 줄에서 같은 이어받은 걷기를 뺐습니다. 바꾼 각 스크립트의 이전 버전과 출력은 옆에 남겨 두었습니다. 일곱 번째는 브리프의 캡처 검사가 마을과 방을 어떻게 프레임에 담을지 종이 위에서 재생하고, 여덟 번째인 arith.py는 모든 파생 수치를 출력하며, 아홉 번째는 앱의 색 상수를 Crystal의 팔레트와 비교하고, 열 번째는 Emerald의 비 준비와 천둥 주기를 소스에서 호출 단위로 재생하며, 열한 번째는 수집가의 프레임 중 수집가 자신이 얼마나 덮는지를 셉니다. 본문의 모든 포켓몬 수치는 스크립트의 출력이며, 각 주석이 그 스크립트를 밝힙니다. Kiradex의 모든 수치는 Mac에서 소스로 읽었거나 내보낸 그림으로 계산한 것이며, iPhone에서 캡처한 것은 없습니다. 10절의 제안은 제 것이고 그렇게 표시했습니다. 그 어느 것도 아직 만들지 않았습니다.

이 사이트의 관련 글: iPhone에서 만드는 픽셀 아트 세계: 16비트 거장들이 알고 있던 것은 이 시리즈의 첫 글로, RealityKit 레시피, 조명 단계표, 법적 경계를 다룹니다. 픽셀 아트 건물: iPhone에서 짓는 집, 홀, 실내는 불 켜진 창을 만들고 roofs.pal과 NightTiles를 읽었습니다. 옛 포켓몬 게임을 빌리지 않고 기리는 법은 Kiradex의 네 시간대를 Crystal의 시각에 비추어 정했습니다. 픽셀 아트 인물: iPhone의 캐릭터와 크리에이터는 비의 크기를 맞추는 기준이 되는 뷰를 측정했습니다. 픽셀 아트의 움직임: iPhone에서의 걷기, 카메라, 문에는 공기를 재는 기준이 되는 걷기가 있습니다. 아무도 접속하지 않아도 살아 있는 픽셀 마을: NPC와 유령은 빛이 따르게 될 방의 시계를 제안합니다. 픽셀 아트 방: 가구 그리드, 상한, 채점은 항목 8이 그 창을 시각에 따라 밝히게 될 방입니다. 픽셀 아트의 길: iPhone에서 만드는 맵 연결과 구역은 만들어진다면 매일의 날씨가 함께 덮게 될 광장 너머의 세계입니다. 그리고 픽셀 아트의 턱, 계단, 다리: 타일로 만드는 세계의 높이는 땅에 남는 점프의 그림자를 측정했고, 빛 속에서 높이를 읽는 일에 대한 Sabotage Studio의 Thierry Boulanger의 말을 인용합니다.

출처


  1. 저자의 측정, 2026년 10월 5일: measure_gen2_daylight.py(이 글을 위한 저자의 증거 폴더), 출력 gen2_daylight.txt(그리고 gen2_yellow_tiles.png. 저작권이 있는 그림에서 파생한 타일 세 개의 4배 렌더로, 분석용으로 보관하며 공개하지 않음). 섹션: A, 시각(constants/misc_constants.asm과 engine/rtc/rtc.asm의 TimesOfDay 표). B, gfx/tilesets/bg_tiles.pal의 시각별 배경 팔레트, 파일의 블록 그대로(아침, 낮, 밤, 어둠, 실내에서 각 팔레트 네 색의 평균 루마. 밤 대 낮. 시각별 색 0. 아침이 바꾸는 색. 파랑에서 빨강과 초록의 평균을 뺀 값. 밤이나 어둠에서 루마 0.6을 넘는 색). B2, 맵이 표시하는 팔레트 세트: data/maps/environment_colors.asm의 환경과 시각별로 파일의 팔레트 42개를 가리키는 인덱스 여덟 개(야외 세트의 WATER는 야외 쌍에서 가져옴)와, 맵 그룹별로 gfx/tilesets/roofs.pal에서 가져오는 LoadMapPals의 지붕 복사(야외 세트의 루마와 밤 대 낮. 표시되는 물, 그 밤 가장 밝은 색과 그 비. (15, 14, 24)를 공유하는 팔레트 다섯 개. 아침 대 낮. 파랑 치우침. 0.6을 넘는 색. 마을이나 도로를 가진 맵 그룹 25개, 그에 걸친 표시되는 ROOF의 비, 그리고 그룹별 일곱 월드 팔레트의 평균 비. 실내 세트). C, gfx/overworld/npc_sprites.pal의 오브젝트 팔레트(낮에서 밤과 어둠으로 어느 색이 바뀌는지). D, gfx/tilesets/roofs.pal(항목 27개, 맵 그룹별 밤 대 낮). E, engine/tilesets/timeofday_pals.asm의 _TimeOfDayPals, _UpdateTimePals, 네 페이드, 필드 루프, 각 페이드를 무엇이 부르는지의 전수 조사(data/maps/setup_scripts.asm의 각 맵 준비 스크립트의 페이드. db -1이 없는 스크립트는 다음 스크립트로 따라감. 밟은 워프, 공중날기, 스크립트 명령 warp가 어느 준비 상수로 불러오는지. home/map.asm의 메뉴 페이드. timeofday_pals.asm 밖의 모든 .asm에 있는 페이드의 special, farcall, mapsetup을 파일별로 센 것. 검은색 쌍의 맵 스크립트 열한 개와 그 줄 번호), 배경 팔레트를 LoadSpecialMapPalette가 LoadMapPals에게서 넘겨받는 타일셋 여섯 개(맵 헤더에서 환경별로 셈), 그리고 그 팔레트를 실제로 불러오는 맵(TILESET_ICE_PATH 위의 INDOOR 맵인 명예의 전당은 제외. INDOOR 맵 74개, 모두 PALETTE_DAY이며 그중 57개가 TILESET_HOUSE 위, 그리고 CAVE 5개), 시작 메뉴 자신의 줄(StartMenu, 그 .Exit, 그 UpdateTimePals 호출, 그 항목 중 어느 것이 FadeToMenu를 부르는지), 그리고 mobile/과 home/map.asm 밖의 모든 call FadeToMenu를 파일별로. F, data/maps/maps.asm의 맵 헤더 388개를 환경과 팔레트 모드별로. 각 map 지시문을 쉼표로 나누고 모든 지시문이 소비되었음을 검증함(이전 파서는 한 단어짜리 필드 여덟 개에 맞추어, 음악 필드가 식인 라디오 타워 헤더 다섯 개를 빠뜨렸으므로 헤더 383개, INDOOR 맵 203개 중 202개가 낮, 383개 중 78개가 시계를 따름, 20.4%로 출력했음. 지금은 388, 208개 중 207개, 388개 중 78개, 20.1%). G, 성도 타일셋의 팔레트 맵, gfx/tilesets/johto_palette_map.asm. 루마는 0~1로 스케일한 5비트 값에 Rec. 601을 적용한 것으로, 감마 없음. 입력: pret pokecrystal, 5beda23. 게시 전 재실행: 섹션 A~D와 G, 그리고 타일 렌더는 전과 같이 출력. 섹션 E에는 페이드 전수 조사, 메뉴 전수 조사, 특별한 표를 받는 맵의 수를 더했고, B2와 F의 고친 파서는 이후 개정에서 더했으며, 이전 스크립트와 출력은 옆에 남겨 둠. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. pret, pokecrystal/constants/misc_constants.asm, 5beda23(MORN_HOUR EQU 4, DAY_HOUR EQU 10, NITE_HOUR EQU 18, 36~38행)와 pokecrystal/engine/rtc/rtc.asm(TimesOfDay, 48행, 50행에 주석 “0400-0959 morn | 1000-1759 day | 1800-0359 nite”), 2026년 10월 5일 열람, https://github.com/pret/pokecrystal/blob/master/engine/rtc/rtc.asm ↩↩↩↩↩

  3. pret, pokecrystal/engine/tilesets/timeofday_pals.asm, 5beda23, 2026년 10월 5일 열람: _TimeOfDayPals(13행), _UpdateTimePals(109행, ld c, $9 ; normal, 이어서 GetTimePalFade와 DmgToCgbTimePals), FadeInFromWhite(115), FadeOutToWhite(122), FadeInFromBlack(146), FadeOutToBlack(153), ReplaceTimeOfDayPals(189, 206행에서 STATUSFLAGS_FLASH_F를 검사), https://github.com/pret/pokecrystal/blob/master/engine/tilesets/timeofday_pals.asm ↩↩↩↩↩

  4. 본문의 측정값에서 낸 저자의 산술: arith.py(이 글을 위한 저자의 작업 폴더), 출력 arith.txt. 이 글을 위한 저자의 증거 폴더에 있는 출력을 읽고, 읽기 전용으로 Kiradex가 내보낸 town.png와 glow.png를 읽음. 출력하는 것: 프레임 속도(2^24 ÷ 280,896과 2^22 ÷ 70,224, 둘 다 59.7275헤르츠). 시각과 하루 중 비율(밤은 24 중 10, 41.7%. Kiradex의 가로등은 13시간, 54.2%). Stardew의 하루(20 × 60 × 0.7 = 840초, 14분. 해 질 녘은 오전 6시부터 실제 9.8, 9.1, 8.4분 뒤). Crystal의 팔레트별 밤 대 낮과 그 평균(0.511), 파랑 치우침의 변화(6.44, 31의 0.208), 색 (15, 14, 24)의 루마 0.498, (30, 30, 11)의 0.898, (27, 31, 27)의 0.947, (28, 31, 16)의 0.916, gen2_daylight.txt 섹션 B2에서 가져온 표시되는 야외 물(낮 0.528, 밤 0.248, 0.470. 그 밤 가장 밝은 색 (15, 13, 27), 0.490), 마을이 표시하는 상태에서 일곱 월드 팔레트의 맵 그룹별 밤 대 낮(0.494~0.539, 25개 그룹 평균 0.509), 표시되는 ROOF의 비(0.369~0.688, 평균 0.477)와 표시되는 파랑 치우침(−1.17~+6.10, 7.27 상승), 아침의 32 중 5(15.6%), YELLOW의 타일 192개 중 3개(1.6%), 다시 불러오기의 64 + 64 + 4 = 132바이트, 페이드의 8프레임(134밀리초), 섹션 F에서 파싱한 맵 헤더(388. 시계를 따르는 맵 388개 중 78개, 20.1%. 낮에 고정된 실내 208개 중 207개. 영원한 밤 맵 27개를 환경별로 CAVE 24, DUNGEON 1, GATE 1, INDOOR 1. 이전의 383, 383개 중 78개, 203개 중 202개를 옆에 적음). Emerald의 13/16(0.8125), 31, 16, 8에서의 맵 3, 비의 페이드(60프레임, 1.005초), 비와 호우의 속도, 낙하, 물보라(262와 268픽셀, 0.301과 0.201초, 7과 10프레임, 0.117과 0.167초, 빗방울의 수명은 25프레임, 0.419초), 생성 주기(지연 + 1: 9와 5프레임), 활성 빗방울 0개부터의 활성화 단계(90, 80, 120프레임, 1.51, 1.34, 2.01초), 그리고 gen3_replay.txt에서 가져온 플레이 중 맑은 하늘로부터의 완전한 전환(준비 호출 25번 + 활성화: 115, 105, 145프레임, 1.93, 1.76, 2.43초. 프레임 59에 맵 3에 있는 팔레트. 프레임 109의 뇌우 첫 번개. 비에서 비로의 개수), 초당 59.73픽셀 걷기에 대한 구름, 안개, 모래바람(0.500, 0.250, 3.60), 천둥의 기다림, 유지, 간격을 초로, 간격 타이머에 1을 더한 어두운 간격(61~76프레임, 1.021~1.272초. 61프레임을 1.0213초로 하여, 번개 시작은 최소 67프레임 떨어짐), 주기 첫 번개까지의 기다림(361~720프레임), 천둥 그림의 타임라인, 그리고 번개 뒤 천둥소리의 지연(1~20프레임, 최대 0.335초. 1~100, 최대 1.674). 야외 헤더의 비율(68개 중 51개, 75.0%. 76개 중 66개, 86.8%)과 좌표 이벤트 86개. 플래시의 원(1,810과 16,286제곱픽셀, 38,400의 4.7%와 42.4%, 면적은 아홉 배). 그림자 스프라이트의 불투명 비율과 Kiradex의 것(48개 중 40개, 알파 153 = 0.60, 루마 0.071). 각 틴트 아래 Kiradex의 아틀라스(0.4318, 0.4488, 0.3719, 0.2639), 틴트를 입은 가장 밝은 픽셀에 대한 불빛 셀(1.60), 컷 네 개(0.0170, 0.0769, 0.1079, 0.1678)와 각 경계에서 30분 램프의 분당 최대 단차(0.0006, 0.0026, 0.0036, 0.0056). 틴트를 통째로 더한 가로등 웅덩이의 중심(0.806)과 그림의 최댓값 0.961로 가중한 것(0.785). 7 + 17 = 24개의 웅덩이. Motion.swift에서 읽은 오늘의 걷기(초당 60으로 16틱에 16픽셀, 초당 60픽셀. 달리기는 120), 구름의 초당 1.640픽셀(걷기의 0.0273, 타일당 9.8초, 16보다 9.75배 느림), 걷기에 대한 제안의 초당 16픽셀(0.2667), 뷰 높이와 같은 거리를 22.4초, 그리고 다이제스트의 다섯 번째 바이트로 다시 계산한 2027년 1월 1일의 방향(153, 215.15625도. 수직 성분은 초당 9.21293픽셀로 358픽셀 높이를 38.86초에 가로지르고, 수평 성분은 13.08136으로 165픽셀 너비를 12.61초에 가로지름), 불투명도 0.55와 0.8에서의 그 그늘(가장 짙은 것 0.763과 0.655, 평균 0.950과 0.927)과 흐린 날(0.404). 59,070제곱픽셀(1.538화면)의 뷰와 그 안의 빗방울. 아틀라스 위의 비와 폭우(0.365, 0.214. 0.337, 0.198). 시간대별 걷는 이의 끌어올린 빛(0.980, 1.000, 0.913, 0.796. 밤에는 장소의 1.34배). 날씨 1년의 젖은 비율. Reduce Motion의 3분의 1과 절반(5방울, 12.3, 초당 434픽셀). 건물 그림자의 33 × 4 × 16 = 2,112픽셀(잔디 28, 길 5, 소품 때문에 건너뛴 행 6)과 기단 아래 셀 40개, 그중 35개가 땅. 비와 폭우로의 페이드의 프레임당 값(컷으로는 0.084와 0.112. 60헤르츠에서 프레임당 0.0014와 0.0019, 120헤르츠에서 0.0007과 0.0009). 1초 페이드가 할당하는 장소 머티리얼을 코드에서 센 것(다시 비추기에 3, 물결에 초당 12, 페이드 동안 60헤르츠에서 180, 120헤르츠에서 360. 문이 보이면 다시 비추기에 4, 페이드 동안 240과 480. 이 줄은 2026년 10월 16일에 추가). 날씨 1년의 젖은 날과 기간(82일, 17 + 19 + 21 + 25. 기간 65개, 가장 긴 것 3). Celeste의 (2048 ÷ 256)^2 = 64슬롯 × 4 = 256. 그리고 저장한 MaterialParameterTypes.BlendMode 페이지의 열거 케이스 두 개로, 토픽 목록에서 읽은 것(parse_apple.py는 이것을 출력하지 않음). 헤더 수를 이어받지 않고 스크립트에서 읽기 위해, 표시되는 팔레트, 비의 완전한 전환, 천둥 간격, 구름의 비와 가로지르는 시간을 더하기 위해, 그리고 오늘의 걷기를 초당 64픽셀로 이어받지 않고 앱의 Motion.swift에서 읽기 위해 개정함. 이전 스크립트와 출력은 옆에 남겨 둠. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  5. 저자의 측정, 2026년 10월 5일: measure_gen3_weather.py(이 글을 위한 저자의 증거 폴더), 출력 gen3_weather.txt. 섹션: A, include/constants/weather.h의 상수. B, src/field_weather_effect.c의 각 날씨의 InitVars와 블렌드 목표. C, src/field_weather.c의 BuildColorMaps를 파이썬으로 재생한 것, sBasePaletteColorMapTypes, include/event_object_movement.h의 팔레트 슬롯. D, 비의 Q28.4 속도, 낙하 시간, 물보라 프레임, 생성 주기(UpdateVisibleRainSprites의 ++rainSpriteVisibleCounter > rainSpriteVisibleDelay, 지연 + 1프레임마다 한 방울, 그리고 한 프레임 안에서의 Rain_InitAll의 루프). E, 구름, 안개, 모래바람의 흐름(모래바람은 src/trig.c의 gSineTable로 6,000프레임 재생). F, 천둥의 타이밍. G, Emerald와 FireRed의 모든 data/maps/*/map.json의 헤더 날씨를 맵 종류별로, 좌표 날씨 이벤트, 두 도로 주기, data/**/*.inc의 스크립트 setweather 호출, 그리고 requires_flash 맵. H, sFlashLevelToRadius와 기본 플래시 레벨. I, src/*.c와 include/**/*.h에서 “timeofday”와 “time_of_day”의 대소문자 구분 없는 이름 검색. 입력: pret pokeemerald, 731ad5b와 pokefirered, 037335f. 게시 전 재실행: D의 마지막 줄을 빼고 모든 섹션이 전과 같이 출력. 그 줄의 라벨은 rainSpriteVisibleDelay 자체를 생성 주기(8과 4프레임마다)로 출력했으나, 지금은 지연 + 1(9와 5프레임마다)을 다 차는 시간과 함께 출력함. 이전 스크립트와 출력은 옆에 남겨 둠. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  6. pret, pokeemerald/src/field_weather.c, 731ad5b, 2026년 10월 5일 열람: sWeatherFuncs(85행, 각 날씨의 initVars, main, initAll, finish), sBasePaletteColorMapTypes[32](114행), StartWeather(154), SetNextWeather(183), Task_WeatherInit(216, 화면 준비가 끝나면 222행에서 날씨의 initAll을 부름), Task_WeatherMain(227: 현재 날씨와 다음 날씨가 다른 동안, 이전 날씨의 finish()를 매 프레임 false를 돌려줄 때까지 부르고(231행), 그다음 새 날씨의 initVars()(235행), colorMapStepCounter = 0(236행), WEATHER_PAL_STATE_CHANGING_WEATHER(237행). 그렇지 않으면 날씨의 main()(244행). 어느 쪽이든 그 뒤에 팔레트 상태 함수(247행)), BuildColorMaps(271), UpdateWeatherColorMap(344, 354행에서 ++colorMapStepCounter >= colorMapStepDelay일 때 컬러 맵을 진행), ApplyColorMap(459). 그리고 include/constants/field_weather.h 4행, MAX_RAIN_SPRITES 24, https://github.com/pret/pokeemerald/blob/master/src/field_weather.c ↩↩↩↩↩↩

  7. pret, pokeemerald/src/field_weather_effect.c, 731ad5b, 2026년 10월 5일 열람: 구름 좌표의 주석 “These coordinates are for the lower half of Route 120.”(이 좌표는 Route 120의 아래쪽 절반을 위한 것)(41행), Clouds_InitVars(95), UpdateCloudSprite의 주석 “Move 1 pixel left every 2 frames.”(2프레임마다 왼쪽으로 1픽셀 이동)(222), sRainSpriteSplashAnimCmd(414), sRainSpriteMovement(449), sRainSpriteFallingDurations(458), Rain_InitVars(471), Rain_InitAll(484, weatherGfxLoaded까지의 루프), Rain_Main(491: 그 세 상태, 496행의 시트, 500행에서 false를 돌려줄 때까지의 CreateRainSprite, 504행에서 false를 돌려줄 때까지의 UpdateVisibleRainSprites), Rain_Finish(513, 다음 날씨가 비 종류이면 곧바로 false를 돌려주고 스프라이트를 유지, 518~524), CreateRainSprite(665: 24개가 있으면 false를 돌려줌, 670~671, 호출당 스프라이트 하나를 만들고, 24번째를 만드는 호출에서 false를 돌려줌, 694~709), UpdateVisibleRainSprites(714, 활성 개수가 목표에 이르면 false를 돌려줌, 716~717, 그리고 ++rainSpriteVisibleCounter > rainSpriteVisibleDelay일 때 빗방울을 활성화, 719행), Sunny_Finish(168, false를 돌려줌), 천둥 상태의 enum(1014~1035), Thunderstorm_InitVars(1037), Downpour_InitVars(1066), 뇌우 패턴의 주석 “(SHORT_BOLT){1,2}(LONG_BOLT)?”(1089)와 “Thunder only plays on the final bolt of the cycle.”(천둥은 주기의 마지막 번개에서만 울린다)(1091), Thunderstorm_Main(1092)과 그 첫머리의 UpdateThunderSound()(1094), 그 준비 상태(1097~1111)와 그 THUNDER_STATE_WAIT_CHANGE 케이스(1112), 이것은 기다림을 건너뛰고 THUNDER_STATE_INIT_CYCLE_1(1114)로 감, THUNDER_STATE_NEW_CYCLE(1116, 1118행의 타이머 (Random() % 360) + 360이 1121행의 THUNDER_STATE_NEW_CYCLE_WAIT로 이어지며, 그 --thunderTimer == 0은 1123행), THUNDER_STATE_INIT_CYCLE_1과 _2(1126과 1131, 1135행의 THUNDER_STATE_SHORT_BOLT로 이어지며, 번개는 1137행, 유지 (Random() % 3) + 6은 1142행), THUNDER_STATE_TRY_NEW_BOLT(1145, 1149행에서 번개의 끝, 1154행에서 간격 타이머 (Random() % 16) + 60), THUNDER_STATE_WAIT_BOLT_SHORT(1169), THUNDER_STATE_INIT_BOLT_LONG(1173, 1174행에서 같은 간격 타이머), THUNDER_STATE_WAIT_BOLT_LONG(1177, 1181행에서 EnqueueThunder(100), 1182행에서 번개, 1183행에서 유지 (Random() & 0xF) + 30), THUNDER_STATE_FADE_BOLT_LONG(1187, 1191행에서 서서히 페이드), EnqueueThunder(1242, 1246행에서 타이머 Random() % waitFrames)와 UpdateThunderSound(1251), FogHorizontal_Main(1392), Sandstorm_Main(1975), Shade_InitVars(2247), sWeatherCycleRoute119(2581), sWeatherCycleRoute123(2588), UpdateWeatherPerDay(2622), https://github.com/pret/pokeemerald/blob/master/src/field_weather_effect.c ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  8. 저자의 측정, 2026년 10월 5일: measure_shadows.py(이 글을 위한 저자의 증거 폴더), 출력 shadows.txt: Emerald의 shadow_small.png, shadow_medium.png, shadow_large.png, shadow_extra_large.png(pret pokeemerald, 731ad5b, graphics/field_effects/pics/)와 Kiradex의 Kiradex/Resources/World/shadow.png의 크기, 불투명 픽셀, 서로 다른 톤의 수. 각각을 불투명 픽셀의 텍스트 마스크로 그림. 게시 전에 다시 실행해 같은 출력을 얻음. ↩↩↩↩↩↩↩↩↩↩

  9. 저자의 측정, 2026년 10월 5일, iPhone이 아니라 Mac에서: measure_kiradex_light.py(이 글을 위한 저자의 증거 폴더), 출력 kiradex_light.txt. 텍스트로 Kiradex 저장소의 Kiradex/World/Daylight.swift, PlazaStage.swift, Air.swift, Kiradex/World/의 모든 Swift 파일, 그리고 scripts/forge/town.py와 buildings.py를 읽고, Pillow로 내보낸 Kiradex/Resources/World/town.png(그 불투명 픽셀에 틴트를 채널별로 적용), cloud.png, mist.png, glow.png, shadow.png, town.json(40×30, 날짜 2026년 10월 3일 21:34)을 읽음. 섹션: A, Daylight의 시간대, 틴트, 계절 색조, 가로등. B, 아틀라스 위의 틴트와 불빛 셀. C, 시계, 그 옵저버, Reduce Motion. D, 공기. E, 마을의 빛, 불빛 셀, 웅덩이, 굴뚝, 건물. F, 그림자. 루마는 0~1 값에 Rec. 601을 적용한 것으로, 감마 없음. 비공개 저장소이며, git도 포지도 실행하지 않고 10월 5일 16:54에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 읽음. 게시 전, 18:11에 커밋 66c116b0 시점에서 재실행: D의 한 줄을 빼고 모든 줄이 전과 같이 출력. 그 줄의 라벨은 초당 4타일의 걷기 속도를 이어받고 있었으나, 그 줄의 수치, 곧 구름이 한 타일을 가로지르는 데 걸리는 9.8초는 그것을 쓰지 않음. 이전 스크립트와 출력은 옆에 남겨 둠. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  10. Blake Crosley, “Honoring the Old Pokémon Games Without Borrowing Them”, blakecrosley.com, 2026년 10월 5일: 3절(Crystal의 MORN_HOUR 4, DAY_HOUR 10, NITE_HOUR 18과 TimesOfDay의 주석. Kiradex의 Daylight.Phase, “morning from 6 to 9, day from 9 to 17, evening from 17 to 20 and night otherwise”(6시부터 9시는 아침, 9시부터 17시는 낮, 17시부터 20시는 저녁, 나머지는 밤)와 “the brief in section 14 keeps it that way”(14절의 브리프는 그것을 그대로 유지한다)라는 진술. 실시간 시계 위의 Emerald의 나무열매와, Emerald의 하루 단위 갱신 열한 가지 목록, 그중 “the weather”(날씨), 함수는 지목하지 않음)와 14절(브리프. Kiradex의 시간대를 유지하며, 그것은 “which are already not Crystal’s 4, 10 and 18 and stay that way”(이미 Crystal의 4, 10, 18이 아니며 그대로 남는다). 그리고 그 “Never” 목록으로, 항목 1은 “tile, sprite, palette or screen layout taken, traced or redrawn from any Pokémon game”(어떤 포켓몬 게임에서든 가져오거나, 따라 그리거나, 다시 그린 타일, 스프라이트, 팔레트, 화면 배치)을 거부하고, 항목 2는 어떤 기능도 써서는 안 되는 프랜차이즈 어휘를 Pokédex와 “Poké-anything”(Poké로 시작하는 무엇이든)부터 Frontier까지 지목하며, 항목 4는 앱이나 포지 안의 “code or data from the decompilations”(디컴파일의 코드나 데이터)를 거부함), https://blakecrosley.com/blog/honoring-the-old-pokemon-games ↩↩↩↩↩↩↩↩↩↩↩↩↩

  11. 저자의 측정과 제안 산술, 2026년 10월 5일, Mac에서: measure_kiradex_proposals.py(이 글을 위한 저자의 증거 폴더), 출력 kiradex_proposals.txt. 섹션: 1, Emerald의 비를 월드 165×358픽셀인 iPhone 18 Pro Max 뷰로 옮긴 것(10,000제곱픽셀당 밀도, 뷰 안의 빗방울, 60과 120헤르츠에서 프레임당 속도, 낙하와 물보라 시간). 2, 17:18 사본의 Motion.swift에서 읽은 Kiradex의 걷기(초당 60틱으로 16틱에 16픽셀, 초당 60픽셀. 달리기는 120. 대각선 걷기 한 걸음은 대각선을 따라 59.0), 각 게임의 걷기에 대한 흐름의 속도(Emerald의 초당 59.7픽셀, Kiradex의 60), 그리고 초당 16픽셀과 걷기의 절반에서의 제안 구름. 3, town.json에서 건물 그림자의 셀: 일곱 건물 각각의 각 행에 대해, 그 행에서 가장 동쪽 건물 셀 바로 동쪽의 셀을 문자별로, 잔디, 길, 포장석인 곳만 그림자를 둠(39개 중 33개). 비교를 위해, 각 열에서 가장 아래 건물 셀 밑의 셀(40개, 그중 35개가 땅). 4, 낮에서 저녁과 저녁에서 밤에 대해, 아틀라스 평균 루마에서의 컷과 30분 램프. 5, 아틀라스 위의 비의 13/16과, 흰색 쪽으로 절반 끌어올린 걷는 이의 빛. 6, 한 구역에서 제안하는 매일 날씨 굴림의 1년치(2027년), sha256("zone|yyyy-mm-dd"), 처음 4바이트를 빅 엔디언, 100으로 나눈 나머지, 제안의 계절 표를 나열한 순서대로 누적으로 따라감(각 계절에 대해 상태별 굴림 값의 범위를 출력함), 젖은 날과 젖은 기간(비, 폭우, 눈의 날이 어떻게 섞이든 연속된 날의 최대 이어짐: 82일, 기간 65개, 가장 긴 것 3), 1월 30일에 걸친 두 구역의 일치, 그리고 다이제스트의 다섯 번째 바이트로 정하는 제안 구름의 방향. 출력에서 PROPOSAL로 표시된 것은 모두 저자의 것. 섹션 3은 각 건물의 경계 상자에서 위의 행별 규칙으로 개정함. 섹션 6은 개정함: 젖은 상태 하나의 이어짐을 세었고(67, 가장 긴 것 3), 1년의 마지막 날에 끝나는 이어짐을 빠뜨렸음. 지금은 위에서 정의한 젖은 기간을 세고, 굴림의 범위와 구름의 방향을 출력함. 18:11에 커밋 66c116b0 시점, 작업 트리의 마을 내보내기와 그림을 읽어 재실행. 섹션 2는 걷기를 Motion.swift에서 읽도록 개정함: 초당 4타일, 초당 64픽셀을 이어받아 오늘의 구름을 걷기의 0.026, 제안을 0.25로 두었음. 이전 스크립트와 출력은 옆에 남겨 두었고, 섹션 1, 3, 4, 5와 섹션 6의 계절 개수는 전과 같이 출력됨. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  12. 이 글을 위한 저자의 조사 자료 “Light, weather and time: how pixel worlds keep a day, and what Kiradex should”(빛, 날씨, 시간: 픽셀 세계는 하루를 어떻게 유지하는가, 그리고 Kiradex는 어떻게 해야 하는가), 2026년 10월 5일 정리. Kiradex 저장소 docs/research/light/01-light.md(비공개. 그날 07:25 날짜이며 16:51에 커밋 cf3beb1e 시점에 읽음), 저자의 증거 폴더에 있는 사본과 동일. 1절(핵심 사실), 2절(사례 연구), 3절(수치가 있는 규칙), 4절(Kiradex를 위한 브리프. 10절의 상태, 표, 계수, 파일, 인수 검사 1~8과 이 글의 10과 11(조사 자료의 9와 10)은 처음 쓰인 그대로 여기서 옴. 이 글은 검사 2~8, 10, 11을 고치며 각각에서 그렇다고 말함. 그 검사 10은 날씨 그림이 “the deny list”(거부 목록)를 통과한다고 말하고, 그 구름 방향은 “the weather roll’s second byte”(날씨 굴림의 두 번째 바이트)에서 옴), 5절(측정한 것과 측정하지 않은 것: 근사, 닿지 못한 페이지, 제안, 공개된 글들에 대한 확인). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  13. pret, pokecrystal/gfx/tilesets/bg_tiles.pal, 5beda23, 2026년 10월 5일 열람: 배경 팔레트 여덟 개짜리 블록 다섯 개(아침, 낮, 밤, 어둠, 실내)와 야외 물 쌍(51~53행: RGB 23,23,31, 18,19,31, 13,12,31, 07,07,07 ; morn/day와 RGB 15,13,27, 10,09,20, 04,03,18, 00,00,00 ; nite), https://github.com/pret/pokecrystal/blob/master/gfx/tilesets/bg_tiles.pal ↩↩

  14. pret, pokecrystal/gfx/overworld/npc_sprites.pal, 5beda23, 2026년 10월 5일 열람: 시간대별 오브젝트 팔레트, https://github.com/pret/pokecrystal/blob/master/gfx/overworld/npc_sprites.pal ↩↩

  15. pret, pokeemerald/include/event_object_movement.h, 731ad5b, 2026년 10월 5일 열람: PALSLOT_PLAYER(12행)부터 PALSLOT_NPC_SPECIAL(22행)까지의 오브젝트 팔레트 슬롯과 그 반사 슬롯, https://github.com/pret/pokeemerald/blob/master/include/event_object_movement.h ↩↩

  16. Stardew Valley Wiki, “Day Cycle”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sdv-day-cycle.html과 sdv-day-cycle.txt로 저장(“Time passes at 0.7 real seconds per in-game minute”(게임 속 1분마다 실제 0.7초가 흐른다). 해 질 녘 “In Spring and Summer , it is 8pm, while in Fall it is at 7pm and Winter is 6pm”(봄과 여름에는 오후 8시, 가을에는 오후 7시, 겨울에는 오후 6시). “indoors the windows turn dark and lamps and sconces light up”(실내에서는 창이 어두워지고 램프와 벽등이 켜진다). 야외에서는 “it does not immediately become full dark, but gradually becomes darker over time”(곧바로 완전히 어두워지지 않고, 시간이 지나며 점점 어두워진다)), https://stardewvalleywiki.com/Day_Cycle ↩↩↩↩↩↩↩↩↩

  17. Stardew Valley Wiki, “Weather”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sdv-weather.html과 sdv-weather.txt로 저장(“Weather changes daily and with the seasons”(날씨는 매일, 그리고 계절에 따라 바뀐다). 다음 날 날씨는 “can be checked by viewing the TV screen”(TV 화면을 보면 확인할 수 있다). “There is a chance for a lightning strike to occur every 10 minutes”(10분마다 벼락이 칠 가능성이 있다). “Snow transparency can be changed in the Options Menu”(눈의 투명도는 옵션 메뉴에서 바꿀 수 있다)), https://stardewvalleywiki.com/Weather ↩↩↩↩↩↩↩↩↩

  18. Stardew Valley Wiki, “Modding:Weather data”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sdv-weather-data.html과 sdv-weather-data.txt로 저장(날씨가 강제되지 않는 날짜에 대한 계절별 각 날씨 종류의 확률), https://stardewvalleywiki.com/Modding:Weather_data ↩↩↩↩↩↩↩↩

  19. Kiradex 소스, Kiradex/World/PlazaStage.swift, 2026년 10월 5일 열람, 마지막은 17:42에 커밋 5a344e3f 시점, 앱 자신의 에이전트가 그날 편집 중이던 작업 트리에서(비공개 저장소. 파일 날짜는 그날 17:22이며, 줄 번호는 그 읽기의 것. 16:51, 커밋 cf3beb1e 시점의 읽기에서는 469행 이후가 4~8줄 적었는데, 파일이 그 뒤 접근성 표현을 얻었기 때문): daylight(at:)(69행, 설정되어 있으면 Daylight.forcedHour를 씀), relight()(77~81, 152행의 구축 뒤와 194행의 공기 준비 뒤에 불림), stepTrace, 플레이어의 마지막 걸음이나 공기의 보고로, “as the stage’s accessibility value”(스테이지의 접근성 값으로서)(60~63, 361행에서 StageAccessibility가 스테이지의 접근성 요소에 줌), content.renderingEffects.depthOfField = .disabled(133), 뷰의 .task 안에서 rig.air.prepare() 뒤에 한 번 스테이지 값에 쓰는 -airProbe 보고(190~193), relight()를 부르는 onChange(of: clock)(248~250), 60초 동안 잠드는 태스크 “The light follows the clock, a minute at a time.”(빛은 시계를 1분씩 따른다)(251~257), 주사선, 3포인트마다 그늘진 줄 하나(344~349), 비네트, 맑음에서 맑음을 거쳐 불투명도 0.28의 검정에 이르는 반지름 900포인트의 방사형 그러데이션(353~355), RoomView(911행에서 선언, 946행에서 PlazaStage를 만들고 975행에서 fitsWhole: false). 시계의 @State(57). PlazaView.words, 상태 줄의 문구(819). 매 프레임 rig.update를 진행시키는 SceneEvents.Update 구독(176~182). stepTrace를 플레이어의 걸음으로 설정하는 rig.onStep(156~160). bubbles(of:in:), TimelineView(.animation(minimumInterval: 0.1)) 아래 머리 위의 말풍선(447~463). 그리고 PlazaView(536), 이것은 QuestBoardView를 시트로 띄우고(690), 방이나 홀을 광장 위에 겹침, “laid over it, not pushed”(밀어 넣지 않고 위에 겹친다), 광장은 그 장소 아래에 머묾(719~724). RoomView의 “A room is entered through the veil, and its floors change under it.”(방에는 베일을 지나 들어가며, 그 아래에서 층이 바뀐다)(936), 그리고 그 client: nil인 PlazaStage(947). 그리고 방, 쇼, 방문에서 돌아오는 광장, “out of the door gone in by, the veil lifting.”(들어간 문으로 나오며, 베일이 걷힌다)(678~679). 그 읽기 시점에 Kiradex/World/에는 significantTimeChangeNotification이나 NSSystemTimeZoneDidChange의 옵저버가 없었음. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  20. Kiradex 소스, Kiradex/World/PlazaRig.swift, 2026년 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 파일 날짜는 15:22이며, 줄 번호는 그 읽기의 것): 주석 “For the card alone: nothing else in the world is lit.”(카드만을 위해. 세계의 다른 어떤 것도 빛을 받지 않는다) 아래의 카드 DirectionalLight(161행과 162행), 리그의 light(211), light(_:lampsOn:)(254)와 걷는 이가 “redrawn in the new light on the next frame”(다음 프레임에 새 빛으로 다시 그린다)이라는 그 주석(262), material(light: .white)를 가진 불 켜진 창의 메시(383), 그리고 리그의 light를 쓰는 sheet.material(column:row:light:)에서 오는 각 걷는 이 프레임의 머티리얼(512, 508행의 add(other:figure:tile:facing:) 안, 그리고 1081, animate(_:) 안). animate(_:) 자체(1038), 여기서 서 있는 걷는 이는 숨 쉬는 대기, 눈 깜박임, 그리고 이따금 idleEmotes 중 하나, 틱, 둘러보기, 어깨 으쓱, 생각하기, 졸기를 보여 주며(136), 다음 것은 6~14초 뒤(1062), 머티리얼이 보여 주는 프레임을 걷는 이의 shown에 기록함(1078~1080), 곧 방향의 행에 시트의 열 수를 곱하고 그림의 열을 더한 것. 플레이어의 첫 대기 이모트는 7초, 첫 깜박임은 2.5초(Walker, 33~35). light(_:lampsOn:)에서 material(light:)를 받는 땅, 주변, 오브젝트(257~259), 그리고 물결 안에서도 그 프레임이 바뀔 때마다, 물이 있는 곳에서는 초당 네 번(231, 240~250). showDoor(at:sheet:column:)에서 리그의 빛을 쓰는 문 그림(617. 머티리얼은 627과 634). build(tiles:collector:arrival:)(362), 이것은 먼저 땅, 주변, 오브젝트에 리그의 빛으로 material(light:)를 줌(363, 370, 376). addQuad, 몇몇 타일 위에 평평하게 놓은 그림(346). worldPoint(at:in:displayScale:)(459). viewPoint(of:in:displayScale:), 월드의 점이 뷰의 어디에 오는지(471). update(_:), 프레임별 갱신으로, 틱 시계를 통해 세계의 틱을 돌린 다음 진열장을 돌리고, 물결을 진행시키고, 공기를 갱신함(952~966), tick()(969)이 걷는 이들과 카메라를 진행시킴. place(_:), 걷는 이의 발을 그 타일 중심에서 0.3타일 아래에 정수 픽셀로 세움(1088~1097). 그리고 lockCamera()(1171~1200), 이것은 카메라를 플레이어 위에, CameraLock.bounds(Kiradex/World/Motion.swift, 258~262행, 날짜 12:36)가 맵 가장자리로 안쪽으로 반올림하는 경계 안에서 설정함. 이전의 파일 읽기가 카메라에 대해 인용한 follow(_:)는 이제 파일에 없음. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  21. Kiradex 소스, Kiradex/World/Daylight.swift, 날짜 2026년 10월 2일, 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 줄 번호는 그 사본의 것): Phase.init(hour:)(13행), tint(26행, “a multiplier on the art’s own colours”(그림 자신의 색에 곱하는 값), “ART SURFACE: four fixed lights for a pixel world”(그림의 표면: 픽셀 세계를 위한 네 개의 고정된 빛)로 선언), lampsOn(36행), Season.init(month:)(54행, “By the month, in the north; the south is a setting for later.”(달로, 북반구 기준. 남반구는 나중에 설정으로)), cast(75행), calendar: Calendar = .current를 가진 now(_:calendar:)(86행), light(phase:season:)(92행), 그리고 -plazaHour에서 읽는 forcedHour(101행). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  22. Kiradex 소스, Kiradex/World/Air.swift, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 줄 번호는 그 사본의 것): 헤더, “Light and air over a place, build 29 of the design plan”(장소 위의 빛과 공기, 디자인 계획의 빌드 29), 끝은 “none of it takes the day’s tint: light is light.”(그 어느 것도 하루의 틴트를 받지 않는다. 빛은 빛이다)(6~12행). lightingModel = .unlit와 blendMode = .add를 가진 glow 프로그램의 디스크립터와 주석 “The program says how to blend; the material says that it blends at all.”(어떻게 블렌딩할지는 프로그램이 말하고, 블렌딩을 하는지 자체는 머티리얼이 말한다)(88~96행). 웅덩이(144~153행). set(phase:season:)(160행부터: 밤에 숨는 구름, 아침의 안개, 가을에 밤을 뺀 모든 시간대의 잎, 168행, update의 276행에 같은 검사, 밤의 반딧불이). makeCloud(175행, 불투명도 0.55, “repeats every 384 world pixels”(월드 384픽셀마다 반복된다)). makeMist(192행, 불투명도 0.7, 덩어리 셋). 잎 14장(209행). 반딧불이 10마리(248행). -airProbe가 보여 주는 보고(105행과 114행에서 조립). 그리고 프레임별 구름 오프셋, cloudOffset += SIMD2(0.004, 0.0015) * dt에 camera / 384를 더한 것(266~268행). 깊이, cloudDepth 2.4, driftDepth 2.45, poolDepth 2.5(19~21행), 잎, 반딧불이, 연기는 driftDepth(237, 251, 287, 314). TileMap.depth(atWorldY:), 1에 맵 아래쪽으로 최대 0.5를 더한 것(Kiradex/World/TileMap.swift 122행). outdoors, 장소에 하늘이 있는지(27행과 71행). 밤에 숨는 구름(163행). 떠다니는 것으로서의 잎(207~215행). 그리고 update(_:camera:view:)(262행). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  23. Blake Crosley, “Pixel-Art Structures: Houses, Halls and Interiors on iPhone”, blakecrosley.com, 2026년 10월 3일: TL;DR의 “nineteen windows and the hall’s two sconces”(창 열아홉 개와 홀의 벽등 두 개). 가로등이 켜질 때 활성화되는, 틴트 없는 두 번째 메시로서의 불 켜진 창에 대한 절. 아틀라스 문단, “the 21 lit cells dedupe to two”(불빛 셀 21개는 중복을 없애면 둘이 된다)와, 두 새 메시의 GPU 비용은 “is not profiled yet”(아직 프로파일하지 않았다)라는 메모. Crystal의 roofs.pal. 그리고 Stardew의 NightTiles와 WindowLight, https://blakecrosley.com/blog/pixel-art-structures-on-iphone ↩↩↩↩↩↩↩↩

  24. Kiradex 포지, scripts/forge/buildings.py, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 줄 번호는 그 사본의 것): 모듈 docstring, “The ground shadow stays off the building: it belongs to the ground layer.”(땅 그림자는 건물에 붙이지 않는다. 그것은 땅 레이어에 속한다)(13~16행). 박공 삼각형에 두는 창, 모양이 gable이고 너비가 최소 5일 때 지붕 블록 한가운데에 두는 K.window(lit=night)(91~93행), 건물의 창 가운데 기록되며(112와 113), 박공지붕 건물 두 채가 가짐. dormer, 불빛 변형 없이 그려지고 창으로 기록되지 않는 지붕 조각(133행과 134행). 그리고 finish 안의, 지붕 아래 세 행의 처마 그림자(195~198행). ↩↩↩↩

  25. pret 디컴파일, 시리즈를 위한 저자의 증거 폴더에 있는 얕은 클론: pokecrystal, 5beda23(2026년 9월 29일 커밋), pokeemerald, 731ad5b(10월 1일), pokefirered, 037335f(9월 26일), pokered, d2704a6(9월 22일), https://github.com/pret ↩

  26. 저자의 읽기, 2026년 10월 5일: parse_apple.py(이 글을 위한 저자의 증거 폴더), 출력 apple_pages.txt. 그날 저장한 Apple 문서 JSON 페이지 열한 개(apple-*.html) 각각의 제목, 요약, 선언, 플랫폼을 출력함. 게시 전에 다시 실행해 같은 출력을 얻음. ↩↩↩

  27. 저자의 측정, 2026년 10월 5일, Mac에서: measure_capture_walk.py(이 글을 위한 저자의 증거 폴더), 출력 capture_walk.txt. Pro Max 카메라가 어디에 자리 잡는지를, Kiradex 소스에서 읽은 리그 자신의 기하로, 시뮬레이터에서의 실행이 아니라 종이 위에서 재생한 것(10월 5일 16:51, 커밋 cf3beb1e, 그날 편집 중이던 작업 트리. 줄 번호는 그 읽기의 것): 3배, 텍셀당 기기 픽셀 8개에서 440×956포인트 뷰, 월드 165×358.5픽셀(PlazaRig.fit, 433~456행). 타일 중심과 점 아래의 타일(TileMap.swift 234~241행). 탭의 월드 점(PlazaRig.worldPoint, 459~463행). 걸을 수 있는 문자(TileMap.swift 35~53행), 앱은 그것을 내보내기의 행에서 가져옴(WorldMap.swift 99~110행). 걷는 이의 발(PlazaRig.place, 1088~1097행, 시트의 32×40 셀과 발 아래 2행은 characters.json에서). 그리고 플레이어 위에 설정하고 맵에 고정한 카메라(PlazaRig.lockCamera, 1171~1200행, Motion.swift의 CameraLock.bounds, 258~262행은 경계를 정수 픽셀로 안쪽으로 반올림함. 재생이 찾는 어느 자리 잡는 점도 경계 위에 있지 않으므로, 반올림은 아무것도 움직이지 않음). 스크립트의 docstring은 나중에 그 줄들에 맞추었고, 이전 읽기의 수치는 옆의 사본에 남겨 둠. 그 출력은 바뀌지 않음. 찾은 것: testTheChimneysSmoke의 탭은 내보내기의 소품인 (18, 8)에 떨어지므로 수집가는 (19, 13)에 머물고, 카메라는 (312, 278)에 있음. 거기서 house-dawn의 띠(열 18, 행 16~20)와 house-moss의 행 3과 4의 띠가 25.2픽셀 이상의 여유를 두고 뷰에 들어오고, 소품인 그 행 5도 들어옴. 가로 0.02~0.98, 세로 0.05~0.95의 정규화된 점 격자 위의 어떤 탭도 house-mine의 띠를 뷰에 넣지 못함. 그리고 플레이어의 1층 방에서, 그 도착 지점 (7, 10)에서 뷰는 가로로 타일 2.34~12.66과 방의 높이 전체에 걸치며, (3, 1)의 커튼 달린 창은 온전히 뷰에 들어오고 (12, 1)의 창은 들어오지 않음. ↩↩↩

  28. 저자의 측정, 2026년 10월 5일, Mac에서: measure_palette_match.py(이 글을 위한 저자의 증거 폴더), 출력 palette_match.txt. 5beda23의 pret pokecrystal의 gfx/tilesets/bg_tiles.pal(168색, 그중 57개가 서로 다름), gfx/overworld/npc_sprites.pal(128, 그중 23개가 서로 다름), gfx/tilesets/roofs.pal(108, 그중 91개가 서로 다름)의 모든 색을 읽고, 각 5비트 채널을 1/31로 스케일해, Kiradex의 Daylight.swift의 색 상수 8개(텍스트로 읽음, 28~31행과 77~80행)와 비교함: 정확한 일치 두 개, 둘 다 순수한 흰색 (31, 31, 31)으로, 29행과 78행. 다른 것은 없음. 그 밖에 가장 가까운 쌍, 79행의 (1, 0.93, 0.84)와 (30, 28, 26)은 한 채널에서 0.0323, 5비트로 한 단계 차이남. ↩↩↩

  29. 저자의 재생, 2026년 10월 5일: replay_gen3_rain_thunder.py(이 글을 위한 저자의 증거 폴더), 출력 gen3_replay.txt. 먼저 731ad5b의 pret pokeemerald 텍스트에 대해, 기대고 있는 관용구를 검증함: Rain_Main의 세 상태, 호출당 스프라이트 하나를 만들고 24번째를 만드는 호출에서 false를 돌려주는 CreateRainSprite, UpdateVisibleRainSprites의 ++rainSpriteVisibleCounter > rainSpriteVisibleDelay, 다음 날씨가 비 종류이면 스프라이트를 유지하는 Rain_Finish, 곧바로 false를 돌려주는 Sunny_Finish, Task_WeatherMain의 교체(이전 날씨의 finish()를 false까지, 그다음 initVars(), 단계 카운터 초기화, 팔레트 상태를 변경 중으로 설정, src/field_weather.c 안)와 UpdateWeatherColorMap의 ++colorMapStepCounter >= colorMapStepDelay, 뇌우의 준비 상태와 THUNDER_STATE_WAIT_CHANGE, 그리고 Thunderstorm_Main 주기의 모든 타이머와 전이. 그런 다음 그것들을 호출 단위로 재생함. 섹션: A, 비 스프라이트가 없는 상태에서 플레이 중 들어가는 비 종류로, Task_WeatherMain이 날씨를 바꾸는 프레임부터 셈(호출 1에서 시트, 호출 2~25에서 스프라이트 24개, 첫 빗방울이 활성화되는 것은 비에서 호출 34, 무거운 종류에서 30, 마지막은 호출 115, 105, 145. 프레임 59에 맵 3에 있는 팔레트. 프레임 109의 뇌우 첫 번개. 맵을 불러올 때 Rain_InitAll이 반복하는 호출, 116, 106, 146). B, 다른 비 종류에서 들어가는 비 종류로, 스프라이트를 유지하고 개수를 5번이나 9번의 호출마다 한 방울씩 옮김. C, THUNDER_STATE_NEW_CYCLE부터의 뇌우 주기를 최소 추첨, 최대 추첨, 그리고 짧은 번개 하나만으로(주기 호출 후 361~720프레임의 첫 번개. 6~8프레임 켜지는 번개. 61~76프레임의 어두운 간격, 간격 타이머에 다음 상태가 걸리는 호출 한 번을 더한 것. 30~45프레임 최대인 긴 번개. 번개 후 1~20이나 1~100프레임 뒤의 소리). ↩↩↩↩

  30. 저자의 측정, 2026년 10월 5일, Mac에서: measure_collector_coverage.py(이 글을 위한 저자의 증거 폴더), 출력 collector_coverage.txt. 커밋 66c116b0 시점 18:07 사본의 인물 시트와 characters.json을 읽고, 읽은 대로의 CollectorComposer를 따름. A, 아래를 보는 프레임 0의 32×40 셀, 1,280픽셀: 몸 시트만으로 377개가 불투명, 시트 123개를 한꺼번에 겹치면 581개(지우개 픽셀을 불투명으로 세면 705개). B, 서 있는 수집가가 보여 주는 그림 11개(PlazaRig.animate(_:)) 각각에 대해 합성한 매니페스트의 기본 인물: 첫 그림에서 불투명 픽셀 408개, 그림 전체에 걸쳐 374~408개, 11개 모두에서 불투명한 것이 290개. C, 저장된 색 값에서 채널별 밤 대 낮: 기본 인물의 픽셀은 끌어올린 빛 아래에서 0.787(290개에서는 0.788), 밤 틴트를 통째로 받으면 0.573(0.575), 끌어올림의 가장 작은 채널은 0.75. 아틀라스 평균 색의 땅, 0.588. 인물의 408픽셀과 땅의 872픽셀로 된 프레임 전체, 올바른 빌드에서 0.638, 걷는 이들에게 틴트를 통째로 입히는 빌드에서 0.584, 몸의 덮음으로는 0.633, 모든 시트의 덮음으로는 0.662. 섹션 D와 E는 2026년 10월 15일에 더했고 A~C는 그대로. D, 각 그림 자신의 색으로 본 290픽셀 마스크: 낮 루마는 0.2989(doze_b)~0.3161(think). 두 캡처에서 같은 그림이면 끌어올림 아래에서 0.7875~0.7884, 틴트를 통째로 받으면 0.5750~0.5768. 그림의 순서쌍 121개에 걸쳐서는 끌어올림 아래에서 0.7456(낮에는 think, 밤에는 doze_b, 0.75 아래인 유일한 쌍)~0.8336, 틴트를 통째로 받으면 최대 0.6099. idle_a로 고정하면 0.7876과 0.5752. E, 마을 아틀라스의 모든 불투명 픽셀(커밋 cf3beb1e 시점 16:51 사본)에서의 땅과, idle_a로 고정한 마스크를 세 파이프라인 아래에서: 저장된 그대로 곱하면 땅 0.5880, 채널 (0.500, 0.580, 0.900), 마스크는 끌어올림 아래에서 0.7876, 틴트를 통째로 받으면 0.5752. 그림과 틴트를 sRGB에서 디코딩해 곱하고 인코딩하면 0.5623, (0.469, 0.554, 0.892), 0.7643과 0.5312. 그림을 디코딩하고 틴트의 숫자를 선형으로 취급하면 0.7742, (0.719, 0.772, 0.951), 0.8885와 0.7557. 그리고 창의 기준, capture_walk.txt의 Pro Max 도착 뷰에 온전히 들어오는 불빛 셀 24개 중 7개, 불빛 픽셀 294개, 모두 웅덩이 24개의 평면(Air.lightPools) 밖에 있고 뷰 중심에서 450포인트 안. 섹션 F, 같은 날 더함: 공기의 깊이, 구름 2.4, 떠다니는 것 2.45, 웅덩이 2.5, 걷는 이들의 1~1.5에 맞섬(TileMap.depth). 구름의 가장 짙은 그늘, 1에서 그 최대 알파(255 중 110)에 불투명도 0.55를 곱한 것을 빼서 0.7627. 걷는 이들에게 틴트를 입히는 빌드에서, 그 그늘이 낮의 마스크 위에 있으면 저장된 그대로 0.7541, 선형으로 0.6964, 틴트의 숫자를 선형으로 취급하면 0.9908. 그리고 도착 시점 (19, 13)에서 수집가 프레임은 월드 픽셀로 x 296~328, y 258~298이며, 웅덩이 24개의 평면 어느 것과도 겹치지 않고, 가장 가까운 것에서 52픽셀 떨어져 있음. 그리고 구름 그늘을 인코딩 전에 선형 빛에서 취하는 경우, 선형으로 0.6076, 틴트의 숫자를 선형으로 취급하면 0.8645. 섹션 G, 같은 날 더함: 파이프라인 견본, 저장값 51과 102인 회색 두 개를 0.25의 고정된 틴트 아래에서 그린 것으로, 세 파이프라인은 그것을 13과 26, 6과 20, 22와 51로 만들며, 어느 둘도 6단계보다 가깝지 않음. 그리고 머티리얼이 모든 틴트를 다시 절반 끌어올리는 빌드에서, 그 견본은 32와 64로 읽혀 가장 가까운 것에서 13단계 떨어지며, 그 밤은 저장된 그대로 땅 0.794024, 채널 (0.750, 0.790, 0.950), 마스크 0.893804를 줌. 섹션 H, 그 뒤에 더함: 견본의 위치, Pro Max 뷰의 포인트로 x 24~56, y 462~478, 가장 먼 모서리는 중심에서 196.7포인트. 도착 시점, 뷰의 포인트로 수집가 프레임은 x 177.3~262.7, y 424.7~531.3이며 견본과 겹치지 않고, 기준 창 7개는 견본에서 266.7포인트 이상, 검사 8의 띠 7개는 144.0 이상 떨어져 있음. 출시된 그림으로 한 계산이지 캡처가 아님. ↩↩↩↩↩↩↩↩↩↩↩↩↩

  31. pret, pokecrystal/constants/ram_constants.asm, 5beda23, 2026년 10월 5일 열람: wTimeOfDay와 그 값 MORN, DAY, NITE, DARKNESS(142~147행), https://github.com/pret/pokecrystal/blob/master/constants/ram_constants.asm ↩

  32. Blake Crosley, “Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew”, blakecrosley.com, 2026년 10월 3일: 2세대 문단(“time of day in Johto is a 64-byte palette reload”(성도의 시간대는 64바이트 팔레트 다시 불러오기다). 이름 붙은 여덟 팔레트), 조명 단계표(Moonlighter, Celeste, Eastward, HD-2D. HD-2D는 “costs more than you’d think”(생각보다 비용이 든다). Octopath Traveler II의 플레이어는 피사계 심도를 끈다), RealityKit 레시피, 그리고 체크리스트의 “Dusk and night as one multiply tint over the world plus hand-drawn emissive variants for lamps, windows and the kiosk sign”(해 질 녘과 밤은 세계 전체에 곱셈 틴트 하나로, 가로등, 창, 키오스크 간판에는 손으로 그린 발광 변형을 더해서), https://blakecrosley.com/blog/pixel-art-world-on-iphone ↩↩↩↩↩↩↩

  33. pret, pokecrystal/data/maps/environment_colors.asm, 5beda23, 2026년 10월 5일 열람: EnvironmentColorsPointers(1~12행: TOWN과 ROUTE는 .OutdoorColors로, INDOOR와 GATE는 .IndoorColors로, CAVE와 DUNGEON은 .DungeonColors로, ENVIRONMENT_5는 .Env5Colors로), 각 표는 시간대마다 팔레트 인덱스 여덟 개짜리 한 줄. .OutdoorColors(15~19), 그 WATER 인덱스는 아침과 낮에 $28, 밤에 $29로 파일의 야외 물 쌍이며, 나머지 일곱은 블록 자신의 것. .IndoorColors(21~25), 아침과 낮에는 실내 블록 $20~$26과 TEXT $07, 그 뒤에 밤과 어둠 블록. .DungeonColors와 .Env5Colors(27~37), 블록 그대로, https://github.com/pret/pokecrystal/blob/master/data/maps/environment_colors.asm ↩↩

  34. pret, pokecrystal/engine/gfx/color.asm, 5beda23, 2026년 10월 5일 열람: LoadMapPals(1197행부터: 먼저 1198행에서 farcall LoadSpecialMapPalette, 1199행에서 jr c, .got_pals, 이것은 그 루틴이 캐리를 세웠을 때 배경 복사를 건너뜀. 그렇지 않으면 8바이트짜리 배경 팔레트 여덟 개. 1257행의 .got_pals부터, 1261행의 MapObjectPals에서 가져오는 오브젝트 팔레트 여덟 개. 그리고 1269행의 cp TOWN 뒤, TOWN이나 ROUTE에서는 1280행의 RoofPals에서 가져오는 맵 그룹의 지붕 색, 1284행의 cp NITE_F로 NITE와 DARKNESS에는 밤 쌍, 1290~1291행에서 wBGPals1 palette PAL_BG_ROOF color 1로 4바이트, 곧 ROOF의 색 1과 2. 배경 인덱스 여덟 개는 1206행의 EnvironmentColorsPointers에서 환경과 시간대별로 옴), 그리고 pokecrystal/engine/tilesets/tileset_palettes.asm, LoadSpecialMapPalette(1~53행: TILESET_POKECOM_CENTER, TILESET_BATTLE_TOWER_INSIDE, 환경이 INDOOR가 아닌 한의 TILESET_ICE_PATH(명예의 전당), TILESET_HOUSE, TILESET_RADIO_TOWER, TILESET_MANSION에 대해 자기만의 표를 불러온 뒤 캐리를 세움. 51행의 .do_nothing이 그것을 지움), https://github.com/pret/pokecrystal/blob/master/engine/gfx/color.asm ↩↩↩↩↩↩

  35. pret, pokecrystal/gfx/tilesets/johto_palette_map.asm, 5beda23, 2026년 10월 5일 열람: 성도 타일셋의 타일 192개 각각의 팔레트, https://github.com/pret/pokecrystal/blob/master/gfx/tilesets/johto_palette_map.asm ↩

  36. pret, pokecrystal/gfx/tilesets/roofs.pal, 5beda23, 2026년 10월 5일 열람: 항목 27개, 맵 그룹마다 아침과 낮 쌍과 밤 쌍, https://github.com/pret/pokecrystal/blob/master/gfx/tilesets/roofs.pal ↩

  37. pret, pokecrystal/engine/overworld/events.asm, 5beda23, 2026년 10월 5일 열람: HandleMapTimeAndJoypad(193행), 이것은 wMapEventStatus가 MAPEVENTS_OFF이면 돌아가고(194~196행), 그렇지 않으면 UpdateTime, GetJoypad, TimeOfDayPals를 부름(198~200행), https://github.com/pret/pokecrystal/blob/master/engine/overworld/events.asm ↩↩

  38. pret, pokecrystal/data/maps/setup_scripts.asm, 5beda23, 2026년 10월 5일 열람: 맵 준비 스크립트 열두 개(4~15행의 표). MapSetupScript_Fly(29행, 30행에 mapsetup FadeOutToWhite, 32행의 MapSetupScript_Warp로 이어지며, 그 mapsetup FadeInFromWhite는 52행으로 끝나기 두 명령 전). MapSetupScript_Door(102, 103행에 mapsetup FadeOutToWhite, 104행의 MapSetupScript_Train으로 이어지며, 그 mapsetup FadeInFromWhite는 121행). MapSetupScript_Connection(81)에는 페이드가 없고, FadeInFromBlack이나 FadeOutToBlack을 지목하는 스크립트는 없음. 또 engine/overworld/events.asm 1005행, WarpToNewMapScript의 newloadmap MAPSETUP_DOOR, 플레이어가 밟는 워프가 실행하는 준비. engine/events/overworld.asm 619행, newloadmap MAPSETUP_FLY. engine/overworld/scripting.asm 2074행, 스크립트 명령 warp를 위한 MAPSETUP_WARP. home/map.asm, FadeToMenu(1910, 1914행에 farcall FadeOutToWhite), CloseSubmenu(1919)와 ExitAllMenus(1927), 이것들은 ReloadTilesetAndPalettes(1966, 그 farcall UpdateTimeOfDayPal은 1979행)를 부르고 FinishExitMenu(1933, 1938행에 farcall FadeInFromWhite)로 끝남. 시작 메뉴, engine/menus/start_menu.asm: StartMenu(13행), 자기만의 Fade 호출은 없고 39, 44, 92행에 call UpdateTimePals(home/time_palettes.asm 20행, UpdateTimePals가 _UpdateTimePals를 부름), 그 .Exit(80), 그리고 call FadeToMenu하는 항목 여섯 개, StartMenu_Option(447), StartMenu_Status(455), StartMenu_Pokedex(466), StartMenu_Pokegear(475), StartMenu_Pack(482), StartMenu_Pokemon(501), 이것들은 CloseSubmenu, ExitAllMenus, 또는 메뉴의 .Clear(155행에 call FinishExitMenu)를 거쳐 돌아옴. FadeToMenu는 mobile/과 home/map.asm 밖의 파일 8개에서 21번 불리며, 그중 6번이 시작 메뉴이고, 나머지는 engine/events/specials.asm(8), engine/pokemon/mail.asm(2), 그리고 engine/items/mart.asm, engine/events/pokecenter_pc.asm, engine/overworld/select_menu.asm, engine/events/move_tutor.asm, engine/events/battle_tower/battle_tower.asm에 각각 한 번으로, gen2_daylight.txt 섹션 E가 셈. 그리고 검은색 쌍을 special로 부르는 맵 스크립트 열한 개, 각각 나가기와 들어오기가 한 번씩: 본문이 지목하는 셋, maps/SproutTower3F.asm(55행과 59행), Route24(29, 33), TeamRocketBaseB2F(110, 118), 그리고 여덟 개 더로, 각각 두 줄과 함께 gen2_daylight.txt 섹션 E에 나열함, https://github.com/pret/pokecrystal/blob/master/data/maps/setup_scripts.asm ↩↩

  39. pret, pokecrystal/data/maps/maps.asm, 5beda23, 2026년 10월 5일 열람: map 매크로(1~15행, 필드 여덟 개: 맵, 그 타일셋, 환경, 랜드마크, 음악, 전화 플래그, 팔레트 모드, 낚시 그룹), 맵 그룹 26개의 포인터(17~46), 그리고 맵 헤더 388개, 각각 환경과 팔레트 모드를 가지며, 그중에는 라디오 타워 다섯 층(95~99)이 있고, 그 음악 필드는 식 RADIO_TOWER_MUSIC | MUSIC_GOLDENROD_CITY. PALETTE_NITE 맵 27개 중 IlexForest(130행)와 TohjoFalls(161행)는 CAVE, BurnedTower1F는 DUNGEON(91행), DragonShrine은 INDOOR(160행), UndergroundPath는 GATE(164행), https://github.com/pret/pokecrystal/blob/master/data/maps/maps.asm ↩↩

  40. pret, pokered/home/overworld.asm, d2704a6, 2026년 10월 5일 열람: 워프 코드의 ROCK_TUNNEL_1F 검사와 ld [wMapPalOffset], a(497~500행), https://github.com/pret/pokered/blob/master/home/overworld.asm ↩↩↩

  41. pret, pokered/home/fade.asm, d2704a6, 2026년 10월 5일 열람: 오프셋을 뺀 FadePal4에서 읽는 LoadGBPal과 FadePal2:: dc 3,3,3,2, 3,3,3,2, 3,3,2,0(66행), https://github.com/pret/pokered/blob/master/home/fade.asm ↩

  42. pret, pokered, d2704a6, 2026년 10월 5일 열람: wMapPalOffset에 대한 모든 쓰기. home/overworld.asm 500행(6, 야외 맵에서 ROCK_TUNNEL_1F로 가는 워프에서), 535행(0, 바깥으로 돌아가는 워프에서. 실내 분기, 508행의 .indoorMaps는 그것을 쓰지 않음), 790행(0, HandleFlyWarpOrDungeonWarp 안). engine/menus/start_sub_menus.asm 187행(0, 플래시). engine/events/black_out.asm 7행(0). engine/battle/init_battle_variables.asm 18행(전투를 위한 0), engine/battle/core.asm이 6667행에서 푸시하고 6768행에서 팝하는 값에서 되돌림. 그리고 data/maps/objects/RockTunnelB1F.asm, 그 warp_event 줄 네 개(15~18)는 모두 ROCK_TUNNEL_1F로 이어짐, https://github.com/pret/pokered ↩

  43. Blake Crosley, “A Pixel Town Alive When Nobody Is Online: NPCs and Ghosts”, blakecrosley.com, 2026년 10월 5일: Emerald의 UpdatePerDay와 그것이 부르는 함수들, 그중 UpdateWeatherPerDay. 그리고 그 7.1절의 브리프의 방 시계: “Every room runs on one clock: the server’s time in UTC, read in the room’s own time zone, one IANA zone per room in the server’s configuration”(모든 방은 하나의 시계로 돈다. UTC의 서버 시각을 방 자신의 시간대로 읽으며, 서버 설정에서 방마다 IANA 시간대 하나), welcome과 조용한 광장의 응답에서 {"zone": "<IANA name>", "clock": <server ms>}로 보내지며, “and while the plaza is open the app takes its day-part from them rather than from the phone, so everyone in a room sees the same townspeople under the same light”(광장이 열려 있는 동안 앱은 시간대를 휴대폰이 아니라 그것에서 가져오므로, 방 안의 모두가 같은 빛 아래 같은 마을 사람들을 본다), “Outside the plaza the phone’s clock stays the collector’s“(광장 밖에서는 휴대폰의 시계가 수집가의 것으로 남는다), Calendar.current를 읽는 오늘의 Daylight.now, 그리고 그 검사 (b), “a client test with the phone’s zone set to a different one from the room’s asserts that the plaza’s day-part follows the room’s clock”(휴대폰의 시간대를 방과 다르게 설정한 클라이언트 테스트가, 광장의 시간대가 방의 시계를 따름을 검증한다), https://blakecrosley.com/blog/pixel-art-town-alive-when-nobody-is-online ↩↩↩↩↩↩↩↩↩

  44. pret, pokeemerald/include/constants/weather.h, 731ad5b, 2026년 10월 5일 열람: WEATHER_NONE(4행)부터 WEATHER_ROUTE123_CYCLE(21행)까지 WEATHER_* 값 18개, SNOW, FOG_DIAGONAL, UNDERWATER를 쓰지 않음으로 표시하는 주석과 SHADE의 “Original name was closer to WEATHER_CLOUDY/OVERCAST”(원래 이름은 WEATHER_CLOUDY/OVERCAST에 가까웠다), 그리고 COORD_EVENT_WEATHER_* 값 13개, https://github.com/pret/pokeemerald/blob/master/include/constants/weather.h ↩

  45. pret, pokeemerald/src/trig.c, 731ad5b, 2026년 10월 5일 열람: gSineTable(5행), https://github.com/pret/pokeemerald/blob/master/src/trig.c ↩

  46. W3C Web Accessibility Initiative, “Understanding Success Criterion 2.3.1: Three Flashes or Below Threshold”, WCAG 2.2 Understanding Docs, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 wcag-three-flashes.html과 .txt로 저장(레벨 A. “Web pages do not contain anything that flashes more than three times in any one second period, or the flash is below the general flash and red flash thresholds”(웹 페이지는 어떤 1초 동안이든 세 번보다 많이 번쩍이는 것을 담지 않거나, 섬광이 일반 섬광 및 적색 섬광 문턱 아래에 있다). “Flashing content can cause migraines, dizziness, nausea, and seizures”(번쩍이는 콘텐츠는 편두통, 어지럼증, 메스꺼움, 발작을 일으킬 수 있다)), https://www.w3.org/WAI/WCAG22/Understanding/three-flashes-or-below-threshold.html ↩↩↩↩↩↩↩

  47. pret, pokeemerald/data/maps/*/map.json, 731ad5b, 2026년 10월 5일 measure_gen3_weather.py로 열람: 맵 518개, 각 헤더의 weather, map_type, requires_flash, coord_events. 예: https://github.com/pret/pokeemerald/blob/master/data/maps/Route119/map.json ↩

  48. pret, pokefirered/data/maps/*/map.json, 037335f, 2026년 10월 5일 measure_gen3_weather.py로 열람: 맵 425개, https://github.com/pret/pokefirered/tree/master/data/maps ↩

  49. pret, pokeemerald/src/field_screen_effect.c, 731ad5b, 2026년 10월 5일 열람: sFlashLevelToRadius와 gMaxFlashLevel(53행과 54행), 그리고 DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2를 중심으로 하는 플래시 효과(980행), https://github.com/pret/pokeemerald/blob/master/src/field_screen_effect.c ↩

  50. pret, pokeemerald/src/overworld.c, 731ad5b, 2026년 10월 5일 열람: SetDefaultFlashLevel(971~979행: gMapHeader.cave가 설정되지 않았으면 레벨 0, FLAG_SYS_USE_FLASH가 있으면 1, 그렇지 않으면 gMaxFlashLevel - 1), 그리고 include/global.fieldmap.h 180행, 헤더의 u8 cave, 이것은 tools/mapjson/mapjson.cpp 164행이 각 맵의 requires_flash에서 씀, https://github.com/pret/pokeemerald/blob/master/src/overworld.c ↩

  51. pret, pokeemerald/graphics/field_effects/pics/, 731ad5b(shadow_small.png, shadow_medium.png, shadow_large.png, shadow_extra_large.png), 2026년 10월 5일 measure_shadows.py로 열람. 재현하지 않음, https://github.com/pret/pokeemerald/tree/master/graphics/field_effects/pics ↩

  52. Blake Crosley, “Pixel-Art Ledges, Stairs and Bridges in a Tile World”, blakecrosley.com, 2026년 10월 5일: 그 3절 “The shadow stays on the ground”(그림자는 땅에 남는다), Red, Crystal, Emerald에서 땅에 남는 점프의 그림자. 그리고 2023년 8월 29일 Screen Rant 인터뷰에서 인용한 Sabotage Studio의 Thierry Boulanger, 레벨이 “to all read well with different levels of height, with the light and everything”(높이가 다른 곳에서도 빛과 모든 것과 함께 잘 읽히도록) 해야 했다는 말(https://screenrant.com/sea-stars-interview-thierry-boulanger/), https://blakecrosley.com/blog/pixel-art-elevation-ledges-bridges ↩↩↩

  53. Stardew Valley Wiki, “Modding:Maps”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sdv-modding-maps.html과 .txt로 저장(조명 속성 AmbientLight, 빛 종류 아홉 가지를 가진 Light, WindowLight. 그리고 NightTiles, “Changes the tile after 7pm”(오후 7시 이후 타일을 바꾼다), “mostly used for lamps in the game”(게임에서는 주로 가로등에 쓰인다)), https://stardewvalleywiki.com/Modding:Maps ↩↩↩↩↩↩

  54. 80.lv, “Moonlighter: Building Pixel Art & Preparing for Switch”, Digital Sun 인터뷰, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 moonlighter-80lv.html과 .txt로 저장, https://80.lv/articles/moonlighter-building-pixel-art-preparing-for-switch ↩

  55. Noel Berry, “Remaking Celeste’s Lighting”, 2017년 9월 25일, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 celeste-lighting.html과 .txt로 저장, https://noelberry.ca/posts/celeste_lighting/ ↩↩

  56. Game Developer, “Eastward’s creators share insights on making pixel art adventures”, Pixpil의 Tommo Zhou 인터뷰, 2021년 10월 11일, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 eastward-gamedev.html과 .txt로 저장, https://www.gamedeveloper.com/art/eastward-s-creators-share-insights-on-making-pixel-art-adventures ↩↩

  57. Nintendo Everything, Octopath Traveler 개발진과의 Nintendo Dream 인터뷰 번역, 2018년 11월 3일, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 octopath-ne.html과 .txt로 저장(조명에 대한 Shizuka Morimoto와 Tomoya Asano), https://nintendoeverything.com/octopath-traveler-devs-on-character-origins-visual-style-initial-hd-rumble-plans-much-more/ Unreal Engine의 Octopath Traveler 페이지 두 개는 가져오기 도구에도 curl에도 HTTP 403을 돌려주었음(octopath-ue.html이 그 403 페이지). ↩↩

  58. Wikipedia, “HD-2D”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 hd2d-wiki.html과 .txt로 저장. 2차 자료(“Typically, a point light source is placed into the scene to make characters and objects cast shadows”(보통 캐릭터와 사물이 그림자를 드리우도록 장면에 점광원을 둔다)), https://en.wikipedia.org/wiki/HD-2D ↩

  59. Alana Hagues, “Triangle Strategy Producers Talk HD-2D And Why Other Devs Haven’t Used it”, Nintendo Life, 2022년 5월 30일, Tomoya Asano와 Yasuaki Arai의 4Gamer 인터뷰를 보도한 것으로, 리드는 “It costs more than you’d think”(생각보다 비용이 든다), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 triangle-nlife.html과 .txt로 저장, https://www.nintendolife.com/news/2022/05/triangle-strategy-producers-talk-hd-2d-and-why-other-devs-havent-used-it ↩↩

  60. Sabotage Studio, Sea of Stars 보도 자료, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sos-presskit.html과 .txt로 저장, https://sabotagestudio.com/presskits/sea-of-stars/ ↩

  61. TechRaptor, “Sea of Stars Gameplay Clip Shows Day & Night Cycle”, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sos-techraptor.html과 .txt로 저장, https://techraptor.net/gaming/news/sea-of-stars-gameplay-clip-shows-day-night-cycle ↩

  62. Raymond Schlitter, “Pixelblog 21: Top Down Objects”, SLYNYRD, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 slynyrd-objects.html과 .txt로 저장, https://www.slynyrd.com/blog/2019/9/18/pixelblog-21-top-down-objects ↩↩↩

  63. Raymond Schlitter, “Pixelblog 43: Top Down Tiles Part 2”, SLYNYRD, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 slynyrd-tiles2.html과 .txt로 저장, https://www.slynyrd.com/blog/2023/3/26/pixelblog-43-top-down-tiles-part-2 ↩↩↩↩↩↩↩↩

  64. Raymond Schlitter, “Pixelblog 44: Top Down Trees”, SLYNYRD, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 slynyrd-trees.html과 .txt로 저장, https://www.slynyrd.com/blog/2023/5/22/pixelblog-44-top-down-trees ↩

  65. Shmuplations, 성검전설 3에 관한 Koichi Ishii 번역 인터뷰, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 sd3-shmuplations.html과 .txt로 저장, https://shmuplations.com/seikendensetsu3/ ↩↩↩↩

  66. Kiradex 소스, Kiradex/World/Glow.metal, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소): glowSurface, 그림의 색에 틴트를 곱한 것을 기본 색과 발광 색 둘 다로 불투명도 1로 설정함. 주석 “Light that adds, as light does”(빛이 그러듯 더하는 빛)와 그 줄 “black adds nothing, and a pool of light never darkens what it lies on, which an alpha halo did.”(검정은 아무것도 더하지 않고, 빛 웅덩이는 자기가 놓인 것을 결코 어둡게 하지 않는다. 알파 헤일로는 그렇게 했다) 아래에 있음(6~10행). ↩↩↩↩↩↩

  67. Kiradex 포지, scripts/forge/air.py, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점에 열람(비공개 저장소): docstring의 그림, glow.png(“a radial pool, white at the centre falling to black”(중심이 희고 검정으로 떨어지는 방사형 웅덩이))와 cloud.png(“a tileable mask of cloud shadow: alpha where a cloud passes”(타일로 이어 붙일 수 있는 구름 그림자 마스크. 구름이 지나는 곳에 알파)), 9~13행. ↩↩

  68. Kiradex 테스트, KiradexUITests/KiradexUITests.swift, 2026년 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소): testThePlazaKeepsTime(502행), -plazaHour 21과 -airProbe로 실행(503). 그리고 testTheChimneysSmoke(523), -plazaHour 12로 실행하고(524), 공기의 보고가 smoke 18을 담기를 기다린 뒤(531행과 532행), 걷기가 “Up the grand stair onto the terrace, left of the fountain”(큰 계단을 올라 테라스로, 분수의 왼쪽으로) 간다는 주석 아래에서(534~537행) 광장의 정규화된 (0.38, 0.3)을 탭함(538). 도우미 wait(for:toRead:)(1171행), launch(1179행, app.launch() 전에 launchArguments를 설정함), save(1212행, 화면의 스크린숏). 파일 날짜는 2026년 10월 5일 10:32이며, 줄 번호는 그 사본의 것. ↩↩↩↩↩↩↩

  69. Kiradex 소스, Kiradex/World/HallView.swift, 2026년 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 파일 날짜는 그날 14:59): 파일을 여는 주석 “The show hall: off the plaza”(쇼 홀: 광장 밖)(5행), 그리고 홀은 “is not networked”(네트워크에 연결되어 있지 않다)이며, 들어갈 때 광장이 방을 떠난다는 것(9~11). “The show is entered through the veil.”(쇼에는 베일을 지나 들어간다)(34). 그리고 그것이 만드는 PlazaStage(57), client: nil과 함께(58). 커밋이 66c116b0이던 18:07에도 파일은 같은 바이트였음. ↩↩↩↩

  70. Kiradex 디자인 계획, docs/research/design/01-art-direction-v2.md, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점에 열람(비공개 저장소): 4절 “The plan, by build,”(빌드별 계획), 그 빌드 29는 빛 웅덩이, 구름 그림자, 안개, 잎, 반딧불이, 그리고 “a vignette and tilt-shift depth of field as the camera’s rendering effects”(카메라의 렌더링 효과로서 비네트와 틸트 시프트 피사계 심도)를 나열함. ↩↩

  71. Apple Developer Documentation, UnlitMaterial(RealityKit), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-unlitmaterial.html로 저장한 페이지 JSON: “A material that doesn’t respond to lights in the scene”(장면의 빛에 반응하지 않는 머티리얼). iOS 13.0+, macOS 10.15+. 그리고 그 토픽 목록의 textureCoordinateTransform, “A two-dimensional transformation to apply to the entity’s primary texture coordinates”(엔티티의 주 텍스처 좌표에 적용할 2차원 변환), 오프셋과 스케일의 순서에 대한 진술은 없음. 그리고 init(applyPostProcessToneMap:), “Creates an UnlitMaterial with the given tone mapping setting”(주어진 톤 매핑 설정으로 UnlitMaterial을 만든다), 평범한 이니셜라이저가 톤 매핑에 대해 무엇을 하는지에 대한 진술은 없음, https://developer.apple.com/documentation/realitykit/unlitmaterial ↩↩↩

  72. Kiradex 소스, Kiradex/World/SpriteSheet.swift, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점에 열람(비공개 저장소. 줄 번호는 그 사본의 것): 오프셋(열 ÷ 열 수, 행 ÷ 행 수)과 스케일(1 ÷ 열 수, 1 ÷ 행 수)을 가진 프레임 머티리얼의 textureCoordinateTransform(65행), 오프셋을 텍스처 왼쪽 위에서 잰다고 기록하는 주석, “measured on the simulator”(시뮬레이터에서 측정함) 아래에 있음. semantic: .color로 만든 시트의 텍스처(37). 그리고 평범한 UnlitMaterial()을 만드는 material(light:)(75와 76). 또 Air.swift 223행, 연기 프레임도 같은 방식으로 설정됨. ↩↩

  73. Kiradex 소스, Kiradex/World/Motion.swift, 2026년 10월 5일 17:18에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 파일 날짜는 그날 12:36이며, 커밋이 66c116b0이던 18:07에도 같은 바이트): 그 헤더, 모션 글의 브리프를 출처로 밝힘(3~6행). TickClock, 디스플레이 속도와 상관없이 세계에 정수 개의 60분의 1초를 건넴, ticksPerSecond = 60(14~52, 상수는 17). Stride.pixels, 16(57), 그리고 Stride.ticks(diagonal:running:)(67~74): 곧은 걷기 한 걸음에 16틱, 달리기에 8, 대각선에 23과 12. 그리고 Stepping.tick()(215), 틱 수가 보폭의 것에 이르면 한 걸음을 끝냄. measure_kiradex_proposals.py와 arith.py는 세 수치를 이 사본에서 읽음. ↩↩↩↩

  74. Kiradex 포지, scripts/forge/town.py, 날짜 2026년 10월 3일, 10월 5일 16:51에 커밋 cf3beb1e 시점에 열람(비공개 저장소. 줄 번호는 그 사본의 것): 범례의 “a lamp post on paving (as l, with its shadow in the stone’s shade)”(포장석 위의 가로등 기둥(l과 같으며, 그 그림자는 돌의 그늘 색))(29행). paint 안(403행부터)의 벽 그림자, “the top four rows of whatever stands at its foot”(그 발치에 있는 것의 위쪽 네 행), 한 단계 어둡게, “the way the light falls at Leene.”(Leene에서 빛이 떨어지는 방식)(426~436행). ↩↩↩↩

  75. Kiradex 소스, Kiradex/World/FigurePreview.swift, 날짜 2026년 10월 4일, 10월 5일 16:51에 커밋 cf3beb1e 시점에 열람(비공개 저장소): 25행의 @Environment(\.accessibilityReduceMotion), Kiradex/World/에서 이 설정을 읽는 유일한 곳. ↩

  76. Kiradex 소스, Kiradex/World/PlazaClient.swift, 날짜 2026년 10월 3일, 10월 5일 17:42에 커밋 5a344e3f 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소): handle(_:)의 case "welcome":(214행), 이것은 서버의 welcome에서 you, room, lines, players를 가져오고 다른 것은 가져오지 않음. endpoint(87~91행), 이것은 실행 인자에서 -plazaServer를 읽으며, 그 주석의 예 ws://127.0.0.1:8300/v1/plaza에서는 “points a run at a local”(실행을 로컬로 향하게 한다) 서버이고, 그렇지 않으면 프로덕션 wss:// 엔드포인트를 씀. 파일 어디에서도 zone이나 clock을 읽지 않음. 18:19에 커밋 66c116b0 시점에 다시 읽음: 같은 바이트. ↩↩↩

  77. Blake Crosley, “Pixel-Art Motion: Walks, Cameras and Doors on iPhone”, blakecrosley.com, 2026년 10월 5일: 브리프의 항목 1, “The walk is 1 pixel a tick, 16 ticks a tile; the run is 2 pixels a tick, 8 ticks”(걷기는 틱당 1픽셀, 타일당 16틱. 달리기는 틱당 2픽셀, 8틱), 60헤르츠 틱에서 걷기는 초당 60픽셀. 앱은 오늘 그 틱과 보폭을 Motion.swift에서 실행함(7절), https://blakecrosley.com/blog/pixel-art-motion-on-iphone ↩↩

  78. Apple Developer Documentation, MaterialParameterTypes.BlendMode(RealityKit), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-mpt-blendmode.html로 저장한 페이지 JSON: “Modes that describe how materials should be blended with content behind them”(머티리얼을 뒤에 있는 콘텐츠와 어떻게 블렌딩할지 기술하는 모드). 열거 케이스 add와 alpha. iOS 18.0+, iPadOS 18.0+, Mac Catalyst 18.0+, macOS 15.0+, tvOS 26.0+, visionOS 2.0+, https://developer.apple.com/documentation/realitykit/materialparametertypes/blendmode ↩↩↩↩↩↩

  79. Apple Developer Documentation, MaterialParameterTypes.BlendMode.add, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-blendmode-add.html로 저장한 페이지 JSON: “Blend by adding the material’s color to the background color, ignoring alpha”(알파를 무시하고 머티리얼의 색을 배경 색에 더해 블렌딩한다). “also known as additive blending or linear dodge”(가산 블렌딩 또는 리니어 닷지라고도 한다). 같은 지원 정보, https://developer.apple.com/documentation/realitykit/materialparametertypes/blendmode/add ↩↩

  80. Apple Developer Documentation, CustomMaterial(RealityKit), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-custommaterial.html로 저장한 페이지 JSON: “A material that works with custom Metal shader functions”(사용자 정의 Metal 셰이더 함수와 함께 작동하는 머티리얼). iOS 15.0+, iPadOS 15.0+, Mac Catalyst 15.0+, macOS 12.0+, tvOS 26.0+, https://developer.apple.com/documentation/realitykit/custommaterial ↩

  81. Apple Developer Documentation, TimelineView(SwiftUI), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-timelineview.html로 저장한 페이지 JSON: “A view that updates according to a schedule that you provide”(제공한 일정에 따라 갱신되는 뷰). iOS 15.0+, https://developer.apple.com/documentation/swiftui/timelineview ↩

  82. Apple Developer Documentation, TimelineSchedule.everyMinute(SwiftUI), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-everyminute.html로 저장한 페이지 JSON: “A schedule for updating a timeline view at the start of every minute”(매분 시작 시점에 타임라인 뷰를 갱신하는 일정). iOS 15.0+, https://developer.apple.com/documentation/swiftui/timelineschedule/everyminute ↩

  83. Apple Developer Documentation, UIApplication.significantTimeChangeNotification(UIKit), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-significanttime.html로 저장한 페이지 JSON: “when, for example, there’s a change to a new day (midnight), a carrier time update, or a change to, or from, daylight savings time”(예를 들어 새로운 날로의 변화(자정), 이동통신사 시간 갱신, 일광 절약 시간으로의 또는 그로부터의 변화가 있을 때) 게시됨. 페이지는 iOS, iPadOS, Mac Catalyst, tvOS, visionOS를 버전 없이 나열함, https://developer.apple.com/documentation/uikit/uiapplication/significanttimechangenotification ↩↩↩↩↩↩

  84. Apple Developer Documentation, NSNotification.Name.NSSystemTimeZoneDidChange(Foundation), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-systemtimezonechange.html로 저장한 페이지 JSON: “A notification posted when the time zone changes”(시간대가 바뀔 때 게시되는 알림). iOS 2.0+, https://developer.apple.com/documentation/foundation/nsnotification/name-swift.struct/nssystemtimezonedidchange ↩↩↩

  85. Apple Developer Documentation, EnvironmentValues.timeZone(SwiftUI), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-timezone.html로 저장한 페이지 JSON: “The current time zone that views should use when handling dates”(뷰가 날짜를 다룰 때 써야 할 현재 시간대). iOS 13.0+, https://developer.apple.com/documentation/swiftui/environmentvalues/timezone ↩

  86. Apple Developer Documentation, EnvironmentValues.accessibilityReduceMotion(SwiftUI), 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-reducemotion.html로 저장한 페이지 JSON: “Whether the system preference for Reduce Motion is enabled”(Reduce Motion 시스템 설정이 켜져 있는지). “If this property’s value is true, UI should avoid large animations, especially those that simulate the third dimension”(이 속성의 값이 true이면, UI는 큰 애니메이션, 특히 3차원을 흉내 내는 애니메이션을 피해야 한다). var accessibilityReduceMotion: Bool { get }으로 선언. iOS 13.0+, https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityreducemotion ↩↩↩↩

  87. Apple Developer Documentation, WeatherKit, 2026년 10월 5일 이 글을 위한 저자의 증거 폴더에 apple-weatherkit.html로 저장한 페이지 JSON: “Deliver weather conditions and alerts to your users”(사용자에게 기상 상황과 경보를 전달한다). iOS 16.0+, https://developer.apple.com/documentation/weatherkit ↩↩↩

  88. Kiradex 소스, Kiradex/World/CollectorComposer.swift, 2026년 10월 5일 18:07에 커밋 66c116b0 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소. 파일 날짜는 10월 4일 07:40), Kiradex/Resources/World/characters.json(날짜 10월 4일 07:20, 16:51 읽기 때와 같은 바이트)과, 같은 때 복사한 인물 시트 123개 fig-*.png와 함께: 헤더, 모든 시트는 “an 8-bit plane whose value is an index × 2 (0 clear, 63 the eraser”(값이 인덱스 × 2인 8비트 평면(0은 투명, 63은 지우개))(5~14행). sparse(_:), 평면의 불투명 픽셀, 곧 투명도 지우개도 아닌 것(66). layers(for:), 늘 몸, 눈, 들고 있는 카드를 더함(131). 그리고 indexPlane(for:), 각 방향에 대해 매니페스트의 순서로 레이어를 겹치며, 마지막 불투명 인덱스가 이김(153). ↩↩

  89. Kiradex 저장소, 2026년 10월 15일 23:53에 git을 실행하지 않고 열람: 파일로 읽은 .git/refs/heads/main, fc9d4876(10월 15일 17:45 커밋). 아래 각 파일은 그 커밋의 객체에서 zlib으로 꺼내 작업 트리의 사본과 바이트 단위로 비교했으며, 모든 경우에 같았음(비공개 저장소. 줄 번호는 그 커밋의 것): Kiradex/World/PlazaClient.swift, roomClock과 roomZone(79~83), roomDate, “The room’s time now, from the welcome’s clock”(welcome의 시계에서 얻은 방의 지금 시각)(109~113), 그리고 json["clock"]과 json["zone"]을 읽는 welcome 핸들러(265~267). server/app/main.py, "zone"과 "clock"을 실어 나르는 welcome(21, 22, 228)과 ZONE, “one for the whole world until rooms are sharded by region”(방이 지역별로 나뉠 때까지 세계 전체에 하나), PLAZA_ZONE이 설정되지 않으면 UTC(77~79). Kiradex/World/PlazaStage.swift, clock “re-read each minute: the light follows it”(매분 다시 읽는다. 빛은 그것을 따른다)(64와 65), 그것을 읽는 relight()(86), 그리고 “A quiet plaza joins no room”(조용한 광장은 어떤 방에도 들어가지 않는다)(919). scripts/forge/protected_names.txt, “Names the world never uses”(세계가 결코 쓰지 않는 이름), 그리고 server/tests/test_names.py, “The deny list: no franchise word and no canon place in anything the world names”(거부 목록: 세계가 이름 붙이는 어떤 것에도 프랜차이즈 단어도 정전의 장소도 넣지 않는다). 작업 트리의 Kiradex/와 KiradexTests/에서 significantTimeChange와 NSSystemTimeZoneDidChange를 검색했으나 아무것도 찾지 못함. 읽기 스크립트와 사본은 이 글을 위한 저자의 증거 폴더에 있음. ↩↩↩

  90. Kiradex 소스, 2026년 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소): Kiradex/World/QuestBoardView.swift(날짜 10월 2일), 퀘스트 게시판, 자기만의 뷰로, PlazaStage.swift의 PlazaView에서(날짜 17:22 파일의 690행, 17:42에 커밋 5a344e3f 시점에 읽음)와 Kiradex/Views/Me/MeView.swift에서(날짜 07:52 파일의 65행) 시트로 띄워짐. ↩

  91. Blake Crosley, “Pixel-Art People: Characters and a Creator on iPhone”, blakecrosley.com, 2026년 10월 3일: iPhone 18 Pro Max에서 “a 440-by-956-point view at 3× shows 165 by 358 world pixels”(3배에서 440×956포인트 뷰는 월드 165×358픽셀을 보여 준다), https://blakecrosley.com/blog/pixel-art-characters-on-iphone ↩

  92. Kiradex 소스, 2026년 10월 5일 16:51에 커밋 cf3beb1e 시점, 그날 편집 중이던 작업 트리에서 열람(비공개 저장소): Kiradex/Views/Me/MeView.swift(날짜 그날 07:52), Me 탭의 “Your Room” 버튼, me-room(272~277행), 이것은 광장의 서버 없이 플레이어 자신의 방을 엶. 그리고 포지의 scripts/forge/interiors.py(날짜 10월 3일), 그 ROOM 격자(57~70행)는 1층의 (3, 1)에 커튼 달린 창 K를, (12, 1)에 창 N을 두며, window(259행)와 curtained_window(278행)로 그림. 내보낸 room.json과 room-up.json에는 창 셀 목록이 없음. ↩↩

  93. Blake Crosley, “Pixel-Art Routes: Map Connections and Districts on iPhone”, blakecrosley.com, 2026년 10월 5일: 그 브리프의 이름과 그림, “The deny list does not exist yet: the dossier promised one in the repository, and the repository has none”(거부 목록은 아직 존재하지 않는다. 조사 자료는 저장소에 하나 두겠다고 약속했지만, 저장소에는 아무것도 없다), 목록과 그 테스트를 만드는 일을 그 브리프의 일부로 삼음, https://blakecrosley.com/blog/pixel-art-world-beyond-the-plaza ↩

관련 게시물

픽셀 아트 건물: iPhone에서 짓는 집, 홀, 실내

Pokémon, SNES RPG, 스타듀 밸리가 집과 실내와 층을 어떻게 짓는지 소스에서 측정하고, Kiradex의 iPhone 마을에 진짜 건물이 들어서기까지를 정리했습니다.

64 분 소요

픽셀 아트의 길: iPhone에서 만드는 맵 연결과 구역

포켓몬, 스타듀 밸리, 동물의 숲은 마을과 마을 사이의 땅을 어떻게 만들까요? 도로, 이음매, 게이트, 지도 화면을 소스에서 측정하고 Kiradex를 위한 브리프로 정리했습니다.

86 분 소요

App Review는 무엇을 보는가, 알려진 범위 안에서: 2026년 10월

2026년 10월 기준 Apple의 App Review를 공개 기록으로 읽습니다. 누가 심사하고, 얼마나 걸리고, 무엇이 거절을 부르며 그 문구는 어떻게 쓰여 있는지, 2025~2026년의 규칙 변경, 그리고 첫 제…

45 분 소요