Materializr
오픈소스 파라메트릭 3D CAD로 제약 스케치·솔리드 모델·나사·SVG·텍스트 조각·STL/STEP 내보내기를 지원합니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
캔버스 하나를 손글씨(digital ink) 에디터로 만드는 프레임워크 비의존 라이브러리. dk-script의 수식 필기 영역을 떼어낸 것이고, 인식·변환은 범위 밖이다. 시험용 앱 → kimilhee.github.io/dk-ink (펜/지우개·두께·되돌리기·획 JSON)README 전문 보기 ↗
캔버스 하나를 손글씨(digital ink) 에디터로 만드는 프레임워크 비의존 라이브러리.
dk-script의 수식 필기 영역을 떼어낸 것이고, 인식·변환은 범위 밖이다.
시험용 앱 → kimilhee.github.io/dk-ink (펜/지우개·두께·되돌리기·획 JSON)
PointerEvent.pressure를 굵기로 반영한다. 캔버스의 lineWidth는 획 하나에
하나뿐이라 점마다 굵기를 못 주므로, 윤곽을 만들어 채운다.dynamicEraser를 켜면 지우개를 빠르게 문지를수록 지름이 커지고(20~180px)
느리게 움직이면 작아진다. 켜면 eraserWidth는 쓰지 않는다.getCoalescedEvents()까지 풀어서 궤적이 각지지 않게 한다.desynchronized 캔버스 힌트로 합성 대기를 줄인다. 예측 점
(getPredictedEvents())은 꺾는 곳에서 선이 튀어 쓰지 않는다.ResizeObserver로 자동 추적한다.onChange가 현재 획 전체를 준다. 그대로 저장하거나
보내면 된다.의존성은 없다. 브라우저 API만 쓴다.
pnpm add dk-ink
import { createInkEditor } from "dk-ink";
const editor = createInkEditor(document.querySelector("canvas")!, {
tool: "pen",
strokeWidth: 3,
widthMode: "pressure",
onChange(strokes) {
console.log(strokes.length);
},
});
editor.tool = "eraser";
editor.setStyle({ eraserWidth: 32 });
editor.undo();
const strokes = editor.getStrokes(); // JSON으로 저장 가능
editor.setStrokes(strokes); // 다시 불러오기
editor.destroy();
캔버스의 크기·테두리는 앱이 정한다. 동작에 필요한 CSS(touch-action: none 등)만
라이브러리가 캔버스에 직접 넣으므로 스타일시트를 따로 불러올 필요가 없다. 넣기 전의 인라인
값은 기억해 두었다가 destroy()에서 되돌리므로, 앱이 걸어둔 스타일을 덮어쓴 채 떠나지 않는다.
다 쓴 획과 막 끝나 "마르는" 획은 캔버스 바로 아래에 겹친 별도 캔버스 두 장에 그린다(캔버스 앞 형제로 DOM에 붙고
destroy()에서 떼어진다). 그래서 배경은 캔버스가 아니라 캔버스를 감싼 요소에 칠해야 한다.
캔버스에 배경을 칠하면 다 쓴 획이 가려진다. 캔버스가 position: static이면 아래 층보다 위에
오도록 position: relative가 들어간다.
현재 도구는 data-tool 속성으로 노출되니 canvas[data-tool="eraser"] { cursor: crosshair }
처럼 쓰면 된다.
InkPoint.t는 PointerEvent.timeStamp 그대로다 (performance.now()와 같은 시간 원점).
뭉쳐 들어온 점들도 각자 실제 샘플 시각을 가지므로, 획순과 필기 속도가 점 데이터에 남는다.
InkEditor| 멤버 | 설명 |
|---|---|
tool | "pen" | "eraser" | "line". 읽기·쓰기. |
drawing | 획이 진행 중인지. |
canUndo / canRedo | 버튼 활성 상태에 쓴다. |
getStrokes() | 내부 상태와 분리된 복사본. |
setStrokes(strokes, options?) | 통째로 교체. { recordHistory: false }면 되돌리기 이력을 건너뛴다. |
getStyle() / setStyle(partial) | 색·굵기·모드·지우개 설정. |
undo() / redo() / clear() | 바뀐 게 있으면 true. |
resize() | ResizeObserver가 부르므로 보통 직접 쓸 일이 없다. |
destroy() | 리스너·옵저버 해제, 이력 비움, 캔버스 스타일·data-tool을 부착 이전으로 복원. 그린 내용은 그대로. |
| 옵션 | 기본값 |
|---|---|
tool | "pen" |
color | "#1d4ed8" |
strokeWidth | 3 (필압 모드에선 최대) |
widthMode | "pressure" |
opacity | 0.7 |
holdToStraightLine | true (끝에서 멈추면 직선) |
straightLineDelay | 700 (대기 시간, ms) |
eraserWidth | 50 |
dynamicEraser | false (속도로 지름 결정) |
showEraserCursor | true |
eraserCursorFill / eraserCursorStroke | 청록 계열 |
historyLimit | 50 (0이면 되돌리기 없음) |
strokes | 초기 획 |
onChange | — |
펜으로 곧게 긋다가 끝에서 기본 0.7초간 멈추면(8px 이내 손떨림 허용) 시작점과 그 자리를 잇는
일정한 두께의 직선으로 바뀐다. 획이 16px 이상이고 모든 점이 선분에서 길이의 8%(최소 6px) 안에
있을 때만 바뀌므로, 쓰기 전에 펜을 대고 머뭇거리거나 꺾인 획 끝에서 멈춰도 직선이 되지 않는다.
바뀐 뒤에도 펜을 떼기 전까지 끝점을 옮길 수 있다. 대기 시간은 straightLineDelay(ms)로 지정하며,
데모에서는 0.5~1.5초 슬라이더로 조절하고 저장한다. holdToStraightLine: false로 끌 수 있다.
tool = "line"이면 기다리지 않고 누른 자리에서 뗀 자리까지 직선을 긋는다. 데모 도구 모음의
직선 버튼이 이 도구를 켜고 끈다.
Stroke는 점 배열이 아니라 { points, style }이다. 획을 시작할 때 그 시점의 색·굵기·모드·
투명도를 복사해 넣으므로, 나중에 setStyle로 설정을 바꿔도 이미 그린 획은 그대로다 —
사람이 그때 그 펜으로 쓴 것이기 때문이다. 지우개로 쪼갠 조각도 원래 획의 스타일을 물려받는다.
type Stroke = { points: InkPoint[]; style: StrokeStyle };
type StrokeStyle = { color: string; strokeWidth: number; widthMode: WidthMode; opacity: number };
setStyle은 앞으로 그릴 획의 설정을 바꾼다. 이미 그린 획을 바꾸려면 getStrokes()로
받아 style을 고친 뒤 setStrokes()로 되돌려 넣으면 된다.
에디터를 쓰지 않고 직접 조립할 때 쓸 순수 함수도 내보낸다:
eraseStrokes · renderStrokes · drawStaticLineStroke · drawOutlineStroke ·
drawEraserCursor · pressureWidth · cloneStrokes · createInkHistory · createDynamicEraser.
createInkHistory의 스냅샷은 배열만 복사하고 획 객체를 공유한다. 넘긴 획을 나중에 고칠
거라면 cloneStrokes로 복사해서 넘긴다.
코드 읽기는 분석 커리큘럼에서 시작한다. 다이어그램은 브라우저에서 바로 열 수 있다:
vp install
vp run playground # 시험용 앱 (펜/지우개/두께/되돌리기/JSON 확인)
vp test
vp check
vp pack # dist/ 빌드
vp run archify:refresh # 최신 코드를 읽고 분석 문서 5개 재생성
playground/는 npm 배포물이 아니다. 라이브러리 소스를 직접 import하므로 수정이 바로 반영되고,
main에 푸시하면 GitHub Pages로 배포된다.
archify:refresh는 Codex CLI의 비대화형 실행을 사용한다.
로그인된 codex CLI, 설치된 archify 스킬, 브라우저 검사용 Chrome/Chromium이 필요하다.
AI가 현재 코드를 다시 분석하므로 실행 시간과 모델 사용량이 발생한다. 소스 변경을 먼저 커밋하면
문서의 근거 링크를 해당 커밋에 고정할 수 있다. 생성 원본과 검증 결과는 새 .archify/ 폴더에
보존하고(로컬에만 두고 커밋하지 않는다), 검증된 HTML 5개를 playground/public/analysis/에 반영한다.
이 명령은 로컬 파일과 patch 버전만 갱신한다. 변경을 검토하고 main에 푸시하면 Pages에 배포된다.
다이어그램 설명은 한국어이며 Viewer 기본 UI는 영어 fallback을 사용한다.