← Back to list

video-reels-stories
by Smarter-Poker
Smarter-Poker-World-Hub
⭐ 0🍴 0📅 Jan 26, 2026
SKILL.md
name: Video Reels & Stories description: Short-form video content like TikTok/Reels and ephemeral stories
Video Reels & Stories Skill
Overview
Build short-form video feeds (Reels) and ephemeral 24-hour stories.
Reels System
Database
CREATE TABLE reels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
author_id UUID REFERENCES auth.users(id),
video_url TEXT NOT NULL,
thumbnail_url TEXT,
caption TEXT,
hashtags TEXT[],
likes_count INTEGER DEFAULT 0,
comments_count INTEGER DEFAULT 0,
views_count INTEGER DEFAULT 0,
duration_seconds INTEGER,
is_featured BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Reel Player Component
function ReelPlayer({ reel, isActive }) {
const videoRef = useRef();
useEffect(() => {
if (isActive) {
videoRef.current.play();
} else {
videoRef.current.pause();
}
}, [isActive]);
return (
<div className="reel-container">
<video
ref={videoRef}
src={reel.video_url}
loop
muted={!isActive}
playsInline
className="reel-video"
/>
<ReelOverlay reel={reel} />
<ReelSidebar
likes={reel.likes_count}
comments={reel.comments_count}
/>
</div>
);
}
Swipeable Feed
import { useSwipeable } from 'react-swipeable';
function ReelsFeed({ reels }) {
const [currentIndex, setCurrentIndex] = useState(0);
const handlers = useSwipeable({
onSwipedUp: () => setCurrentIndex(i => Math.min(i + 1, reels.length - 1)),
onSwipedDown: () => setCurrentIndex(i => Math.max(i - 1, 0)),
preventScrollOnSwipe: true
});
return (
<div {...handlers} className="reels-feed">
{reels.map((reel, index) => (
<ReelPlayer
key={reel.id}
reel={reel}
isActive={index === currentIndex}
/>
))}
</div>
);
}
Stories System
Database
CREATE TABLE stories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
author_id UUID REFERENCES auth.users(id),
media_url TEXT NOT NULL,
media_type TEXT DEFAULT 'image', -- 'image', 'video'
duration_seconds INTEGER DEFAULT 5,
created_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ DEFAULT NOW() + INTERVAL '24 hours'
);
CREATE TABLE story_views (
story_id UUID REFERENCES stories(id),
viewer_id UUID REFERENCES auth.users(id),
viewed_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (story_id, viewer_id)
);
Stories Bar Component
function StoriesBar({ stories, onStoryClick }) {
const groupedByUser = groupStoriesByUser(stories);
return (
<div className="stories-bar">
{groupedByUser.map(userStories => (
<StoryAvatar
key={userStories.userId}
user={userStories.user}
hasUnviewed={userStories.hasUnviewed}
onClick={() => onStoryClick(userStories)}
/>
))}
</div>
);
}
Story Viewer
function StoryViewer({ stories, onClose }) {
const [index, setIndex] = useState(0);
const [progress, setProgress] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setProgress(p => {
if (p >= 100) {
if (index < stories.length - 1) {
setIndex(i => i + 1);
return 0;
} else {
onClose();
return 100;
}
}
return p + (100 / (stories[index].duration_seconds * 10));
});
}, 100);
return () => clearInterval(timer);
}, [index, stories]);
return (
<div className="story-viewer">
<StoryProgressBars stories={stories} current={index} progress={progress} />
<StoryMedia story={stories[index]} />
<StoryHeader user={stories[index].author} onClose={onClose} />
</div>
);
}
Components
ReelsFeed.jsx- Full-screen vertical scrollReelPlayer.jsx- Video player with controlsReelSidebar.jsx- Like/comment/share buttonsStoriesBar.jsx- Horizontal story avatarsStoryViewer.jsx- Full-screen story playerCreateStory.jsx- Capture/upload story
Score
Total Score
50/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon