아이콘을 만들고 고치는 단독 앱. 다른 프로젝트가 없어도 혼자 돕니다. 설치할 것은 Node 하나뿐입니다 — npm 도, 빌드도, 인터넷도 필요 없습니다.
| 더블클릭 | 무엇 |
|---|---|
앱_실행.cmd |
주소창·탭 없는 단독 창 (Edge/Chrome 의 --app) |
웹_실행.cmd |
기본 브라우저 탭 |
다른 아이콘 폴더를 열려면 그 폴더를 .cmd 위에 끌어다 놓거나 인자로 줍니다:
앱_실행.cmd "D:\어느\아이콘폴더"
명령줄로 직접:
node 코어/서버.mjs
node 코어/서버.mjs --icons "D:\어느\아이콘폴더" --port 9000주소는 http://127.0.0.1:8788/ 입니다. 127.0.0.1 에만 열립니다 — 밖에서는 안 보입니다.
코어\ 앱 자신 — 서버 · 편집기 · 파서 · lint · 자체검사
아이콘\ 기본 작업 폴더 (icons\ 301장 + manifest.json + 액센트_색상.json)
저장소\ 모아 둔 아이콘 창고 + 찾아보는 화면
--icons 로 연 폴더에만 씁니다. 앱 코드에는 서버가 절대 쓰지 않습니다.
쓸 수 있는 것도 화이트리스트에 걸린 셋뿐입니다 — icons\*.svg · _편집로그.jsonl · 액센트_색상.json.
manifest.json 은 이 통로로 못 씁니다(403). 새 아이콘을 만들 때만 전용 통로가 따로 씁니다 — 아래 참조.
편집기 왼쪽 위 + 새 아이콘. id·이름·그룹을 넣고, 빈 캔버스나 지금 고른 아이콘 복제로 시작합니다.
누르면 icons\<id>.svg 와 manifest 항목이 같이 생깁니다. 둘을 같이 만드는 이유가 있습니다 —
manifest_갱신.mjs 는 manifest 에 이미 있는 항목만 훑기 때문에, 파일만 놓으면 항목이 영영
안 생기고 lint 가 「파일에만 있음」으로 떨어집니다.
그다음은 여느 아이콘과 같습니다: + 도형 으로 모양을 얹고 저장 + 검증.
| 밑그림 | 참조 그림을 캔버스 뒤에 깝니다. 🖼 그림 고르기 또는 Ctrl+V. 진하기 조절·치우기 |
| 정점 x·y | 도형 편집에서 고른 정점을 숫자로 그 자리에 보냅니다 |
| SVG 원문 | 이제 고칠 수 있습니다. d="…" 를 통째로 붙여넣고 「↧ 원문 적용」 |
| 📦 보관함에서 | 저장소 창고의 아이콘을 아이콘 폴더로 가져옵니다 |
원문 적용은 「읽히는가」만 봅니다 — <svg>·</svg>·viewBox="0 0 24 24"·모든 <path> 의 d 가
M 으로 시작하는가. lint 는 저장할 때 서버가 진짜로 돌립니다 (두 벌로 만들지 않습니다).
창고는 더하기 전용이라 거기서 직접 못 고칩니다. 가져오면 아이콘 폴더에 새로 만들어지고
(/api/new 그대로 — id 검사·중복 거절·manifest 항목 포함), 고치는 것은 그쪽입니다.
⚠ 밑그림은 저장되지 않습니다. 브라우저 메모리에만 있고 새로 고치면 사라집니다 —
서버가 쓸 수 있는 것은 icons\*.svg · _편집로그.jsonl · 액센트_색상.json 셋뿐이고,
밑그림 하나 때문에 그 가드를 열지 않았습니다.
⚠ id 는 영구 불변입니다. 파일명이 곧 id 이고 manifest·저장소·다른 프로젝트가 그것으로 부릅니다. 그래서 이미 있는 id 는 덮어쓰지 않고 거절합니다.
✎ 밑그림 생성 창의 칸 나누기 칸(밑그림 칸 바로 아래)입니다. 아이콘이 여러 개 그려진 시트 한 장을 칸으로 나누고, 칸마다 채운 면 아이콘 하나를 만듭니다.
| 차례 | |
|---|---|
| ① 그림 선택 | 창 맨 위 🖼 그림 선택 으로 시트를 깝니다 |
| ② ▦ 칸 나누기 | 빈 줄 · 빈 열로 칸을 자동으로 나누고 번호를 매깁니다(읽는 차례 — 위에서 아래, 왼쪽에서 오른쪽) |
| ③ 칸 고치기 | 칸을 누르면 고르고 Delete 로 뺍니다(제목 줄 같은 것). 가장자리를 끌면 크기, 빈 곳을 끌면 새 칸. 떨어진 조각이 따로 칸이 되면 칸틈, 떨어진 줄이 따로 줄이 되면 줄틈 을 올립니다 |
| ④ 크기 · 이름 · 그룹 | 크기는 같은 배율(시트에서 가장 긴 칸이 20칸 — 아이콘끼리 크기 비가 산다)이 기본, 칸마다 꽉 도 됩니다. 이름 앞머리 · 그룹은 unnamed 가 기본입니다 |
| ⑤ ⇶ 아이콘 N개 만들기 | 칸마다 unnamed01 · unnamed02 … 로 만듭니다. 이미 있는 번호는 건너뜁니다. 한글 · 영문 이름은 id 그대로입니다 |
미리보기(24 · 16px)가 만들 모양을 보여 줍니다. 만드는 길은 + 새 아이콘과 같은 /api/new 이고,
다 만든 뒤 검증(manifest · lint)을 한 번 돌립니다.
⚠ 칸이 켜 있는 동안 Delete 는 칸을 뺍니다 — 그림을 지우지 않습니다. 그림을 고치려면 칸 나누기를 끄세요(Esc).
⚠ 밝은 바탕에 어두운 단색으로 그린 시트를 전제로 합니다. 먹과 바탕은 자동으로 가릅니다(오츠 문턱).
⚠ 아이콘에는 밑그림에 대한 것을 아무것도 안 적습니다 — 시트 파일 이름도 «어느 칸에서 왔나» 도 없습니다.
⚠ 만든 뒤 node 코어/러스트_내보내기.mjs · node 저장소/저장소_생성.mjs 를 따로 돌립니다(창이 알려 줍니다).
따온 그림은 꺾인 이음매를 조금 늘립니다 — 자체검사가 «늘었다» 고 하면 까닭을 적고 기준을 올립니다.
id 를 잘못 적었을 때만 쓰는 아주 좁은 되돌리기입니다. 버튼은 조건이 맞을 때만 나타납니다:
- 이 서버를 띄운 뒤 이 앱으로 만든 것 — 서버를 다시 띄우면 못 지웁니다
- 만든 뒤로 한 번도 안 바뀐 것 — 한 번이라도 그려서 저장했으면 그건 작업물입니다
둘 다 서버가 지문(SHA-256)으로 직접 확인합니다. 화면이 주장하는 것은 믿지 않습니다. 누르면 두 번 묻고, 파일과 manifest 항목을 같이 지웁니다.
그 밖의 아이콘을 지우는 기능은 없습니다. 오래된 것을 정리하려면 icons\<id>.svg 를 손으로
지우고 manifest 항목도 같이 지운 뒤 node 코어/lint.mjs --dir <폴더> 로 확인하세요.
<폴더>\icons\*.svg ← 24×24 · stroke-width 1.25 · currentColor
<폴더>\manifest.json ← id · label_ko · label_en · group · accent · accentClasses
<폴더>\액센트_색상.json ← (없어도 됩니다. 없으면 설계 기본값으로 돕니다)
없으면 서버가 뜨지 않고 이유를 말합니다. 빈 폴더를 열어 「성공」하는 쪽이 더 위험합니다.
저장소\보관함\ 은 더하기 전용 창고입니다. 지우지 않습니다 — 지우면 그만큼 선택지가 사라집니다.
| 칸 | 무엇 |
|---|---|
현재 |
지금 쓰는 것 전량 |
후보 |
예전 변형 시안 (@이전 · @face 등) |
수집 |
새로 모아 온 것 |
기하알파벳 |
A–Z 26자 (도구 아이콘이 아님) |
node 저장소/수집.mjs <파일|폴더> # 새 아이콘 들여오기
node 저장소/보관함_추가.mjs --write # 작업 폴더의 변화를 창고에 더하기
node 저장소/저장소_생성.mjs # 찾아보는 화면 다시 만들기node 코어/자체검사.mjs열두 가지를 봅니다:
- 🔴 원본 프로젝트를 가리키는 곳이 없는가 — 이 앱의 값어치는 「혼자 돈다」 하나입니다
- 파일이 다 있는가
- 아이콘 폴더가 성립하는가 (lint 9규칙 · manifest 1:1)
- 파서 단위 테스트 85건
- 편집기 스크립트 구문 — 깨지면 화면이 조용히 아무것도 안 합니다
- 저장소 창고와 화면이 맞는가
.cmd두 개가 실행 가능한 꼴인가 — CRLF · BOM 없음 · 레이블 아스키- 액센트 색이 갈라지지 않았는가 — 팔레트 ↔ 설계 기본값
- 화면 배선 — 화면이 부르는 id·서버 경로가 실제로 있는가
- 러스트 내보내기가 낡지 않았는가
- 세 렌더러(편집기·저장소·내보내기)가 같은 색 클래스를 같은 뜻으로 그리는가 — 그룹별 색까지
- 화면의 이름 — 죽은 id · 중복 id · 만들기 전에 쓰기(TDZ)
⑨번이 잡는 것: 버튼만 빼고 JS 참조를 남기면 $('#없는것') 이 null 을 주고 화면이 조용히
죽습니다. ⑤번(구문 검사)은 이걸 못 잡습니다 — 문법은 멀쩡하기 때문입니다.
⑫번의 TDZ 도 같은 자리입니다. 최상위 const 를 그보다 위에서 부르면
Cannot access … before initialization 으로 스크립트가 통째로 죽는데, 구문은 멀쩡합니다.
모든 쓰기는 _편집로그.jsonl 에 서버가 직접 남깁니다. 화면에게 「저장했으면 알려 달라」고
시키지 않습니다 — 부르는 것을 잊을 수 있는 구조는 언젠가 반드시 잊습니다(실제로 그래서
편집 저장이 로그에 한 줄도 없었습니다).
{"ts":"…","act":"write","path":"icons/foo.svg","bytes":341,"changed":true,
"before":"4fa517dd…","after":"a380f840…","ua":"Mozilla/5.0 …","prev":"<바뀌기 전 SVG>"}prev 는 복구 수단입니다. 잘못 저장했으면 그 값을 그대로 다시 써 넣으면 됩니다.
act 는 write · new · undo-new 세 가지입니다. 이 로그는 지우지 않습니다.
cd 실행파일
npm install # 처음 한 번 — 397 MB 받습니다 (인터넷 필요)
npm start # 창 띄워 보기
npm run build # → 실행파일\dist\아이콘 편집기-win32-x64\아이콘 편집기.exeElectron 껍데기는 코어를 감싸기만 합니다 — 코어\서버.mjs 를 자식 프로세스로 띄우고
창은 그 주소를 엽니다. 빈 포트를 자동으로 찾으므로 개발용 서버와 나란히 떠 있어도 됩니다.
이 폴더가 없어도 앱은 돕니다. node 코어/서버.mjs 는 여전히 Node 하나로 돌아갑니다.
⚠ 포장한 exe 는 자기 옆의 resources\아이콘\ 을 씁니다. 포장한 순간의 사본이라
원본 아이콘\ 과는 별개입니다 — 한쪽을 고쳐도 다른 쪽은 안 바뀝니다.
2026-08-21 부터 git 저장소입니다. 지문(안전저장.mjs)은 「무엇이 바뀌었나」를 보고,
git 은 「무엇으로 되돌릴까」를 맡습니다. 둘 다 씁니다.
🔴 .gitattributes 를 건드리지 마세요. 기본은 * -text(바이트 그대로)이고
*.cmd 만 eol=crlf 입니다. 흔한 * text=auto 로 바꾸면 이 저장소는 줄바꿈이 섞여 있어서
받는 순간 파일들이 말없이 바뀌고, .cmd 가 LF 로 떨어지면 실행 스크립트가 한 줄도 안 돕니다.
_무결성지문.txt 와 _백업/ 은 산출물이라 추적하지 않습니다 — 받은 뒤
node 코어/안전저장.mjs 를 한 번 돌리면 지문이 다시 생깁니다.
색의 원천은 팔레트 json(액센트_색상.json)입니다. 액센트_기본값.mjs 는 팔레트가 없을 때
쓰는 설계 기본값입니다. 이 둘이 갈라지면 지금 화면은 멀쩡하고 새 폴더를 열 때만 옛 색이 나옵니다.
팔레트 json 의 그룹 에 그룹마다 칸의 색을 따로 둘 수 있습니다. 적힌 칸만 그 그룹(manifest group)
아이콘에 입히고, 안 적힌 칸은 전체 색(색)을 따릅니다.
"그룹": { "iris": { "acc-amber": { "light": "#b57611", "dark": "#e0a03a" } } }편집기에서는 색칸을 우클릭해 뜬 컬러칩 위의 전체 · 그룹 · 이름 에서 고르고,
「그룹 값 지우기」로 전체 색에 돌아갑니다. 고르는 순서(그룹 → 팔레트 → 설계 기본값)는
액센트_기본값.mjs 의 칸색 하나이고, 편집기·저장소 화면·러스트 내보내기가 같이 씁니다.
그룹 색을 바꾼 뒤에는 둘을 다시 만들어야 자체검사를 통과합니다 — 안 만들면 ⑩ · ⑪ 이 잡습니다.
node 코어/러스트_내보내기.mjs
node 저장소/저장소_생성.mjsnode 코어/색상_대조.mjs # 이 폴더 팔레트 ↔ 설계 기본값
node 코어/색상_대조.mjs --write # 기본값을 지금 팔레트에 맞춤
node 코어/색상_대조.mjs --대조 "<저쪽 폴더>" # 다른 프로젝트 팔레트와 대조같은 아이콘을 다른 프로젝트에서도 쓴다면 그쪽 팔레트는 자동으로 따라가지 않습니다.
--대조 가 다른 칸을 짚고 붙여 넣을 조각을 내줍니다 — 앱 폴더 밖은 읽기 전용이라 사람이 옮깁니다.
옮긴 뒤 그 프로젝트에서 색 반영을 한 번 돌려야 합니다. 아이콘 SVG 에는 색이 들어 있지 않고,
소비층(러스트·목업 등)이 생성 시점에 이 값을 구워 넣기 때문입니다.
무결성 지문이 언제 것인지도 함께 알려 줍니다(없어도 검사는 통과합니다).
lint.mjs 는 그 위에 manifest 필수 필드(id·file·label_ko·label_en·group)가 채워졌는지도 봅니다.
빈칸이 있어도 이 앱은 멀쩡히 돌지만, 아이콘을 가져다 쓰는 쪽이 그 값을 요구합니다.
낱개로도 돕니다:
node 코어/lint.mjs --dir 아이콘
node 코어/manifest_갱신.mjs --dir 아이콘 --write
node 코어/경로편집.test.mjsnode 코어/안전저장.mjs전 파일 SHA-256 을 _무결성지문.txt 에 적고, 지난번과 대조해 무엇이 사라지고
무엇이 바뀌었는지 알려 줍니다. 함께 무결성도 봅니다 — 0바이트 · UTF-8 디코드 ·
널바이트/제어문자 · JSON 파싱 · HTML/SVG 종결.
node 코어/안전저장.mjs --확인만 # 대조만, 아무것도 쓰지 않음
node 코어/안전저장.mjs --백업 # 지시받았을 때만 — _백업\ 에 ZIP지문 사본 하나는 앱 폴더 옆(E:\_아이콘편집기_지문.txt)에도 씁니다 — 폴더가 통째로
사라져도 「어디에 몇 개가 있어야 했는지」가 남게 하려는 것입니다. 앱 폴더 밖으로 쓰는 곳은
이 파일 하나뿐이고, 다른 바깥 경로는 스크립트가 막습니다.
⚠ ZIP 백업(--백업)은 앱 폴더 안(_백업\)에 쌓입니다 — 폴더가 사라지면 같이 사라집니다.
외부 매체 사본이 필요하면 직접 관리하세요.
E:\01. 메뉴와도구툴 의 편집기·저장소를 2026-08-21 에 복제했습니다.
원본은 그대로 남아 있습니다 — 사용자 확정(「우리 편집기는 그대로 둡니다」).
파일 10개가 두 벌이 됐고, 무엇이 왜 갈라졌는지는 _갈림점.md 에 SHA-256 지문과 함께 적혀 있습니다.
자동으로 동기화되지 않습니다. 그게 「완전히 별개」의 뜻입니다.
2026-08-25 아침에 재 보니 코어\경로편집.mjs 하나만 원본과 한 글자도 다르지 않았습니다.
그날 오후에 그것도 갈라졌습니다 — 호 손잡이를 만들며 arcGeom·arcMid·arcThrough·
arcBulgeLine·arcHandlesOf 다섯을 더했습니다. 이제 열 개 전부 갈라져 있습니다.
경로편집.test.mjs 85건이 그것을 지킵니다.
코어 13개 중 6개는 이 앱에서 새로 쓴 것입니다 — 서버 · 자체검사 · 안전저장 · 러스트_내보내기 · 색상_대조 · 쓰임_찾기.