mlv2boii 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/holdw.py +21 -0
  2. package/index.html +107 -81
  3. package/loader.svg +26 -40
  4. package/package.json +1 -1
package/holdw.py ADDED
@@ -0,0 +1,21 @@
1
+ import keyboard
2
+ import time
3
+
4
+
5
+
6
+ def start():
7
+ keyboard_pressing = True
8
+ while keyboard_pressing:
9
+ keyboard.press("W")
10
+ time.sleep(0.1)
11
+
12
+ if keyboard.is_pressed("C"):
13
+ keyboard_pressing = False
14
+ while not (keyboard.is_pressed("X")):
15
+ time.sleep(0.1)
16
+ keyboard_pressing = True; start()
17
+
18
+ start()
19
+
20
+
21
+
package/index.html CHANGED
@@ -70,22 +70,41 @@
70
70
  @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
71
71
  .skel { background: linear-gradient(100deg, #18181c 30%, #202024 45%, #18181c 60%); background-size: 200% 100%; animation: shimmer 1.6s ease-in-out infinite; }
72
72
 
73
- [data-fx] { will-change: transform, opacity; }
74
-
75
- .hero-orb { animation: heroFloat 7s ease-in-out infinite; }
76
- .hero-line { animation: heroLine 2.8s ease-in-out infinite; }
77
- @keyframes heroFloat {
78
- 0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
79
- 50% { transform: translate3d(0, 12px, 0) scale(1.04); }
80
- }
81
- @keyframes heroLine {
82
- 0%, 100% { opacity: .35; transform: scaleX(.7); }
83
- 50% { opacity: 1; transform: scaleX(1); }
84
- }
85
- </style>
73
+ [data-fx] { will-change: transform, opacity; }
74
+
75
+ .hero-orb { animation: heroFloat 7s ease-in-out infinite; }
76
+ .hero-line { animation: heroLine 2.8s ease-in-out infinite; }
77
+ @keyframes heroFloat {
78
+ 0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
79
+ 50% { transform: translate3d(0, 12px, 0) scale(1.04); }
80
+ }
81
+ @keyframes heroLine {
82
+ 0%, 100% { opacity: .35; transform: scaleX(.7); }
83
+ 50% { opacity: 1; transform: scaleX(1); }
84
+ }
85
+
86
+ /* Blank Overlay Lock Screen */
87
+ #blank-overlay {
88
+ position: fixed;
89
+ inset: 0;
90
+ background-color: #000000;
91
+ z-index: 99999;
92
+ display: flex;
93
+ transition: opacity 0.4s ease, visibility 0.4s ease;
94
+ }
95
+ #blank-overlay.unlocked {
96
+ opacity: 0;
97
+ visibility: hidden;
98
+ pointer-events: none;
99
+ }
100
+ </style>
86
101
  </head>
87
102
 
88
103
  <body class="bg-ink-950 text-ink-100 font-sans antialiased min-h-screen">
104
+
105
+ <!-- Blank Overlay Screen -->
106
+ <div id="blank-overlay"></div>
107
+
89
108
  <div class="grain"></div>
90
109
  <div class="spotlight"></div>
91
110
 
@@ -95,7 +114,7 @@
95
114
  <a href="#" class="flex items-center gap-2 shrink-0 group">
96
115
  <span class="relative h-2 w-2">
97
116
  <span class="absolute inset-0 rounded-full bg-red-500"></span>
98
- <span class="absolute inset-0 animate-ping rounded-full bg-red-500 opacity-60"></span>
117
+ <span class="absolute inset-0 animate-ping rounded-full bg-red-500 opacity-60"></span>
99
118
  </span>
100
119
  <span class="font-display font-semibold tracking-tight text-[15px] leading-none">mlv2</span>
101
120
  </a>
@@ -112,27 +131,27 @@
112
131
  </div>
113
132
 
114
133
  <div class="border-t border-ink-800/60">
115
- <div id="category-bar" class="mx-auto flex max-w-5xl items-center justify-center gap-1.5 overflow-x-auto px-4 py-2.5 sm:px-6"></div>
134
+ <div id="category-bar" class="mx-auto flex max-w-5xl items-center justify-center gap-1.5 overflow-x-auto px-4 py-2.5 sm:px-6"></div>
116
135
  </div>
117
136
  </header>
118
137
 
119
138
  <!-- ================= MAIN ================= -->
