xhub-reels-sdk
v0.1.6
Published
High-performance Short Video / Reels SDK for React — optimized for Flutter WebView
Downloads
25
Maintainers
Readme
xhub-reels-sdk
High-performance Short Video / Reels SDK for React — optimized for Flutter WebView.
Why?
Built as a leaner, faster alternative focused on solving real-world WebView performance issues:
| Problem | Solution |
|---|---|
| React state updates during drag → jank | Pointer Events + direct DOM, zero React during drag |
| querySelectorAll per animation frame | MutationObserver slot cache, O(1) lookup |
| setTimeout polling for sync | Single store.subscribe |
| CSS transitions interrupted by React renders | Web Animations API (imperative, cancellable) |
| Static class-level global cache | Instance-scoped prefetch cache |
| 1153-line Feed component | Split into focused, testable units |
Installation
npm install xhub-reels-sdkPeer dependencies:
npm install react react-dom # >=18.0.0Quick Start
import {
ReelsProvider,
MockDataSource,
MockInteraction,
} from 'xhub-reels-sdk';
import { MyFeed } from './MyFeed';
export function App() {
return (
<ReelsProvider
adapters={{
dataSource: new MockDataSource(),
interaction: new MockInteraction(),
}}
>
<MyFeed />
</ReelsProvider>
);
}With Your Own Data Source
import type { IDataSource, FeedPage } from 'xhub-reels-sdk';
class MyAPIDataSource implements IDataSource {
async fetchFeed(cursor?: string | null): Promise<FeedPage> {
const res = await fetch(`/api/feed?cursor=${cursor ?? ''}`);
const data = await res.json();
return {
items: data.videos,
nextCursor: data.nextCursor,
hasMore: data.hasMore,
};
}
}Hooks
import { useFeed, usePlayer, useResource } from 'xhub-reels-sdk';
function MyFeed() {
const { items, loading, loadInitial, loadMore } = useFeed();
const { focusedIndex, setFocusedIndex, shouldRenderVideo } = useResource();
const { isPlaying, togglePlay, handlers } = usePlayer();
// ...
}Gesture Engine
import { usePointerGesture, useSnapAnimation } from 'xhub-reels-sdk';
function SwipeableFeed() {
const { animateSnap, animateBounceBack } = useSnapAnimation();
const { bind } = usePointerGesture({
onDragOffset: (offset) => {
// Direct DOM — zero React state during drag
containerRef.current!.style.transform = `translateY(${offset}px)`;
},
onSnap: (direction) => {
const next = direction === 'forward' ? index + 1 : index - 1;
goToIndex(next);
animateSnap(targets);
},
onBounceBack: () => animateBounceBack(targets),
});
return <div {...bind} style={{ touchAction: 'none' }}>...</div>;
}Architecture
xhub-reels-sdk
├── types/ ← Pure TypeScript interfaces (no deps)
├── domain/ ← Business logic (zustand/vanilla, no React)
│ ├── PlayerEngine — State machine + Circuit Breaker
│ ├── FeedManager — Pagination, LRU, SWR, dedup
│ ├── OptimisticManager — Debounced like/follow + rollback
│ └── ResourceGovernor — Max 3 video DOM nodes
├── gesture/ ← Pointer Events + Web Animations API
│ ├── usePointerGesture — Zero React during drag
│ └── useSnapAnimation — Cancellable snap animation
├── components/ ← React components
│ └── ReelsProvider — Context + DI container
├── hooks/ ← useSyncExternalStore-based hooks
│ ├── useFeed
│ ├── usePlayer
│ └── useResource
└── adapters/mock/ ← Development mocksPerformance Targets
| Metric | Target | |---|---| | Bundle size | < 35KB gzip | | First video load | < 1s on WiFi | | Scroll FPS | 60fps | | Max video DOM nodes | 3 | | React renders per swipe | 1 (on snap only) |
Bundle Size Limits
| Package | Limit |
|---|---|
| xhub-reels-sdk | 35KB gzip |
Development
# Install
npm install
# Build package
npm run build
# Run demo app
npm run dev
# Tests
npm run test
# Type check
npm run typecheck
# Lint + format
npm run lint:fixRelease
# Bump version
npm version patch # or minor / major
# Tag and push (triggers GitHub Actions publish)
git tag v0.1.1 && git push --tagsLicense
MIT
