diff --git a/polaris.config.js b/polaris.config.js
index 4f918d0..fda6cdf 100644
--- a/polaris.config.js
+++ b/polaris.config.js
@@ -1,4 +1,4 @@
-import configTemplate from './polaris.config.template.js';
+import configTemplate from './polaris.config.template.js';
/**
* @type {configTemplate}
@@ -6,7 +6,7 @@ import configTemplate from './polaris.config.template.js';
export default {
port: 8080,
mode: 'dev',
- minify: true,
+ minify: false,
assetScrambling: true,
allowDangerousTemplateInsert: true
};
\ No newline at end of file
diff --git a/server/index.js b/server/index.js
index 3f91907..3996093 100644
--- a/server/index.js
+++ b/server/index.js
@@ -15,7 +15,7 @@ const app = express();
const server = http.createServer();
const bareServer = createBareServer('/bare/');
const mode = (process.argv[2] === 'prod' || process.argv[2] === 'dev' ? process.argv[2] : (process.argv[3] === 'prod' || process.argv[3] === 'dev' ? process.argv[3] : (config.mode === 'prod' || config.mode === 'dev' ? config.mode : 'prod')));
-const port = (process.argv[2] !== 'prod' && process.argv[2] !== 'dev' && Boolean(Number(process.argv[2]))) ? process.argv[2] : (Boolean(Number(process.argv[3])) ? process.argv[3] : (Boolean(Number(config.port)) ? config.port : (mode === 'prod' ? 80 : 8080 ) ));
+const port = (process.argv[2] !== 'prod' && process.argv[2] !== 'dev' && Boolean(Number(process.argv[2]))) ? process.argv[2] : (Boolean(Number(process.argv[3])) ? process.argv[3] : (Boolean(Number(config.port)) ? config.port : (mode === 'prod' ? 80 : 8080)));
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
app.get('/cdn/*', cors({
@@ -61,7 +61,7 @@ app.get('/asset/:token', async (req, res, next) => {
TokenManager.delete(req.params.token);
res.setHeader('content-type', token.data.type);
- res.end(await rewriter.auto(fs.readFileSync(token.data.asset), token.data.type));
+ res.end(await rewriter.auto(fs.readFileSync(token.data.asset), token.data.type, token.data.asset.replace(path.join(__dirname, '../static'), '')));
} else next();
} else next();
}
@@ -73,21 +73,27 @@ app.get('/uv/service*', async (req, res) => {
});
app.use(async (req, res, next) => {
- const {
- exists,
- path: filePath
- } = pathToFile(req.path, path.join(__dirname, '../static'));
+ if (req.path === '/index') res.redirect('/');
+ else {
+ const {
+ exists,
+ path: filePath
+ } = pathToFile(req.path, path.join(__dirname, '../static'));
- if (exists) {
- res.setHeader('content-type', mime.getType(filePath));
+ if (exists) {
+ if (req.path.endsWith('.html')) res.redirect(req.path.slice(0, -5));
+ else {
+ res.setHeader('content-type', mime.getType(filePath));
- if (mime.getType(filePath) === 'text/html') res.end(await rewriter.html(fs.readFileSync(filePath)));
- else if (mime.getType(filePath) === 'text/javascript') res.end(await rewriter.javascript(fs.readFileSync(filePath)));
- else if (mime.getType(filePath) === 'text/css') res.end(await rewriter.css(fs.readFileSync(filePath)));
- else res.sendFile(filePath);
- } else {
- res.setHeader('content-type', 'text/html');
- res.status(404).end(await rewriter.html(fs.readFileSync(path.join(__dirname, '../pages/404.html'))));
+ if (mime.getType(filePath) === 'text/html') res.end(await rewriter.html(fs.readFileSync(filePath), req.path));
+ else if (mime.getType(filePath) === 'text/javascript') res.end(await rewriter.javascript(fs.readFileSync(filePath), req.path));
+ else if (mime.getType(filePath) === 'text/css') res.end(await rewriter.css(fs.readFileSync(filePath), req.path));
+ else res.sendFile(filePath);
+ }
+ } else {
+ res.setHeader('content-type', 'text/html');
+ res.status(404).end(await rewriter.html(fs.readFileSync(path.join(__dirname, '../pages/404.html'))));
+ }
}
});
diff --git a/server/utils/rewriter.js b/server/utils/rewriter.js
index e41114e..2695093 100644
--- a/server/utils/rewriter.js
+++ b/server/utils/rewriter.js
@@ -92,43 +92,54 @@ const html = (data) => {
});
};
-const javascript = (data) => {
+const javascript = (data, filePath) => {
return new Promise((resolve, reject) => {
const imports = String(data).split('import ')
.map(data => data.split('from ')[1])
.filter(data => Boolean(data))
- .map(data => data.split(';')[0]
+ .map(data => data.split('\n')[0]
.replaceAll('\'', '')
.replaceAll('`', '')
- .replaceAll('"', ''))
- .filter(data => fs.existsSync(path.join(__dirname, '../templates', data + '.javascript')));
-
+ .replaceAll('"', '')
+ .replaceAll(';', ''))
+ .map(data => {
+ if (data.startsWith('./')) return {
+ originalFile: data,
+ newFile: path.join(filePath.split('/').slice(0, -1).join('/'), data)
+ };
+ else if (data.startsWith('../')) return {
+ originalFile: data,
+ newFile: path.join(filePath.split('/').slice(0, -1).join('/'), data)
+ };
+ else return {
+ originalFile: data,
+ newFile: data
+ };
+ })
+ .filter(data => fs.existsSync(path.join(__dirname, '../static', data.newFile)));
let javascript = String(data);
- if (config.assetScrambling) for (let i = 0; i < imports.length; i++) {
- javascript = javascript.replace(imports[i], '/asset/' + TokenManager.generate('asset', 20000, {
- asset: path.join(__dirname, '../static', imports[i]),
- type: 'text/javascript'
- }).token);
- }
+ if (config.assetScrambling) for (let i = 0; i < imports.length; i++) javascript = javascript.replace(imports[i].originalFile, '/asset/' + TokenManager.generate('asset', 20000, {
+ asset: path.join(__dirname, '../static', imports[i].newFile),
+ type: 'text/javascript'
+ }).token);
- if (config.minify) resolve(JavaScriptObfuscator.obfuscate(javascript,
- {
- compact: true,
- controlFlowFlattening: true,
- controlFlowFlatteningThreshold: 1,
- numbersToExpressions: true,
- simplify: true,
- stringArrayShuffle: true,
- splitStrings: true,
- stringArrayThreshold: 1
- }).getObfuscatedCode());
+ if (config.minify) resolve(JavaScriptObfuscator.obfuscate(javascript, {
+ compact: true,
+ controlFlowFlattening: true,
+ controlFlowFlatteningThreshold: 1,
+ numbersToExpressions: true,
+ simplify: true,
+ stringArrayShuffle: true,
+ splitStrings: true,
+ stringArrayThreshold: 1
+ }).getObfuscatedCode());
else resolve(javascript);
});
};
-const css = (data) => {
+const css = (data, filePath) => {
return new Promise((resolve, reject) => {
const imports = String(data).split('url(')
.map(data => {
@@ -143,37 +154,48 @@ const css = (data) => {
else return undefined;
})
.filter(data => {
- if (data) {
- try {
- new URL(data);
+ if (data) try {
+ new URL(data);
- return false;
- } catch (e) {
- if (data.startsWith('/')) return true;
- else return false;
- }
+ return false;
+ } catch (e) {
+ return true;
} else return false;
})
- .filter(data => fs.existsSync(path.join(__dirname, '../templates', data + mime.getExtension(data))));
+ .map(data => {
+ // console.log(path.join(filePath.split('/').slice(0, -1).join('/')));
+
+ if (data.startsWith('./')) return {
+ originalFile: data,
+ newFile: path.join(filePath.split('/').slice(0, -1).join('/'), data)
+ };
+ else if (data.startsWith('../')) return {
+ originalFile: data,
+ newFile: path.join(filePath.split('/').slice(0, -1).join('/'), data)
+ };
+ else return {
+ originalFile: data,
+ newFile: data
+ };
+ })
+ .filter(data => fs.existsSync(path.join(__dirname, '../static', data.newFile)));
let css = String(data);
- if (config.assetScrambling) for (let i = 0; i < imports.length; i++) {
- css = css.replace(imports[i], '/asset/' + TokenManager.generate('asset', 20000, {
- asset: path.join(__dirname, '../static', imports[i]),
- type: mime.getType(path.join(__dirname, '../static', imports[i]))
- }).token);
- }
-
+ if (config.assetScrambling) for (let i = 0; i < imports.length; i++) css = css.replace(imports[i].originalFile, '/asset/' + TokenManager.generate('asset', 20000, {
+ asset: path.join(__dirname, '../static', imports[i].newFile),
+ type: mime.getType(path.join(__dirname, '../static', imports[i].newFile))
+ }).token);
+
if (config.minify) resolve(css.replace(/(\r\n|\n|\r)/gm, '').replaceAll(' ', ' '));
else resolve(css);
});
};
-const auto = async (data, type) => {
+const auto = async (data, type, filePath) => {
if (type === 'text/html') return await html(data);
- else if (type === 'text/javascript' || type === 'application/javascript') return await javascript(data);
- else if (type === 'text/css') return await css(data);
+ else if (type === 'text/javascript' || type === 'application/javascript') return await javascript(data, filePath);
+ else if (type === 'text/css') return await css(data, filePath);
else return data;
};
diff --git a/static/apps.html b/static/apps.html
index 963ca2d..ecedb57 100644
--- a/static/apps.html
+++ b/static/apps.html
@@ -15,12 +15,14 @@
-
+
+
+
diff --git a/static/assets/JSON/changelog.json b/static/assets/JSON/changelog.json
index a94e214..73f9ee7 100644
--- a/static/assets/JSON/changelog.json
+++ b/static/assets/JSON/changelog.json
@@ -1,7 +1,7 @@
[
{
- "date": "some/time/2023?",
- "simpleDescription": "Version 1.2 Release"
+ "date": "1/1/2024",
+ "simpleDescription": "2024 Update!!!"
},
{
"date": "11/23/2023",
diff --git a/static/assets/css/footer.css b/static/assets/css/footer.css
new file mode 100644
index 0000000..8d4ecf7
--- /dev/null
+++ b/static/assets/css/footer.css
@@ -0,0 +1,89 @@
+footer {
+ position: relative;
+ text-align: left;
+ background-image: url('/assets/img/background.jpeg');
+ background-attachment: fixed;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ user-select: none;
+ padding: 4% 5% 2% 5%;
+ color: #fff;
+ margin-top: 50px;
+ text-shadow: 0px 0px 20px rgba(0, 0, 0, 0.616);
+}
+
+footer p {
+ text-shadow: 0px 0px 20px rgba(0, 0, 0, 0.616);
+}
+
+footer h1 {
+ font-family: 'Lato-Black';
+ color: #fff;
+ margin: 0px;
+ margin-bottom: 10px;
+}
+
+footer::before {
+ display: block;
+ content: '';
+ height: 270px;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100vw;
+ z-index: -1;
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
+}
+
+footer .socials {
+ margin-bottom: 20px;
+}
+
+footer .socials i {
+ margin: 10px;
+ margin-left: 5px;
+ margin-right: 5px;
+ font-size: 20px;
+ cursor: pointer;
+}
+
+footer .socials a {
+ color: #fff;
+}
+
+footer .socials a:hover {
+ color: #fff;
+}
+
+footer .socials a::before {
+ display: none;
+}
+
+footer .socials i:is(:first-child) {
+ margin-left: 0px;
+}
+
+footer .right {
+ position: absolute;
+ right: 5%;
+ text-align: right;
+}
+
+footer .right a {
+ display: block;
+ margin-top: 20px;
+}
+
+footer .title:not(:last-child) {
+ display: flex;
+ margin: 0px;
+}
+
+footer .title img {
+ width: 40px;
+ height: 40px;
+ margin-left: 10px;
+ filter: drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.616));
+ border-radius: 1vh;
+}
\ No newline at end of file
diff --git a/static/assets/css/main.css b/static/assets/css/main.css
index 4f56977..4599427 100644
--- a/static/assets/css/main.css
+++ b/static/assets/css/main.css
@@ -1,9 +1,10 @@
@import url('https://site-assets.fontawesome.com/releases/v6.2.0/css/all.css');
-@import url('/assets/css/fonts.css');
-@import url('/assets/css/themes.css');
-@import url('/assets/css/nav.css');
-@import url('/assets/css/sidebar.css');
-@import url('/assets/css/dropdown.css');
+@import url('./fonts.css');
+@import url('./themes.css');
+@import url('./nav.css');
+@import url('./sidebar.css');
+@import url('./dropdown.css');
+@import url('./footer.css');
* {
font-family: 'Lato';
@@ -21,6 +22,10 @@ body {
background-repeat: no-repeat;
}
+.centered {
+ text-align: center;
+}
+
html {
min-height: 100%;
}
@@ -517,6 +522,11 @@ img.featured:hover {
transition: border 0.5s linear;
}
+.content {
+ margin-left: 100px;
+ margin-right: 100px;
+}
+
@keyframes beat {
0%,
50%,
diff --git a/static/assets/js/apps.js b/static/assets/js/apps.js
index 6b1146e..0659851 100644
--- a/static/assets/js/apps.js
+++ b/static/assets/js/apps.js
@@ -1,5 +1,5 @@
-import PolarisError from '/assets/js/error.js';
-import { loadWorker } from '/assets/js/wpm.js';
+import { loadProxyWorker } from './utils.js';
+import PolarisError from './error.js';
const tiltEffectSettings = {
max: 8,
@@ -18,7 +18,8 @@ const load = () => {
document.querySelector('.apps').appendChild(el);
el.addEventListener('click', async () => {
- await loadWorker('uv');
+ await loadProxyWorker('uv');
+
localStorage.setItem('frameData', JSON.stringify({
type: 'app',
app
@@ -67,4 +68,4 @@ function setTransition(event) {
export default {
load
-};
+};
\ No newline at end of file
diff --git a/static/assets/js/cheats.js b/static/assets/js/cheats.js
index 12c9388..0925126 100644
--- a/static/assets/js/cheats.js
+++ b/static/assets/js/cheats.js
@@ -1,4 +1,4 @@
-import PolarisError from '/assets/js/error.js';
+import PolarisError from './error.js';
const tiltEffectSettings = {
max: 8,
diff --git a/static/assets/js/eastereggs.js b/static/assets/js/eastereggs.js
index d8a38e0..57db5c2 100644
--- a/static/assets/js/eastereggs.js
+++ b/static/assets/js/eastereggs.js
@@ -161,7 +161,7 @@ easterEggs.push({
font-size: 5.5vh;
left: 50%;
-ms-transform: translate(-50%);
- transform: translate(-50%);">Hamster`;
+ transform: translate(-50%);">Hamter`;
menu.appendChild(caller);
const call = document.createElement('div');
diff --git a/static/assets/js/frame.js b/static/assets/js/frame.js
index e901ee7..3c7ac1a 100644
--- a/static/assets/js/frame.js
+++ b/static/assets/js/frame.js
@@ -1,6 +1,5 @@
const load = () => {
let frameData = JSON.parse(localStorage.getItem('frameData'));
- if (!frameData) location.href = '/';
const iframe = document.querySelector('.frame');
@@ -29,7 +28,7 @@ const load = () => {
document.querySelector('#gameicon').src = "https://cdn3.iconfinder.com/data/icons/feather-5/24/search-512.png";
document.querySelector('#gametitle').textContent = "Proxy";
} else document.querySelector('#gametitle').textContent = 'Failed to load proxy.';
- } else location.href = '/';
+ }
document.querySelector('#fullscreen').addEventListener('click', () => {
const iframe = document.querySelector('.frame');
diff --git a/static/assets/js/games.js b/static/assets/js/games.js
index 74c7807..8ef809c 100644
--- a/static/assets/js/games.js
+++ b/static/assets/js/games.js
@@ -1,31 +1,28 @@
-import PolarisError from './error.js';
-import { workerLoaded, loadWorker } from './wpm.js';
+import PolarisError from '/assets/js/error.js';
+import { loadProxyWorker } from '/assets/js/utils.js';
const tiltEffectSettings = {
- max: 8, // max tilt rotation (degrees (deg))
- perspective: 1000, // transform perspective, the lower the more extreme the tilt gets (pixels (px))
- scale: 1.05, // transform scale - 2 = 200%, 1.5 = 150%, etc..
- speed: 800, // speed (transition-duration) of the enter/exit transition (milliseconds (ms))
- easing: 'cubic-bezier(.03,.98,.52,.99)' // easing (transition-timing-function) of the enter/exit transition
+ max: 8,
+ perspective: 1000,
+ scale: 1.05,
+ speed: 800,
+ easing: 'cubic-bezier(.03,.98,.52,.99)'
};
-let games = []; // store all games
-let filteredGames = []; // store filtered games
+let games = [];
+let filteredGames = [];
const load = () => {
fetch('/assets/JSON/games.json').then(res => res.json()).then(data => {
games = data;
- filteredGames = games; // initialize filtered games with all games
+ filteredGames = games;
- renderGames(filteredGames); // render games initially
+ renderGames(filteredGames);
- // Add event listener to search input
const searchInput = document.getElementById('searchInput');
searchInput.addEventListener('input', filterGames);
})
- .catch(e => {
- new PolarisError('Failed to load games');
- });
+ .catch(e => new PolarisError('Failed to load games'));
};
function filterGames() {
@@ -34,20 +31,14 @@ function filterGames() {
filteredGames = games.filter(game => game.name.toLowerCase().includes(searchTerm));
- renderGames(filteredGames); // render filtered games
+ renderGames(filteredGames);
}
function renderGames(gamesToRender) {
const gamesContainer = document.querySelector('.games');
const popularGamesContainer = document.querySelector('.popular-games');
- gamesContainer.innerHTML = ''; // clear previous games
- popularGamesContainer.innerHTML = ''; // clear previous popular games
-
- function openGameInNewTab(game) {
- const x = window.open('about:blank', '_blank');
- const index = game.source;
- x.document.write(`
`);
-}
+ gamesContainer.innerHTML = '';
+ popularGamesContainer.innerHTML = '';
gamesToRender.forEach(game => {
const el = document.createElement('div');
@@ -62,20 +53,15 @@ function renderGames(gamesToRender) {
popularGamesContainer.appendChild(popularEl);
popularEl.addEventListener('click', async () => {
- if (!workerLoaded) await loadWorker();
- const frameData = {
- type: 'game',
- game
- };
- if (game.openinnewtab === 'yes') {
- window.open(game.source, '_blank');
- console.log('Open game in new tab:', frameData);
- } else if (game.openinaboutblank === 'yes') {
- openGameInNewTab(game);
- console.log('Open game in about:blank:', frameData);
- } else {
- localStorage.setItem('frameData', JSON.stringify(frameData));
- location.href = '/view';
+ await loadProxyWorker('uv');
+
+ if (game.openinnewtab === 'yes') window.open(game.source);
+ else {
+ localStorage.setItem('frameData', JSON.stringify({
+ type: 'game',
+ game
+ }));
+ location.href = '/view';
}
});
@@ -85,21 +71,20 @@ function renderGames(gamesToRender) {
}
el.addEventListener('click', async () => {
- if (!workerLoaded) await loadWorker();
+ await loadProxyWorker();
+
const frameData = {
type: 'game',
game
};
+
if (game.openinnewtab === 'yes') {
- window.open(game.source, '_blank');
- console.log('Open game in new tab:', frameData);
- } else if (game.openinaboutblank === 'yes') {
- openGameInNewTab(game);
- console.log('Open game in about:blank:', frameData);
- } else {
- localStorage.setItem('frameData', JSON.stringify(frameData));
- location.href = '/view';
- }
+ window.open(game.source, '_blank');
+ console.log('Open game in new tab:', frameData);
+ } else {
+ localStorage.setItem('frameData', JSON.stringify(frameData));
+ location.href = '/view';
+ }
});
el.addEventListener('mouseenter', gameMouseEnter);
@@ -122,10 +107,8 @@ function gameMouseMove(event) {
const mouseY = event.clientY - centerY;
const rotateXUncapped = (+1) * tiltEffectSettings.max * mouseY / (gameHeight / 2);
const rotateYUncapped = (-1) * tiltEffectSettings.max * mouseX / (gameWidth / 2);
- const rotateX = rotateXUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max :
- (rotateXUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateXUncapped);
- const rotateY = rotateYUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max :
- (rotateYUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateYUncapped);
+ const rotateX = rotateXUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max : (rotateXUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateXUncapped);
+ const rotateY = rotateYUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max : (rotateYUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateYUncapped);
game.style.transform = `perspective(${tiltEffectSettings.perspective}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(${tiltEffectSettings.scale}, ${tiltEffectSettings.scale}, ${tiltEffectSettings.scale})`;
}
@@ -139,11 +122,10 @@ function setTransition(event) {
const game = event.currentTarget;
clearTimeout(game.transitionTimeoutId);
game.style.transition = `transform ${tiltEffectSettings.speed}ms ${tiltEffectSettings.easing}`;
- game.transitionTimeoutId = setTimeout(() => {
- game.style.transition = '';
- }, tiltEffectSettings.speed);
+
+ game.transitionTimeoutId = setTimeout(() => game.style.transition = '', tiltEffectSettings.speed);
}
export default {
load
-};
+};
\ No newline at end of file
diff --git a/static/assets/js/main.js b/static/assets/js/main.js
index 9e38fcc..895236b 100644
--- a/static/assets/js/main.js
+++ b/static/assets/js/main.js
@@ -1,15 +1,13 @@
-// Don't touch
-import { load } from './settings.js';
-import Games from './games.js';
-import Apps from './apps.js';
+import loadEasterEggs from './eastereggs.js';
+import PolarisError from './error.js';
+import Settings from './settings.js';
import Search from './search.js';
import Cheats from './cheats.js';
+import Games from './games.js';
import Frame from './frame.js';
-import PolarisError from './error.js';
+import Apps from './apps.js';
-const Settings = {
- load: load
-};
+loadEasterEggs();
onbeforeunload = (e) => {
if (localStorage.getItem('prevent_close') === 'true') {
@@ -25,62 +23,52 @@ window.onhashchange = () => {
else document.querySelector('.sidebar').classList.remove('active');
};
-if (window.self === window.top) {
- setTimeout(async () => {
- Settings.load();
+if (window.self === window.top) setTimeout(async () => {
+ Settings.load();
- if (location.pathname === '/games') Games.load();
- if (location.pathname === '/apps') Apps.load();
- if (location.pathname === '/search') Search.load();
- if (location.pathname === '/cheats') Cheats.load();
- if (location.pathname === '/view') Frame.load();
- }, 500);
-}
+ if (location.pathname === '/games') Games.load();
+ if (location.pathname === '/apps') Apps.load();
+ if (location.pathname === '/search') Search.load();
+ if (location.pathname === '/cheats') Cheats.load();
+ if (location.pathname === '/view') Frame.load();
+}, 500);
if (location.pathname === '/') {
fetch('/assets/JSON/games.json').then(res => res.json()).then(games => {
const gameName = 'Tiny Fishing';
const game = games.filter(g => g.name === gameName)[0];
- document.querySelector('.featuredimg').addEventListener('click', () => {
+ document.querySelector('.featured').addEventListener('click', () => {
localStorage.setItem('frameData', JSON.stringify({
type: 'game',
game
}));
-
+
location.href = '/view';
});
- document.querySelector('.featuredimg').src = '/assets/img/wide/tinyfishing.png';
+ document.querySelector('.featured').src = '/assets/img/wide/tinyfishing.png';
}).catch(e => new PolarisError('Failed to load featured game.'));
-
- fetch('/assets/JSON/changelog.json').then(res => res.json()).then(changelog => changelog.forEach(change => {
- const date = document.createElement('p');
- date.textContent = change.date;
- date.classList = 'small';
- document.querySelector('#changelog').appendChild(date);
-
- const descwrap = document.createElement('p');
+
+ fetch('/assets/JSON/changelog.json').then(res => res.json()).then(changelog => changelog.forEach(change => {
+ const date = document.createElement('p');
+ date.textContent = change.date;
+ date.classList = 'small';
+ document.querySelector('#changelog').appendChild(date);
+
+ const descwrap = document.createElement('p');
const description = document.createElement('i');
- description.textContent = change.simpleDescription;
- description.classList = 'small';
- document.querySelector('#changelog').appendChild(description);
- }));
-/*
-var items = ['the start', 'What are you doing here?', '"School"', 'I dont get paid enough','What Up Son?','help','i like bagle','3.14159265359','Who thought this was a good idea?','Stage 4','i have a concerning lump on my back','Bean was here','Your Mother','Pacer Test','Why did he leave','by the way...','Kilroy was here','Kilroy is here','look behind you','West Virginia','theres a reason','Country road','Thats a wrap','Pretty','No','Yes','leave me','What square?','uhhh','Plutocracy','Practically Free*','capitalize this','Place Holder','Try me','fine','Why are we doing this again?','half eaten saltine crackers are underated','Javascript > Java','L + Ratio','Cope','I Love Refrigerators','That Happened.','Pedicure','(insert message here)','terminal','💀💀💀','finnish','who writes these?','reference','I am going to peel the skin off your face (:','bye','no','the fact is','run','uh what','hello world','Positively awful','tax fraud','comatose state','Not me','my second job is a discord mod','kids bop','Is it just me or','Hello people','74% Incomplete','wake up','Monster Energy','ew','The amount of pain I am in right now is unimaginable','chicken','men','What?','Your opinion is invalid','gay pride','Im going','4skin','/0','Who said that?','No Fair.','Famous... Enough','Parent Approved!','Teacher Approved!','Treason','Just do it already!','You\'re Fired','Not worth it','was there a reason?','the egg came first','patriotism','Family Friendly','Do you ever feel like a plastic bag Drifting through the windWanting to start again? Do you ever feel, feel so paper thin Like a house of cards One blow from caving in?','Why?','discord is in the first o','Shane Dawson likes cats','who stole this','unblock linux','darn you','gushers','yummy','charles loves you','mekhi loves anime', 'pls dont type smurf :)'];
-
- function getRandomFact() {
- var randomIndex = Math.floor(Math.random() * items.length);
- return items[randomIndex];
- }
-
- // When the page loads, set the innerHTML of elements with class 'blue' to a random item
- window.addEventListener('load', function() {
- var blue = document.getElementsByClassName('blue');
- for (var i = 0; i < blue.length; i++) {
- blue[i].innerHTML = getRandomFact();
- }
- });
-*/
+ description.textContent = change.simpleDescription;
+ description.classList = 'small';
+ document.querySelector('#changelog').appendChild(description);
+ }));
}
-const Polaris = { Settings, Games, Apps, Frame, PolarisError };
-export default Polaris;
\ No newline at end of file
+
+if (window.scrollY !== 0) document.querySelector('.navbar').classList.add('scrolling');
+else document.querySelector('.navbar').classList.remove('scrolling');
+
+window.onscroll = () => {
+ if (window.scrollY !== 0) document.querySelector('.navbar').classList.add('scrolling');
+ else document.querySelector('.navbar').classList.remove('scrolling');
+}
+
+export default { Settings, Games, Apps, Frame, PolarisError };
\ No newline at end of file
diff --git a/static/assets/js/page/game.js b/static/assets/js/page/game.js
new file mode 100644
index 0000000..8ef809c
--- /dev/null
+++ b/static/assets/js/page/game.js
@@ -0,0 +1,131 @@
+import PolarisError from '/assets/js/error.js';
+import { loadProxyWorker } from '/assets/js/utils.js';
+
+const tiltEffectSettings = {
+ max: 8,
+ perspective: 1000,
+ scale: 1.05,
+ speed: 800,
+ easing: 'cubic-bezier(.03,.98,.52,.99)'
+};
+
+let games = [];
+let filteredGames = [];
+
+const load = () => {
+ fetch('/assets/JSON/games.json').then(res => res.json()).then(data => {
+ games = data;
+ filteredGames = games;
+
+ renderGames(filteredGames);
+
+ const searchInput = document.getElementById('searchInput');
+ searchInput.addEventListener('input', filterGames);
+ })
+ .catch(e => new PolarisError('Failed to load games'));
+};
+
+function filterGames() {
+ const searchInput = document.getElementById('searchInput');
+ const searchTerm = searchInput.value.toLowerCase();
+
+ filteredGames = games.filter(game => game.name.toLowerCase().includes(searchTerm));
+
+ renderGames(filteredGames);
+}
+
+function renderGames(gamesToRender) {
+ const gamesContainer = document.querySelector('.games');
+ const popularGamesContainer = document.querySelector('.popular-games');
+ gamesContainer.innerHTML = '';
+ popularGamesContainer.innerHTML = '';
+
+ gamesToRender.forEach(game => {
+ const el = document.createElement('div');
+ el.classList = 'game';
+ el.innerHTML = `

${game.name}
`;
+ gamesContainer.appendChild(el);
+
+ if (game.popular === 'yes') {
+ const popularEl = document.createElement('div');
+ popularEl.classList = 'game';
+ popularEl.innerHTML = `

${game.name}
`;
+ popularGamesContainer.appendChild(popularEl);
+
+ popularEl.addEventListener('click', async () => {
+ await loadProxyWorker('uv');
+
+ if (game.openinnewtab === 'yes') window.open(game.source);
+ else {
+ localStorage.setItem('frameData', JSON.stringify({
+ type: 'game',
+ game
+ }));
+ location.href = '/view';
+ }
+ });
+
+ popularEl.addEventListener('mouseenter', gameMouseEnter);
+ popularEl.addEventListener('mousemove', gameMouseMove);
+ popularEl.addEventListener('mouseleave', gameMouseLeave);
+ }
+
+ el.addEventListener('click', async () => {
+ await loadProxyWorker();
+
+ const frameData = {
+ type: 'game',
+ game
+ };
+
+ if (game.openinnewtab === 'yes') {
+ window.open(game.source, '_blank');
+ console.log('Open game in new tab:', frameData);
+ } else {
+ localStorage.setItem('frameData', JSON.stringify(frameData));
+ location.href = '/view';
+ }
+ });
+
+ el.addEventListener('mouseenter', gameMouseEnter);
+ el.addEventListener('mousemove', gameMouseMove);
+ el.addEventListener('mouseleave', gameMouseLeave);
+ });
+}
+
+function gameMouseEnter(event) {
+ setTransition(event);
+}
+
+function gameMouseMove(event) {
+ const game = event.currentTarget;
+ const gameWidth = game.offsetWidth;
+ const gameHeight = game.offsetHeight;
+ const centerX = game.offsetLeft + gameWidth / 2;
+ const centerY = game.offsetTop + gameHeight / 2;
+ const mouseX = event.clientX - centerX;
+ const mouseY = event.clientY - centerY;
+ const rotateXUncapped = (+1) * tiltEffectSettings.max * mouseY / (gameHeight / 2);
+ const rotateYUncapped = (-1) * tiltEffectSettings.max * mouseX / (gameWidth / 2);
+ const rotateX = rotateXUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max : (rotateXUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateXUncapped);
+ const rotateY = rotateYUncapped < -tiltEffectSettings.max ? -tiltEffectSettings.max : (rotateYUncapped > tiltEffectSettings.max ? tiltEffectSettings.max : rotateYUncapped);
+
+ game.style.transform = `perspective(${tiltEffectSettings.perspective}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(${tiltEffectSettings.scale}, ${tiltEffectSettings.scale}, ${tiltEffectSettings.scale})`;
+}
+
+function gameMouseLeave(event) {
+ event.currentTarget.style.transform = `perspective(${tiltEffectSettings.perspective}px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)`;
+ setTransition(event);
+}
+
+function setTransition(event) {
+ const game = event.currentTarget;
+ clearTimeout(game.transitionTimeoutId);
+ game.style.transition = `transform ${tiltEffectSettings.speed}ms ${tiltEffectSettings.easing}`;
+
+ game.transitionTimeoutId = setTimeout(() => game.style.transition = '', tiltEffectSettings.speed);
+}
+
+export default {
+ load
+};
\ No newline at end of file
diff --git a/static/assets/js/search.js b/static/assets/js/search.js
index 6ecb3ae..5d713e2 100644
--- a/static/assets/js/search.js
+++ b/static/assets/js/search.js
@@ -1,5 +1,5 @@
-import PolarisError from '/assets/js/error.js';
-import { loadWorker } from '/assets/js/wpm.js';
+import PolarisError from './error.js';
+import { loadProxyWorker } from './utils.js';
const load = () => {
const xor = {
@@ -20,7 +20,7 @@ const load = () => {
e.preventDefault();
if (typeof navigator.serviceWorker === 'undefined') new PolarisError('Failed to load Proxy');
- await loadWorker('uv');
+ await loadProxyWorker('uv');
const url = /^(http(s)?:\/\/)?([\w-]+\.)+[\w]{2,}(\/.*)?$/.test(query.value) ? ((!query.value.startsWith('http://') && !query.value.startsWith('https://')) ? 'https://' + query.value : query.value) : 'https://www.google.com/search?q=' + encodeURIComponent(query.value);
@@ -28,6 +28,7 @@ const load = () => {
type: 'proxy',
source: `/uv/service/${xor.encode(url)}`
}));
+
location.href = '/view';
});
}
diff --git a/static/assets/js/settings.js b/static/assets/js/settings.js
index a5f4a67..426538e 100644
--- a/static/assets/js/settings.js
+++ b/static/assets/js/settings.js
@@ -1,5 +1,5 @@
-import PolarisError from '/assets/js/error.js';
-import Theme from '/assets/js/themes.js';
+import PolarisError from './error.js';
+import Theme from './themes.js';
const isScrollable = (element) => element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
@@ -205,4 +205,4 @@ const load = () => {
new Settings();
};
-export { load, Settings };
+export default { load, Settings };
diff --git a/static/assets/js/themes.js b/static/assets/js/themes.js
index 4b3a6c8..f65528b 100644
--- a/static/assets/js/themes.js
+++ b/static/assets/js/themes.js
@@ -1,47 +1,34 @@
-const set = (name, value) => {
- if (!localStorage.getItem('settings')) {
- localStorage.setItem('settings', JSON.stringify({}));
- } else {
- try {
- JSON.parse(localStorage.getItem('settings'));
- } catch (e) {
- localStorage.setItem('settings', JSON.stringify({}));
- }
- }
+import { storage } from './utils.js';
- const settings = JSON.parse(localStorage.getItem('settings'));
- settings[name] = value;
- localStorage.setItem('settings', JSON.stringify(settings));
-};
-
-const get = (name) => {
- if (!localStorage.getItem('settings')) {
- localStorage.setItem('settings', JSON.stringify({}));
- } else {
- try {
- JSON.parse(localStorage.getItem('settings'));
- } catch (e) {
- localStorage.setItem('settings', JSON.stringify({}));
- }
- }
-
- const settings = JSON.parse(localStorage.getItem('settings'));
- return settings[name];
-}
+const settingsStorage = storage('settings');
class Theme {
constructor() {
- this.theme = get('theme');
+ this.theme = settingsStorage.get('theme');
if (this.theme) this.set(this.theme);
else this.set('system-default');
}
+ /**
+ * Set the theme of the page
+ * @param {string} theme The name of the theme
+ * @param {boolean} save Whether or not the theme should be saved
+ */
set = (theme, save) => {
document.body.setAttribute('data-theme', theme);
+ this.theme = theme;
- if (save !== false) set('theme', theme);
- }
+ if (save !== false) settingsStorage.set('theme', theme);
+ };
+
+ /**
+ * Get the current theme
+ * @returns {string}
+ */
+ get = () => {
+ return document.body.getAttribute('data-theme');
+ };
}
export default new Theme();
\ No newline at end of file
diff --git a/static/assets/js/utils.js b/static/assets/js/utils.js
index e69de29..e16461b 100644
--- a/static/assets/js/utils.js
+++ b/static/assets/js/utils.js
@@ -0,0 +1,72 @@
+/**
+ * The storage interface for polaris
+ * @param {string} containerName
+ */
+const storage = (containerName) => {
+ return {
+ /**
+ * Get a value from the storage container
+ * @param {string} name The name of the value
+ * @returns {string}
+ */
+ get: (name) => {
+ if (!localStorage.getItem(containerName)) localStorage.setItem(containerName, JSON.stringify({}));
+ else {
+ try {
+ JSON.parse(localStorage.getItem(containerName));
+ } catch (e) {
+ localStorage.setItem(containerName, JSON.stringify({}));
+ }
+ }
+
+ const container = JSON.parse(localStorage.getItem(containerName));
+ return container[name];
+ },
+ /**
+ * Set a value from a storage container
+ * @param {string} name The name of the value
+ * @param {string | object} value The value to be set
+ */
+ set: (name, value) => {
+ if (!localStorage.getItem(containerName)) localStorage.setItem(containerName, JSON.stringify({}));
+ else {
+ try {
+ JSON.parse(localStorage.getItem(containerName));
+ } catch (e) {
+ localStorage.setItem(containerName, JSON.stringify({}));
+ }
+ }
+
+ const container = JSON.parse(localStorage.getItem(containerName));
+ container[name] = value;
+
+ localStorage.setItem(containerName, JSON.stringify(container));
+ }
+ };
+};
+
+/**
+ * Register a proxy service worker
+ * @param {'uv' | 'dynamic'} proxy
+ */
+const loadProxyWorker = async (proxy) => await navigator.serviceWorker.register(`/${proxy}/sw.js`, {
+ scope: `/${proxy}/service/`
+});
+
+/**
+ * Load the page javascript
+ */
+const loadPageScript = () => {
+ if (location.href) {
+
+ }
+};
+
+export default {
+ storage,
+ loadProxyWorker
+};
+export {
+ storage,
+ loadProxyWorker
+};
\ No newline at end of file
diff --git a/static/assets/js/wpm.js b/static/assets/js/wpm.js
deleted file mode 100644
index 40a5277..0000000
--- a/static/assets/js/wpm.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const loadWorker = async (proxy) => await navigator.serviceWorker.register(`/${proxy}/sw.js`, {
- scope: `/${proxy}/service/`,
-});
-
-export {
- loadWorker
-};
diff --git a/static/cheats.html b/static/cheats.html
index 298a9c9..cb6dff4 100644
--- a/static/cheats.html
+++ b/static/cheats.html
@@ -11,7 +11,7 @@
Cheats | Polaris
-
+
@@ -21,6 +21,8 @@
+
+
diff --git a/static/games.html b/static/games.html
index d70a031..782aada 100644
--- a/static/games.html
+++ b/static/games.html
@@ -15,7 +15,7 @@
-