120
- <main class="relative z-10 mx-auto max-w-5xl px-4 sm:px-6 py-8 sm:py-12">
121
-
122
- <!-- ================= HERO ================= -->
123
- <section class="relative mx-auto mb-10 max-w-2xl overflow-hidden rounded-[2rem] border border-ink-700/70 bg-ink-900/65 px-5 py-10 text-center shadow-[0_24px_80px_-40px_rgba(232,20,47,0.5)] sm:px-10 sm:py-14">
124
- <div class="hero-orb pointer-events-none absolute -right-20 -top-24 h-64 w-64 rounded-full bg-red-500/10 blur-3xl"></div>
125
- <div class="hero-orb pointer-events-none absolute -bottom-28 -left-20 h-56 w-56 rounded-full bg-red-700/10 blur-3xl" style="animation-delay: -3.5s"></div>
126
- <div class="relative">
127
- <div class="mx-auto mb-5 flex w-fit items-center gap-2 rounded-full border border-red-500/25 bg-red-500/[0.07] px-3 py-1 text-[10px] font-mono uppercase tracking-[0.22em] text-red-300">
128
- <span class="h-1.5 w-1.5 rounded-full bg-red-400 shadow-[0_0_12px_rgba(255,77,97,0.9)]"></span>
129
- Play something
130
- </div>
131
- <h1 class="font-display text-4xl font-semibold tracking-[-0.05em] text-ink-50 sm:text-6xl">Your next <span class="text-red-400">favorite</span> game.</h1>
132
- <p class="mx-auto mt-4 max-w-md text-sm leading-6 text-ink-300 sm:text-[15px]">A curated shelf of quick escapes, hidden gems, and games worth one more round.</p>
133
- <div class="hero-line mx-auto mt-7 h-px w-24 bg-gradient-to-r from-transparent via-red-400 to-transparent"></div>
134
- </div>
135
- </section>
139
+ <main class="relative z-10 mx-auto max-w-5xl px-4 sm:px-6 py-8 sm:py-12">
140
+
141
+ <!-- ================= HERO ================= -->
142
+ <section class="relative mx-auto mb-10 max-w-2xl overflow-hidden rounded-[2rem] border border-ink-700/70 bg-ink-900/65 px-5 py-10 text-center shadow-[0_24px_80px_-40px_rgba(232,20,47,0.5)] sm:px-10 sm:py-14">
143
+ <div class="hero-orb pointer-events-none absolute -right-20 -top-24 h-64 w-64 rounded-full bg-red-500/10 blur-3xl"></div>
144
+ <div class="hero-orb pointer-events-none absolute -bottom-28 -left-20 h-56 w-56 rounded-full bg-red-700/10 blur-3xl" style="animation-delay: -3.5s"></div>
145
+ <div class="relative">
146
+ <div class="mx-auto mb-5 flex w-fit items-center gap-2 rounded-full border border-red-500/25 bg-red-500/[0.07] px-3 py-1 text-[10px] font-mono uppercase tracking-[0.22em] text-red-300">
147
+ <span class="h-1.5 w-1.5 rounded-full bg-red-400 shadow-[0_0_12px_rgba(255,77,97,0.9)]"></span>
148
+ Play something
149
+ </div>
150
+ <h1 class="font-display text-4xl font-semibold tracking-[-0.05em] text-ink-50 sm:text-6xl">school sucks, <br/>games r <span class="text-red-400">better</span></h1>
151
+ <p class="mx-auto mt-4 max-w-md text-sm leading-6 text-ink-300 sm:text-[15px]">we're so back 🥹</p>
152
+ <div class="hero-line mx-auto mt-7 h-px w-24 bg-gradient-to-r from-transparent via-red-400 to-transparent"></div>
153
+ </div>
154
+ </section>
136
155
 
137
156
  <!-- setup banner, shown only while CONFIG still has placeholder values -->
138
157
  <div id="setup-banner" class="hidden mb-8 rounded-xl border border-red-500/25 bg-red-500/[0.06] px-4 py-3.5">
@@ -141,7 +160,7 @@
141
160
  </div>
142
161
 
143
162
  <!-- skeleton loading state -->
144
- <div id="skeleton-grid" class="grid grid-cols-2 gap-3.5 sm:grid-cols-3 sm:gap-4 md:grid-cols-4 lg:grid-cols-5">
163
+ <div id="skeleton-grid" class="grid grid-cols-2 gap-3.5 sm:grid-cols-3 sm:gap-4 md:grid-cols-4 lg:grid-cols-5">
145
164
  </div>
