메뉴 클릭 시 해당 섹션으로 부드럽게 이동하고, 스크롤 위치에 따라 활성 섹션을 자동으로 추적하는 크로스 프레임워크 라이브러리입니다.
- 자동 활성 섹션 추적: IntersectionObserver를 사용한 정확한 섹션 감지
- 크로스 프레임워크: React, Vue 3, Svelte 지원
- 경량: Core 패키지는 zero dependency
- TypeScript: 완전한 타입 정의 제공
- URL 해시 동기화: 활성 섹션을 URL hash에 자동 반영
- 키보드 네비게이션:
Alt+ArrowDown/Alt+ArrowUp지원 - 커스텀 스크롤 컨테이너:
window외의 스크롤 영역 지원 - 스크롤 진행률 추적: 섹션별 0–1 progress 콜백
npm install @jump-section/reactnpm install @jump-section/vuenpm install @jump-section/sveltenpm install @jump-section/coreimport { ScrollSectionProvider, useScrollSection } from '@jump-section/react';
function App() {
return (
<ScrollSectionProvider offset={-80} behavior="smooth" hash keyboard>
<Navigation />
<Content />
</ScrollSectionProvider>
);
}
function Navigation() {
const { scrollTo, activeId } = useScrollSection();
return (
<nav>
<button
onClick={() => scrollTo('section-1')}
className={activeId === 'section-1' ? 'active' : ''}
>
Section 1
</button>
<button
onClick={() => scrollTo('section-2')}
className={activeId === 'section-2' ? 'active' : ''}
>
Section 2
</button>
</nav>
);
}
function Content() {
const { registerRef: ref1 } = useScrollSection('section-1');
const { registerRef: ref2 } = useScrollSection('section-2');
return (
<main>
<section ref={ref1}>
<h2>Section 1</h2>
</section>
<section ref={ref2}>
<h2>Section 2</h2>
</section>
</main>
);
}<script setup lang="ts">
import { ScrollSectionProvider } from '@jump-section/vue';
</script>
<template>
<ScrollSectionProvider :offset="-80" behavior="smooth" hash keyboard>
<Navigation />
<Content />
</ScrollSectionProvider>
</template>Navigation.vue
<script setup lang="ts">
import { useScrollSection } from '@jump-section/vue';
const { scrollTo, activeId } = useScrollSection();
</script>
<template>
<nav>
<button @click="scrollTo('section-1')" :class="{ active: activeId === 'section-1' }">
Section 1
</button>
<button @click="scrollTo('section-2')" :class="{ active: activeId === 'section-2' }">
Section 2
</button>
</nav>
</template>Content.vue
<script setup lang="ts">
import { useScrollSection } from '@jump-section/vue';
const { registerRef: section1Ref } = useScrollSection('section-1');
const { registerRef: section2Ref } = useScrollSection('section-2');
</script>
<template>
<main>
<section :ref="section1Ref"><h2>Section 1</h2></section>
<section :ref="section2Ref"><h2>Section 2</h2></section>
</main>
</template>import { ScrollManager } from '@jump-section/core';
const manager = new ScrollManager({
offset: -80,
behavior: 'smooth',
hash: true,
keyboard: true,
});
manager.registerSection('section-1', document.getElementById('section-1')!);
await manager.scrollTo('section-1');
const unsubscribe = manager.onActiveChange((activeId, meta) => {
console.log('Active:', activeId, '| Previous:', meta.previous, '| Direction:', meta.direction);
});
manager.destroy();| Option | Type | Default | Description |
|---|---|---|---|
offset |
number |
0 |
고정 헤더 등을 위한 수직 오프셋 (px) |
behavior |
ScrollBehavior |
'smooth' |
스크롤 동작: 'smooth' | 'instant' | 'auto' |
hash |
boolean |
false |
활성 섹션을 URL hash에 자동 동기화 |
keyboard |
boolean |
false |
Alt+ArrowDown / Alt+ArrowUp 키보드 네비게이션 활성화 |
root |
HTMLElement | null |
null |
커스텀 스크롤 컨테이너 (window 대신 사용) |
jump-section/
├── packages/
│ ├── core/ # framework-agnostic core (zero dependency)
│ ├── react/ # React hooks + components
│ ├── vue/ # Vue 3 composables + component
│ └── svelte/ # Svelte composables
├── docs/
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
- Node.js >= 18
- pnpm >= 9.0.0
pnpm install
pnpm build
pnpm test
pnpm format| Command | Description |
|---|---|
pnpm build |
전체 패키지 빌드 (turbo) |
pnpm test |
전체 테스트 실행 (vitest) |
pnpm test:coverage |
커버리지 포함 테스트 |
pnpm format |
코드 포맷팅 (prettier) |
pnpm check-exports |
패키지 export 검증 |
GitHub Actions에서 anthropics/claude-code-action이
동작합니다. 상주 서버는 없습니다.
| 워크플로우 | 트리거 | 하는 일 |
|---|---|---|
weekly-planning.yml |
매주 월요일 09:00 (KST) | 저장소 상태를 보고 개선 이슈를 제안 |
ai-implement.yml |
이슈에 ai-implement 라벨 |
구현 + 테스트 + 문서까지 하고 Draft PR 생성 |
claude.yml |
이슈/PR에서 @claude 멘션 |
빌드 에러 수정, 리뷰 코멘트 반영, 질문 응답 |
auto-format.yml |
수동 (workflow_dispatch) |
Prettier 포맷만 적용 (LLM 미사용) |
기본 흐름은 제안 → 라벨 → 구현 → 리뷰입니다. 주간 기획이 만든 이슈를 확인하고 ai-implement
라벨을 붙이면 Draft PR까지 자동으로 올라오고, 사람이 리뷰합니다. PR에서 고칠 게 있으면 코멘트로
@claude를 멘션하세요.
@claude CI 빌드 에러를 고쳐줘
@claude 이 리뷰 코멘트 반영해줘
AI가 만든 브랜치는 반드시 사람이 리뷰한 뒤 머지합니다 (CLAUDE.md「AI 파이프라인 거버넌스」).
저장소를 바꾸는 일은 위의 Actions가, 실패를 알아채는 일은 로컬 n8n(.n8n/)이 맡습니다.
| 워크플로우 | 방식 | 하는 일 |
|---|---|---|
ci-failure-alert.json |
15분마다 GitHub API 폴링 | 새로 실패한 워크플로우 실행을 Discord로 알림 |
워크플로우마다 if: failure()를 심는 대신 한 곳에서 모든 실패를 봅니다 — 앞으로 추가되는
워크플로우까지 자동으로 포함됩니다. 웹훅을 받지 않아 터널이 필요 없고, 읽기 전용 토큰만 씁니다.
bash scripts/n8n-setup.sh # .env 생성 → 값 입력 → 다시 실행하면 기동맥이 꺼져 있는 동안에는 알림이 지연됩니다(유실되지는 않습니다 — 폴링이라 다음 기동 때 따라잡습니다).
- Claude GitHub App 설치
claude setup-token으로 토큰을 만들어 저장소 Secrets에CLAUDE_CODE_OAUTH_TOKEN으로 추가 (구독 기반이라 API 과금이 없습니다)- 저장소 Labels에
ai-proposal,ai-implement추가
Issue를 열거나 Pull Request를 보내주세요.
ISC © k_jin.0
