
본문 이미지를 나중에 넣는 게 아니라 — SEOJing 글쓰기.
SEOJing에서 새 글을 쓸 때 대표 이미지와 본문 이미지를 빼먹지 않도록, 블로그 맵과 글쓰기 파이프라인 안에 시각 판단 단계를 넣은 과정을 정리했다.
SEOJing post brief
SEOJing 요약 쇼츠를 독립 콘텐츠가 아니라 포스트 상단 요약과 블로그 유입 장치로 설계한 이유를 1분으로 압축했습니다.
이 영상은 글의 대체물이 아니라 입구입니다. 더 긴 맥락, 판단 근거, 실제 운영 기준은 아래 본문에서 이어집니다.
처음에는 “AI로 영상 만든다”는 말을 조금 넓게 보고 있었다. 글 하나를 넣으면 쇼츠가 나오고, 그걸 유튜브나 인스타에 올리면 되는 식의 자동화로 생각하기 쉽다. 그런데 SEOJing에 그대로 붙이기에는 어색했다.
SEOJing 글은 그냥 콘텐츠 덩어리가 아니다. 대부분이 어떤 기능을 만들다가 기준을 다시 잡은 기록이고, OkayJing 운영 판단이나 스터디 흐름처럼 맥락을 같이 읽어야 이해되는 글이 많다. 여기서 영상만 따로 튀어나가면, 영상은 눈길을 끌 수는 있어도 글과 분리된다.
이번에 잡은 기준은 그래서 조금 다르다.
영상은 글의 대체물이 아니라, 글로 들어오는 입구여야 한다.
처음 의심한 건 영상 생성 방식이었다. Motion Canvas처럼 코드를 짜서 모션그래픽을 만들지, FFmpeg로 카드형 영상을 만들지, 아니면 Sora나 Runway 같은 생성형 영상을 써야 하는지 같은 선택지가 먼저 보였다.
그런데 막상 SEOJing에 붙이려고 보니, 렌더러보다 앞에 있는 문제가 있었다.
이 영상이 어디에 붙을 것인가?
소셜에만 올릴 영상이면 훅이 강한 게 중요하다. 하지만 SEOJing 포스트 안에 들어갈 영상이면 성격이 달라진다. 글의 제목, 설명, 태그, 본문 흐름과 같은 선상에 있어야 한다. 영상의 첫 문장이 세더라도, 그 강함은 포스트의 실제 문제에서 나와야 한다.
그래서 기능의 출발점을 이렇게 바꿨다.
글을 요약해서 영상 만들기
가 아니라,
SEOJing 포스트 상단에 붙을 요약 쇼츠 만들기
이 차이가 생각보다 컸다. 후자는 영상 생성보다 콘텐츠 계약에 가깝다.
가장 단순한 방법은 MDX 본문에 <video> 태그를 직접 박는 것이다. 하지만 그건 SEOJing 구조와 잘 맞지 않았다. 나중에 모든 글의 요약 영상을 목록화하거나, 소셜용 파일과 블로그 상단 파일을 구분하거나, 자막/포스터/제공자를 추적하려면 본문 안에 숨어 있으면 불편하다.
그래서 포스트 frontmatter에 summaryVideo를 추가했다.
summaryVideo:
src: /summary-videos/SEOJing/summary-video-pipeline/summary-short.mp4
title: SEOJing 글 위에 붙는 요약 쇼츠
caption: 글을 대체하는 영상이 아니라, 본문으로 들어가는 입구로 만든 요약 영상입니다.
subtitles: /summary-videos/SEOJing/summary-video-pipeline/subtitles.srt
provider: supertonic
이 구조가 마음에 드는 이유는 명확하다. 영상이 글의 메타데이터가 된다. cover가 글 바깥의 대표 이미지를 담당한다면, summaryVideo는 글 안쪽의 진입 영상을 담당한다.
cover
→ 목록과 카드에서 글을 고르게 만든다
summaryVideo
→ 글에 들어온 뒤, 본문을 읽을 이유를 빠르게 만든다
둘 다 진입점이지만 위치와 역할이 다르다.
Motion Canvas가 훨씬 멋있어 보이는 건 맞다. 장면별로 텍스트가 움직이고, 비교표가 등장하고, 도식이 전환되는 영상을 만들 수 있다. 하지만 지금 SEOJing에 먼저 필요한 건 “멋진 데모”보다 반복 가능한 기본값이었다.
이번 MVP는 이렇게 잡았다.
SEOJing post
→ scenes JSON
→ Supertonic3 TTS
→ subtitles.srt
→ FFmpeg/Pillow 카드형 9:16 영상
→ public/summary-videos/<slug>/summary-short.mp4
→ frontmatter summaryVideo로 연결
이 흐름은 화려하지 않다. 대신 빠르고, 디버깅하기 쉽고, 글마다 같은 방식으로 붙일 수 있다. 지금 단계에서는 이게 더 중요했다.
특히 TTS는 오케이징에서 튜닝해둔 Supertonic3 쪽을 기본값으로 썼다. Edge TTS는 편하지만, SEOJing 포스트 상단에 붙는 영상이라면 목소리도 OkayJing 쪽 운영 톤과 이어지는 편이 낫다.
겉으로 보면 영상 카드 하나가 추가된 것처럼 보이지만, 실제로는 세 층을 건드렸다.
첫 번째는 content parser다. packages/utils/src/content.ts에서 frontmatter의 summaryVideo 객체를 읽을 수 있게 했다. 기존에는 title, date, tags, description, cover 정도만 안정적으로 파싱했다. 여기에 영상 메타데이터가 들어간다.
두 번째는 타입이다. ContentFrontmatter에 ContentSummaryVideo를 추가했다. 이걸 해두면 글 목록, 상세 페이지, 나중의 검색 인덱스나 RSS 확장에서도 같은 계약을 쓸 수 있다.
세 번째는 article page다. apps/web/src/app/blog/[...slug]/page.tsx에서 ArticleHeader 아래에 SummaryVideo를 렌더링한다. 포스트에 summaryVideo.src가 없으면 아무것도 나오지 않는다. 그래서 기존 글은 건드리지 않고, 준비된 글만 영상을 가진다.
이게 이번 기능의 핵심이다. 새 기능을 넣었지만 모든 글에 새 UI를 강제로 밀어 넣지는 않는다.
요약 쇼츠를 만들 때 가장 조심해야 하는 건 훅이다. 영상은 첫 2초가 중요하니까 자극적인 문장을 쓰고 싶어진다. 하지만 SEOJing에서는 그 훅이 글의 주제에서 벗어나면 바로 어색해진다.
예를 들어 이 기능을 소개하면서 이런 식으로 시작하면 안 된다.
AI 영상 제작의 시대가 왔다
너무 넓다. 이 글의 주제는 AI 영상 제작 전체가 아니라, SEOJing 포스트를 어떻게 영상으로 요약하고 블로그에 다시 연결할 것인가다.
더 맞는 훅은 이쪽이다.
영상은 글을 대체하면 안 됐다
이 문장은 지금 기능의 판단과 바로 연결된다. 요약 쇼츠가 소셜에서 관심을 끄는 건 좋다. 하지만 결국 독자가 더 자세한 내용을 읽으러 블로그에 들어와야 한다. 그래서 영상은 독립 콘텐츠라기보다 압축된 문 앞 표지에 가깝다.
복잡한 모션그래픽을 하고 싶다면 Motion Canvas로 가면 된다. 그런데 바로 렌더러를 바꾸면 다시 한 번 도구 중심으로 흐른다. 먼저 정해야 하는 건 장면 계약이다.
예를 들면 이런 구조다.
{
"kind": "point",
"title": "영상은 글의 입구다",
"caption": "소셜 훅은 허용하지만, 포스트 주제 밖으로 나가면 안 됩니다.",
"diagram": {
"type": "pipeline",
"items": ["post", "scenes", "tts", "video", "blog"]
}
}
이렇게 장면 데이터에 diagram과 motion 정보를 넣어두면, 지금의 FFmpeg 렌더러도 쓰고 나중의 Motion Canvas 렌더러도 같은 데이터를 볼 수 있다.
내가 원하는 방향은 이렇다.
scenes.normalized.json
├─ ffmpeg-card renderer
│ └─ 빠른 블로그 상단 영상
└─ motion-canvas renderer
└─ 소셜 업로드용 고품질 모션그래픽
즉 Motion Canvas는 목표가 아니라 출력 방식 중 하나다. 진짜 중심은 포스트에서 장면을 뽑는 기준이다.
영상이 블로그 위에 들어오면, 영상도 SEOJing 디자인 시스템의 일부가 된다. 색이 다르고, 카드 모서리나 여백이 다르고, 타이포가 따로 놀면 바로 티가 난다.
그래서 다음 단계는 Motion Canvas보다 디자인 토큰화가 먼저다.
SEOJing design tokens
→ summary-video-theme.json
→ FFmpeg renderer
→ Motion Canvas renderer
이렇게 가야 같은 포스트에서 카드, cover, inline visual, summary video가 한 흐름으로 보인다. 영상만 멋있는 건 오히려 실패에 가깝다. SEOJing 글의 일부처럼 보여야 한다.
이 기능은 현재 로컬에서 구현되고 검증된 상태다. 포스트에 summaryVideo를 붙이고, 정적 mp4와 자막을 연결하고, 빌드가 통과하는 것까지 확인했다. 다만 이 글을 공개 포스트로 말하려면 배포까지 이어져야 한다.
그래서 지금 단계에서 정확한 표현은 이렇다.
SEOJing 요약 쇼츠 삽입 기능을 로컬 구현했고,
포스트 frontmatter 기반으로 반복 가능한 계약을 만들었다.
아직 “모든 SEOJing 글에 자동 영상이 붙는다”는 말은 하면 안 된다. 자동 생성, 디자인 토큰 연동, Motion Canvas 고품질 렌더러는 다음 단계다.
이 구분을 해두는 게 중요하다. SEOJing 글은 기능 홍보보다 판단 기록에 가깝고, 판단 기록은 어디까지 됐는지를 정확히 적어야 한다.
이번 작업은 영상 기능을 붙였다기보다, SEOJing 글에 영상이 들어오는 자리를 만든 작업에 가깝다.
요약 쇼츠는 글을 대체하지 않는다. 글의 주제를 먼저 압축하고, 독자가 본문을 읽을 이유를 만든다. 그래서 영상 스크립트도 포스트 밖으로 튀면 안 되고, 영상 파일도 frontmatter 계약 안에 들어와야 한다.
다음에 할 일은 분명하다.
돌이켜보면 이 기능에서 중요한 건 “AI로 영상을 만들었다”가 아니었다. 글과 영상 사이의 책임 경계를 먼저 잡은 것이다. 그 경계가 있어야, 나중에 모션그래픽이 화려해져도 SEOJing 글의 일부로 남을 수 있다.
docs/seojing-summary-video-roadmap.md/Users/seojing/.hermes/scripts/summary_video_maker.pyapps/web/src/widgets/summary-video/SummaryVideo.tsxpackages/utils/src/content.tsPost Q&A
글 위에 영상을 붙인다는 것 — SEOJing 요약 쇼츠 파이프라인 전체를 기준으로 질문과 피드백을 받아요.답을 본 뒤에는 이 내용을 댓글로 달아서 서징에게도 물어볼 수 있어요. 작성자가 직접 볼 수 있어요!