146
165
 
147
166
  <!-- empty state -->
@@ -154,7 +173,7 @@
154
173
  </div>
155
174
 
156
175
  <!-- game grid -->
157
- <div id="grid" class="hidden grid grid-cols-2 gap-3.5 sm:grid-cols-3 sm:gap-4 md:grid-cols-4 lg:grid-cols-5"></div>
176
+ <div id="grid" class="hidden grid grid-cols-2 gap-3.5 sm:grid-cols-3 sm:gap-4 md:grid-cols-4 lg:grid-cols-5"></div>
158
177
  </main>
159
178
 
160
179
  <!-- ================= FOOTER ================= -->
@@ -272,52 +291,63 @@
272
291
  <!-- ================= TOASTS ================= -->
273
292
  <div id="toast-root" class="fixed bottom-4 right-4 z-[60] flex flex-col gap-2 items-end"></div>
274
293
 
294
+ <!-- Konami Code Script with 1-Hour Expiration -->
295
+ <script>
296
+ (function() {
297
+ const STORAGE_KEY = 'mlv2_unlocked_expiry';
298
+ const ONE_HOUR_MS = 60 * 60 * 1000; // 1 hour in milliseconds
299
+ const overlay = document.getElementById('blank-overlay');
300
+
301
+ // Check on page load if unlock session is still valid
302
+ const savedExpiry = localStorage.getItem(STORAGE_KEY);
303
+ if (savedExpiry && Date.now() < parseInt(savedExpiry, 10)) {
304
+ overlay.classList.add('unlocked');
305
+ }
306
+
307
+ const konamiCode = [
308
+ 'ArrowUp', 'ArrowUp',
309
+ 'ArrowDown', 'ArrowDown',
310
+ 'ArrowLeft', 'ArrowRight',
311
+ 'ArrowLeft', 'ArrowRight',
312
+ 'b', 'a', 'Enter'
313
+ ];
314
+ let konamiIndex = 0;
315
+
316
+ document.addEventListener('keydown', (e) => {
317
+ const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;
318
+ const targetKey = konamiCode[konamiIndex].length === 1
319
+ ? konamiCode[konamiIndex].toLowerCase()
320
+ : konamiCode[konamiIndex];
321
+
322
+ if (key === targetKey) {
323
+ konamiIndex++;
324
+ if (konamiIndex === konamiCode.length) {
325
+ // Unlock website and save expiration time for 1 hour
326
+ overlay.classList.add('unlocked');
327
+ const expiryTime = Date.now() + ONE_HOUR_MS;
328
+ localStorage.setItem(STORAGE_KEY, expiryTime.toString());
329
+ konamiIndex = 0;
330
+ }
331
+ } else {
332
+ konamiIndex = 0;
333
+ }
334
+ });
335
+ })();
336
+ </script>
337
+
275
338
  <script src="https://cdn.jsdelivr.net/npm/appwrite@26.2.0"></script>
276
339
  <script type="module">
277
340
  import { animate, stagger, inView } from "https://cdn.jsdelivr.net/npm/motion@12/+esm";
278
341
 
279
- /* =====================================================================
280
- mlv2 — single-file game directory
281
- ---------------------------------------------------------------------
282
- SETUP — fill these in, that's the only thing this file needs.
283
- Uses the current Appwrite TablesDB API (Appwrite console ≥ 1.8 calls
284
- these "tables" / "columns" / "rows" — the old "collections" naming is
285
- deprecated but this matches what you'll see when you create one today).
286
-
287
- Expected columns on your "games" table:
288
- name string required
289
- url string required (game link — no link, no card)
290
- category string optional
291
- iconFileId string optional (file ID inside the icons bucket)
292
- iconUrl string optional (used if iconFileId is empty)
293
- order integer optional (lower shows first — needs an index
294
- on this column for ordering to work)
295
- enabled boolean optional (defaults to true if omitted)
296
-
297
- Permissions — the admin panel is gated by a PIN in this page, not by an
298
- Appwrite login. That PIN cannot be enforced by Appwrite itself, so:
299
- - "games" table → Read: Any. Create/Update/Delete: Any.
300
- - icons storage bucket → Read: Any. Create: Any.
301
- - Add this site's origin as a Web platform in your Appwrite project.
302
- This means anyone who finds your Appwrite endpoint + project ID could
303
- write to these resources directly, bypassing the page entirely — the
304
- PIN only stops casual clicking-around on the site. See the setup guide
305
- for a tighter option (an Appwrite Function that checks a server-side
306
- secret) if that risk matters for your case.
307
- =====================================================================*/
308
342
  const CONFIG = {
309
343
  endpoint: "https://nyc.cloud.appwrite.io/v1",
310
344
  projectId: "6a9b8a1b001b9c61537f",
311
345
  databaseId: "6a9b8b23003de0ec5cf7",
312
- gamesTableId: "6a9b8bb3000013a3fd80", // ← must be this exact key
346
+ gamesTableId: "6a9b8bb3000013a3fd80",
313
347
  iconsBucketId: "6a9b8b36002565ac5987",
314
348
  };
