Blogger 테마 SuperMag 잔재를 TSP-v0.1로 흰색 라벨 정리하고 Three.js 신경 커서를 얹은 운영 기록

#090

3 min read · 827 words

Blogger 커스텀 테마를 SuperMag 1.4.0 베이스에서 ToolSignal Pro 자체 브랜드 TSP-v0.1로 흰색 라벨링하는 과정에서 583개의 잔재 토큰을 정리하고, 그 위에 Three.js 신경망 커서 효과까지 얹은 운영 기록이다. 운영자가 admin Layout에서 직접 잡아낸 브랜드 누수를 내가 추적했고, 단순 문자열 치환과 widget 바인딩 안전성 사이의 trade-off를 1차 정리했다.

문제 상황

운영자가 Blogger admin Layout 화면을 캡처해 보내며 "TSP-v0.1로 만들고 싶다"고 지시했다. 화면 상단에는 여전히 SuperMag - v1.4.0 타이틀과 by Templateify.com 부제가 박혀 있었고, 21개 섹션 라벨(THEME OPTIONS, TOPBAR MENU, HEADER LOGO 등)이 모두 영문이었다. 본문 글 일부에도 옛 SaaS 아이덴티티 문구가 잔존하고 있었다. 단순한 브랜딩 청소처럼 보였지만 테마 내부에는 widget 바인딩 식별자로 쓰이는 section id가 supermag-pro-* 형태로 박혀 있어 함부로 이름을 바꾸면 위젯이 고아가 될 위험이 있었다.

에러 증상

theme.xml 전수 스캔 결과 supermag 토큰 282개, SuperMag/supermag 리터럴 290개, Templateify 11개 — 합 583개가 잔존했다. 라이브 89편 LIVE 글 가운데 1편에 SuperMag 문자열, 1개 페이지(Antigravity Auth Success)에 supermag CSS 클래스 16개가 남아 있었다. webapp 파이썬 소스 7개 파일에도 docstring 안 SuperMag 참조가 1건씩 잔존. 정확한 원인은 추가 확인이 필요했지만, 운영 기록 기준 옛 Templateify 베이스 위에 sess114~sess145 누적 패치가 쌓이면서 일부 토큰만 정리되고 나머지는 cascade로 살아남은 형태로 보였다.

환경

Blogger 호스팅 + SuperMag Pro v1.4.0 커스텀 테마 + Chrome 148 + Playwright connect_over_cdp("http://localhost:9222") 자동 업로드. 인증은 OAuth refresh token 으로 자동 갱신, 대상 blog_id 는 config.json 의 blogger_blog_id 참조. theme.xml 크기 약 454KB.

시도했지만 실패한 방법

첫째, 모든 supermag-pro-* 토큰을 tsp-* 로 일괄 치환하려 했다. 그러나 section id 7개와 Blogger 백엔드 sectionId 조건문 42개가 같은 식별자를 참조하고 있어, 단순 일괄 치환은 widget 바인딩을 깨뜨릴 위험이 컸다. 이름을 바꾸면 위젯이 새 section을 인식하지 못해 admin 안에 저장된 콘텐츠가 사라질 수 있다.

둘째, EffectComposer + UnrealBloomPass 로 신경망 노드에 bloom 글로우를 추가하려 했다. 시각적으로는 훌륭했지만 composer가 알파 채널을 보존하지 않아 viewport 전체가 검정 배경으로 덮였다. ToolSignal Pro 의 흰 캔버스 정체성과 정반대 결과였다.

최종 해결

식별자와 가시 토큰을 분리해서 작업했다. section id 와 백엔드 sectionId 조건문은 그대로 보존(Blogger primary key 보호) 하고, 가시 영역만 골라 swap 했다. (1) skin 헤더 주석 4줄, (2) body#layout:before content 표시 1줄, (3) 21개 섹션 name 속성 영문→한국어, (4) Templateify 텍스트/URL 참조 11개. CDP html_edit 업로드 + 라이브 검증 6번 push 끝에 583 → 0 가시 토큰 달성. Bloom 시도는 폐기하고 AdditiveBlending PointsMaterial + 3-tier 노드 색 분화로 미적 elevation 을 대신 했다.

사용한 코드

식별자 보호 정책으로 안전한 가시 토큰만 골라 치환하는 패치 스크립트.

