feat: StationOverlay 렌더링 최적화 및 스무딩 적용 close #1
- 텍스트(측점/POI) 전 프레임 사전 계산 Map (requestIdleCallback 백그라운드) - 드론 데이터 이동 평균 스무딩 (smoothFrame ±N프레임) - 30fps→60fps 프레임 간 선형 보간 (performance.now() 기반) - EMA(지수이동평균) 표시 위치 스무딩 (α=0.01 기본값) - 글씨 2배 크기, bold, strokeText 테두리, 배경 박스 제거 - 카메라 파라미터 패널에 smooth/EMA α 슬라이더 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
80
.claude/hooks/guard-history-fields.py
Normal file
80
.claude/hooks/guard-history-fields.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
PostToolUse(Write) 훅: 히스토리 파일 필수 필드 검증
|
||||
path.json 의 history_path 하위 *.md 파일에
|
||||
소요 시간 / Context 사용량 누락 시 exit 2로 Write 차단
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
|
||||
# ── path.json 로드 ────────────────────────────────────────────────────────────
|
||||
HOOKS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
PATH_JSON = os.path.join(HOOKS_DIR, "path.json")
|
||||
|
||||
try:
|
||||
with open(PATH_JSON, encoding="utf-8") as f:
|
||||
paths = json.load(f)
|
||||
except Exception:
|
||||
paths = {}
|
||||
|
||||
history_path = paths.get("history_path", "docs/history").replace("\\", "/").rstrip("/")
|
||||
# history_path 하위 어느 깊이든 *.md 이면 검사
|
||||
history_pattern = re.escape(history_path) + r"/.+\.md$"
|
||||
|
||||
# ── 훅 입력 파싱 ──────────────────────────────────────────────────────────────
|
||||
try:
|
||||
data = json.load(sys.stdin)
|
||||
except Exception:
|
||||
sys.exit(0)
|
||||
|
||||
tool_input = data.get("tool_input", {})
|
||||
file_path = tool_input.get("file_path", "")
|
||||
content = tool_input.get("content", "")
|
||||
|
||||
normalized = file_path.replace("\\", "/")
|
||||
if not re.search(history_pattern, normalized):
|
||||
sys.exit(0)
|
||||
|
||||
missing = []
|
||||
|
||||
if not re.search(
|
||||
r"\*\*소요\s*시간\*\*|^##\s*소요\s*시간|소요\s*시간\s*:",
|
||||
content,
|
||||
re.MULTILINE,
|
||||
):
|
||||
missing.append("소요 시간")
|
||||
|
||||
if not re.search(
|
||||
r"\*\*Context\s*사용량\*\*|^##\s*Context\s*사용량|Context\s*사용량\s*:",
|
||||
content,
|
||||
re.MULTILINE | re.IGNORECASE,
|
||||
):
|
||||
missing.append("Context 사용량")
|
||||
|
||||
if missing:
|
||||
sys.stderr.write("[BLOCKED] 히스토리 파일 필수 항목 누락: " + ", ".join(missing) + "\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write("파일 상단에 다음 항목을 반드시 포함하세요:\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write(" **소요 시간**: X분\n")
|
||||
sys.stderr.write(" **Context 사용량**: input Xk / output Xk tokens\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write("파일: " + file_path + "\n")
|
||||
sys.exit(2)
|
||||
|
||||
# ── 이슈 번호 검사 (없으면 사용자에게 질문 요청) ──────────────────────────────
|
||||
if not re.search(r"\*\*이슈\*\*\s*[:\s]+#\d+", content, re.MULTILINE):
|
||||
sys.stderr.write("[이슈 번호 필요] 히스토리 파일에 이슈 번호가 없습니다.\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write("사용자에게 다음을 질문하세요:\n")
|
||||
sys.stderr.write(" '이 작업과 관련된 Gitea 이슈 번호가 있나요? (예: #1 / 없으면 #0)'\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write("답변 후 파일 상단에 추가하고 다시 저장하세요:\n")
|
||||
sys.stderr.write(" **이슈**: #N\n")
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.write("파일: " + file_path + "\n")
|
||||
sys.exit(2)
|
||||
|
||||
sys.exit(0)
|
||||
Reference in New Issue
Block a user