SEOJing에서 새 글을 쓸 때 대표 이미지와 본문 이미지를 빼먹지 않도록, 블로그 맵과 글쓰기 파이프라인 안에 시각 판단 단계를 넣은 과정을 정리했다.
SEOJing 글을 소셜용 영상으로 따로 소비시키는 게 아니라, 포스트 상단 요약과 블로그 유입 장치로 연결하기 위해 summaryVideo frontmatter와 Supertonic3 기반 요약 쇼츠 파이프라인을 붙인 과정을 정리했다.

SEOJing 블로그에 대표 이미지를 자동으로 붙이는 실험을 실제로 돌려봤다. 검색 기반 cover 삽입과 Codex CLI 기반 정적 SVG 생성이 같은 frontmatter 경로로 연결됐다.

SEOJing 포스트 목록을 파일 탐색기처럼만 두지 않고, 최신 글부터 실제 사진 기반 리소그래프 배경을 붙이는 실험을 정리합니다. 이미지는 배경만 만들고, 제목과 아이콘은 블로그 UI가 맡는 쪽으로 방향을 바꿨습니다.
SEO Jing 개발 열두째 날. code-block 테스트 14개 추가로 커버리지 대폭 개선, 모바일 프레젠테이션에서 FullscreenView 방향 전환 문제와 스크롤 멈춤 버그 수정.
useEffect 의존성 배열에 불필요한 값이 포함되면 cleanup과 재실행이 뒤엉켜 DOM 상태가 꼬일 수 있다. 프레젠테이션 모드에서 발생한 모바일 스크롤 고착 버그를 통해 원인과 해결 패턴을 정리한다.
SEO Jing 개발 열한째 날. PC 프레젠테이션 확대/축소 컨트롤 추가, 모바일 orientation 판단 로직 개선, FullscreenView를 독립 컴포넌트로 분리 및 PC 대응.
한국어 MDX 블로그를 만들다 vinext 프레임워크의 ByteString 버그를 발견하고, 이슈를 작성하고, PR을 올리기까지의 과정
vinext가 빠른 이유를 이해하기 위해, SSR부터 Hydration, 빌드 도구, Edge Runtime, Web Vitals, RSC, CDN 캐싱, ISR, PPR까지 웹 렌더링 성능의 전체 그림을 정리한다
모바일 Safari에서 100vh가 화면을 넘치는 이유, vh/svh/lvh/dvh의 차이, JavaScript에서 실제 뷰포트를 구하는 방법, 그리고 전체화면 UI를 만들 때 알아야 할 CSS zoom과 모바일 판정 패턴까지 정리한다.
SEO Jing 개발 열째 날. 프레젠테이션 모드의 모바일 UX 문제들을 전면 수정. 퀴즈·코드블록·이미지·포스트목록 처리 개선, 롱프레스 UX 및 하단 바 레이아웃 안정화. 모바일 뷰포트·리스트 분할 문제 수정, 채움 비율 보수적으로 조정, 포스트 탐색기 자연 정렬 적용.
SEO Jing 개발 아홉째 날. 프레젠테이션 기능 추가, 퀴즈 구조 변경, 모바일 반응형, 코드블럭 사용성, 테스팅 도입.
모바일 웹에서 코드 블록을 가로로 넓게 보여주고 싶었다. screen.orientation.lock()은 iOS에서 안 되고, PWA manifest는 브라우저에서 무시된다. 결국 CSS transform으로 가짜 회전을 만들었고, 그 과정에서 엄지 접근성까지 고민하게 됐다.
MDX 파일을 수정하지 않고, 렌더된 DOM을 h2 기준으로 자르고 화면 높이에 맞춰 자동 페이지네이션하는 프레젠테이션 모드를 만들었다. 리스트 높이 측정이 왜 틀리는지 디버깅한 과정과, ul/ol을 li 단위로 분할하는 해결책을 정리한다.
SEO Jing 개발 여덟째 날. 아티클 퀴즈 디자인시스템 구현과 스터디 대면 자료 작성.
MDX 블로그에 퀴즈 컴포넌트를 만들면서, Context 기반 Compound Component로 시작했다가 index 문제에 막혀 React.Children API를 채택하게 된 과정을 정리한다.
SEO Jing 개발 일곱째 날. Front Matter CMS 설치와 관련 게시물 이동 탐색기 구현.
SEO Jing 개발 여섯째 날. 데스크탑 비율 수정과 씨랩 스터디 사전 진단 자료 작성.
SEO Jing 개발 다섯째 날. shiki를 rehype-prism-plus로 교체하고, gray-matter 직접 구현, MDX 모듈화, 페이지 내 검색, 테이블 디자인시스템까지.
SEO Jing 개발 넷째 날. lint, codecov, Cloudflare 배포, fs 런타임 이슈.
배포 후 블로그 포스트가 404를 반환하던 문제부터, gray-matter eval 차단, next-mdx-remote eval 차단까지 — 세 겹으로 터진 이슈를 하나씩 해결한 기록
localStorage를 읽는 컴포넌트에서 하이드레이션 불일치가 발생하는 원인과, useState+useEffect가 아닌 useSyncExternalStore가 정답인 이유를 정리한다.
vinext 프로젝트를 GitHub Actions로 Cloudflare Workers에 자동 배포하는 방법과 실제 겪은 트러블슈팅 기록
코드 하이라이팅에 Shiki를 쓰면 왜 RSC에서 WebAssembly.instantiate() 에러가 터지는지, 그리고 빌드 타임 하이라이팅으로 어떻게 해결했는지 정리한다.
CLI 코드 리뷰에서 받은 피드백과 전체 코드 수정 계획을 정리했다.
localStorage만으로 글 읽기 추적, 스크롤 진행률, 댓글 감지를 구현한 과정을 정리했다.
블로그 디테일 페이지에서 MDX를 렌더링하기 위해 검토한 라이브러리들과 최종 선택 과정.
SEO Jing 개발 셋째 날. MDX 라이브러리 이슈, 반응형, 코드블럭, 댓글, 다크모드, 코드 리뷰.
디자인 시스템 구현 시 파일 구조, 디자인 토큰, 유의 사항을 정리했다.
Tailwind v4 환경에서 폰트가 메인 페이지에서만 적용되지 않던 원인과 Hydration Mismatch 이슈를 정리했다.
MDX 파일의 경로 탐색 로직과 콘텐츠 트리 생성 과정을 정리했다.
MDX 파일 구조를 JSON으로 변환하기 위해 Node.js의 fs 모듈을 배워봤다.
SEO Jing 개발 둘째 날. 디자인 시스템 확장, 블로그 스켈레톤, 폰트 이슈 해결.
SEO Jing 프로젝트의 기술 스택 선정과 전체적인 개발 플로우 정리.
Storybook의 사용법과 디자인 시스템 개발에서의 장점을 정리했다.
MDX의 개념과 블로그에서 활용하는 이유를 정리했다.
SEO Jing 개발 첫째 날. 디자인 컨셉 설정과 디자인 시스템 구축을 시작했다.
SEO Jing을 개발하게 된 이유입니다.
프로젝트가 중단되는 이유에 대한 자기 회고입니다.