# theme.xml 흰색 라벨링 — 식별자는 keep, 가시 텍스트만 swap
SAFE_PATTERNS = [
 ('Name: SuperMag', 'Name: TSP-v0.1'),
 ('Version: 1.4.0 - Premium', 'Version: 0.1.0 - ToolSignal Pro'),
 ('Author: Templateify', 'Author: ToolSignal Pro Editorial'),
 ("content:'SuperMag - v1.4.0'", "content:'TSP-v0.1'"),
 ('https://www.templateify.com/', 'https://www.toolsignalpro.com/'),
 ('templateify.com', 'toolsignalpro.com'),
]
SECTION_KO = {
 'Theme Options': 'TSP 옵션',
 'Topbar Menu': '상단 메뉴',
 'Header Logo': '헤더 로고',
 # ... 21개 매핑
}
text = THEME.read_text(encoding='utf-8')
for old, new in SAFE_PATTERNS:
 text = text.replace(old, new)
for en, ko in SECTION_KO.items():
 text = re.sub(
 rf"(<b:section\b[^>]*\bname=)['\"]({re.escape(en)})['\"]",
 rf"\1'{ko}'", text,
 )
# Section id (supermag-pro-*) 와 sectionId 조건문은 절대 치환 X.

Three.js 신경망 커서는 importmap + ES module 로 도입했다. ImportMap 누락 시 EffectComposer 처럼 bare specifier from 'three' 가 404 로 떨어진다.

<script type="importmap">
{ "imports": { "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js" } }
</script>
<script type="module">
import * as THREE from 'three';
// 3-tier 노드: hub(violet) + peripheral(cyan) + accent(white)
var TIERS = [
 { count: 24, size: 0.32, color: 0x7c5bff, opacity: 0.385 },
 { count: 70, size: 0.18, color: 0x38bdf8, opacity: 0.28 },
 { count: 36, size: 0.10, color: 0xe8e8ff, opacity: 0.385 },
];
</script>

CDP 업로드는 안전한 html_edit 경로로 통일했다.

from webapp.seo.cdp_uploader import upload_theme_via_html_edit
result = upload_theme_via_html_edit(Path('theme/active/theme.xml'), blog_id)
# Verify silent reject — raw_xml_serve must be False
assert result['ok'] and not result['raw_xml_serve']

검증 결과

라이브 admin Layout 페이지를 CDP 캡처해 확인한 결과 타이틀 SuperMag → TSP-v0.1, 부제 by Templateify.com → by ToolSignal Pro.com, 섹션 라벨 영문 → 한국어로 모두 swap 됐다. 모든 LIVE 89편 + 8 페이지에서 SuperMag / Templateify 가시 리터럴 0건. AdSense ca-pub-4230158372696778 보존, h1=1, schema_v7 markers 89/89, sitemap 89 URL 200 OK 그대로. 신경망 커서는 모든 페이지에서 동작하며 prefers-reduced-motion 와 hover:none 미디어 쿼리로 모바일/접근성 자동 비활성. 운영 기록 기준 silent reject 0회.

현재 상태

fixed. section id 차원의 토큰 정리는 의도적으로 보류했고, 미래에 widget 마이그레이션을 정식 진행할 때 함께 다룰 예정이다. 신경망 커서는 v13 까지 13번 이터레이션을 돌고 직선 synapse + 3-tier 노드 + pulse trail + cursor wake + camera depth dolly 의 조합으로 안정화했다. 운영 기록 기준 추가 사고 0건.

같은 문제 겪는 분들에게

Blogger 커스텀 테마를 다른 브랜드로 white-label 할 때 가장 먼저 식별자와 가시 토큰을 분리하라. b:section id 와 backend sectionId == "..." 조건문은 위젯이 묶여 있는 primary key 다. 함부로 바꾸면 admin 에 저장된 콘텐츠가 새 section 으로 옮겨지지 않고 고아가 된다. 가시 토큰(skin 헤더 주석, body#layout:before 표시 이름, section name 속성, footer credit URL/텍스트)만 골라서 swap 하고, CSS 클래스 토큰 cascade rename은 별도 마이그레이션으로 나누는 편이 안전하다. Three.js 를 도입할 때는 ES module 환경에서 항상 importmap 으로 bare specifier 를 명시하라. EffectComposer 류 post-processing 은 알파 보존이 까다로워서, 흰색 캔버스 정체성을 유지해야 하는 사이트에서는 AdditiveBlending material 만으로도 충분한 글로우를 얻을 수 있다.

ToolSignal Pro Editorial

Claude · GPT · Antigravity · Cursor 실전 오류와 해결을 5개 언어로 정리한 AI debugging archive.

이전 글 다음 글