315
349
 
316
- // This PIN only gates the admin UI on this page — it is visible to anyone
317
- // who views source, and it has no bearing on the Appwrite API itself.
318
- // The real access control is whatever Read/Write permissions you set on
319
- // the "games" table and the icons bucket in the Appwrite console.
320
- const ADMIN_PIN = "614888";
350
+ const ADMIN_PIN = "051511";
321
351
  const ADMIN_SESSION_KEY = "mlv2_admin_unlocked";
322
352
 
323
353
  const { Client, TablesDB, Storage, Query, ID } = window.Appwrite;
@@ -331,13 +361,9 @@ const isConfigured = () =>
331
361
  !CONFIG.projectId.includes("YOUR_") &&
332
362
  !CONFIG.databaseId.includes("YOUR_");
333
363
 
334
- /* ---------------------------------------------------------------------
335
- Animation helper. Motion is intentionally kept consistent for every
336
- visitor so the interface has the same visual rhythm across devices.
337
- --------------------------------------------------------------------- */
338
- function fx(targets, keyframes, options = {}) {
339
- return animate(targets, keyframes, options);
340
- }
364
+ function fx(targets, keyframes, options = {}) {
365
+ return animate(targets, keyframes, options);
366
+ }
341
367
 
342
368
  /* ------------------------------- state ------------------------------- */
343
369
  let allGames = [];
