Felerous Arcade SDK v4.3.8 Rehberi
HTML5 Canvas, Phaser 3 ve WebGL oyunlarınızı PlayZone platformuna 2 satırda bağlayarak oyunculara sıfır indirmeyle ulaştırın. Çift motorlu köprü mimarisi, gerçek zamanlı skor telemetrisi, 18 kademeli profil başarımları, Modüler CubeRig 2.5D Avatarlar, Arkadaş İsimli Botlar ve Steam-tarzı Topluluk Atölyesi (Workshop UGC).
⚡ 1. 5 Dakikada Hızlı Başlangıç
Felerous Arcade ekosisteminin felsefesi: "Oyun akıcı çalışır (Dumb Engine), Platform skorları ve başarımları akıllıca yönetir (Smart Platform)."
İster kendi oyununuzu geliştirin, ister Yapay Zekaya (Gemini, Claude, Cursor) oyun yazdırın; Felerous ekosistemine küresel liderlik tablosu, oyuncu kimliği ve skor kaydı eklemek artık sadece 2 satır kod! Karmaşık biletler, süre hesaplamaları ve UI tabloları SDK tarafından otomatik yönetilir.
<!-- 1. Köprüyü ekleyin -->
<script src="https://store.felerous.com/js/felerous-bridge_html5.js"></script>
<script>
// 2. Oyun bittiğinde skoru gönderin & yerleşik şık liderlik tablosunu ekrana açın:
felerousBridge.submitScore(score); // Süre, bilet ve güvenlik arka planda otomatik!
felerousBridge.showLeaderboard(); // Sıfır CSS hamallığı; neon cam modal anında açılır!
</script>
felerousBridge.mountBadge()felerousBridge.player.namefelerousBridge.openReviews()felerous-bridge_html5.js (~13KB), Phaser 3 projeleri için sahne yaşam döngüsü ve ses yönetimi entegreli felerous-bridge_phaser.js kullanın. Küp Avatar ve Canlı NPC kullanmak isterseniz bağımsız felerous-cuberig-sdk.js eklentisini dahil edebilirsiniz.
<!-- 1. HTML5 Arcade Köprüsünü Dahil Edin (Ultra Hafif ~13KB, Sıfır Bağımlılık) -->
<script src="https://store.felerous.com/js/felerous-bridge_html5.js"></script>
<!-- İsteğe Bağlı: Oyununuzda Küp Avatar / Canlı Drivatar kullanacaksanız ekleyin -->
<script src="https://store.felerous.com/js/felerous-cuberig-sdk.js"></script>
<script>
// 2. Konsoldan aldığınız kimliklerle el sıkışmayı başlatın:
felerousBridge.init({
gameSlug: 'dusen-sicimler', // Oyununuzun benzersiz slug kodu
appId: 1000002, // Geliştirici Konsolundaki App ID
bridgeToken: 'fel_sec_ORNEK_UYGULAMA_ANAHTARI', // Konsoldan alınan oyun kanal anahtarınız
mountBadge: true, // Köşeye canlı [🏆 Liderlik | 👤 Oyuncu] rozeti ekler
onReady: (player) => {
console.log('✓ Oyuncu oturumu doğrulandı:', player.name, player.felerousId);
},
onAchievementConfirmed: (achId) => {
console.log('🏆 Başarım Supabase bulutuna mühürlendi:', achId);
}
});
// 3. Başarım açma:
felerousBridge.unlockAchievement('first_clear');
// 4. Skor bildirimi (Tek sayı veya detaylı obje kabul eder):
felerousBridge.submitScore({
score: 18450,
difficultyTier: 'lvl2',
difficultyLabel: 'Klasik',
durationSeconds: 120,
achievements: ['first_clear'],
stats: { lines_cleared: 15, apm: 90 }
});
</script>
<!-- 1. Phaser 3 & Phaser Köprüsünü Dahil Edin -->
<script src="https://cdn.jsdelivr.net/npm/phaser@3.80.1/dist/phaser.min.js"></script>
<script src="https://store.felerous.com/js/felerous-bridge_phaser.js"></script>
<!-- İsteğe Bağlı Küp Avatar SDK -->
<script src="https://store.felerous.com/js/felerous-cuberig-sdk.js"></script>
<script>
class ArcadeScene extends Phaser.Scene {
constructor() { super('ArcadeScene'); }
create() {
// Sahneyi ve Oyunu Köprüye Bağla (Otomatik pause/resume, mute ve delta süre sayacı aktif olur)
felerousBridge.attachScene(this);
felerousBridge.init({
gameSlug: 'dusen-sicimler',
appId: 1000002,
bridgeToken: 'fel_sec_ORNEK_UYGULAMA_ANAHTARI',
onReady: async (player) => {
console.log('✓ Phaser Sahnesinde Oyuncu Eşleşti:', player.name);
// Küp Avatar yüklüyse oyuncunun renk paletini WebGL sprite'a giydir
if (window.FelerousCubeRig) {
const avatar = await FelerousCubeRig.getAvatar(player.felerousId);
if (avatar && avatar.palette && this.playerSprite) {
felerousBridge.applyTint(this.playerSprite, avatar.palette.primary);
}
}
}
});
}
gameOver(finalScore) {
// Otomatik hesaplanan net süre ve engine_type: 'Phaser3_WebGL' telemetrisiyle skoru gönder
felerousBridge.submitScore({
score: finalScore,
difficultyTier: 'lvl2',
difficultyLabel: 'Klasik'
});
felerousBridge.showLeaderboard();
}
}
const config = { type: Phaser.AUTO, width: 1600, height: 900, scene: ArcadeScene };
const game = new Phaser.Game(config);
</script>
Yerel Test & Konsol Simülasyon Modu (Local Dev Mock)
Oyununuzu kendi bilgisayarınızda (localhost veya doğrudan index.html dosyasını açarak) test ettiğinizde köprü otomatik yerel test moduna geçer:
- Tarayıcı DevTools konsolunda renkli
[FelerousBridge: Yerel Test Modu (v4.3)]rozeti açılır. - Sanal bir test oyuncusu profili (
DEV-TEST-001) tahsis edilir veonReadycallback'i otomatik tetiklenir. submitScore()çağırdığınızda gönderilen tüm skor yükü (payload), süre ve başarımlar konsola detaylı tablo halinde basılır. "Köprü çalışıyor mu?" şüphesine yer kalmaz!
📁 2. Evrensel Klasör Standardı
Cloudflare R2 kovanına yüklenecek olan oyun paketinizin kök dizini standart ve temiz olmalıdır:
[oyun-slug-kodu]/ (Örn: dusen-sicimler/)
├── index.html # Oyunun giriş noktası (HTML5 Canvas)
├── manifest.json # [ÖNERİLEN] FDB dosya ağacı & paket kimliği
├── achievements.json # [ÖNERİLEN] Oyunun tüm başarımları (v1.0.1)
├── changelog.json # [OPSİYONEL] Sürüm geçmişi (FDB Depo sekmesinde gösterilir)
├── icon.png # 512x512 kare vitrin ikonu (1:1)
├── cover.png # Yatay vitrin kapağı (16:9 - 1600x900 veya 1920x1080)
├── banner.png # Geniş sinematik afiş görseli (16:9 - 1920x1080 Full HD)
├── shortcut.png # [4. GÖRSEL STANDARDI] 512x512 mobil ana ekran (PWA) & masaüstü kısayol simgesi (yoksa icon.png kullanılır)
├── css/
│ └── style.css # Oyun stilleri (100dvh ve koyu mod korumalı)
└── js/
├── felerous-bridge.js # Felerous Store resmi köprü SDK'sı
├── sound.js # 8-bit prosedürel Web Audio motoru
└── game.js # Oyun mantığı ve döngüsü
server.js, node_modules/, .git/ veya geçici geliştirici notları bulunmamalıdır. Sadece tarayıcının doğrudan çalıştıracağı saf dosyalar yer almalıdır.
🎨 2.1 FelerousStore Arcade — 4 Görsel Standardı (Vitrin + Mobil/Masaüstü Kısayol)
Oyun paketinizin Cloudflare R2 kovan kök dizininde, PlayZone vitrininde, Haber Merkezinde ve oyuncuların telefon ana ekranı / PC masaüstü kısayollarında en yüksek kalitede sunulması için aşağıdaki 4 görsel standardı tanımlanmıştır:
| Dosya Adı | En-Boy Oranı | Standart Çözünürlük | Format | Mağaza & Cihazdaki Kullanım Alanı |
|---|---|---|---|---|
| icon.png | 1:1 (Kare) | 512×512 px | PNG | Mağaza vitrin listesi simgesi, Haber Merkezi oyun rozeti, FDB logosu ve tarayıcı favicon'u. |
| cover.png | 16:9 (Yatay Vitrin) | 1600×900 px (veya 1920×1080) | PNG | FelerousStore oyun kartı kapağı, Haber Merkezi küçük görseli ve oyun açılış splash ekranı. |
| banner.png | 16:9 (Geniş Afiş) | 1920×1080 px (Full HD) | PNG | PlayZone oyun detay sayfasının ve FDB veri takibinin en üstündeki sinematik hero/afiş arka planı. |
| shortcut.png | 1:1 (Maskable Kısayol) | 512×512 px | PNG | 4. Görsel Standardı: Oyuncuların PlayZone üzerinden telefon ana ekranına (iOS/Android PWA) veya PC masaüstüne (Tauri / .url) eklediği uygulama kısayol simgesi. (Pakette yoksa sistem otomatik olarak icon.png dosyasını kullanır.) |
📄 3. MANIFEST.JSON Spesifikasyonu & FDB Dosya Ağacı
Oyun paketinin sürümünü mühürlemek, FDB (FELEROUS Database) sisteminde dosya ağacını listelemek ve Geliştirici Panelindeki formu tek tıkla otomatik doldurmak için kök dizinde manifest.json yer alır.
Retro / Piksel, Bulmaca, Aksiyon), kapak görseli ve kontrolleri doğrudan Geliştirici Paneli üzerinden yönetilir. manifest.json vitrin filtrelerini ezmez; FDB dosya ağacını oluşturmak ve geliştiriciye form doldurma kolaylığı sağlamak için teknik bir kimlik belgesidir.
{
"id": "dusen-sicimler",
"slug": "dusen-sicimler",
"name": "Düşen Sicimler",
"version": "1.0.5",
"developer": "Subushaki",
"publisher": "FELEROUS",
"category": "Retro / Piksel",
"game_type": "web",
"entry": "index.html",
"icon": "icon.png",
"cover": "cover.png",
"banner": "banner.png",
"shortcut": "shortcut.png",
"orientation": "portrait_or_landscape",
"resolution": {
"width": 1080,
"height": 1920,
"responsive": true
},
"features": {
"achievements": true,
"leaderboards": true,
"anti_cheat": true,
"telemetry": true
},
"files": [
{ "name": "index.html", "type": "Oyun Giriş Dosyası" },
{ "name": "banner.png", "type": "Afiş Görseli" },
{ "name": "cover.png", "type": "Kapak Görseli" },
{ "name": "icon.png", "type": "Oyun İkonu" },
{ "name": "manifest.json", "type": "Oyun Yapılandırması" },
{ "name": "achievements.json", "type": "Başarım Veritabanı" },
{ "name": "changelog.json", "type": "Sürüm Notları" },
{ "name": "js/game.js", "type": "Oyun Motoru & Mantığı" },
{ "name": "js/felerous-bridge_html5.js", "type": "Platform SDK Köprüsü" },
{ "name": "js/sound.js", "type": "8-bit Ses Motoru" },
{ "name": "css/style.css", "type": "Stil Dosyası" }
]
}
| Alan | Tür | Açıklama |
|---|---|---|
id |
String | Veritabanı ve API ile eşleşen benzersiz kimlik (snake_case). Örn: dusen_sicimler. |
slug |
String | URL ve R2 klasör adı (kebab-case). Örn: dusen-sicimler. |
version |
String | Anlık oyun sürümü (SemVer formatı: "1.0.3"). FDB Depo başlığında gösterilir. |
orientation |
String | Mobil yön tercihi: "portrait", "landscape" veya "portrait_or_landscape". |
features |
Object | Oyunun desteklediği platform yetenekleri (başarımlar, liderlik tabloları, hile koruması, telemetri). |
files |
Array | FDB "Depolar" (Depots) sekmesinde taranan dosya listesi. Her dosyanın adı ve insan-okunabilir işlevi belirtilir. |
🏆 4. ACHIEVEMENTS.JSON Spesifikasyonu (18 Başarım Tam Referansı)
Felerous Store ekosisteminde başarımların tek doğru kaynağı (Single Source of Truth) oyun kökündeki achievements.json dosyasıdır. FDB Başarımlar sekmesi, oyun içi HUD bildirimleri ve oyuncunun Steam-standardı Profil Vitrini bu dosyayı okur.
{
"game_id": "dusen-sicimler",
"version": "1.0.5",
"total": 18,
"achievements": [
{
"id": "first_clear",
"title": "İlk Adım",
"description": "İlk satırını başarıyla temizle.",
"icon": "🧱",
"category": "progression",
"rarity": "common",
"points": 10
},
{
"id": "tetris_master",
"title": "Düşen Sicim",
"description": "Tek hamlede 4 satır birden sil.",
"icon": "⚡",
"category": "skill",
"rarity": "rare",
"points": 25
},
{
"id": "combo_king",
"title": "Kombo Ustası",
"description": "En az 4x ardışık satır kombosu yap.",
"icon": "🌪️",
"category": "skill",
"rarity": "epic",
"points": 50
},
{
"id": "hard_dropper",
"title": "Işık Hızı",
"description": "Tek oyunda 25 kez sert düşüş (smash) yap.",
"icon": "💥",
"category": "speed",
"rarity": "uncommon",
"points": 15
},
{
"id": "survivor",
"title": "Kabus Gazisi",
"description": "Kabus modunda en az 60 saniye hayatta kal.",
"icon": "🛡️",
"category": "survival",
"rarity": "legendary",
"points": 100
},
{
"id": "architect",
"title": "Büyük Mimar",
"description": "Tek bir oyunda 50+ satır sil.",
"icon": "👑",
"category": "endurance",
"rarity": "epic",
"points": 50
},
{
"id": "high_scorer",
"title": "Puan Avcısı",
"description": "Tek bir oyunda 20.000 puanı aş.",
"icon": "🎯",
"category": "score",
"rarity": "rare",
"points": 30
},
{
"id": "tactician",
"title": "Usta Taktisyen",
"description": "Hold (saklama) özelliğini en az 10 kez kullan.",
"icon": "🔄",
"category": "strategy",
"rarity": "uncommon",
"points": 15
},
{
"id": "double_trouble",
"title": "Çifte Vuruş",
"description": "Toplam 50 İkili Satır (2 satır birden) temizle.",
"icon": "2️⃣",
"category": "skill",
"rarity": "uncommon",
"points": 20
},
{
"id": "triple_threat",
"title": "Üçlü Tehdit",
"description": "Toplam 25 Üçlü Satır (3 satır birden) temizle.",
"icon": "3️⃣",
"category": "skill",
"rarity": "rare",
"points": 35
},
{
"id": "back_to_back",
"title": "Ardarda Tetris",
"description": "Arka arkaya 2 Tetris (4 satır) yap.",
"icon": "🔥",
"category": "skill",
"rarity": "epic",
"points": 60
},
{
"id": "perfect_clear",
"title": "Mükemmel Temizlik",
"description": "Tahtayı tamamen boşalt (Perfect Clear).",
"icon": "✨",
"category": "skill",
"rarity": "legendary",
"points": 120
},
{
"id": "speed_demon",
"title": "Hız Canavarı",
"description": "1 dakika içinde 40 satır temizle.",
"icon": "⏱️",
"category": "speed",
"rarity": "rare",
"points": 40
},
{
"id": "marathon_runner",
"title": "Maratoncu",
"description": "Toplam 1000 satır temizle.",
"icon": "🏃",
"category": "endurance",
"rarity": "epic",
"points": 75
},
{
"id": "piece_master",
"title": "Parça Ustası",
"description": "Toplam 1000 parça indir.",
"icon": "🎮",
"category": "progression",
"rarity": "rare",
"points": 30
},
{
"id": "apm_champion",
"title": "Hızlı Parmaklar",
"description": "Bir oyunda 300 APM (Aksiyon/Dk) üzerine çık.",
"icon": "⚡",
"category": "speed",
"rarity": "epic",
"points": 55
},
{
"id": "nightmare_warrior",
"title": "Kabus Savaşçısı",
"description": "Kabus modunda 120 saniye hayatta kal.",
"icon": "👹",
"category": "survival",
"rarity": "legendary",
"points": 170
},
{
"id": "millionaire",
"title": "Milyoner",
"description": "Toplam 1.000.000 kariyer puanı topla.",
"icon": "💎",
"category": "score",
"rarity": "legendary",
"points": 100
}
]
}
profile.html) oyuncunun açtığı başarımlar, toplam başarıma oranlanarak dinamik renkli Steam ilerleme çubuğunda (BAŞARIMLAR: N/18 (%X)) ve akordeon detay çekmecesinde sergilenir.
📜 5. CHANGELOG.JSON Spesifikasyonu (FDB Sürüm Günlüğü & Depolar)
Oyununuz güncellendikçe FDB (FELEROUS Database) "Depolar" sekmesinde sürüm geçmişinin otomatik taranıp SteamDB tarzında değişiklik günlüğü (patch notes) olarak sunulması için kök dizinde changelog.json tutulur.
[
{
"version": "v1.0.3",
"date": "2026-09-27T18:35:00Z",
"description": "Başarım açılışı ve ses motoru stabilite güncellemesi.",
"changes": [
"Başarım kilidi açıldığında oluşan ses motoru uyumsuzluğu giderildi",
"Kesintisiz oyun için başarım akışları tam korumalı (fail-safe) hale getirildi",
"Özel prosedürel zafer arpeji (playAchievement) ses motoruna eklendi"
]
},
{
"version": "v1.0.2",
"date": "2026-09-27T00:00:00Z",
"description": "Canvas doğrudan dokunmatik kaydırma ve jest kontrolleri güncellemesi.",
"changes": [
"Tahta üzerinde doğrudan parmakla sola/sağa hassas blok kaydırma eklendi",
"Yatay kaydırma sırasında kazara düşüşleri önleyen eksen kilidi (axis lock) geliştirildi",
"Aşağı hızlı kaydırmada (flick down) doğrudan zemine yapışma (Hard Drop) eklendi",
"Tek dokunuşla (tap) 90 derece döndürme ve yukarı kaydırmayla saklama (Hold) entegre edildi"
]
},
{
"version": "v1.0.1",
"date": "2026-09-26T21:30:00Z",
"description": "18 Başarım Paketi ve Kariyer Takibi güncellemesi.",
"changes": [
"10 yeni beceri ve kariyer başarımı eklendi (toplam 18 başarım)",
"Kümülatif kariyer istatistikleri ve SafeStorage kalıcılığı sağlandı",
"Perfect Clear (Mükemmel Temizlik) ve Back-to-Back Tetris tespiti eklendi"
]
},
{
"version": "v1.0.0",
"date": "2026-09-26T21:00:00Z",
"description": "Düşen Sicimler resmi PlayZone ve FDB lansman sürümü.",
"changes": [
"8 adet Arcade başarımı entegre edildi",
"Gerçek zamanlı Supabase telemetrisi bağlandı",
"FDB Depo tarama desteği eklendi",
"Mobil, Samsung Internet ve Safari tam uyumluluk optimizasyonları yapıldı"
]
}
]
🛡️ 6. Resmi Köprü SDK: felerous-bridge_html5.js & felerous-bridge_phaser.js (v4.3.8 — 6 Katmanlı Skor Doğrulama, Origin Kontrolü & Atölye UGC)
Oyununuz ile PlayZone çerçevesi arasındaki tüm iletişimi yöneten köprü sınıfı. Sahte skor ve manipülasyonları engellemek için App ID, Çift Yönlü Origin Doğrulaması, Steam-Tarzı Topluluk Atölyesi (Workshop UGC) ve tek kullanımlık Oturum Bileti (Session Ticket) mekanizmasını içerir. Ayrıca iframe dışındayken otomatik Yerel Test & Simülasyon Modu sağlar:
- Çift Yönlü Köken (Origin) Doğrulaması: Köprü, gelen postMessage olaylarını yalnızca yetkili Felerous platform alan adlarından (
https://store.felerous.com,https://arcade.felerous.com,https://developer.felerous.com) ve yerel test kökenlerinden (localhost,127.0.0.1) kabul eder. Üçüncü taraf veya sahte iframe'lerden gelen mesajlar sessizce elenir. - Korumalı Anahtar Saklama (
game_secrets): Sunucu/webhook anahtarları asla umumigamestablosunda veya istemci JS kodunda tutulmaz; Row Level Security (RLS) politikalarıyla korunanpublic.game_secretstablosunda saklanır. - Liderlik Tablosunda Kimlik Sabitlemesi (Anti-Spoofing): Supabase veritabanındaki
enforce_arcade_score_identity()tetikleyicisi sayesinde oyuncu skor gönderirken başka birininfelerous_idveyaplayer_namekimliğini taklit edemez; oturum açtığı gerçekprofileskaydı zorunlu olarak mühürlenir. - Tek Kullanımlık Oturum Bileti (Session Ticket) & Erken Skor Kuyruğu: Oyun açıldığında ve her yeni elde (
startSession()) tek kullanımlık süreli bilet üretilir. Oyuncu el sıkışma tamamlanmadan skor gönderirse, v4.3.8 kuyruğu (_pendingScores) bileti bekleyip skoru kayıpsız iletir. - Hız & Mantık Analizi (Velocity Check): Oyun süresiyle uyuşmayan imkansız puanlar (örneğin 3 saniyede 1 milyon puan) otomatik elenir ve güvenlik günlüğüne kaydedilir.
- Geliştirici 2FA Güvencesi: Konsolda anahtar yenileme, paket yükleme ve silme gibi tüm kritik işlemler TOTP tabanlı 2FA oturum bileti ile korunur.
📖 Geliştirici Entegrasyon Rehberi (3 Kolay Adım)
Kimlik bilgilerinize Konsol'da 3 kolay yerden ulaşabilirsiniz:
1) Güvenlik Masası (4. Katman),
2) PlayZone Oyunlarım ekranı, veya
3) Oyun Düzenle (#edit) sayfası (Bölüm 4). İstemci (tarayıcı) kodunda yalnızca herkese açık gameSlug ve sayısal App ID (örn: 1000010) kullanılır; gizli tokenler istemci koduna gömülmez.
game_secrets tablosundan anında silinir ve yenisi üretilir.
Oyununuzun altyapısına göre optimize edilmiş resmi CDN betiğini index.html dosyanıza ekleyin:
<script src="https://store.felerous.com/js/felerous-bridge_html5.js"></script>
<script src="https://store.felerous.com/js/felerous-bridge_phaser.js"></script>
<script src="https://store.felerous.com/js/felerous-cuberig-sdk.js"></script>
Oyun başladığında konsoldan aldığınız kimliklerle el sıkışmayı başlatın. HTML5 için doğrudan çağırabilir, Phaser 3 için felerousBridge.attachScene(this) ile sahneyi bağlayabilirsiniz:
<script>
felerousBridge.init({
gameSlug: 'neon-volt',
appId: 1000010,
mountBadge: 'top-right',
onReady: (player) => {
console.log('✓ Oyuncu hazır:', player.name, player.felerousId);
}
});
// Oyun bittiğinde (tek satır veya detaylı obje):
felerousBridge.submitScore(14500, 'lvl2');
felerousBridge.showLeaderboard();
</script>
<script>
class MyGameScene extends Phaser.Scene {
create() {
felerousBridge.attachScene(this); // Otomatik duraklatma, sessize alma ve oynanış süresi
felerousBridge.init({
gameSlug: 'neon-volt',
appId: 1000010,
onReady: (player) => {
console.log('✓ Phaser Sahnesinde Oyuncu Eşleşti:', player.name);
}
});
}
onGameOver(finalScore) {
felerousBridge.submitScore({
score: finalScore,
difficultyTier: 'lvl2',
difficultyLabel: 'Uzman'
});
felerousBridge.showLeaderboard();
}
}
</script>
Oyununuzu PlayZone'a yüklemeden önce kendi bilgisayarınızda (localhost, 127.0.0.1 veya doğrudan dosya olarak) çalıştırdığınızda SDK durumu otomatik algılar (isEmbedded = false):
- Sanal Test Oturumu:
DEV-TEST-001kodlu test profili simüle edilir,onReadyveon('ready')dinleyicileri 50ms içinde otomatik ateşlenir. - Görsel Konsol Logları: Tarayıcının F12 konsolunda stilize edilmiş
[Yerel Test & Simülasyon Modu Aktif (v4.3)]bildirim kartı gösterilir. - Polimorfik Skor & Başarım Doğrulaması:
submitScore(14500)veyasubmitScore({ score: 14500, difficultyTier: 'lvl2' })çağrıldığında yük verileri konsolda doğrulanır. - Sahte Liderlik Tablosu & Neon Cam Modal:
showLeaderboard()veyarequestLeaderboard()çağrıldığında anında mock ilk 3 sıralama verisi ve yerleşik Neon Cam arayüzü açılır.
/**
* 🛡️ FELEROUS ARCADE BRIDGE SDK — HTML5 / CANVAS / WEBGL EDITION (v4.3.8)
* Resmi CDN: https://store.felerous.com/js/felerous-bridge_html5.js
* Phaser 3 CDN: https://store.felerous.com/js/felerous-bridge_phaser.js
*
* Özellikler:
* - Polimorfik submitScore(score, tier) & submitScore({ score, difficultyTier, ... })
* - Yerleşik Neon Cam Liderlik Tablosu (showLeaderboard / closeLeaderboard) & Köşe Rozeti (mountBadge)
* - Erken skor gönderimlerini koruyan _pendingScores kuyruğu (FELEROUS_PLAYER_INFO el sıkışmasını bekler)
* - Çift yönlü Origin doğrulaması, Pause / Resume / Mute sinyalleri, Cloud Save & Workshop UGC
* - Hem kanonik (name, felerousId, avatar) hem alias (username, displayName, felId, avatarUrl) oyuncu alanları
*/
class FelerousBridgeHTML5 {
constructor(config = {}) {
if (typeof config === 'string') config = { gameSlug: config };
this.version = '4.3.8-html5';
this.engine = 'html5';
this.gameSlug = config.gameSlug || config.gameId || 'felerous-game';
this.appId = config.appId || null;
this.bridgeToken = config.bridgeToken || null;
this.targetOrigin = config.targetOrigin || 'https://store.felerous.com';
this.player = this._buildPlayerObject({
name: 'Oyuncu',
felerousId: null,
avatar: 'https://store.felerous.com/image/felerous/FELEROUS.png',
isGuest: true,
userId: null
});
this.sessionTicket = null;
this.leaderboard = [];
this.friends = [];
this._pendingScores = [];
this._memoryStorage = {};
this._verifiedParentOrigin = null;
this.isEmbedded = typeof window !== 'undefined' && window.self !== window.top;
this.sessionStartTime = Date.now();
this.isReady = false;
this._resolveReady = null;
this.ready = new Promise((resolve) => {
this._resolveReady = resolve;
});
this._listeners = { ready: [], pause: [], resume: [], mute: [], leaderboard: [], achievement: [], friends: [] };
this.workshop = new FelerousWorkshopClient(this);
if (config.onReady) this.on('ready', config.onReady);
if (config.onLeaderboard) this.on('leaderboard', config.onLeaderboard);
if (config.onAchievementConfirmed) this.on('achievement', config.onAchievementConfirmed);
this._setupListeners();
}
_isLocalDevEnvironment() {
if (typeof window === 'undefined' || !window.location) return false;
const protocol = window.location.protocol;
const host = (window.location.hostname || '').toLowerCase();
return (
protocol === 'file:' ||
host === 'localhost' ||
host === '127.0.0.1' ||
host === '::1' ||
host === '[::1]' ||
host.endsWith('.local')
);
}
_isTrustedOrigin(origin) {
if (!origin || typeof origin !== 'string') return false;
const trustedOrigins = [
'https://store.felerous.com',
'https://arcade.felerous.com',
'https://developer.felerous.com',
'https://felerous-store.vercel.app'
];
if (this.targetOrigin && this.targetOrigin !== '*' && !trustedOrigins.includes(this.targetOrigin)) {
trustedOrigins.push(this.targetOrigin);
}
if (trustedOrigins.includes(origin)) return true;
if (this._isLocalDevEnvironment()) {
return /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(origin);
}
return false;
}
_resolveTargetOrigin() {
if (this._verifiedParentOrigin && this._isTrustedOrigin(this._verifiedParentOrigin)) {
return this._verifiedParentOrigin;
}
if (typeof document !== 'undefined' && document.referrer) {
try {
const refOrigin = new URL(document.referrer).origin;
if (this._isTrustedOrigin(refOrigin)) return refOrigin;
} catch (_) {}
}
if (this.targetOrigin && this.targetOrigin !== '*' && this._isTrustedOrigin(this.targetOrigin)) {
return this.targetOrigin;
}
return 'https://store.felerous.com';
}
_buildPlayerObject(raw = {}) {
const name = raw.name || raw.player_name || raw.username || raw.displayName || 'Oyuncu';
const felerousId = raw.felerousId || raw.felerous_id || raw.felId || null;
const avatar = raw.avatar || raw.avatar_url || raw.avatarUrl || 'https://store.felerous.com/image/felerous/FELEROUS.png';
const isGuest = raw.isGuest !== undefined ? Boolean(raw.isGuest) : Boolean(raw.is_guest);
const userId = raw.userId || raw.user_id || raw.id || felerousId || null;
return {
name, felerousId, avatar, isGuest, userId,
username: name, displayName: name, felId: felerousId, avatarUrl: avatar, id: userId || felerousId || 'guest'
};
}
on(event, callback) {
if (typeof callback !== 'function') return this;
if (!this._listeners[event]) this._listeners[event] = [];
this._listeners[event].push(callback);
if (event === 'ready' && this.isReady) callback(this.player);
return this;
}
onReady(cb) { return this.on('ready', cb); }
onLeaderboard(cb) { return this.on('leaderboard', cb); }
onAchievementConfirmed(cb) { return this.on('achievement', cb); }
onFriends(cb) { return this.on('friends', cb); }
_emit(event, data, extra) {
(this._listeners[event] || []).forEach(fn => {
try { fn(data, extra); } catch (e) { console.warn('[FelerousBridge]', e); }
});
}
init(options = {}) {
if (typeof options === 'string') options = { gameSlug: options };
if (options.gameSlug || options.gameId) this.gameSlug = options.gameSlug || options.gameId;
if (options.appId) this.appId = options.appId;
if (options.bridgeToken) this.bridgeToken = options.bridgeToken;
if (options.targetOrigin) this.targetOrigin = options.targetOrigin;
if (options.onReady) this.on('ready', options.onReady);
if (options.onLeaderboard) this.on('leaderboard', options.onLeaderboard);
if (options.onAchievementConfirmed) this.on('achievement', options.onAchievementConfirmed);
if (options.mountBadge) {
this.mountBadge(typeof options.mountBadge === 'object' ? options.mountBadge : { position: options.mountBadge });
}
this.sessionStartTime = Date.now();
return new Promise((resolve) => {
const handleReady = (p) => {
if (this._resolveReady) this._resolveReady(p);
resolve(p);
};
if (this.isReady && this.player) {
handleReady(this.player);
return;
}
this.on('ready', handleReady);
if (this.isEmbedded) {
this._postToParent({
type: 'FELEROUS_INIT_PLAYER',
game_id: this.gameSlug,
app_id: this.appId,
bridge_token: this.bridgeToken,
timestamp: Date.now()
});
} else if (this._isLocalDevEnvironment()) {
// 🧪 Yerel Geliştirici Simülasyon Modu (Yalnızca localhost / 127.0.0.1 / file://)
setTimeout(() => {
if (!this.isReady) {
this.player = this._buildPlayerObject({
name: 'Geliştirici (Yerel Test)',
felerousId: 'DEV-TEST-001',
avatar: 'https://store.felerous.com/image/felerous/FELEROUS.png',
isGuest: false,
userId: 'mock-dev-id'
});
this.sessionTicket = 'mock_tkt_' + Date.now();
this.isReady = true;
this._emit('ready', this.player);
}
}, 50);
} else {
// 🌐 Üretim Ortamında Doğrudan Açılış — Standalone Misafir Modu
setTimeout(() => {
if (!this.isReady) {
this.player = this._buildPlayerObject({
name: 'Misafir Oyuncu',
felerousId: null,
avatar: 'https://store.felerous.com/image/felerous/FELEROUS.png',
isGuest: true,
userId: null
});
this.sessionTicket = null;
this.isReady = true;
this._emit('ready', this.player);
}
}, 50);
}
});
}
_setupListeners() {
if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') return;
window.addEventListener('message', (event) => {
if (this.isEmbedded) {
if (event.source !== window.parent) return;
if (!this._isTrustedOrigin(event.origin)) return;
this._verifiedParentOrigin = event.origin;
} else if (!this._isLocalDevEnvironment()) {
return;
}
const data = event.data;
if (!data || typeof data !== 'object') return;
switch (data.type) {
case 'FELEROUS_PLAYER_INFO':
case 'FELEROUS_AUTH_SUCCESS':
this.player = this._buildPlayerObject(data);
if (data.session_ticket) this.sessionTicket = data.session_ticket;
this.isReady = true;
if (this._resolveReady) this._resolveReady(this.player);
this._flushPendingScores();
this._emit('ready', this.player);
break;
case 'FELEROUS_LEADERBOARD_UPDATE':
this.leaderboard = data.leaderboard || [];
this._emit('leaderboard', this.leaderboard);
break;
case 'FELEROUS_ACHIEVEMENT_CONFIRMED':
this._emit('achievement', data);
break;
case 'FELEROUS_FRIENDS_DATA':
this._emit('friends', data.friends || []);
break;
}
});
}
_flushPendingScores() {
if (!this.sessionTicket || !this._pendingScores || this._pendingScores.length === 0) return;
const queue = this._pendingScores.splice(0, this._pendingScores.length);
queue.forEach(payload => {
payload.session_ticket = this.sessionTicket;
this._postToParent(payload);
});
}
submitScore(input = 0, maybeTier = 'lvl1') {
let cfg = {};
if (typeof input === 'number') {
cfg = (typeof maybeTier === 'object' && maybeTier !== null)
? { ...maybeTier, score: input }
: { score: input, difficultyTier: typeof maybeTier === 'string' ? maybeTier : 'lvl1' };
} else if (typeof input === 'object' && input !== null) {
cfg = input;
}
const rawDuration = cfg.durationSeconds !== undefined && cfg.durationSeconds !== null
? Number(cfg.durationSeconds)
: Math.floor((Date.now() - this.sessionStartTime) / 1000);
const duration = Math.max(1, Math.floor(Number.isFinite(rawDuration) ? rawDuration : 1));
const payload = {
type: 'FELEROUS_SUBMIT_SCORE',
game_id: this.gameSlug,
app_id: this.appId,
bridge_token: this.bridgeToken,
session_ticket: this.sessionTicket,
score: Math.max(0, Math.floor(Number(cfg.score) || 0)),
level_reached: cfg.levelReached || 1,
lines_cleared: cfg.linesCleared || 0,
difficulty_tier: cfg.difficultyTier || 'lvl1',
difficulty_label: cfg.difficultyLabel || 'Standart',
duration_seconds: duration,
achievements: cfg.achievements || [],
stats: cfg.stats || {},
timestamp: Date.now()
};
if (this.isEmbedded) {
if (!this.sessionTicket) {
if (this._pendingScores.length < 20) this._pendingScores.push(payload);
this._postToParent({
type: 'FELEROUS_INIT_PLAYER',
game_id: this.gameSlug,
app_id: this.appId,
bridge_token: this.bridgeToken,
timestamp: Date.now()
});
} else {
this._postToParent(payload);
}
}
return Promise.resolve(payload);
}
unlockAchievement(achievementId) {
if (!achievementId) return;
this._postToParent({
type: 'FELEROUS_UNLOCK_ACHIEVEMENT',
game_id: this.gameSlug,
app_id: this.appId,
session_ticket: this.sessionTicket,
achievement_id: achievementId,
timestamp: Date.now()
});
}
requestLeaderboard(difficultyTier = null) {
if (this.isEmbedded) {
this._postToParent({
type: 'FELEROUS_GET_LEADERBOARD',
game_id: this.gameSlug,
difficulty_tier: difficultyTier
});
}
}
getLeaderboard(difficultyTier = null) { return this.requestLeaderboard(difficultyTier); }
saveCloudData(slotOrData = 'default', maybeData = undefined) {
const slotKey = (maybeData === undefined && typeof slotOrData === 'object') ? 'default' : String(slotOrData || 'default');
const data = (maybeData === undefined && typeof slotOrData === 'object') ? slotOrData : maybeData;
try { localStorage.setItem(`felerous_cloud_${this.gameSlug}_${slotKey}`, JSON.stringify(data)); } catch (e) {}
if (this.isEmbedded) {
this._postToParent({ type: 'FELEROUS_CLOUD_SAVE', game_id: this.gameSlug, app_id: this.appId, session_ticket: this.sessionTicket, slot: slotKey, data, timestamp: Date.now() });
}
return Promise.resolve({ success: true, slot: slotKey });
}
loadCloudData(slotKey = 'default') {
try {
const raw = localStorage.getItem(`felerous_cloud_${this.gameSlug}_${slotKey}`);
return Promise.resolve(raw ? JSON.parse(raw) : null);
} catch (e) { return Promise.resolve(null); }
}
openReviews() {
if (this.isEmbedded) {
this._postToParent({
type: 'FELEROUS_OPEN_REVIEWS',
game_id: this.gameSlug,
app_id: this.appId,
timestamp: Date.now()
});
}
}
exitToPlayzone() {
const targetUrl = 'https://store.felerous.com/playzone';
if (this.isEmbedded) {
this._postToParent({ type: 'FELEROUS_EXIT_GAME', game_id: this.gameSlug, redirect_url: targetUrl });
}
setTimeout(() => {
try {
if (window.top && window.top !== window.self) window.top.location.href = targetUrl;
else window.location.href = targetUrl;
} catch (e) {
window.location.href = targetUrl;
}
}, 150);
}
_postToParent(payload) {
if (!this.isEmbedded || typeof window === 'undefined' || !window.parent || window.parent === window.self) return;
try {
const targetOrigin = this._resolveTargetOrigin();
if (!targetOrigin || targetOrigin === '*') return;
window.parent.postMessage(payload, targetOrigin);
} catch (e) {
console.warn('[FelerousBridge] postMessage hatası:', e);
}
}
}
📋 felerousBridge API Referans Kataloğu (v4.3)
Aşağıdaki metotlar hem felerous-bridge_html5.js hem felerous-bridge_phaser.js motorlarında birebir aynı sözleşmeyle desteklenir:
| Metot / Özellik | Motor | Dönüş Tipi | Açıklama & Kullanım Örneği |
|---|---|---|---|
init(options) |
Tüm Motorlar | Promise<Player> |
Başlangıç el sıkışması: { gameSlug, appId, mountBadge, onReady }. |
submitScore(input, tier) |
Tüm Motorlar | ScorePayload |
Polimorfik Tak-Çalıştır: Tek sayı (submitScore(14500, 'lvl2')) veya detaylı obje (submitScore({ score: 14500, difficultyTier: 'lvl2', durationSeconds: 95 })) kabul eder. |
showLeaderboard(options) |
Tüm Motorlar | void |
Yerleşik Neon Cam Modal: Oyunun üzerine sıfır CSS ile küresel skor tablosunu açar. Phaser'da sahneyi otomatik dondurur (pause). |
closeLeaderboard() |
Tüm Motorlar | void |
Açık olan liderlik tablosu modalını kapatır; Phaser sahnesini devam ettirir (resume). |
mountBadge(options) |
Tüm Motorlar | HTMLElement |
Oyunun köşesine (top-right, top-left vb.) minik tıklanabilir [🏆 Liderlik | 👤 Oyuncu] rozeti koyar. |
unlockAchievement(id) |
Tüm Motorlar | void |
Belirtilen başarımı anında Supabase bulutuna mühürler ve HUD bildirimini tetikler. |
requestLeaderboard(tier) / getLeaderboard(tier) |
Tüm Motorlar | void |
Platformdan ham Top 10 sıralama verisini talep eder (felerous:leaderboard_update olayını ateşler). |
saveCloudData(slot, data) / loadCloudData(slot) |
Tüm Motorlar | Promise<any> |
Oyuncunun ilerlemesini buluta ve yerel önbelleğe kaydeder / geri yükler. |
getFriends() / getFriendBotNames(opts) / getFriendsOrBots(count) |
Tüm Motorlar | Promise<Array> |
Oyuncunun onaylı arkadaşlarını veya botlara atanmaya hazır isim/profil listesini döner. |
workshop.publish(data) / getItems(filters) / subscribe(id) / vote(id, dir) |
Tüm Motorlar | Promise<Object> |
Steam-tarzı Topluluk Atölyesi (UGC): oyun içinden harita, taret veya blueprint paylaşma ve indirme. |
openReviews() / exitToPlayzone() |
Tüm Motorlar | void |
Oyun içi İnceleme Modalını açar veya güvenli şekilde PlayZone vitrinine çıkış yapar. |
player (Özellik) |
Tüm Motorlar | FelerousPlayer |
Aktif oyuncu kimliği: Kanonik (name, felerousId, avatar, isGuest, userId) ve alias (username, displayName, felId, avatarUrl, id). Asla null dönmez. |
attachScene(scene) / attachGame(game) / bindPhaserGame(game) |
Phaser 3 Özel | this |
Aktif Phaser sahnesini veya Game örneğini bağlar. Otomatik scene.pause(), sound.mute ve delta süre sayacını devreye sokar. |
applyTint(sprite, color) / hexToInt(hex) |
Phaser 3 Özel | void / number |
Hex renk kodunu (örn: '#38bdf8') WebGL 0xRRGGBB tint sayısına çevirip Phaser Sprite nesnesine uygular. |
Kendi oyununuzu bir yapay zekaya sıfırdan yazdırırken veya var olan bir Canvas/Phaser oyununu PlayZone'a uyarlatırken aşağıdaki tek paragraflık kuralı AI'ya yapıştırmanız yeterlidir:
Bu oyunu FELEROUS PlayZone Arcade SDK v4.3 standardına uyumlu hale getir:
1. HTML'e <script src="https://store.felerous.com/js/felerous-bridge_html5.js"></script> köprüsünü dahil et (Phaser 3 kullanıyorsan felerous-bridge_phaser.js ve create() içinde felerousBridge.attachScene(this) çağır).
2. Oyun başlangıcında felerousBridge.init({ gameSlug: 'oyun-slug', onReady: (player) => console.log(player.name, player.felerousId) }) ile oturumu başlat.
3. Oyun bittiğinde skoru ilet: felerousBridge.submitScore(score, 'lvl1'); ve küresel skor tablosunu aç: felerousBridge.showLeaderboard();
4. Oyuncu kimliğini felerousBridge.player.name (veya player.username) üzerinden oku. Ekstra CSS veya modal tablosu tasarlama; yerleşik Felerous HUD overlay'ini kullan.
📡 7. İki Yönlü Olay Sözleşmeleri (PostMessage Kataloğu)
Oyun (iFrame) ile ev sahibi PlayZone oynatıcı çerçevesi arasındaki tam çift yönlü olay haberleşme tablosu:
| Olay Adı (Type) | Yön | Açıklama | Yük (Payload) |
|---|---|---|---|
FELEROUS_INIT_PLAYER |
Oyun ➔ Platform | Oyun açıldığında kimlik doğrulama, dinamik oturum bileti (session ticket) ve liderlik tablosunu talep eder. | { type, game_id, app_id, bridge_token, timestamp } |
FELEROUS_PLAYER_INFO |
Platform ➔ Oyun | Giriş yapmış kullanıcının profilini, oturum biletini ve doğrulama durumunu oyuna aktarır. | { type, player_name, avatar_url, felerous_id, is_guest, user_id, session_ticket, app_id, verified } |
FELEROUS_UNLOCK_ACHIEVEMENT |
Oyun ➔ Platform | Başarım kazanıldığında anında Supabase user_achievements tablosuna yazar ve PlayZone HUD bildirimini tetikler. |
{ type, game_id, app_id, bridge_token, session_ticket, achievement_id, timestamp } |
FELEROUS_ACHIEVEMENT_CONFIRMED |
Platform ➔ Oyun | Başarım Supabase bulutuna başarıyla mühürlendiğinde köprüye geri teyit sinyali döner. | { type, game_id, achievement_id, synced: true } |
FELEROUS_SUBMIT_SCORE |
Oyun ➔ Platform | Oyun bittiğinde skoru arcade_scores tablosuna kaydeder, oyuncu kütüphanesine oyunu otomatik ekler ve skor sıralamasını günceller. |
{ type, game_id, app_id, bridge_token, session_ticket, score, level_reached, lines_cleared, difficulty_tier, difficulty_label, duration_seconds, achievements, stats, timestamp } |
FELEROUS_GET_LEADERBOARD |
Oyun ➔ Platform | İlgili oyunun Top 10 skor tablosunu talep eder. | { type, game_id, difficulty_tier } |
FELEROUS_LEADERBOARD_UPDATE |
Platform ➔ Oyun | Güncel ilk 10 skor sıralamasını dizi formatında oyuna gönderir. | { type, game_id, difficulty_tier, leaderboard: [...] } |
FELEROUS_SET_MUTE |
Platform ➔ Oyun | PlayZone üst HUD ses butonundan gelen ses aç/kapa komutu. | { type, muted: true/false } |
FELEROUS_PAUSE |
Platform ➔ Oyun | PlayZone üst HUD duraklat butonuna basıldığında oyunu durdurur. | { type } |
FELEROUS_RESUME |
Platform ➔ Oyun | PlayZone üst HUD devam butonuna basıldığında oyunu sürdürür. | { type } |
FELEROUS_EXIT_GAME |
Oyun ➔ Platform | Oyuncunun güvenli şekilde PlayZone vitrinine dönmesini sağlar. | { type, game_id, redirect_url } |
FELEROUS_WORKSHOP_PUBLISH |
Oyun ➔ Platform | Oyun içinden doğrudan Atölye'ye yeni bir tasarım, blueprint veya mod yayınlar (DB seviyesinde maks 512KB payload ve saatte 10 adet hız sınırı korumalı). | { type, req_id, game_id, payload: { title, category, description, footprint, blueprintData, tags } } |
FELEROUS_WORKSHOP_GET_ITEMS |
Oyun ➔ Platform | Oyuna ait onaylı Atölye eserlerini, popüler blueprintleri ve modları listeler. | { type, req_id, game_id, filters: { category, search, limit, offset, sort } } |
FELEROUS_WORKSHOP_SUBSCRIBE |
Oyun ➔ Platform | Oyuncunun bir Atölye eserine abone olmasını veya abonelikten çıkmasını sağlar. | { type, req_id, item_id, subscribe: true/false } |
FELEROUS_WORKSHOP_VOTE |
Oyun ➔ Platform | Bir Atölye eserine olumlu veya olumsuz oy verilmesini sağlar (Sayaçlar veritabanı tetikleyicisiyle güvene alınmıştır). | { type, req_id, item_id, vote_type: 'up'/'down' } |
FELEROUS_GET_FRIENDS |
Oyun ➔ Platform | Oyuncunun onaylı arkadaş listesini talep eder (Bot isimleri ve sosyal özellikler için). | { type, req_id, game_id } |
FELEROUS_FRIENDS_DATA |
Platform ➔ Oyun | Güvenlik filtresinden geçmiş arkadaş listesini oyuna iletir (Yalnızca sanitize edilmiş id, name, username, avatar). | { type, req_id, friends: [...] } |
FELEROUS_AVATAR_GET_MY_SPEC |
Oyun ➔ Platform | Oyuncunun profile.html üzerinde tasarladığı 2.5D Küp Avatar (CubeRig v1) spec verisini talep eder. |
{ type, req_id, rig_family: 'cube_v1' } |
FELEROUS_AVATAR_MY_SPEC_RESULT |
Platform ➔ Oyun | Kullanıcının aktif gardırop ve kıyafet spec JSON verisini döner. | { type, req_id, spec: { gender, skinTone, hairStyle, outfit, accessory, ... } } |
FELEROUS_AVATAR_GET_NPC_POOL |
Oyun ➔ Platform | Canlı oyuncu avatarlarından oluşan dinamik NPC havuzunu talep eder (şehir simülasyonu sakinleri, uzay filosu pilotları, arena rakipleri vb.). | { type, req_id, count, category, min_wealth, max_wealth, vip_only } |
FELEROUS_AVATAR_NPC_POOL_RESULT |
Platform ➔ Oyun | Kategoriye göre filtrelenmiş gerçek oyuncu avatarları dizisini döner. | { type, req_id, npcs: [...] } |
Oyununuz iframe veya hızlı CDN önbelleği üzerinden açıldığında
window.addEventListener('DOMContentLoaded', ...) olayı betikleriniz yüklenmeden çoktan tetiklenmiş olabilir. Oyununuzun siyah ekranda kalmaması için başlatıcınızı mutlaka document.readyState kontrollü tasarlayın:
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', launchGame);
} else {
launchGame();
}
🧭 8. Zorluk Kademeleri & Liderlik Tablosu Entegrasyonu
PlayZone skor tablosunda adil rekabet sağlamak için skorlar zorluk kademelerine (Difficulty Tiers) göre filtrelenir.
lvl1/ Acemi: Yavaş düşüş hızı, yeni başlayanlar için.lvl2/ Klasik: Standart arcade dengesi (varsayılan kademe).lvl3/ Usta: Yüksek hız ve daha agresif tempo.lvl4/ Kabus: Zirve refleks gerektiren aşırı hız kademesi.
Skor gönderirken difficulty_tier: 'lvl2' ve difficulty_label: 'Klasik' parametrelerini sağladığınızda PlayZone ve FDB liderlik tablolarında bu sekmeler otomatik ayrışır.
🛠️ 9. Steam-Tarzı Topluluk Atölyesi (Workshop & UGC) Mimarisi (v4.3.8)
Oyununuzda oyuncuların kendi tasarımlarını (taretler, binalar, fabrikalar, haritalar veya genel blueprintler) oluşturup harici bir geliştirici portalına girmeden doğrudan oyun içinden tek tıkla FELEROUS Atölyesi'ne yüklemelerini ve diğer oyuncuların paylaştığı eserleri oyun içine aktarmalarını sağlayan çift yönlü UGC (User-Generated Content) motoru.
FELEROUS Store ve Topluluk kuralları gereği, Atölye desteği olan ancak henüz en az 1 onaylı eseri yayınlanmamış oyunların Atölye sekmeleri veya filtre menüleri vitrinde asla boş/anlamsız olarak görünmez. İlk eser yayınlandığında
games.workshop_items_count veritabanı tetikleyicisiyle otomatik artar ve Atölye sekmeleri canlıya geçer.
- Maksimum 512 KB Payload Tavanı: Kanvas blueprintleri PostgreSQL veritabanında
CHECK (octet_length(blueprint_data::text) <= 524288)kısıtlamasıyla korunur. Ağır model veya DoS amaçlı şişirilmiş veriler sunucuya giremez. - Anti-Spam & Rate-Limiting: Kullanıcı başına 15 saniye cooldown ve saatte maksimum 10 Atölye eseri paylaşma sınırı veritabanı seviyesinde (
BEFORE INSERT TRIGGER) kilitlenmiştir. - Kimlik Taklidi Engeli: Eserin yazarı (
author_id) istemciden manipüle edilemez; Supabase RLS ve veritabanı kontrolüyle zorunlu olarak oturum açan kullanıcının gerçekauth.uid()kimliğine bağlanır. - Mühürlü Sayaçlar (Tamper-Proof Counters):
upvotes_countvesubscribers_countgibi vitrin sayaçları doğrudan güncellenemez. Yalnızcaworkshop_votesveworkshop_subscriptionsilişkisel tablolarındaki gerçek eylemler üzerinden otomatik hesaplanır.
JavaScript Entegrasyon Örnekleri (felerousBridge.workshop)
// Oyuncu editörde veya stüdyoda "Atölyede Paylaş" butonuna bastığında:
const result = await felerousBridge.workshop.publish({
gameSlug: 'neonvolt',
title: 'Özel Arena Parkuru Mk-IV',
category: 'map', // 'map', 'skin', 'blueprint', 'mod'
description: 'Gelişmiş neon engeller ve çift hızlı hızlandırma hatlarına sahip arena haritası.',
footprint: '2x2', // Ayak izi (1x1, 2x2, 3x3 vb.)
previewImage: canvas.toDataURL('image/png'), // Küçük resim (thumbnail)
blueprintData: myMapModelData, // JSON formatında model/çizim verisi (Maks 512KB)
tags: ['neon', 'arena', 'speed', 'custom']
});
if (result.success) {
alert('🎉 Tasarımınız FELEROUS Topluluk Atölyesi\'nde yayınlandı! Eser ID: ' + result.item_id);
} else {
alert('Yayınlama hatası: ' + result.error);
}
// Oyun içi Varlık Mağazasında (Roblox Toolbox tarzı) topluluk modellerini getirin:
const res = await felerousBridge.workshop.getItems({
gameSlug: 'neonvolt',
category: 'map', // Opsiyonel filtre
search: 'neon', // Opsiyonel arama kelimesi
sort: 'popular', // 'popular', 'newest', 'subscribers'
limit: 20
});
if (res.success && res.items.length > 0) {
res.items.forEach(item => {
console.log(`[Atölye] ${item.title} — Yazar: ${item.author_name} — 👍 ${item.upvotes_count}`);
// Modeli oyuna yüklemek için:
// myGameEngine.loadBlueprint(item.blueprint_data);
});
}
// Eseri beğenme (+1 Upvote):
await felerousBridge.workshop.vote(item.id, 'up');
// Esere abone olma (Kullanıcı kütüphanesine kaydetme):
await felerousBridge.workshop.subscribe(item.id, true);
postMessage köprüsü çalışırken, gelecekte Tauri masaüstü istemcisine geçildiğinde window.__TAURI__.invoke çağrısıyla yerel dosya sistemine bağlanacaktır. Geliştirici kodunda tek bir satır dahi değişiklik gerektirmez!
🤖 10. Arkadaş İsimli Botlar & Sosyal Köprü (Social Friends Bridge - v4.2)
Oyunlarda en eğlenceli dinamiklerden biri yapay zeka botlarının ve NPC'lerin isimleridir. Felerous Arcade SDK v4.2 ile geliştiriciler, standart rastgele bot isimlerinin yerine (örn: AlphaBot, BetaBot) oyuncunun FELEROUS Store'daki gerçek arkadaşlarının kullanıcı adlarını oyun içi botlara, düşmanlara veya refakatçilere atayabilir.
Oyun geliştirici isterse bu sistemi oyun kodlarına entegre edip bir "🤖 Arkadaş İsimli Botlar (Açık/Kapalı)" anahtarına bağlar. Oyuncu dilediğinde bu seçeneği açarak, düşman kulelerini veya düşen kristalleri arkadaşlarının adıyla görebilir ("Ahmet_TR seni vurdu!" veya "Subushaki kristali toplandı!").
- Hassas Veri İzolasyonu: Oyun iframe'ine oyuncunun e-posta adresi, şifresi, oturum tokeni veya özel profil ayarları ASLA aktarılmaz. PlayZone köprüsü yalnızca kamuya açık
{ id, name, username, avatar_url }alanlarını filtreleyerek sunar. - Yedek İsim Havuzu (Fallback Pool): Oyuncu misafir oturumundaysa, çevrimdışıysa veya oyunun ihtiyaç duyduğu bot sayısından daha az arkadaşı varsa (örneğin 3 arkadaşı var ama oyunda 10 bot var),
getFriendBotNames()eksik kalanları geliştiricinin tanımladığıfallbackNameshavuzundan otomatik tamamlar. Oyun asla hata vermez veya takılmaz. - Yerel Simülasyon Desteği: Geliştirici kendi bilgisayarında (
localhost,file://) oyunu test ederken PlayZone iframe'i dışında bile olsa SDK otomatik mock arkadaş listesi üreterek geliştirme akışını kesintisiz sürdürür.
Metot Referansı
| Metot | Dönüş Tipi | Açıklama |
|---|---|---|
felerousBridge.getFriends() |
Promise<Array> |
Oyuncunun onaylı arkadaşlarının sanitize edilmiş listesini döner: [{ id, name, username, avatar_url }]. |
felerousBridge.getFriendBotNames(options) |
Promise<string[]> |
Botlar için doğrudan kullanıma hazır isim dizisi döner. options: { count: 10, fallbackNames: [...], shuffle: true }. Arkadaş isimlerini fallback havuzuyla güvenle harmanlar.
|
felerousBridge.onFriends(callback) |
void |
Arkadaş listesi platformdan geldiğinde tetiklenen reaktif olay dinleyicisidir. |
felerousBridge.social.getBotNamePool(opts) |
Promise<string[]> |
Sosyal modül altındaki kısayol metodudur (window.FelerousSocialBridge). |
1. JavaScript & HTML5 Canvas Uygulaması
Aşağıdaki örnek, oyun içi bir Toggle Switch ile oyuncunun bu özelliği açıp kapatabilmesini, ayarın SafeStorage'da saklanmasını ve bot doğuşunda (spawn) arkadaş isimlerinin Canvas üzerine çizilmesini gösterir:
class MyGame {
constructor() {
this.useFriendBots = SafeStorage.getItem('friend_bots_enabled') !== 'false';
this.botNames = [];
this.bots = [];
this.setupFriendBotToggle();
this.loadBotNames();
}
// 1. Ayarı ve Butonu Bağla
setupFriendBotToggle() {
const toggle = document.getElementById('toggle-friend-bots');
if (toggle) {
toggle.checked = this.useFriendBots;
toggle.addEventListener('change', (e) => {
this.useFriendBots = e.target.checked;
SafeStorage.setItem('friend_bots_enabled', this.useFriendBots ? 'true' : 'false');
this.loadBotNames(); // İsim havuzunu yenile
});
}
}
// 2. Felerous SDK ile İsim Havuzunu Yükle
async loadBotNames() {
if (!this.useFriendBots) {
// Özellik kapalıysa varsayılan bot isimlerini kullan
this.botNames = ['AlphaBot', 'BetaBot', 'OmegaBot', 'Titan', 'Ghost'];
return;
}
try {
this.botNames = await felerousBridge.getFriendBotNames({
count: 15,
fallbackNames: ['AlphaBot', 'BetaBot', 'OmegaBot', 'Spectre', 'Viper', 'Ghost'],
shuffle: true
});
console.log('🤖 Bot isimleri hazırlandı:', this.botNames);
} catch (err) {
this.botNames = ['AlphaBot', 'BetaBot', 'OmegaBot'];
}
}
// 3. Bot Doğarken İsim Ata
spawnBot() {
const randomName = this.botNames[Math.floor(Math.random() * this.botNames.length)] || 'Bot';
this.bots.push({
x: Math.random() * canvas.width,
y: 0,
name: randomName,
speed: 3
});
}
// 4. Canvas Üzerinde Botu ve İsmini Çiz
render(ctx) {
for (const bot of this.bots) {
// Bot gövdesi
ctx.fillStyle = '#ef4444';
ctx.fillRect(bot.x - 15, bot.y - 15, 30, 30);
// Botun üstüne arkadaş ismini yaz
ctx.font = '11px -apple-system, sans-serif';
ctx.fillStyle = '#bae6fd';
ctx.textAlign = 'center';
ctx.fillText(bot.name, bot.x, bot.y - 20);
}
}
}
2. Godot Engine (GDScript Web Export)
Godot 4 WebGL export projelerinde JavaScriptBridge sınıfı üzerinden arkadaş listesini çekip bot düğümlerinize (Label3D veya Label) atayabilirsiniz:
extends Node
var friend_bot_names: Array = []
var _js_callback: JavaScriptObject
func _ready():
if OS.has_feature("web"):
_js_callback = JavaScriptBridge.create_callback(_on_friends_received)
# HTML5 katmanındaki felerousBridge'e çağrı yap
JavaScriptBridge.eval("""
if (window.felerousBridge) {
window.felerousBridge.getFriendBotNames({ count: 10, fallbackNames: ['CyberBot', 'DroidX', 'Titan'] })
.then(names => window._godotFriendsCallback(JSON.stringify(names)));
}
""")
var window = JavaScriptBridge.get_interface("window")
window._godotFriendsCallback = _js_callback
func _on_friends_received(args):
if args.size() > 0:
var json_str = args[0]
var parsed = JSON.parse_string(json_str)
if typeof(parsed) == TYPE_ARRAY:
friend_bot_names = parsed
print("Godot: Arkadaş Bot İsimleri Yüklendi: ", friend_bot_names)
func spawn_bot():
var bot_instance = preload("res://Bot.tscn").instantiate()
if friend_bot_names.size() > 0:
bot_instance.bot_name = friend_bot_names.pick_random()
add_child(bot_instance)
3. Unity WebGL (C# & .jslib)
Unity WebGL projelerinde Assets/Plugins/WebGL/FelerousBridge.jslib köprü eklentisi kullanarak isimleri C# koduna aktarabilirsiniz:
mergeInto(LibraryManager.library, {
FetchFriendBotNames: function (gameObjectNamePtr, callbackMethodNamePtr) {
var objName = UTF8ToString(gameObjectNamePtr);
var methodName = UTF8ToString(callbackMethodNamePtr);
if (window.felerousBridge) {
window.felerousBridge.getFriendBotNames({ count: 10 })
.then(function(names) {
SendMessage(objName, methodName, JSON.stringify(names));
});
}
}
});
using System.Runtime.InteropServices;
using UnityEngine;
public class GameManager : MonoBehaviour
{
[DllImport("__Internal")]
private static extern void FetchFriendBotNames(string gameObjectName, string callbackMethodName);
public string[] friendBotNames;
void Start()
{
#if UNITY_WEBGL && !UNITY_EDITOR
FetchFriendBotNames(gameObject.name, "OnFriendNamesReceived");
#else
friendBotNames = new string[] { "AlphaBot", "BetaBot", "OmegaBot" };
#endif
}
public void OnFriendNamesReceived(string jsonArray)
{
friendBotNames = JsonUtility.FromJson<string[]>(jsonArray);
Debug.Log("Unity: Arkadaş bot isimleri yüklendi!");
}
}
Çok oyunculu veya takım tabanlı oyunlarda (örn. Mavi Takım vs Kırmızı Takım), oyuncunun gerçek arkadaşlarının isimlerini kendi takımındaki yapay zeka müttefiklerine verirseniz ("Ahmet_TR seni koruyor!"), oyuncunun arkadaşlarıyla birlikte oynuyormuş gibi hissetmesini sağlayabilir ve oturum süresini katlayabilirsiniz!
🎭 11. Küp Avatar (CubeRig v1) & Canlı NPC Havuzu Mimarisi (v4.3.8)
FELEROUS ekosisteminin devrimsel "Tek Kimlik, Sınırsız Temsil" mimarisi: Oyuncular Felerous Store profilinde (profile.html) kendi 2.5D Küp Avatarlarını tasarlar; bu avatar hem PlayZone arcade dünyalarında canlı bir rakip veya liderlik yarışçısı olarak yerini alır, hem de ekosistemdeki bağımsız oyunlarda canlı bir müttefik, komutan veya şehir sakini olarak taşınır.
- Omuz Perspektifli Z-Order Katmanlaması: Karakterler sağa baktığında sağ kol gövde arkasına düşer ve sol kol öne gelir (sola baktığında tam tersi). 2.5D derinlik hissi kağıt bebek hissini ortadan kaldırır.
- 14 Katmanlı Z-Index Hiyerarşisi: Gölge, bacaklar, gövde, kafa, yüz hatları (kadın/erkek, allık, kirpik), saç ve şapkalar, sokak modası kıyafetleri (hoodie, takım elbise, crop-top), aksesuarlar ve çantalar.
- Kültürel & Başarım Prestij Yuvaları: Klasik Pala Bıyık, Nazar Boncuğu, Ay-Yıldızlı Milli Forma, Nostaljik Kasket ile 5 ve 15 başarım açanlara özel Altın Vizör, Zümrüt Taç ve Amiral Zırhı.
- Canlı Oyuncu NPC Havuzu (RPC):
getNPCPool()çağrısıyla sistemdeki gerçek oyuncuların profilleri AVM müşterisi, uzay pilotu veya uzaylı tüccar olarak oyununuza akar ($W = 120 + 65 \cdot \ln(1 + H) + 8 \cdot \sqrt{A}$ logaritmik bütçe formülüyle).
Standart arcade oyunlarının yükleme süresini ve boyutunu minimumda tutmak için Küp Avatar motoru çekirdek köprüden bağımsız hale getirilmiştir. Oyununuza CubeRig karakterlerini dahil etmek için betiği eklemeniz yeterlidir:
<script src="https://store.felerous.com/js/felerous-cuberig-sdk.js"></script>
felerousBridge.avatars Metot Referansı
| Metot | Dönüş Tipi | Açıklama |
|---|---|---|
FelerousCubeRig.getAvatar(felIdOrUser) |
Promise<Object> |
Belirtilen FEL-ID (örn: 'FEL-1001'), kullanıcı adı veya aktif oturumdaki oyuncunun CubeRig JSON spec verisini döner. |
FelerousCubeRig.getNPCPool(count) |
Promise<Array> |
Canlı oyuncu avatarlarından oluşan hazır NPC / Drivatar havuzunu çeker (Varsayılan: 20). |
felerousBridge.avatars.getMyAvatar(rigFamily) |
Promise<Object> |
Oyuncunun profile.html'de tasarladığı aktif CubeRig spec JSON verisini döner (Varsayılan: 'cube_v1'). |
felerousBridge.avatars.saveMyAvatar(spec, photoDataUrl) |
Promise<Object> |
Yeni avatar spec'ini ve isteğe bağlı $256 \times 256$ avatar profil görselini Supabase'e kaydeder. |
felerousBridge.avatars.getNPCPool(options) |
Promise<Array> |
Canlı oyuncu avatarlarından oluşan NPC havuzunu çeker.options: { count: 15, category: 'fashion', minWealth: 100, maxWealth: 3000, vipOnly: false }
|
Kullanım Örneği: Avatar Çizimi & NPC Havuzu
// 1. Köprüyü ve Avatar Çiziciyi Başlatın
const bridge = window.felerousBridge;
const renderer = new FelerousAvatarRenderer({ pixelScale: 2 });
// 2. Oyuncunun Kendi Avatarını Alıp Çizdirin
const mySpec = await bridge.avatars.getMyAvatar('cube_v1');
renderer.render(ctx, mySpec, 200, 300, {
facing: 'right', // 'left' veya 'right' (Omuz Z-Order katmanlaması otomatik)
isWalking: true, // Yürüyüş mafsal salınımı
walkCycleTime: performance.now(),
holdsBag: true, // Elinde AVM alışveriş poşeti
bagColor: '#e74c3c'
});
// 3. Canlı Oyuncu NPC Havuzunu Çekip Oyuna Doldurun
const npcs = await bridge.avatars.getNPCPool({ count: 10, category: 'fashion' });
npcs.forEach((npc, index) => {
console.log(`[NPC Doğdu] ${npc.player_name} — Bütçe: ₺${npc.simulated_budget} — VIP: ${npc.is_vip}`);
// NPC avatar verisini sahneye ekleyin:
// spawnCustomer(npc.avatar_spec, npc.player_name, npc.simulated_budget);
});
🦀 12. Tauri v2 Masaüstü İstemcisi & Çift Yönlü IPC Köprüsü
FELEROUS Ekosistemi hem modern web tarayıcılarında (PlayZone Web PWA) hem de Tauri v2 tabanlı Masaüstü Başlatıcıda (FELEROUS Launcher) sıfır konfigürasyonla çalışacak çift motorlu mimariye sahiptir.
if (isDesktop) ayrımı yapmanıza gerek yoktur. felerous-bridge.js çalışma anında ortamı otomatik tespit eder. Tarayıcıdaysa güvenli window.postMessage, masaüstü istemcisindeyse yerel Rust çekirdeğine window.__TAURI__.core.invoke ile doğrudan bağlanır.
| Protokol | Ortam | Mekanizma | Gecikme |
|---|---|---|---|
| Web PlayZone | Chrome, Edge, Safari, Firefox | iFrame ➔ window.postMessage / window.onmessage |
< 2ms |
| Tauri v2 Desktop | Windows (.exe), Linux, macOS | Rust Core ➔ invoke('felerous_bridge_dispatch') & listen('felerous_platform_message') |
< 0.1ms (Sıfır IPC Darboğazı) |
💬 12.1 Oyuncu İncelemeleri & Topluluk Oylaması (PlayZone Reviews HUD — v4.2)
PlayZone oyunları, oyuncuların oyun deneyimini anında oylayabilmesi (👍 Tavsiye Ediyorum / 👎 Tavsiye Etmiyorum) ve klasik inceleme metinleri yazabilmesi için yerleşik bir Oyuncu İncelemeleri Motoru barındırır.
Oyuncuların verdiği oylar doğrudan Supabase public.reviews tablosuna işlenir ve public.game_review_summary görünümü üzerinden anlık hesaplanır:
- Ezici Çoğunlukla Olumlu: En az 5 inceleme ve %95+ olumlu tavsiye oranı.
- Çok Olumlu: %80 - %94 arası olumlu tavsiye oranı.
- Çoğunlukla Olumlu: %70 - %79 arası olumlu tavsiye oranı.
- Karışık: %40 - %69 arası denge durumu.
- Çoğunlukla Olumsuz: %40 altı olumsuz çoğunluk.
// Oyun bittiğinde veya oyuncu ana menüde "⭐ Oyunu Değerlendir" butonuna bastığında:
function onGameOverOrFeedbackClick() {
// PlayZone üst çubuğundaki oylama & yorum modalını tetikler:
felerousBridge.openReviews();
}
⭐ 12.2 Google Zengin Sonuçlar & Schema.org Standardı (Otomatik SEO)
PlayZone'a yüklenen her oyun, FELEROUS sunucu katmanı (api/playzone.js) tarafından Google standartlarında Zengin Sonuç (Rich Snippet) etiketleriyle indekslenir.
🔍 Google Arama Motoru İçin Uygulanan Otomatik Standartlar
- VideoGame + WebApplication Çift Türü: Google'ın "Yalnızca tek başına VideoGame tipine zengin sonuç kartı göstermeme" kuralı gereği, oyununuz otomatik olarak
["VideoGame", "WebApplication"]tipiyle sunulur. - Canlı Yıldız Skoru (AggregateRating): Oyuncuların verdiği incelemeler 1.0 - 5.0 ölçeğinde hesaplanarak Google arama sonuçlarında altın yıldızlar (⭐⭐⭐⭐⭐ 4.8 / 5) ve inceleme sayısı olarak görünür.
- Ücretsiz Oynanabilir Fiyatlandırma:
offers: { price: "0", priceCurrency: "TRY" }tanımıyla Google oyununuzu "Ücretsiz Oyna" kartı olarak öne çıkarır.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": ["VideoGame", "WebApplication"],
"name": "Düşen Sicimler",
"applicationCategory": "GameApplication",
"operatingSystem": "Web Browser, HTML5, WebGL",
"inLanguage": "tr",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "TRY",
"availability": "https://schema.org/InStock"
},
"author": {
"@type": "Organization",
"name": "Subushaki"
},
"publisher": {
"@type": "Organization",
"name": "FELEROUS",
"url": "https://felerous.com"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"bestRating": "5",
"worstRating": "1",
"ratingCount": "18"
}
}
</script>
📱 13. Mobil & Çapraz Tarayıcı "Altın Kuralları"
Mobil tarayıcılarda (Safari, Samsung Internet, Chrome Mobil) kusursuz deneyim sağlamak için şu 5 altın kural uygulanmalıdır:
1. Dynamic Viewport (100dvh)
Mobil gezinti çubuğu hareket ettiğinde sayfanın taşmasını engeller (100dvh en sonda yer alarak modern tarayıcılarda öncelik kazanır):
html, body, #game-container {
height: 100vh;
height: -webkit-fill-available;
height: 100dvh;
overflow: hidden;
position: fixed;
width: 100%;
}
2. SafeStorage (Safari Gizli Mod & Iframe Koruması)
Safari Gizli Modunda localStorage çökmelerini engeller:
window.SafeStorage = {
_mem: {},
getItem(k) {
try { return localStorage.getItem(k); }
catch (e) { return this._mem[k] || null; }
},
setItem(k, v) {
try { localStorage.setItem(k, v); }
catch (e) { this._mem[k] = String(v); }
}
};
3. Web Audio API Otomatik Oynatma Uyandırıcısı (unlockAudio)
Kullanıcının ilk dokunuşunda ses motorunu uyandırır ve yalnızca running durumuna geçtiğinde dinleyiciyi kaldırır:
function unlockAudio() {
if (!window.audioCtx) return;
if (window.audioCtx.state === 'suspended') {
window.audioCtx.resume().then(() => {
if (window.audioCtx.state === 'running') {
document.removeEventListener('pointerdown', unlockAudio);
}
}).catch(() => {});
} else if (window.audioCtx.state === 'running') {
document.removeEventListener('pointerdown', unlockAudio);
}
}
document.addEventListener('pointerdown', unlockAudio, { passive: true });
4. Samsung Internet Renk Bozulması Koruması
Gece modunda canvas renklerinin tersine çevrilmesini engeller:
:root { color-scheme: dark; }
canvas { color-scheme: dark; forced-color-adjust: none; touch-action: none; }
5. Dokunmatik Jestler ve Eksen Kilidi (Axis Lock)
Düşen Sicimler v1.0.5 ile geliştirilen sezgisel doğrudan Canvas jest kontrol modeli:
// Yatay sürüklemede kazara düşüşleri engelleyen eksen kilidi
let touchStartX = 0, touchStartY = 0, isDragging = false;
canvas.addEventListener('touchstart', (e) => {
const t = e.touches[0];
touchStartX = t.clientX;
touchStartY = t.clientY;
isDragging = true;
}, { passive: true });
canvas.addEventListener('touchmove', (e) => {
if (!isDragging) return;
const dx = e.touches[0].clientX - touchStartX;
const dy = e.touches[0].clientY - touchStartY;
// Eksen kilidi: Yatay hareket dikey hareketten fazlaysa sola/sağa kaydır
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 28) {
if (dx > 0) game.moveRight(); else game.moveLeft();
touchStartX = e.touches[0].clientX;
}
}, { passive: true });
canvas.addEventListener('touchend', (e) => {
isDragging = false;
});
🌐 14. Dağıtım Modelleri: Felerous R2 Bulut vs Harici Sunucu
Felerous PlayZone ekosisteminde oyununuzu iki farklı mimariyle milyonlarca oyuncuya ulaştırabilirsiniz:
Oyununuzun tüm dosyaları (HTML, JS, CSS, ses ve görseller) tek bir ZIP arşivi olarak sunulur. Felerous Güvenlik Masası'nın onayının ardından oyun arcade.felerous.com/[oyun-slug]/index.html adresiyle küresel Cloudflare Edge CDN üzerinden sıfır sunucu maliyetiyle yayınlanır.
Oyununuzu kendi bulut altyapınızda (Cloudflare Pages, Vercel, Render, Node.js VPS, AWS veya özel alan adınızda) barındırırsınız. PlayZone oyununuzu güvenli bir sandbox iframe içerisinde vitrine bağlar.
Harici Sunucuda Barındırma İçin 3 Demir Güvenlik Kuralı:
https:// ve wss:// olmalıdır.
postMessage API'si üzerinden ana PlayZone arayüzüne iletilir.
⚡ 15. Felerous Canlı Telemetri Protokolü (v1.0)
Çok oyunculu veya yaşayan dünyalara sahip web oyunlarında sunucu sağlığını, canlı oyuncu sayısını ve Drivatar bot aktivitelerini FELEROUS Store ve FDB vitrinine gerçek zamanlı aktarma standardıdır.
Standart REST Telemetri Endpoint'i (HTTP GET):
Çok oyunculu oyun sunucunuzda (örn: https://neon-volt.onrender.com/stats veya https://api.studio.com/stats) aşağıdaki JSON şemasını dönen hafif bir HTTP GET uç noktası tanımlamalısınız:
{
"protocol": "felerous-telemetry-v1",
"status": "online",
"service": "neon-volt-multiplayer",
"timestamp": 1727701800000,
"uptime": 14200,
"performance": {
"tps": 30.0,
"tickIntervalMs": 33.33,
"memoryMB": 42
},
"players": {
"online": 3,
"max": 30,
"humans": 3,
"bots": 10,
"list": [
{ "id": "p_1", "name": "Vortex", "score": 2400, "isVerified": true }
]
},
"bots": {
"count": 10,
"archetypes": [
{ "name": "SiberCellat", "title": "Psikopat Avcı (Bwoniknife)", "score": 1420 }
]
},
"arena": {
"radius": 2900,
"foodCount": 650
},
"leaderboard": [
{ "rank": 1, "name": "Vortex", "score": 2400, "isPlayer": true },
{ "rank": 2, "name": "SiberCellat", "score": 1420, "isPlayer": false }
]
}
Zorunlu Sunucu HTTP Başlıkları (CORS):
Store vitrini ve FDB'nin tarayıcı seviyesinde canlı verileri sorgulayabilmesi için sunucu yanıtınızda şu başlıklar bulunmalıdır:
☁️ 16. İnceleme Süreci, Dağıtım & Geliştirici Portalı
Oyununuzu milyonlarca oyuncuya güvenli ve yüksek performansla sunmak için FELEROUS Güvenlik Masası, Cloudflare R2 ve Geliştirici Portalı entegrasyonu:
arcade.felerous.com kovanına konuşlandırılır.
felerous-games Cloudflare R2 kovanında ve https://arcade.felerous.com/[oyun-slug]/index.html özel alan adında barındırılır. SSL, küresel CDN önbellekleme ve sandbox iframe güvenliği otomatik olarak devrededir.
Yayınlama & İnceleme Adımları:
- Oyun dosyalarınızı standart klasör hiyerarşisinde (
index.html,manifest.json,achievements.json,changelog.json,cover.png,banner.png,icon.png,shortcut.png,js/,css/) hazırlayın ve bir ZIP arşivi haline getirin (veya harici barındırma kullanıyorsanız canlı web adresinizi hazırlayın). - Geliştirici Portalı'na (
/developer) gidin ve "Web Oyunları (PlayZone Arcade)" sekmesini açın. - Oyun Başlığı, Motoru, Türü, Açıklaması, Dağıtım Türü (R2 veya Harici URL) ve çok oyunculu ise Telemetri bağlantısını girip "Web Oyununu İncelemeye Gönder" butonuna basın.
- FELEROUS Yönetim Masası paketi veya canlı bağlantıyı inceleyip güvenlik, 100dvh mobil düzeni, SafeStorage ve SDK köprüsünü test eder.
- Onaylanan oyun PlayZone vitrininde ve mağazada yayına girer.
- Oyun onaylandıktan sonra geliştirici; başlık, açıklama, kontroller ve yeni güncelleme paketleri sunma konusunda daha geniş ve özgür yönetim paneline sahip olur.
purchases tablosuna payment_method: 'arcade_play' olarak) ekler ve oyuncunun profilindeki "Sahip Olunan Oyun" sayacını artırır.
🧪 17. İnteraktif JSON Doğrulayıcı
Oyununuzu R2'ye yüklemeden önce manifest.json, achievements.json veya changelog.json dosyanızı buraya yapıştırıp şema geçerliliğini anında test edebilirsiniz: