🎨 실시간 디자인 에디터 및 배경 연출 소개
본 문서는 재빌드 및 재배포 없이 테마 설정을 실시간으로 반영하는 시스템과 4가지 배경 설정(단색, 그라디언트, 배경 이미지, 커스텀 자바스크립트 캔버스)에 대한 기본 구성을 소개합니다.
🌌 1. 실시간 디자인 에디터 개요
디자인 에디터에서 설정값을 변경하고 저장할 때 블로그 서버나 CDN 서비스를 다시 빌드하고 배포할 필요가 전혀 없습니다.
저장 즉시 데이터베이스가 갱신되며, 방문자의 브라우저 화면에 CSS 변수와 배경 렌더링 모듈이 1초 만에 실시간으로 반영됩니다.
🎨 테마 기본 설정 항목
- 기본 색상 구성: 주 테마 색상(Primary), 보조 색상(Secondary), 본문 글자 색상(Text), 포인트 강조 색상(Accent), 카드 및 위젯 배경(Card Bg), 테두리 색상(Border) 등을 조절할 수 있습니다.
- 레이아웃 세부 수치: 좌우 여백(Side Margin), 전체 화면 최대 가로 폭(Max Width), 카드 모서리 둥글기(Border Radius), 입체감을 주는 그림자 효과(Box Shadow)를 지원합니다.
- 타이포그래피 설정: Google Fonts 목록에서 원하는 글꼴 이름을 기입해 서체를 적용하고, 본문 폰트 종류와 기본 글자 크기(Base Font Size)를 설정할 수 있습니다.
🧱 2. 기기별 독립 위젯 배치
레이아웃 설계 시 마우스 드래그 앤 드롭으로 위젯의 위치와 순서를 지정할 수 있으며, 접속하는 독자의 기기 크기에 맞춰 레이아웃을 다르게 구성할 수 있는 필터링 기능을 제공합니다.
- Desktop (데스크톱 전용): 화면이 넓은 PC 환경에서만 해당 위젯(예: 태그 클라우드, 카테고리 트리 등)을 출력합니다. 모바일 접속 시에는 HTML 단계에서 요소를 사전에 제외하여 로딩 속도를 유지해 줍니다.
- Mobile (모바일 전용): 데스크톱에서는 보이지 않고, 스마트폰 화면 크기에서만 모바일 친화적으로 단독 출력되도록 제한합니다.
🌈 3. 4가지 배경 설정 종류
블로그 전체의 감성을 완성하는 배경 화면은 총 4가지 타입을 지원합니다.
① Solid (단색 배경)
- 선호하는 색상의 헥스(HEX) 코드(예:
#3b82f6)나 HSL 색상 코드를 지정하여 가장 깔끔하고 포스트 본문에 집중하기 좋은 화면을 만듭니다.
② Gradient (그라디언트 배경)
- 그라디언트 빌더(Gradient Builder) 도구를 사용하여 여러 컬러가 자연스럽게 섞이는 선형 그라디언트를 구성합니다.
- 각도 조절(Direction) 슬라이더와 **색상 정지점(Stops)**을 마우스로 추가하고 이동하며 시작색, 중간 경유색, 종점색을 배합할 수 있습니다.
③ Image (배경 이미지 & 글래스모피즘 필터 조합)
- 배경으로 사용할 사진의 주소(URL)를 입력하거나, 업로드(Upload) 버튼을 사용해 미디어 파일을 보관함에 추가합니다.
- 업로드 이미지 최적화: 이미지를 등록하면 시스템이 WebP 형식으로 자동 변환하여 로딩 성능 저하를 방지합니다.
- 글래스모피즘 효과: 배경 이미지가 텍스트 가독성을 저해하지 않도록, 아래의 제어 설정을 활용해 반투명 유리창 스타일을 구현할 수 있습니다.
| 설정 항목 | 권장 조작 범위 | 상세 설명 |
|---|---|---|
| 배경 블러 (Glass Blur) | 5px ~ 15px |
글자가 놓이는 콘텐츠 카드 하단에 투명한 유리 재질 느낌의 필터를 입힙니다. |
| 유리창 틴트 농도 (Overlay Opacity) | 10% ~ 30% |
유리창 뒤편에 깔리는 반투명 마스크의 불투명도를 결정합니다. |
| 유리창 틴트 색상 (Overlay Color) | #000000 또는 #ffffff |
마스크 색상을 어둡게(Dark) 혹은 밝게(Light) 연출하여 글자의 선명한 대비(Contrast)를 확보합니다. |
④ Custom JavaScript (커스텀 자바스크립트 및 Canvas 배경)
- 방문자 브라우저에서 배경용 Canvas 애니메이션을 직접 구동할 수 있도록 커스텀 자바스크립트 입력을 지원합니다.
- 캔버스 요소(
canvas id="bg-canvas")에 직접 렌더링을 제어할 수 있으며, 이와 연동되는 세부 보안 및 절전 시스템은 아래 [4. 커스텀 자바스크립트 연동 사양] 에서 설명합니다.
⚡ 4. 커스텀 자바스크립트 연동 사양
보안 사고를 예방하고 모바일 기기 배터리를 보존하기 위해 아래와 같은 격리 정책 및 절전 시스템이 적용됩니다.
🔒 격리 보안 시스템 (Sandbox & CSP)
블로그 어드민일지라도 악성 스크립트 유입으로 인한 보안 사고를 막기 위해 다음과 같은 보안 정책이 상시 가동됩니다.
- 격리된 Sandbox 구조: 캔버스 코드는 오직 스크립트 실행만 인가된 격리된
iframe내부에서 구동됩니다. 부모 페이지의 DOM 노드나 로그인 정보 등에 접근하여 데이터를 탈취하거나 위변조하는 동작이 기술적으로 차단됩니다. - 콘텐츠 보안 정책 (CSP) 제한: 외부 서버와의 네트워크 통신 및 외부 스크립트 호출이 전면 차단됩니다. 따라서 외부 서버로 데이터를 유출하는 것이 불가능합니다.
- JS API 허용 차단: 보안을 해칠 수 있는
fetch,XMLHttpRequest,WebSocket,eval,new Function,document.cookie,localStorage등의 API가 감지되면 보안 필터(jsValidator.ts)가 이를 자동으로 주석 처리(/* f_e_t_c_h (blocked) */)하여 무력화합니다.
🔋 배터리 보존 및 절전 기술
- 화면 밖 자동 일시정지: 사용자가 화면을 스크롤하여 배경 애니메이션이 완전히 시야에서 사라지면, 브라우저가 CPU/GPU를 낭비하지 않도록 프레임 렌더링 루프를 일시정지(Sleep) 상태로 전환합니다. 화면에 다시 노출되면 즉각 재생(Resume)됩니다.
- 모바일 프레임 스로틀링: 스마트폰이나 태블릿 등 모바일 기기로 접속하는 경우 기기 발열 방지를 위해 기본적으로 애니메이션이 정지됩니다. "모바일 기기에서도 애니메이션 구동" 옵션을 명시적으로 체크하면 실행할 수 있으며, 이때 성능에 부담이 가지 않도록 파티클 개수를 자동으로 축소 제어하는 매개변수가 연동됩니다.
📝 5. 예제 스크립트 코드 3종
배경 설정 메뉴에서 **[Custom JavaScript]**를 선택하고, 아래 코드 중 하나를 복사하여 적용할 수 있습니다.
[!NOTE]
스크립트를 작성할 때에는 배경을 그릴 대상 캔버스 요소를 찾기 위해 반드시document.getElementById('bg-canvas')아이디명을 사용하여 컨텍스트를 획득해 주시기 바랍니다.
❄️ 예제 A. 겨울 눈송이 (Snowfall)
화면 위에서 눈송이들이 아래로 천천히 떨어지는 배경 애니메이션입니다.
(function() {
const canvas = document.getElementById('bg-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
let width = canvas.width = window.innerWidth;
let height = canvas.height = window.innerHeight;
// 모바일 스로틀 감지
const divisor = (window.bgConfig && window.bgConfig.mobileThrottleDivisor) || 1;
const maxSnowflakes = Math.floor(100 / divisor);
const snowflakes = [];
class Snowflake {
constructor() {
this.reset();
this.y = Math.random() * height; // 초기 임의 고도 설정
}
reset() {
this.x = Math.random() * width;
this.y = -10;
this.radius = Math.random() * 3 + 1;
this.speed = Math.random() * 1 + 0.5;
this.opacity = Math.random() * 0.6 + 0.2;
}
update() {
this.y += this.speed;
// 부드러운 흔들림 주기
this.x += Math.sin(this.y / 30) * 0.5;
if (this.y > height || this.x < 0 || this.x > width) {
this.reset();
}
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = `rgba(25, 25, 255, ${this.opacity})`;
ctx.fill();
}
}
// 파티클 생성
for (let i = 0; i < maxSnowflakes; i++) {
snowflakes.push(new Snowflake());
}
function animate() {
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < snowflakes.length; i++) {
snowflakes[i].update();
snowflakes[i].draw();
}
requestAnimationFrame(animate);
}
// 창 크기 조절 이벤트
window.addEventListener('resize', () => {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
});
animate();
})();
🕸️ 예제 B. 별자리 연결망 (Constellation Network)
파티클 노드들이 무작위로 부유하며, 서로 가까워지면 얇은 선으로 연결되어 그물 형태를 구성하는 배경 애니메이션입니다.
(function() {
const canvas = document.getElementById('bg-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
let width = canvas.width = window.innerWidth;
let height = canvas.height = window.innerHeight;
const divisor = (window.bgConfig && window.bgConfig.mobileThrottleDivisor) || 1;
const particleCount = Math.floor(80 / divisor);
const particles = [];
const connectionDistance = 100;
class Particle {
constructor() {
this.x = Math.random() * width;
this.y = Math.random() * height;
this.vx = (Math.random() - 0.5) * 0.8;
this.vy = (Math.random() - 0.5) * 0.8;
this.radius = Math.random() * 2 + 1.5;
}
update() {
this.x += this.vx;
this.y += this.vy;
// 화면 경계 튕기기
if (this.x < 0 || this.x > width) this.vx *= -1;
if (this.y < 0 || this.y > height) this.vy *= -1;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(99, 102, 241, 0.4)'; // 파스텔 인디고 컬러
ctx.fill();
}
}
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle());
}
function drawLines() {
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < connectionDistance) {
const alpha = (connectionDistance - dist) / connectionDistance * 0.18;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(99, 102, 241, ${alpha})`;
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
}
function animate() {
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].draw();
}
drawLines();
requestAnimationFrame(animate);
}
window.addEventListener('resize', () => {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
});
animate();
})();
🌊 예제 C. 파도 일렁임 (Fluid Sine Waves)
화면 하단에서 여러 갈래의 반투명 파도가 부드럽게 일렁이는 배경 애니메이션입니다.
(function() {
const canvas = document.getElementById('bg-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
let width = canvas.width = window.innerWidth;
let height = canvas.height = window.innerHeight;
let wave1 = {
y: height * 0.85,
length: 0.005,
amplitude: 25,
frequency: 0.012
};
let wave2 = {
y: height * 0.88,
length: 0.008,
amplitude: 15,
frequency: 0.022
};
let increment = 0;
function animate() {
ctx.clearRect(0, 0, width, height);
// 첫 번째 뒷 파도 그리기 (반투명 파스텔 청록)
ctx.beginPath();
ctx.moveTo(0, height);
for (let i = 0; i < width; i++) {
ctx.lineTo(i, wave1.y + Math.sin(i * wave1.length + increment) * wave1.amplitude);
}
ctx.lineTo(width, height);
ctx.fillStyle = 'rgba(45, 212, 191, 0.1)';
ctx.fill();
// 두 번째 앞 파도 그리기 (반투명 파스텔 하늘)
ctx.beginPath();
ctx.moveTo(0, height);
for (let i = 0; i < width; i++) {
ctx.lineTo(i, wave2.y + Math.sin(i * wave2.length - increment * 1.5) * wave2.amplitude);
}
ctx.lineTo(width, height);
ctx.fillStyle = 'rgba(56, 189, 248, 0.15)';
ctx.fill();
// 모바일 환경에 따른 속도 차등 제어
const speedFactor = (window.bgConfig && window.bgConfig.mobileThrottleDivisor) ? 0.3 : 1;
increment += wave1.frequency * speedFactor;
requestAnimationFrame(animate);
}
window.addEventListener('resize', () => {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
wave1.y = height * 0.85;
wave2.y = height * 0.88;
});
animate();
})();
📱 6. 모바일 개별 배경 설정
기기 환경에 맞춰 배경 설정을 차별화하여 성능을 최적화할 수 있습니다.
- 데스크톱 배경: 데스크톱 환경에서는 Custom JavaScript를 선택하여 원하는 Canvas 애니메이션을 구동할 수 있습니다.
- 모바일 개별 배경 체크: [모바일 기기에서 데스크톱과 다른 배경 설정 사용] 스위치를 활성화합니다.
- 모바일 배경 경량화: 독립된 모바일 설정에서 배경을 Solid(단색) 또는 **Gradient(그라디언트)**로 선택하여 모바일 리소스 부하를 최소화합니다.
- 효과: 배터리 소모와 성능이 중요한 모바일 기기에서는 스크립트 실행 부하가 없는 가벼운 배경을 제공하고, PC 환경에서는 다채로운 시각 효과를 온전히 표현하도록 이원화할 수 있습니다.
댓글 0개
댓글을 작성하려면 로그인이 필요합니다.