Day 2 Dev Log: From Zero to a Complete Meme Contest Ecosystem
Yesterday we had a basic meme upload. Today we shipped a full-stack meme contest platform with voting, sharing, score tracking, social media integration, dashboards, badges, and more — all in a single day.
This is the raw, unfiltered dev log of everything we built for motorcyclediaries.fun/memes.
What We Started With
A simple meme page where users could upload images. That's it. No voting, no scoring, no sharing, no stats.
By the end of the day, here's what we shipped:
1. Animated Score Bar System on Top 3 Podium
The Top 3 memes now have a live animated score bar underneath each card.
How it works:
- Every like pushes the bar forward (green → cyan gradient)
- Every dislike pushes it back (red → orange gradient)
- When a vote happens, the bar pulses with a glow animation (
barPulse) - The score number does a pop-scale effect (
scorePop) - All updates happen in real-time — no page refresh needed
@keyframes barPulse {
0% { box-shadow: 0 0 0 rgba(57,255,20,0); }
50% { box-shadow: 0 0 12px rgba(57,255,20,.4); }
100% { box-shadow: 0 0 0 rgba(57,255,20,0); }
}
.score-bar {
transition: width .8s cubic-bezier(.4,0,.2,1);
}
The score bar percentage is calculated as:
const pct = Math.max(2, Math.min(100,
((score + MAX_SCORE) / (MAX_SCORE * 2)) * 100
));
This maps a score range of -MAX_SCORE to +MAX_SCORE onto a 2%–100% bar width. Even negative scores still show a small sliver so the bar never fully disappears.
2. Video & GIF Support
Memes aren't just images anymore. We added full support for:
- GIF — animated memes
- MP4 — video memes up to 10MB
- WebM — web-optimized video
Backend changes (PHP):
$allowed_types = [
'image/jpeg', 'image/png', 'image/gif',
'image/webp', 'video/mp4', 'video/webm'
];
Frontend rendering:
Videos auto-play muted and loop in both the podium and grid views:
function isVideo(url) { return /\.(mp4|webm)$/i.test(url); }
const media = isVid
? `<video class="pc-media" src="${m.url}" muted loop autoplay playsinline></video>`
: `<img class="pc-media" src="${m.url}" alt="Meme">`;
The lightbox viewer also handles video — pause on close, controls visible.
CSP Headers Updated:
media-src 'self' blob:;
img-src 'self' data: blob:;
3. Social Media Share System with Bonus Points
This was the big feature. Every meme can now be shared on X/Twitter, Telegram, or copied as a link.
Each share gives the meme +2 bonus score points.
The scoring formula:
Total Score = (Likes - Dislikes) + (Shares × 2)
Backend: Share Tracking API
New share action in our PHP API:
case 'share':
$shareKey = 'ip:' . md5($ip) . ':' . $platform . ':' . $meme_id;
if (isset($db['shares'][$shareKey])) {
echo json_encode(['success' => true, 'bonus' => false]);
exit;
}
$m['shares'] = ($m['shares'] ?? 0) + 1;
$db['shares'][$shareKey] = [
'platform' => $platform,
'time' => date('c')
];
Anti-abuse: One bonus per platform per IP per meme. You can share on all 3 platforms = max +6 points per meme per person.
Frontend: Share Buttons with Effects
Every podium card and grid card gets share buttons:
- 𝕏 Share — opens Twitter intent with pre-filled text
- ✈️ Share — opens Telegram share dialog
- 🔗 Copy — copies meme URL to clipboard
When a share earns bonus points:
- Button gets a
shareGlowanimation - Score bar updates in real-time
- Particle explosion fires
- Score number pops
async function doShare(memeId, memeUrl, platform, btn) {
// Open share window
window.open(shareUrl(memeId, memeUrl, platform), '_blank');
// Record share & get bonus
const r = await fetch(API + '?action=share', {
method: 'POST',
body: JSON.stringify({ meme_id: memeId, platform })
});
const d = await r.json();
if (d.success && d.bonus) {
updatePodiumBarShare(memeId);
spawnParticles(btn, 'like');
}
}
4. Open Graph & Twitter Card Meta Tags
The memes page had zero social preview when shared on any platform. We added full OG and Twitter Card tags:
<meta property="og:title" content="$MOTO Meme Contest | Motorcycle Diaries">
<meta property="og:description" content="Create the best $MOTO memes...">
<meta property="og:image" content="https://motorcyclediaries.fun/images/og-image.jpg">
<meta property="og:image:width" content="1024">
<meta property="og:image:height" content="1024">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@motodiariesfun">
<meta name="twitter:image" content="https://motorcyclediaries.fun/images/og-image.jpg">
Now when anyone shares motorcyclediaries.fun/memes on Twitter, Telegram, Discord, WhatsApp — they see a rich preview with title, description, and image.
5. Dashboard Meme Integration
This was the deepest feature. Connected wallet users can now see their complete meme activity inside their rider dashboard.
API: Enhanced /my Endpoint
The API now returns comprehensive stats:
{
"memes": [...],
"stats": {
"total": 3,
"total_likes": 12,
"total_dislikes": 2,
"total_shares": 5,
"total_score": 20,
"top3_count": 1
}
}
The score uses the unified memeScore() function:
function memeScore($m) {
$likes = $m['likes'] ?? 0;
$dislikes = $m['dislikes'] ?? 0;
$shares = $m['shares'] ?? 0;
return ($likes - $dislikes) + ($shares * 2);
}
Dashboard: "Your Meme Activity" Card
On the dashboard overview, a new card appears showing:
- Uploads / Likes / Shares counts
- Total Score / Top 3 Finishes
- Thumbnail grid of your uploaded memes (with score overlay)
- Auto-earned tags and badges
Earned Tags & Badges System
Based on your meme activity, you automatically earn labels:
| Badge | Requirement |
|---|---|
| 🖼️ Meme Creator | Upload 1+ meme |
| ❤️🔥 Popular Memer | 10+ total likes |
| 🚀 Viral Meme | 50+ total likes |
| 🏆 Top 3 | Reach Top 3 ranking |
| 📤 Share Master | 5+ total shares |
These appear as colored tag pills on the dashboard and activate corresponding badges in the Rewards section.
Hero Bar Tag
If you've uploaded any memes, a pink 🖼️ MEME CREATOR tag appears next to your wallet address in the dashboard header bar — visible at all times.
Memes Tab: Full Stats View
The dedicated Memes tab in the dashboard now shows:
- Complete stat overview with all metrics
- Grid of all your uploaded memes with per-meme stats (likes, dislikes, shares, score)
- Featured badge indicator on featured memes
- Upload form for new memes (now supports video too)
6. Improved Navigation
Desktop Sidebar
The sidebar got a significant readability upgrade:
- Width:
180px→220px - Font:
Orbitron 0.6rem→Outfit 0.95rem(~60% larger) - Icons:
0.9rem→1.15rem - Better padding and hover states
Mobile Tabs
Mobile navigation tabs were redesigned:
- Font:
0.48rem→0.75rem(~56% larger) - Added emoji icons: 🏠 Dashboard, 🏆 Grand Prix, 🤝 Referral, etc.
- Better borders and active state styling
-
display:flexalignment for icon + text
7. Clean URL Routing
Added Apache rewrite rules so all pages work without .html extensions:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L]
</IfModule>
Now motorcyclediaries.fun/memes works cleanly instead of requiring /memes.html.
The Technical Architecture
Here's the full stack powering the meme contest:
Frontend: Vanilla HTML/CSS/JS (zero frameworks)
Backend: PHP API with JSON file storage
Storage: Server filesystem for uploads
Voting: IP-based (md5 hash), no wallet required
Sharing: IP + platform tracking
Scoring: (likes - dislikes) + (shares × 2)
Hosting: Hostinger shared hosting
CDN: Cloudflare
Cost: ~$3/month
Why JSON files instead of a database?
For a meme contest with hundreds (not millions) of entries, JSON files with LOCK_EX are simpler, faster to iterate, and require zero database setup. The entire data model fits in one file. When we outgrow it, migrating to SQLite or MySQL is trivial.
Why IP-based voting instead of wallet-based?
We want maximum participation. Requiring wallet connection just to vote kills engagement. IP-based (one vote per IP per meme) keeps it fair while being frictionless. Wallet connection is only needed for uploading memes.
What's Next
- Weekly automated winner selection and reward distribution
- Meme of the Week auto-feature on social channels
- Enhanced dashboard analytics with graphs
- Community-driven meme categories and tags
The Numbers
| Metric | Count |
|---|---|
| Features shipped today | 7 major |
| API endpoints added/updated | 3 |
| CSS animations created | 4 |
| Lines of code changed | ~800 |
| Deployment cycles | 12 |
| Frameworks used | 0 |
| Total infrastructure cost | ~$3/month |
Try It Yourself
- Meme Contest: motorcyclediaries.fun/memes
- Dashboard: motorcyclediaries.fun/dashboard
- Main Site: motorcyclediaries.fun
- Telegram: @motodiariesbot
- X/Twitter: @motodiariesfun
Upload a meme. Vote on others. Share for bonus points. See your stats on the dashboard.
Everything is live right now.
Final Thought
You don't need React. You don't need Next.js. You don't need a $50K infrastructure budget.
Sometimes all you need is vanilla HTML, a PHP file, a JSON storage, and the stubborn refusal to stop shipping.
Born to Ride. Forced to HODL. Never stop building.
This is part of the Motorcycle Diaries Dev Log series — documenting every step of building a crypto community project from scratch with $0 budget.
Top comments (0)