-
Notifications
You must be signed in to change notification settings - Fork 122
Open
Description
Error code
ERRW:0.85:K1.0:SL0.1:PU0.05:AS
Were you logged in?
Yes
Your username (if logged in)
KanYe_West
Your HTML
<link rel="icon" type="image/png" href="favicon.jpg">
<link rel="stylesheet" href="style.css">
<header>
<div class="header-left">
<img src="favicon.jpg" alt="favicon" class="header-favicon">
<span class="header-title">Two Sentence Horrors</span>
</div>
<div class="header-center">
<span class="creator">made for <a href="https://www.tiktok.com/@jarrett_warlick" class="header-link"
target="_blank">@Jarrett_Warlick</a></span>
<button class="info-btn" id="infoBtn" aria-label="Information">about</button>
<a href="/projects" class="info-btn" aria-label="More Games">more games</a>
<div class="share-container">
<button class="info-btn" id="shareBtn" aria-label="Share">share</button>
<div id="copyToast" class="copy-toast">Copied!</div>
</div>
</div>
<div class="header-right">
<span class="creator">by <a href="/" target="_blank">fish-eater</a></span>
<button class="donate-btn" onclick="window.open('https://buymeacoffee.com/wyattkarnes', '_blank')">Donate</button>
</div>
</header>
<main>
<div class="main-layout">
<!-- About Panel -->
<div class="about-panel" id="aboutPanel">
<div class="about-content">
<button class="panel-close" id="closePanel">×</button>
<h3>about this game</h3>
<p>try to guess the horror story from the first sentence</p>
<p>this site was made for my friend, Jarrett, for his tiktok page</p>
<p><strong><a href="https://git.disroot.org/fisheater/2sentenceexplorer">Source Code</a></strong></p>
<p>any questions or if you want me to make you something:</p>
<p><strong>Contact:</strong> <a href="mailto:wyattekarnes@gmail.com">wyattekarnes@gmail.com</a></p>
</div>
</div>
<!-- Content Column -->
<div class="content-column">
<!-- Game Container -->
<div class="game-container">
<div class="story" id="story"><span class="loading">loading horror...</span></div>
<div class="selectors">
<select id="subreddit">
<option value="TwoSentenceHorror">r/TwoSentenceHorror</option>
<option value="badtwosentencehorrors">r/badtwosentencehorrors</option>
</select>
<select id="sort">
<option value="year">popular (recent)</option>
<option value="all">popular (all time)</option>
<option value="random">random</option>
</select>
<button id="reload">more</button>
</div>
</div>
<!-- Comments Card -->
<div id="commentsOverlay" class="comments-card">
<iframe src="/creation/comments?url=2sentenceexplorer" class="comments-iframe" id="commentsIframe"></iframe>
</div>
</div>
</div>
</main>
<button id="showCommentsBtn" class="comments-trigger">show comments</button>
<script src="script.js"></script>Your JavaScript
const CORS_PROXY = "https://cors.eu.org/";
// if cors.eu.org is down:
// https://cors.io/?u=
// https://corsproxy.io/?url=
const POST_LIMIT = 600;
let stories = [], index = 0, lastSub = "", lastSort = "";
const shuffle = arr => {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
};
async function getStories(sub, sort) {
const base = `https://www.reddit.com/r/${sub}/`;
let url = (sort === "all" || sort === "year")
? `${base}top.json?t=${sort}&limit=${POST_LIMIT}`
: `${base}new.json?limit=${POST_LIMIT}`;
const resp = await fetch(CORS_PROXY + encodeURIComponent(url));
if (!resp.ok) throw new Error("Fetch error or CORS fail");
const data = await resp.json();
return data.data.children.filter(p =>
!p.data.stickied && !p.data.over_18 &&
p.data.selftext && p.data.selftext !== '[removed]' && p.data.selftext !== '[deleted]'
).map(p => ({
title: p.data.title,
text: p.data.selftext.trim(),
score: p.data.score
}));
}
function renderStory(story) {
const censoredText = story.text.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, ' ');
document.getElementById("story").innerHTML =
`<span class="first-sentence">${story.title}</span>
<span class="censor-block" id="hiddenSentence" title="reveal">
<mark class="censor-highlight">${censoredText}</mark>
</span>
<span class="upvotes">${story.score.toLocaleString()} upvotes</span>`;
const el = document.getElementById("hiddenSentence");
const mark = el.querySelector('.censor-highlight');
let isRevealed = false;
el.addEventListener('click', function () {
if (isRevealed) {
mark.textContent = censoredText;
mark.style.background = '#101010';
mark.style.color = '#101010';
el.setAttribute("title", "reveal");
} else {
mark.textContent = story.text;
mark.style.background = 'transparent';
mark.style.color = '#181818';
el.removeAttribute("title");
}
isRevealed = !isRevealed;
});
}
async function loadStoriesAndShow(resetIdx = true) {
const sub = document.getElementById("subreddit").value;
const sort = document.getElementById("sort").value;
document.getElementById("story").innerHTML = '<span class="loading">loading horror...</span>';
try {
// fetch if options changed or none loaded yet
if (sub !== lastSub || sort !== lastSort || !stories.length) {
stories = shuffle(await getStories(sub, sort));
lastSub = sub; lastSort = sort;
if (resetIdx) index = 0;
}
if (!stories.length) throw new Error("No stories found.");
renderStory(stories[index]);
} catch (e) {
document.getElementById("story").innerHTML =
`<span class="loading">failed to load: ${e.message}</span>`;
}
}
function nextStory() {
if (!stories.length) { loadStoriesAndShow(); return; }
index = (index + 1) % stories.length;
renderStory(stories[index]);
}
document.getElementById("reload").onclick = nextStory;
document.getElementById("subreddit").onchange = () => loadStoriesAndShow();
document.getElementById("sort").onchange = () => loadStoriesAndShow();
window.onload = () => loadStoriesAndShow();
// about panel functionality
const infoBtn = document.getElementById('infoBtn');
const aboutPanel = document.getElementById('aboutPanel');
const closePanel = document.getElementById('closePanel');
function togglePanel(e) {
if (e) e.stopPropagation();
if (aboutPanel) {
aboutPanel.classList.toggle('closed');
}
}
if (infoBtn) {
infoBtn.addEventListener('click', togglePanel);
}
if (closePanel) {
closePanel.addEventListener('click', togglePanel);
}
// close panel with Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && aboutPanel && !aboutPanel.classList.contains('closed')) {
aboutPanel.classList.add('closed');
}
});
// share button functionality
const shareBtn = document.getElementById("shareBtn");
const copyToast = document.getElementById("copyToast");
if (shareBtn && copyToast) {
shareBtn.addEventListener("click", () => {
navigator.clipboard.writeText(window.location.href).then(() => {
copyToast.classList.add("show");
setTimeout(() => {
copyToast.classList.remove("show");
}, 2000);
}).catch(err => {
console.error("Failed to copy: ", err);
});
});
}
// clicking the favicon 5 times disables the background (easter egg)
let clickCount = 0;
let backgroundEnabled = false; // Disabled by default as requested
const headerFavicon = document.querySelector('.header-favicon');
if (headerFavicon) {
headerFavicon.addEventListener('click', (e) => {
e.preventDefault();
clickCount++;
console.log(`Favicon clicked! Count: ${clickCount}`);
// toggle background on 5th click
if (clickCount === 5) {
backgroundEnabled = !backgroundEnabled;
const container = document.querySelector('.game-container'); // Updated selector
if (backgroundEnabled) {
// Show background
if (container) container.classList.add('has-background');
console.log('Background enabled');
} else {
// Hide background
if (container) container.classList.remove('has-background');
console.log('Background disabled');
}
clickCount = 0;
}
});
}
// Comments overlay functionality
const showCommentsBtn = document.getElementById('showCommentsBtn');
const commentsOverlay = document.getElementById('commentsOverlay');
const commentsIframe = document.getElementById('commentsIframe');
let commentCount = 0;
async function fetchCommentCount() {
try {
const response = await fetch('/creation/comment_count.py?page=2sentenceexplorer');
if (response.ok) {
const data = await response.json();
commentCount = data.count || 0;
updateButtonText();
}
} catch (error) {
console.error('Failed to fetch comment count:', error);
}
}
function updateButtonText() {
if (!showCommentsBtn) return;
const countText = commentCount > 0 ? ` (${commentCount})` : '';
if (commentsOverlay.classList.contains('open')) {
showCommentsBtn.textContent = `hide comments${countText}`;
} else {
showCommentsBtn.textContent = `show comments${countText}`;
}
}
if (showCommentsBtn && commentsOverlay) {
showCommentsBtn.addEventListener('click', () => {
commentsOverlay.classList.toggle('open');
updateButtonText();
});
// Fetch count on load
fetchCommentCount();
// Dark scrollbar for iframe
if (commentsIframe) {
commentsIframe.onload = () => {
try {
const doc = commentsIframe.contentDocument;
if (doc) {
const style = doc.createElement('style');
style.textContent = `
body { color-scheme: dark; }
::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: #191919; }
::-webkit-scrollbar-thumb { background: #444; border-radius: 6px; border: 3px solid #191919; }
::-webkit-scrollbar-thumb:hover { background: #555; }
* { scrollbar-color: #444 #191919; }
`;
doc.head.appendChild(style);
}
} catch (e) {
console.warn("Cannot style iframe scrollbar (cross-origin?)");
}
};
}
}Your CSS
body {
background: #fff;
font-family: Georgia, serif;
display: flex;
flex-direction: column;
margin: 0;
min-height: 100vh;
overflow-x: hidden;
position: relative;
}
@keyframes moveDiagonal {
from {
background-position: 0 0;
}
to {
background-position: 422px 140px;
}
}
header {
width: 100%;
padding: 0.6em;
background: #191919;
color: #fff;
font-size: 1.1em;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
position: sticky;
top: 0;
z-index: 10;
box-shadow: 0 1.5px 6px #ccc;
box-sizing: border-box;
gap: 1em;
}
.header-left,
.header-right {
flex: 1;
display: flex;
align-items: center;
min-width: fit-content;
}
.header-right {
justify-content: flex-end;
}
.header-favicon {
width: 28px;
height: 28px;
flex-shrink: 0;
border-radius: 4px;
cursor: pointer;
transition: transform 0.3s;
padding-right: 10px;
}
.header-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.header-center {
display: flex;
align-items: center;
gap: 1.5em;
justify-content: center;
}
.header-link {
text-decoration: none;
font-size: 0.9em;
white-space: nowrap;
transition: opacity 0.2s;
}
.header-link:hover {
opacity: 0.8;
}
.info-btn {
background: transparent;
border: 1.5px solid #fff;
color: #fff;
border-radius: 5px;
font-size: 0.75em;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 7px 18px;
transition: background 0.2s, transform 0.15s;
font-weight: bold;
line-height: 1;
}
.info-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.1);
}
.share-container {
position: relative;
display: flex;
align-items: center;
}
.copy-toast {
position: absolute;
top: 110%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 4px 10px;
border-radius: 4px;
font-size: 0.7em;
font-family: sans-serif;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
white-space: nowrap;
z-index: 100;
}
.copy-toast.show {
opacity: 1;
}
/* Layout */
.main-layout {
display: flex;
align-items: flex-start;
justify-content: center;
gap: 20px;
width: 100%;
max-width: 1200px;
padding: 0 16px;
box-sizing: border-box;
margin-top: 1.6em;
transition: all 0.3s ease;
}
.about-panel {
width: 300px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 1;
transform: translateX(0);
margin-right: 0;
height: fit-content;
position: relative;
flex-shrink: 0;
}
.about-panel.closed {
width: 0;
opacity: 0;
margin-right: -20px;
/* Compensate for grid gap */
padding: 0;
transform: translateX(-20px);
pointer-events: none;
}
.about-content {
padding: 24px;
width: 300px;
/* Force width to prevent reflow */
box-sizing: border-box;
}
.about-content h3 {
margin: 0 0 1em;
color: #191919;
font-size: 1.2em;
}
.about-content p {
margin: 0.8em 0;
line-height: 1.5;
color: #333;
font-size: 0.95em;
}
.about-content a {
color: #191919;
text-decoration: underline;
font-weight: 600;
}
.panel-close {
position: absolute;
top: 10px;
right: 10px;
background: transparent;
border: none;
font-size: 1.8em;
color: #999;
cursor: pointer;
line-height: 1;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
transition: color 0.2s;
}
.panel-close:hover {
color: #333;
}
/* Header Right Styles */
.header-right {
display: flex;
align-items: center;
gap: 0.8em;
flex-shrink: 0;
}
header .creator {
font-size: 0.85em;
font-style: italic;
white-space: nowrap;
flex-shrink: 0;
}
.donate-btn {
font-size: 0.85em;
padding: 5px 12px;
background: #fff;
color: #191919;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s, transform 0.15s;
font-family: Georgia, serif;
font-weight: 600;
white-space: nowrap;
}
.donate-btn:hover {
background: #f0f0f0;
transform: scale(1.05);
}
.donate-btn:active {
background: #e0e0e0;
}
main {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.game-container {
width: 100%;
text-align: center;
border-radius: 12px;
box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.15);
position: relative;
overflow: hidden;
background: rgba(255, 255, 255, 0.8);
padding: 26px 16px 20px 16px;
transition: all 0.3s ease;
}
.game-container::before {
content: '';
position: absolute;
inset: 0;
background-image: url('graphic.png');
background-repeat: repeat;
background-size: 422px 140px;
animation: moveDiagonal 30s linear infinite;
opacity: 0.2;
z-index: 0;
pointer-events: none;
display: none;
}
.game-container>* {
position: relative;
z-index: 1;
}
.game-container.has-background::before {
display: block;
}
.story {
font-size: 1.2em;
line-height: 1.55;
color: #181818;
margin-bottom: 3px;
word-break: break-word;
}
.first-sentence {
font-weight: 500;
display: block;
margin-bottom: 7px;
}
.censor-block {
font-style: italic;
font-weight: 500;
cursor: pointer;
user-select: none;
display: inline;
}
.censor-highlight {
background: #101010;
color: #101010;
border-radius: 3px;
padding: 2px 4px;
transition: background 0.15s, color 0.15s;
display: inline;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
}
.upvotes {
display: block;
font-size: 14px;
color: #6c6c4e;
font-style: italic;
margin-top: 7px;
margin-bottom: 1px;
letter-spacing: 0.1em;
}
.loading {
font-size: 18px;
color: #999;
margin: 1em 0;
}
.selectors {
display: flex;
gap: 10px;
justify-content: center;
margin-top: 15px;
flex-wrap: wrap;
}
select,
button {
font-family: inherit;
padding: 7px 9px;
font-size: 15px;
border-radius: 4px;
border: 1.3px solid #aaa;
background: #fcfcfc;
margin-bottom: 0;
}
button {
font-size: 16px;
border: none;
background: #191919;
color: #fff;
border-radius: 5px;
cursor: pointer;
margin-left: 12px;
font-family: Georgia, serif;
transition: background 0.18s, transform 0.15s;
padding: 7px 18px;
display: inline-block;
}
button:hover {
transform: scale(1.06);
}
button:active {
background: #444;
}
a {
color: #777;
text-decoration: none;
transition: transform 0.15s;
display: inline-block;
}
a:hover {
transform: scale(1.05);
}
@media (max-width: 900px) {
.main-layout {
flex-direction: column;
align-items: center;
}
.about-panel {
width: 100%;
max-width: 700px;
margin-right: 0;
margin-bottom: 20px;
}
.about-panel.closed {
margin-bottom: -300px;
margin-right: 0;
transform: translateY(-20px);
opacity: 0;
}
.about-content {
width: 100%;
}
}
@media (max-width: 500px) {
.header-left,
.header-right,
.header-center {
flex: 1 1 100%;
justify-content: center;
text-align: center;
}
header .creator {
font-size: 0.75em;
}
.donate-btn {
font-size: 0.75em;
padding: 4px 10px;
}
.header-favicon {
width: 24px;
height: 24px;
}
.header-title {
font-size: 0.9em;
}
}
/* Content Column for stacking game and comments */
.content-column {
flex: 1;
max-width: 1000px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.game-container {
width: 100%;
max-width: 700px;
text-align: center;
border-radius: 12px;
box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.15);
position: relative;
overflow: hidden;
background: rgba(255, 255, 255, 0.8);
padding: 26px 16px 20px 16px;
transition: all 0.3s ease;
}
/* Comments Section Styles */
.comments-trigger {
position: fixed;
bottom: 20px;
left: 20px;
z-index: 100;
margin: 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.comments-card {
width: 100%;
height: 0;
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
opacity: 0;
pointer-events: none;
margin-top: 0;
border: 8px solid #191919;
box-sizing: border-box;
}
.comments-card.open {
height: 600px;
opacity: 1;
pointer-events: all;
margin-top: 20px;
}
.comments-iframe {
flex: 1;
border: none;
width: 100%;
height: 100%;
color-scheme: dark;
}
@media (max-width: 500px) {
.comments-card.open {
height: 600px;
/* Keep height consistent or auto? */
}
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels