“j/Place” is a collaborative pixel art platform inspired by Reddit’s r/place, allowing users to collectively create art on a shared 100x100 pixel canvas. The application features real-time Firebase synchronization, time-based access controls, and administrative override systems, creating a community-driven digital art experience.
place/
└── index.html # Complete collaborative canvas application (219 lines)
const firebaseConfig = {
apiKey: "AIzaSyDOxf4qulZfD3397qItNxSBmxewsMjRvjY",
authDomain: "joshbruceonline-place.firebaseapp.com",
databaseURL: "https://joshbruceonline-place-default-rtdb.europe-west1.firebasedatabase.app",
projectId: "joshbruceonline-place",
storageBucket: "joshbruceonline-place.appspot.com",
messagingSenderId: "64709899732",
appId: "1:64709899732:web:ae44c1bff52de856b9d241"
};
firebase.initializeApp(firebaseConfig);
const database = firebase.database();
const switchFirebaseConfig = {
apiKey: "AIzaSyCRPBjKJfKoLO52TqROpQ3I9X-nEL-0btE",
databaseURL: "https://joshbruceonline-switch-default-rtdb.europe-west1.firebasedatabase.app/",
authDomain: "joshbruceonline-switch.firebaseapp.com",
projectId: "joshbruceonline-switch",
storageBucket: "joshbruceonline-switch.appspot.com",
messagingSenderId: "592073701037",
appId: "1:592073701037:web:309eb7bed49885153a7824"
};
// Initialize Firebase with the 'switch' app instance
const switchApp = firebase.initializeApp(switchFirebaseConfig, 'switch');
const switchDb = switchApp.database();
const switchPageRef = switchDb.ref('place');
const redirectLinkRef = switchDb.ref('redirectLink');
.grid {
margin-top: 20px;
display: grid;
grid-template-columns: repeat(100, 20px); /* 100x100 grid with 20px squares */
grid-gap: 0; /* No gap between squares */
}
.square {
width: 20px;
height: 20px;
border: 1px solid #ccc;
}
// Create the grid and load colors from Firebase
for (let y = 0; y < 100; y++) {
for (let x = 0; x < 100; x++) {
const square = document.createElement("div");
square.classList.add("square");
square.dataset.x = x; /* Store coordinate data */
square.dataset.y = y;
canvas.appendChild(square);
// Load the color from Firebase
setColorFromFirebase(x, y);
}
}
// Data stored as: canvas/x_y
database.ref(`canvas/${x}_${y}`).set({
x: x,
y: y,
color: selectedColor
});
function setColorFromFirebase(x, y) {
const square = document.querySelector(`[data-x="${x}"][data-y="${y}"]`);
database.ref(`canvas/${x}_${y}`).on("value", (snapshot) => {
const data = snapshot.val();
if (data) {
square.style.backgroundColor = data.color;
} else {
square.style.backgroundColor = "white"; /* Default color */
}
});
}
function isTimeInRange() {
const now = new Date();
const startTime = new Date();
startTime.setHours(9, 0, 0); /* 9:00 AM start */
const endTime = new Date();
endTime.setHours(9, 1, 0); /* 9:01 AM end (1-minute window) */
return now >= startTime && now <= endTime;
}
// Check if the current time is within the specified range
if (isTimeInRange()) {
// Redirect to https://joshbruce.online
window.location.href = "https://joshbruce.online";
}
switchPageRef.on('value', (snapshot) => {
const isPageActive = snapshot.val();
if (isPageActive === false) {
// Get the 'redirectLink' value
redirectLinkRef.once('value', (snapshot) => {
const redirectLink = snapshot.val();
if (redirectLink) {
// Redirect to the 'redirectLink' value
window.location.href = redirectLink;
} else {
// If 'redirectLink' is not set, redirect to a default URL
window.location.href = 'https://joshbruce.online/backrooms';
}
});
}
});
body {
margin: 0;
padding: 0;
font-family: Helvetica, Arial, sans-serif;
text-align: center;
}
/* Center everything horizontally */
body, .grid, .color-menu {
display: flex;
flex-direction: column;
align-items: center;
}
<select id="color">
<option value="red">Red</option>
<option value="orange">Orange</option>
<option value="yellow">Yellow</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="cyan">Cyan</option>
<option value="pink">Pink</option>
<option value="purple">Purple</option>
<option value="black">Black</option>
<option value="brown">Brown</option>
<option value="grey">Grey</option>
<option value="white">White</option>
</select>
h1, label {
font-family: Helvetica, Arial, sans-serif;
font-weight: bold;
}
let selectedSquare = null;
// Add event listeners to grid squares
canvas.addEventListener("click", (event) => {
if (event.target.classList.contains("square")) {
const square = event.target;
selectedSquare = square;
square.style.backgroundColor = colorSelect.value; /* Preview color */
}
});
// Add event listener to submit button
submitButton.addEventListener("click", () => {
const name = nameInput.value;
const color = colorSelect.value;
// Get the selected square's coordinates
const x = selectedSquare.dataset.x;
const y = selectedSquare.dataset.y;
// Save the data to Firebase
database.ref(`canvas/${x}_${y}`).set({
x,
y,
color,
});
});
Standard Colors: Red, Orange, Yellow, Green, Blue, Cyan, Pink, Purple, Black, Brown, Grey, White Total Options: 12 distinct colors Format: HTML color names for simplicity
canvas/
├── 0_0: { x: 0, y: 0, color: "red" }
├── 0_1: { x: 0, y: 1, color: "blue" }
├── 1_0: { x: 1, y: 0, color: "green" }
└── ... (up to 99_99)
switch/
├── place: true/false
└── redirectLink: "https://example.com"
// Potential security concerns:
// - No rate limiting on pixel placement
// - No user authentication required
// - Public Firebase configuration exposed
// - Administrative database credentials visible
j/Place represents a creative implementation of collaborative digital art, successfully combining real-time synchronization with sophisticated access controls. The dual-Firebase architecture and time-based restrictions create a unique social experiment in digital community art creation.
Technical Rating: 8.1/10
The application successfully creates an engaging social art platform that demonstrates advanced real-time web technologies while fostering community creativity within controlled parameters.