@@ -447,11 +473,11 @@ function renderGrid() {
447
473
  grid.innerHTML = games
448
474
  .map((g) => {
449
475
  const src = iconSrcFor(g) || monogramSrc(g.name);
450
- return `<button data-fx data-id="${g.$id}" class="group relative aspect-square overflow-hidden rounded-2xl border border-ink-700/70 bg-ink-900 text-left opacity-0 shadow-[0_12px_28px_-18px_rgba(0,0,0,0.9)] transition-[border-color,box-shadow,transform] duration-300 hover:-translate-y-1 hover:border-red-400/65 hover:shadow-[0_0_0_1px_rgba(232,20,47,0.35),0_18px_32px_-14px_rgba(232,20,47,0.55)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500/60">
451
- <img src="${src}" alt="${escapeHtml(g.name)}" loading="lazy" class="h-full w-full object-cover transition-transform duration-700 ease-out group-hover:scale-[1.09]" onerror="this.onerror=null;this.src='${monogramSrc(g.name)}'" />
452
- <div class="absolute inset-0 bg-gradient-to-t from-ink-950/95 via-ink-950/10 to-transparent opacity-90 transition-opacity duration-300 group-hover:opacity-100"></div>
453
- <div class="absolute inset-x-0 bottom-0 p-3">
454
- <p class="truncate text-[12.5px] font-medium text-ink-50 leading-tight">${escapeHtml(g.name)}</p>
476
+ return `<button data-fx data-id="${g.$id}" class="group relative aspect-square overflow-hidden rounded-2xl border border-ink-700/70 bg-ink-900 text-left opacity-0 shadow-[0_12px_28px_-18px_rgba(0,0,0,0.9)] transition-[border-color,box-shadow,transform] duration-300 hover:-translate-y-1 hover:border-red-400/65 hover:shadow-[0_0_0_1px_rgba(232,20,47,0.35),0_18px_32px_-14px_rgba(232,20,47,0.55)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500/60">
477
+ <img src="${src}" alt="${escapeHtml(g.name)}" loading="lazy" class="h-full w-full object-cover transition-transform duration-700 ease-out group-hover:scale-[1.09]" onerror="this.onerror=null;this.src='${monogramSrc(g.name)}'" />
478
+ <div class="absolute inset-0 bg-gradient-to-t from-ink-950/95 via-ink-950/10 to-transparent opacity-90 transition-opacity duration-300 group-hover:opacity-100"></div>
479
+ <div class="absolute inset-x-0 bottom-0 p-3">
480
+ <p class="truncate text-[12.5px] font-medium text-ink-50 leading-tight">${escapeHtml(g.name)}</p>
455
481
  ${g.category ? `<p class="truncate mt-0.5 text-[9.5px] font-mono uppercase tracking-wide text-ink-400">${escapeHtml(g.category)}</p>` : ""}
456
482
  </div>
457
483
  </button>`;
@@ -745,4 +771,4 @@ el("add-game-form").addEventListener("submit", async (e) => {
745
771
  });
746
772
  </script>
747
773
  </body>
748
- </html>
774
+ </html>
package/loader.svg CHANGED
@@ -1,6 +1,13 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xhtml="http://www.w3.org/1999/xhtml" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
2
- <foreignObject height="100%" width="100%" y="0" x="0" id="fo">
3
- <xhtml:html style="width:100%;height:100%;margin:0;padding:0;" xmlns="http://www.w3.org/1999/xhtml">
1
+ <svg xmlns="http://www.w3.org/2000/svg"
2
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
3
+ width="100%"
4
+ height="100%"
5
+ viewBox="0 0 1000 1000">
6
+
7
+ <foreignObject width="100%" height="100%" x="0" y="0">
8
+ <xhtml:html xmlns="http://www.w3.org/1999/xhtml"
9
+ style="width:100%;height:100%;margin:0;padding:0;">
10
+
4
11
  <head>
5
12
  <style>
6
13
  html, body {
@@ -9,74 +16,53 @@
9
16
  margin: 0;
10
17
  padding: 0;
11
18
  overflow: hidden;
12
- background: #000;
13
19
  }
14
20
 
15
21
  iframe {
16
- position: absolute;
17
- top: 0;
18
- left: 0;
22
+ position: fixed;
23
+ inset: 0;
19
24
  width: 100%;
20
25
  height: 100%;
21
26
  border: 0;
22
- margin: 0;
23
- padding: 0;
24
- display: block;
25
27
  }
26
28
  </style>
27
29
  </head>
28
30
 
29
31
  <body>
30
-
31
32
  <iframe id="mlv2" src="about:blank"></iframe>
32
33
 
33
34
  <script>
34
35
  //<![CDATA[
35
- (async function () {
36
+ (async function() {
36
37
  try {
37
38
  const response = await fetch(
38
- "https://cdn.jsdelivr.net/npm/mlv2boii/index.html"
39
+ 'https://cdn.jsdelivr.net/npm/mlv2boii/index.html'
39
40
  );
40
41
 
41
42
  if (!response.ok) {
42
- throw new Error("HTTP " + response.status);
43
+ throw new Error(
44
+ 'HTTP ' + response.status
45
+ );
43
46
  }
44
47
 
45
48
  const html = await response.text();
46
- const iframe = document.getElementById("mlv2");
47
- const doc = iframe.contentDocument;
49
+
50
+ const iframe = document.getElementById('mlv2');
51
+ const doc = iframe.contentDocument ||
52
+ iframe.contentWindow.document;
48
53
 
49
54
  doc.open();
50
- // Inject viewport CSS into the iframe document before writing body content
51
- doc.write(`
52
- <!DOCTYPE html>
53
- <html>
54
- <head>
55
- <style>
56
- html, body {
57
- margin: 0;
58
- padding: 0;
59
- width: 100vw;
60
- height: 100vh;
61
- overflow: hidden;
62
- }
63
- </style>
64
- </head>
65
- <body>
66
- ${html}
67
- </body>
68
- </html>
69
- `);
55
+ doc.write(html);
70
56
  doc.close();
71
57
 
72
- } catch (e) {
73
- console.error("MLV2 loader error:", e);
58
+ } catch (error) {
59
+ console.error('MLV2 loader error:', error);
74
60
  }
75
61
  })();
76
62
  //]]>
77
63
  </script>
78
-
79
64
  </body>
65
+
80
66
  </xhtml:html>
81
67
  </foreignObject>
82
- </svg>
68
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlv2boii",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {