안녕하세요! 그로스로그 입니다!😊 🌱
"CSS에 그런 속성이 있겠지" 하고 시작했다가 네 시간을 쓴 기록, 그리고 프로그램의 1이 회로에서는 5V라는 걸 손으로 확인한 기록. 3기 5회차입니다.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 매 회차 운영진이 모든 글을 읽고, 그중 특히 마음에 남은 글을 함께 골라 큐레이션합니다.
01
⬛ QR 마스크 만들기 (SVG)
강단 님
QR 스캔 화면을 만드는 작업입니다. 화면 전체는 어둡게 흐리고, 가운데 네모만 뚫려서 선명하게 보이는 그 화면이요.
첫 문장이 이 글의 전부를 말합니다. "만만하게 봤다가 큰코다친 경험."
최소 기능 20~30분으로 잡고 시작했다가 4시간 넘게 씨름합니다.
clip-path도, mask-composite도 안 됐어요. 결국 SVG 마스크로 풀어냅니다.3회차에서 HTML 스트림을 파고드셨던 그분입니다. 이번엔 실무에서 정면으로 막힌 기록이에요.
조금 더 들어가 보면
요구사항은 세 줄로 정리됩니다.
1. 전체 영역에 검은 마스크(블러 처리)가 있다
2. 가운데 구멍이 뚫려 있다
3. 구멍 내부는 선명하게 보인다
3번이 함정입니다. 이게 왜 어려운지가 이 글의 핵심이에요.
CSS는 "부여"는 쉽지만 "제외"가 어렵습니다. 글의 표현이 정확해요.
여기가 문제의 정체입니다. "이 영역에 블러를 걸어라"는 쉽습니다. 그런데 "이 영역만 빼고 전부에 블러를 걸어라"는 CSS 사고방식에 없어요.
그래서 순진하게 시도하면 결과가 정반대로 나옵니다. 글에 그대로 적혀 있죠.
3. 정사각형 외부 : 선명 (흐려야 함🤯)"
🧭 왜 clip-path와 mask로도 안 됐나
글이 두 속성의 차이를 명확히 정리합니다.
· clip-path — "보이는 부분"만 남기는 것
· mask — "가리는 부분/비우는 부분"을 조절하는 것
개념상으로는 mask가 답처럼 보입니다. 실제로 radial-gradient로 가운데를 투명하게 만드는 시도를 하죠.
그런데 안 됩니다. 글이 짚은 이유가 정확해요.
구멍을 뚫은 게 아니라 그 위에 흰 테두리 네모를 올려둔 것이었던 겁니다. 겉보기는 비슷한데, 아래 레이어의 블러는 그대로 살아 있어요. 가운데가 흐린 이유입니다.
그다음 mask-composite: xor, mask-composite: exclude 같은 속성까지 동원합니다. 글의 표현이 재미있어요. "듣도 보도 못한 속성을 사용해도 결과는 이랬다."
그리고 여기서 판단이 나옵니다.
이 문장이 이 글에서 가장 값진 부분입니다. 값을 계속 만지는 것과 접근 자체를 바꾸는 것 — 언제 갈아탈지를 아는 게 실력이거든요.
📝 원문에서는 이렇게 해결합니다
방향을 바꿉니다. CSS로 구멍을 뚫는 대신, SVG로 구멍 뚫린 그림을 그려서 덮는 방식이요.
글의 비유가 좋습니다. "미술 용어를 빌리자면 '선'이 아닌 '면치기'로 구현하는 것."
<defs>
<mask id="hole" maskUnits="userSpaceOnUse"
x="0" y="0" width={deviceWidth} height={deviceHeight}>
<rect width="100%" height="100%" fill="white" />
<rect
x="50%" y="50%"
width={boxSize} height={boxSize}
rx="20" ry="20"
fill="black"
transform={`translate(-${boxHalf}, -${boxHalf})`}
/>
</mask>
</defs>
<rect
width="100%" height="100%"
fill="black" fillOpacity="0.7"
mask="url(#hole)"
/>
흰색과 검은색의 뜻을 알면 전부 읽힙니다. SVG 마스크에서 흰색은 "보여라", 검은색은 "가려라"예요.
그래서 전체를 흰색으로 칠하고(= 다 보여라), 가운데 네모만 검은색으로 칠합니다(= 여기만 가려라). 그 마스크를 검은 반투명 사각형에 씌우면, 가운데만 뚫린 어두운 판이 완성됩니다.
CSS에서 그렇게 안 되던 "여집합"이 SVG에서는 색을 칠하는 일이 된 거예요. 문제를 다른 언어로 옮기니 표현이 가능해진 경우입니다.
transform={translate(-boxHalf, -boxHalf)}도 짚어둘 만합니다. x="50%"는 사각형의 왼쪽 위 모서리를 화면 중앙에 두는 거라, 그대로 두면 오른쪽 아래로 치우칩니다. 절반만큼 되돌려 진짜 가운데에 놓는 거죠.
🧭 그리고 반응형까지
글이 마지막에 짚은 부분이 실무적입니다.
그래서 resize 이벤트를 듣고 기기 크기를 다시 잽니다.
useEffect(() => {
startScanning()
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
return으로 리스너를 정리한 것이 중요합니다. 안 지우면 컴포넌트가 사라진 뒤에도 리스너가 남아 메모리 누수가 되거든요. 4시간 싸운 뒤에도 이런 뒷정리를 챙긴 게 눈에 띕니다.
QR 스캔 화면은 모바일에서 가로세로가 바뀌는 일이 흔하니 이 처리가 꼭 필요합니다.
큐레이터 노트
막힌 과정을 그대로 남겼기 때문에 뽑았습니다.
보통은 성공한 방법만 적습니다. 실패한 시도는 부끄러우니까요. 그런데 이 글은 실패 코드를 그대로 붙여뒀습니다. mask-composite: xor까지 써봤다는 것도요.
이게 왜 값진가 하면, 같은 문제를 만난 사람이 같은 길을 다시 걷지 않아도 되기 때문입니다. "CSS로 될 것 같은데?"라고 생각한 사람이 이 글을 보면 4시간을 아낍니다.
"만만하게 봤다가 큰코다친"이라는 첫 문장도 좋았어요. 30분 예상이 4시간이 된 걸 숨기지 않았습니다. 견적이 빗나가는 건 흔한 일이고, 그걸 적어두면 다음 견적이 정확해집니다.
그리고 이 저자의 3기 기록을 보면 흐름이 있습니다. 3회차 HTML 스트림, 이번엔 CSS 마스크. 9회차와 10회차에도 계속 등장하세요. 3기 최다 큐레이션 중 한 분입니다.
02
💡 아두이노의 디지털 신호와 논리값에 대해
김혜경 님
아두이노를 처음 공부하며 만난 HIGH/LOW, 5V/0V, 1/0, True/False가 서로 어떻게 연결되는지를 정리한 글입니다.
5V 핀과 GND 핀이 각각 무슨 역할인지, 왜 5V 핀 대신 디지털 핀을 쓰는지, 풀다운 저항이 왜 필요한지를 짚어요.
그리고 TinkerCAD로 두 가지 실습을 합니다. LED 깜빡이기와 버튼으로 LED 켜기요. 회로 연결부터 코드까지 전부 있습니다.
2회차에서 다익스트라를 정리하셨던 그분입니다. 이번엔 소프트웨어가 하드웨어와 만나는 자리예요.
조금 더 들어가 보면
이 글이 잇는 다리가 뭐냐면, 프로그래밍에서 쓰는 1과 0이 물리 세계에서 무엇인가입니다.
글의 표가 그 연결을 한눈에 보여줍니다.
| 전압 | 아두이노 상태 | 논리 값 | 논리 상태 | 상태 |
|---|---|---|---|---|
| 5V | HIGH | 1 | True | 켜짐(ON) |
| 0V | LOW | 0 | False | 꺼짐(OFF) |
소프트웨어만 하다 보면 true와 false는 그냥 추상적인 값입니다. 그런데 여기서는 true가 실제로 5볼트의 전압이에요. 코드 한 줄이 전자의 움직임을 만듭니다.
⚡ 5V 핀과 GND 핀, 그리고 "기준점"
글이 전류를 설명하는 방식이 좋습니다. 물의 비유를 씁니다.
그래서 GND 핀이 없으면 회로가 안 돕니다. 물이 흘러갈 곳이 없는 것과 같아요. 글의 표현대로 "GND 핀이 없으면 전류가 갈 곳을 잃기 때문에"입니다.
전기를 처음 만나는 개발자가 가장 헷갈리는 게 이 부분입니다. "전원만 연결하면 되는 거 아닌가?" 싶은데, 나가는 길과 돌아오는 길이 둘 다 있어야 하거든요.
🧭 왜 5V 핀이 아니라 디지털 핀을 쓰는가
이 글에서 가장 좋은 질문입니다. 5V 핀도 5V를 주는데 왜 굳이 13번 핀을 쓸까요?
답이 명쾌합니다.
그리고 이 한 줄로 정리합니다. "디지털 핀은 마치 프로그래밍 가능한 스위치처럼 동작한다."
"전원"과 "제어 신호"의 차이를 정확히 짚은 겁니다. 5V 핀은 콘센트이고, 디지털 핀은 스위치가 달린 콘센트예요. 깜빡이려면 스위치가 필요하죠.
코드로 보면 이렇습니다.
void setup() {
pinMode(13, OUTPUT); // 13번 핀을 출력으로 설정
}
void loop() {
digitalWrite(13, HIGH); // LED 켜기 (5V = HIGH)
delay(1000); // 1초 대기
digitalWrite(13, LOW); // LED 끄기 (0V = LOW)
delay(1000); // 1초 대기
}
setup()은 한 번, loop()는 무한 반복입니다. 전원이 들어와 있는 한 계속 도는 구조예요. 웹 프로그래밍의 이벤트 기반 사고와는 결이 다릅니다.
🔘 풀다운 저항 — 왜 아무것도 안 해도 값이 튀는가
두 번째 실습에서 나오는 개념이 흥미롭습니다.
버튼을 안 눌렀을 때, 디지털 핀 2번은 무슨 값을 읽을까요? 직관적으로는 "0"일 것 같습니다. 그런데 아니에요.
아무 데도 연결되지 않은 핀은 "떠 있는(floating)" 상태가 됩니다. 주변의 미세한 전기 잡음에 흔들려서 HIGH와 LOW를 제멋대로 오갑니다. 버튼을 건드리지도 않았는데 LED가 깜빡이는 현상이 이겁니다.
풀다운 저항이 이걸 막습니다. 글의 설명이 정확해요.
버튼을 안 누르면 저항을 통해 GND로 이어지니 확실하게 0V를 읽고, 버튼을 누르면 5V가 들어옵니다. 이때 저항이 크기 때문에(10kΩ) 대부분의 전류는 디지털 핀 쪽으로 갑니다.
"기본값을 명시적으로 정해두는 것" — 소프트웨어에서 변수를 초기화하는 것과 같은 이야기입니다. 초기화 안 한 변수가 쓰레기 값을 갖는 것처럼, 연결 안 한 핀은 쓰레기 신호를 읽어요.
void loop() {
int buttonState = digitalRead(buttonPin); // 버튼 상태 읽기
if (buttonState == HIGH) { // 버튼이 눌림 (5V = 1)
digitalWrite(ledPin, HIGH); // LED 켜기
} else { // 버튼이 안 눌림 (0V = 0)
digitalWrite(ledPin, LOW); // LED 끄기
}
}
digitalRead가 돌려주는 값이 곧 논리값입니다. 전압을 읽었는데 if문에 그대로 들어가요. 물리와 논리가 만나는 지점입니다.
큐레이터 노트
추상화 아래로 한 층 내려간 기록이라 뽑았습니다.
프로그래밍을 하다 보면 true와 false가 너무 익숙해져서 그게 무엇인지 묻지 않게 됩니다. 이 글은 그 아래에 전압이 있다는 걸 손으로 확인해요. 개념이 몸에 남는 방식입니다.
질문을 스스로 만든 것도 좋았습니다. "왜 13번 핀인가", "왜 5V 핀이 아닌가", "풀다운 저항이 왜 필요한가". 튜토리얼을 그냥 따라 했다면 안 나왔을 질문들이에요. 따라 하다가 걸린 지점을 그냥 넘기지 않은 겁니다.
그리고 첫머리의 이 문장이 인상적이었습니다.
"두서 없는 메모"라고 하셨지만, 실제로는 개념 → 원리 → 실습 → 정리 순서로 아주 잘 짜여 있습니다. 겸손한 표현과 실제 완성도가 반대인 글이었어요.
TinkerCAD를 쓴 것도 좋은 선택이었습니다. 부품 없이 브라우저에서 회로를 짜볼 수 있으니 진입 장벽이 훨씬 낮아지죠. 이 글을 읽고 바로 따라 해볼 수 있습니다.
💡 두 편을 겹쳐 읽으며
한 편은 CSS와 SVG, 한 편은 전압과 저항입니다. 멀어 보이죠.
그런데 두 글은 같은 자리에 서 있습니다. 둘 다 "쓰던 층에서는 안 되는 일"을 만났습니다.
강단 님은 CSS 안에서 답을 찾다가 네 시간을 썼습니다. 여집합을 표현할 방법이 없었으니까요. 답은 CSS 밖, SVG에 있었습니다.
김혜경 님은 코드 위에서만 보면 1과 0인 것을 회로까지 내려가 확인했습니다. 왜 핀이 흔들리는지는 소프트웨어 층에서 아무리 봐도 안 나오거든요.
한 층 옮기니 풀렸다 — 두 글이 공통으로 보여주는 장면입니다.
그리고 여기엔 조건이 하나 붙습니다. 그 층이 있다는 걸 알아야 옮길 수 있어요. SVG로 마스크를 만들 수 있다는 걸 몰랐다면 계속 CSS 값만 만졌을 겁니다. 풀다운 저항이라는 개념을 몰랐다면 "왜 자꾸 깜빡이지"에서 멈췄겠죠.
그래서 당장 안 쓸 것 같은 걸 배워두는 게 의미가 있습니다. 언젠가 막혔을 때 갈아탈 곳을 아는 것 — 그게 쌓인 게 실력이니까요.
이번 회차에서 가져갈 것
1. CSS는 "제외"가 어렵다. 영역의 여집합만 골라내는 건 CSS 사고방식에 없습니다. 구멍 뚫린 마스크가 필요하면 SVG를 떠올리세요.
2. 값을 계속 만지고 있다면 접근을 의심하기. 디테일 조정으로 될 일과 방식을 바꿔야 할 일은 다릅니다. "더 이상 값 조정으로 될 일이 아니다"를 판단하는 데 걸리는 시간이 실력이에요.
3. 실패한 시도도 기록하기. 성공한 코드만 남기면 읽는 사람이 같은 길을 다시 걷습니다. "이건 안 되더라"가 4시간을 아껴줍니다.
4. 전원과 제어 신호는 다르다. 5V 핀은 항상 켜진 콘센트, 디지털 핀은 스위치입니다. 켰다 껐다 해야 하면 제어 가능한 쪽을 쓰세요.
5. 연결 안 한 핀은 쓰레기 값을 읽는다. 초기화 안 한 변수와 같습니다. 풀다운(또는 풀업) 저항으로 기본값을 명시해두세요.
좋은 글 남겨주신 강단 님, 김혜경 님께 감사드립니다! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.