Tüm yazılar
06 · Tasarım ve etkileşim · 2026.10 · 6 dk

x³: Mauve gizli modunu bulunabilir ve ucuz tutmak

Footer'daki devilyxrd yazısının x harfine üç kez tıklayınca site Mauve moduna geçiyor. Bu notta sırrın kendini nasıl ele verdiğini, açılınca neleri değiştirdiğini ve bütün bunları hareket azaltma tercihine saygı duyarak birkaç sınıf ve değişkenle nasıl ucuz tuttuğumu anlatıyorum.

01Bulunabilir bir sır

Kimsenin bulamadığı gizli bir özellik aslında yoktur. O yüzden ipuçlarını katmanlı koydum. Footer'daki büyük wordmark'ın x harfi aslında bir düğme ve yanında küçük bir üs duruyor: x³. Kimse dokunmadıysa x, yedi saniyelik bir döngüyle ara ara sallanıyor (xwob). Konsolu açan biri renkli bir x³ ve alttaki x'e üç kez dokunmasını söyleyen kısa bir not görüyor; consoleHint bunu sayfa mount edildikten sonra yazdırıyor. Bir de kestirme var: komut paletinde Mauve modunu açıp kapatan bir eylem.

x düğmesinin bir aria-label'ı var (Mauve modunu aç / kapat). Yani ekran okuyucu kullanan biri için bu bir sır bile değil, düz bir düğme. Sürpriz görsel tarafta kalıyor, erişim tarafında değil.

Komut paletindeki eylem de arama dizininin bir parçası. searchIndex.ts bu eylemi iki dildeki etiketiyle ve mauve, iris, secret, gizli gibi anahtar kelimelerle kaydediyor; paleti açıp gizli ya da mauve yazan biri doğrudan bu eylemi buluyor. Bu, sırrı bilen ama footer'a inmek istemeyen biri için bir kestirme. Palet eylemi de header rozeti gibi toggleSecret çağırıyor, yani üç tık beklemeden modu çeviriyor ve kutlamayı ekranın ortasından oynatıyor.

02Üç tık

Sayaç ui store'unda tek bir sayı: secret. Her tıkta artıyor ve modun açık olup olmadığı ondan türetiliyor. Footer'daki üs ui.secret % 3 || 3 değerini gösteriyor; sırayla x¹, x², x³. Her tıkta x 30 derece daha dönüyor ve kısa bir toast x¹ ya da x² yazıyor. Üçüncü tık modu çeviriyor.

src/stores/ui.ts, src/composables/useSecretMode.ts
// src/stores/ui.ts
export const mauve = computed(() => Math.floor(ui.secret / 3) % 2 === 1)

// src/composables/useSecretMode.ts
export function clickSecret(x: number, y: number, xEl?: HTMLElement) {
  ui.secret++
  const step = ui.secret % 3
  if (xEl && !isReduced()) gsap.to(xEl, { rotate: step * 30, duration: 0.5, ease: 'back.out(3)' })
  document.documentElement.classList.add('x-found')
  if (step === 0) celebrate(x, y)
  else showToast(step === 1 ? 'x¹' : 'x²', 1200)
}

İlk tıkta html elemanına x-found sınıfı ekleniyor ve sallanma duruyor. İpucu işini yaptı, artık dikkat çekmesine gerek yok. Durumu tek bir sayıdan türetmenin bir faydası da açıp kapatmanın aynı hesapla çalışması: altıncı tık modu kapatıyor, dokuzuncu yeniden açıyor.

03Açılınca ne oluyor

celebrate fonksiyonu önce durumu kaydediyor ve bir toast gösteriyor. Ardından hareket azaltma kapalıysa iki animasyon oynuyor. Birincisi shockwave: tıklanan noktadan ekranın en uzak köşesine kadar büyüyen bir clip-path dairesi. Eleman body'ye ekleniyor, mix-blend-mode: difference ile altındaki sayfayı tersine çeviriyor ve GSAP zaman çizelgesi bitince kaldırılıyor. İkincisi scatter: footer wordmark'ının harfleri rastgele konum ve açılardan elastik bir easing ile yerlerine dönüyor.

Mod açıkken değişenlerin hepsi CSS'te, .app.mv altında. Iris değişkeni Mauve'a (#C7A8BE) eşitleniyor, yani vurgu rengini kullanan her şey birlikte değişiyor. İmleç değişkenleri x şeklindeki SVG'lere dönüyor. .app.mv::after bütün ekranın üstüne, tıklamaları engellemeyen ince yatay çizgiler seriyor. Hero'da ise kaos seviyesi 1'den 2'ye çıkıyor; artıların dönüşü ve rastgele sapmaları bu sayıyla çarpılıyor, halkalar daha fazla dönüyor.

tokens.css, shell.css
/* tokens.css */
.app.mv { --iris: var(--mauve); }

/* shell.css */
.app.mv::after { content: ''; position: fixed; inset: 0; z-index: 300; pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(199, 168, 190, .045) 0 1px, transparent 1px 3px); }
html:not(.x-found) .ftw .xbtn { animation: xwob 7s var(--e) 3s infinite; }
@media (prefers-reduced-motion: reduce) { .ftw .xbtn { animation: none !important; } }
Bir sırrın değeri bulunduğu andaki küçük sürprizde; bedelini her ziyaretçiye ödetmemek gerekiyor.

04Kalıcılık ve çıkış

Mod oturum boyunca sürüyor. persist, sessionStorage'a dvx-secret anahtarıyla 1 ya da 0 yazıyor; main.ts mount sonrasında restoreSecret çağırıyor ve değer 1 ise ui.secret 3 oluyor. Bunu bilerek mount sonrasına koydum: prerender edilen HTML her zaman normal modda, istemcinin ilk render'ı da aynı işaretlemeyi üretmeli. sessionStorage seçmemin sebebi de bunun bir oyun olması; sekme kapandığında sitenin normal haline dönmesini istedim. Depolama engellenmişse try/catch modun kapalı başlamasını sağlıyor.

Mod açıkken header'da kesikli Mauve kenarlıklı bir rozet beliriyor: Mauve ×. Tıklanınca toggleSecret çalışıyor; sayacı bir sonraki üçün katına atlatıyor ve aynı kutlamayı tıklanan noktadan oynatıyor. Rozet, modu tesadüfen açan birinin footer'a geri inmeden çıkabilmesi için var.

05Hareket azaltma ve maliyet

prefers-reduced-motion açıksa x dönmüyor, shockwave ve scatter oynamıyor, sallanma animasyonu CSS'te kapalı. Mod yine açılıyor, toast yine çıkıyor; sadece hareket yok. Hero'daki tıklama dalgası da bu durumda hiç üretilmiyor.

Maliyet tarafında mod kapalıyken neredeyse hiçbir şey çalışmıyor: bir sayı, bir computed ve x üzerinde bir CSS animasyonu. Shockwave elemanı yalnızca tıklama anında oluşuyor ve iş bitince siliniyor. Mod açılınca hero, mauve değerini izleyip bütün hücreleri bir kez yeniden çiziyor (repaintAll), sonra her şey normal döngüsüne dönüyor. Ayrı bir tema dosyası ya da ayrı bir bileşen ağacı yok.

İlgili yazılar
  1. 07Dil adreste yaşar: Türkçe kökte, İngilizce /en altındaArayüz2026.106 dk
  2. 08XSLT ile süslenen sitemap.xml'den gerçek bir HTML site haritasınaArama ve GEO2026.105 dk