Compare commits
3 Commits
main
...
c++-crow-b
| Author | SHA1 | Date | |
|---|---|---|---|
| 6360b41e9a | |||
| 217adf91e9 | |||
| a7404fed3d |
@@ -1,65 +1,33 @@
|
||||
name: Deploy website
|
||||
run-name: ${{ gitea.actor }} is deploying update
|
||||
name: Build and push container image
|
||||
run-name: ${{ gitea.actor }} is building and pushing container image
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
GITEA_DOMAIN: git.alfieking.dev
|
||||
GITEA_REGISTRY_USER: acetheking987
|
||||
RESULT_IMAGE_NAME: acetheking987/alfieking.dev
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Setup SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy
|
||||
run: |
|
||||
ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
|
||||
set -e
|
||||
|
||||
APP_DIR=/var/www/alfieking.dev
|
||||
RELEASES_DIR=$APP_DIR/releases
|
||||
TIMESTAMP=$(date +%Y%m%d%H%M%S)
|
||||
NEW_RELEASE=$RELEASES_DIR/$TIMESTAMP
|
||||
KEEP_RELEASES=5
|
||||
|
||||
echo "Creating release directory..."
|
||||
mkdir -p $NEW_RELEASE
|
||||
|
||||
echo "Cloning public repository..."
|
||||
git clone --depth 1 -b main \
|
||||
https://git.alfieking.dev/acetheking987/alfieking.dev.git \
|
||||
$NEW_RELEASE
|
||||
|
||||
echo "Installing dependencies..."
|
||||
source $APP_DIR/venv/bin/activate
|
||||
pip install -r $NEW_RELEASE/requirements.txt
|
||||
|
||||
echo "Switching symlink..."
|
||||
ln -sfn $NEW_RELEASE $APP_DIR/current
|
||||
|
||||
echo "Changing ownership..."
|
||||
chown -R www-data:www-data /var/www/alfieking.dev/releases/$TIMESTAMP
|
||||
chown -R www-data:www-data /var/www/alfieking.dev/current
|
||||
|
||||
echo "Restarting Gunicorn (downtime incomming XD)..."
|
||||
systemctl restart alfieking.dev.service
|
||||
|
||||
echo "Cleaning old releases..."
|
||||
CURRENT_TARGET=$(readlink -f $APP_DIR/current)
|
||||
|
||||
cd $RELEASES_DIR
|
||||
for dir in $(ls -dt */ | tail -n +$((KEEP_RELEASES+1))); do
|
||||
FULL_PATH="$RELEASES_DIR/${dir%/}"
|
||||
if [ "$FULL_PATH" != "$CURRENT_TARGET" ]; then
|
||||
rm -rf "$FULL_PATH"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Deployment successful."
|
||||
EOF
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Log in to registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.GITEA_DOMAIN }}
|
||||
username: ${{ env.GITEA_REGISTRY_USER }}
|
||||
password: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
tags: ${{ env.GITEA_DOMAIN }}/${{ env.RESULT_IMAGE_NAME }}:latest
|
||||
5
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
.env
|
||||
__pycache__
|
||||
.venv
|
||||
build/
|
||||
.vscode/
|
||||
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "thirdparty/inja"]
|
||||
path = thirdparty/inja
|
||||
url = https://github.com/pantor/inja
|
||||
[submodule "thirdparty/nlohmann"]
|
||||
path = thirdparty/nlohmann
|
||||
url = https://github.com/nlohmann/json
|
||||
15
include/errors.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef ERRORS_HPP
|
||||
#define ERRORS_HPP
|
||||
|
||||
#include <crow.h>
|
||||
#include "templating.hpp"
|
||||
|
||||
extern Templating templating;
|
||||
|
||||
struct CustomErrorHandler {
|
||||
struct context {};
|
||||
void before_handle(crow::request& req, crow::response& res, context&) {}
|
||||
void after_handle(crow::request& req, crow::response& res, context&);
|
||||
};
|
||||
|
||||
#endif
|
||||
25
include/templating.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef TEMPLATING_HPP
|
||||
#define TEMPLATING_HPP
|
||||
|
||||
#include <inja/inja.hpp>
|
||||
#include <crow.h>
|
||||
#include <string>
|
||||
|
||||
class Templating {
|
||||
public:
|
||||
explicit Templating(const std::string& template_dir);
|
||||
|
||||
crow::response render_template(const std::string& template_name, const inja::json& data);
|
||||
crow::response render_template(const std::string& template_name);
|
||||
|
||||
std::string render_template_string(const std::string& template_name, const inja::json& data);
|
||||
std::string render_template_string(const std::string& template_name);
|
||||
|
||||
private:
|
||||
inja::Environment inja_env;
|
||||
std::string template_dir; // absolute path to templates
|
||||
|
||||
std::string preprocess_template(const std::string& template_name);
|
||||
};
|
||||
|
||||
#endif
|
||||
51
makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# Directories
|
||||
INCLUDE_DIRS = include thirdparty/inja/include thirdparty/nlohmann/include
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
|
||||
# Compiler and linker settings
|
||||
CXX = g++
|
||||
LIBS =
|
||||
CXXFLAGS = -std=c++17 $(foreach dir,$(INCLUDE_DIRS),-I$(dir))
|
||||
|
||||
# Source and object files
|
||||
SRC = $(wildcard $(SRC_DIR)/*.cpp)
|
||||
|
||||
# Target executable
|
||||
UNAME := $(shell uname -s)
|
||||
BUILD_DIR := $(BUILD_DIR)/$(UNAME)
|
||||
OBJ_DIR := $(BUILD_DIR)/objs
|
||||
BIN = $(BUILD_DIR)/main
|
||||
|
||||
# Object files corresponding to the source files (now in obj directory)
|
||||
OBJS = $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(basename $(notdir $(SRC)))))
|
||||
|
||||
# development target with debugging
|
||||
dev: CXXFLAGS += -g -Wall -Wformat
|
||||
dev: all
|
||||
|
||||
# Release target
|
||||
release: CXXFLAGS += -O3
|
||||
release: all
|
||||
|
||||
# Create directories for build output
|
||||
dirs:
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
|
||||
# Clear build directory
|
||||
clear:
|
||||
@find $(OBJ_DIR) -type f -name '*.o' -exec rm -f {} +
|
||||
|
||||
# Pattern rule for source files in src directory
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
all: dirs clear $(BIN)
|
||||
@echo Build complete
|
||||
|
||||
$(BIN): $(OBJS)
|
||||
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
@@ -1,7 +0,0 @@
|
||||
psycopg2-binary
|
||||
python-dotenv
|
||||
flask-session
|
||||
requests
|
||||
flask
|
||||
markdown
|
||||
gunicorn
|
||||
18
src/blog.py
@@ -1,18 +0,0 @@
|
||||
from os import getenv as env
|
||||
import psycopg2, logging
|
||||
|
||||
|
||||
log = logging.getLogger("blog")
|
||||
|
||||
|
||||
log.info("connecting to database")
|
||||
conn = psycopg2.connect(
|
||||
host = env("PG_HOST"),
|
||||
port = env("PG_PORT"),
|
||||
dbname = env("PG_DBNAME"),
|
||||
user= env("PG_USER"),
|
||||
password = env("PG_PASSWORD")
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# Imports
|
||||
from flask import Blueprint, render_template, abort, request
|
||||
import os, markdown
|
||||
|
||||
try:
|
||||
from src.name import get_name
|
||||
except ImportError:
|
||||
from name import get_name
|
||||
|
||||
|
||||
# Create blueprint
|
||||
bp = Blueprint('dynamic_routes', __name__)
|
||||
template_folder = "templates"
|
||||
|
||||
|
||||
# helper func
|
||||
def get_path(file) -> str:
|
||||
return os.path.join(template_folder, "pages", file)
|
||||
|
||||
|
||||
# Get all files in folder
|
||||
def ListFiles(path):
|
||||
path = get_path(path)
|
||||
files = []
|
||||
for root, dirs, files_in_dir in os.walk(path):
|
||||
for file in files_in_dir:
|
||||
files.append(os.path.relpath(os.path.join(root, file), path))
|
||||
for dir in dirs:
|
||||
files.append(os.path.relpath(os.path.join(root, dir), path) + '/')
|
||||
return files
|
||||
|
||||
|
||||
# Catch-all route for generic pages
|
||||
@bp.route('/<path:filename>')
|
||||
def catch_all(filename):
|
||||
if os.path.exists(get_path(filename)):
|
||||
if os.path.isdir(get_path(filename)):
|
||||
return render_template(
|
||||
'bases/directory.html',
|
||||
directory=filename + "/" if not filename.endswith('/') else filename,
|
||||
pages=ListFiles(filename),
|
||||
name=get_name(request)
|
||||
)
|
||||
|
||||
return render_template(f'pages/{filename}', name=get_name(request))
|
||||
|
||||
elif os.path.exists(get_path(filename + '.html')):
|
||||
return render_template(f'pages/{filename}.html', name=get_name(request))
|
||||
|
||||
elif os.path.exists(get_path(filename + '.md')):
|
||||
output = markdown.markdown(open(get_path(filename + '.md'), "r").read())
|
||||
return render_template(
|
||||
f'bases/md.html',
|
||||
title = filename.split("/")[-1],
|
||||
markdown = output,
|
||||
name=get_name(request)
|
||||
)
|
||||
|
||||
else:
|
||||
abort(404, f"'{filename}' not found")
|
||||
13
src/errors.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "errors.hpp"
|
||||
|
||||
|
||||
std::string render_404_template(const crow::request& req) {
|
||||
return templating.render_template_string("errors/404.html", {{"requested_url", req.url}});
|
||||
}
|
||||
|
||||
void CustomErrorHandler::after_handle(crow::request& req, crow::response& res, context&) {
|
||||
if (res.code == 404 && res.body.empty()) {
|
||||
res.set_header("Content-Type", "text/html");
|
||||
res.body = render_404_template(req);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
from flask import Blueprint, render_template, request
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
try:
|
||||
from src.name import get_name
|
||||
except ImportError:
|
||||
from name import get_name
|
||||
|
||||
|
||||
bp = Blueprint("errors", __name__)
|
||||
|
||||
|
||||
@bp.route('/500')
|
||||
@bp.app_errorhandler(500)
|
||||
def internal_server_error(error:HTTPException=None):
|
||||
return render_template('errors/500.html', error=error, name=get_name(request)), 500
|
||||
|
||||
|
||||
@bp.route('/404')
|
||||
@bp.app_errorhandler(404)
|
||||
def not_found(error:HTTPException=None):
|
||||
return render_template('errors/404.html', error=error, name=get_name(request)), 404
|
||||
|
||||
|
||||
@bp.route('/400')
|
||||
@bp.app_errorhandler(400)
|
||||
def bad_request(error:HTTPException=None):
|
||||
return render_template('errors/400.html', error=error, name=get_name(request)), 400
|
||||
|
||||
|
||||
@bp.route('/idk')
|
||||
@bp.app_errorhandler(Exception)
|
||||
def idk(error:HTTPException=None):
|
||||
if not isinstance(error, HTTPException):
|
||||
error = HTTPException("I honestly dont know")
|
||||
error.code = 418
|
||||
|
||||
return render_template(
|
||||
'errors/error.html',
|
||||
code = error.code,
|
||||
description = error.description,
|
||||
err_name = error.name,
|
||||
name=get_name(request)
|
||||
), error.code
|
||||
18
src/main.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#define CROW_STATIC_DIRECTORY "../static"
|
||||
#include "templating.hpp"
|
||||
#include "errors.hpp"
|
||||
#include <crow.h>
|
||||
|
||||
|
||||
Templating templating{"../templates"};
|
||||
|
||||
|
||||
int main() {
|
||||
crow::App<CustomErrorHandler> app;
|
||||
|
||||
CROW_ROUTE(app, "/")([]() {
|
||||
return templating.render_template("index.html");
|
||||
});
|
||||
|
||||
app.port(8080).multithreaded().run();
|
||||
}
|
||||
80
src/main.py
@@ -1,80 +0,0 @@
|
||||
# IMPORTS
|
||||
from flask import Flask, render_template, request
|
||||
from os import getenv as env
|
||||
import logging
|
||||
|
||||
try:
|
||||
import src.dynamic_routes as dynamic_routes
|
||||
import src.errors as errors
|
||||
import src.pg_log as pg_log
|
||||
from src.name import get_name
|
||||
except ImportError:
|
||||
import dynamic_routes, errors, pg_log
|
||||
from name import get_name
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
|
||||
# LOGGING
|
||||
pg_log_handler = pg_log.PgLog(
|
||||
host = env("PG_HOST"),
|
||||
port = env("PG_PORT"),
|
||||
dbname = env("PG_DBNAME"),
|
||||
user= env("PG_USER"),
|
||||
password = env("PG_PASSWORD")
|
||||
)
|
||||
pg_log_handler.setLevel(logging.DEBUG)
|
||||
|
||||
stream_log_handler = logging.StreamHandler()
|
||||
stream_log_handler.setFormatter(
|
||||
logging.Formatter("%(asctime)s - %(levelname)s: %(message)s")
|
||||
)
|
||||
stream_log_handler.setLevel(logging.INFO)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(stream_log_handler)
|
||||
log.addHandler(pg_log_handler)
|
||||
|
||||
werkzeug_logger = logging.getLogger("werkzeug")
|
||||
werkzeug_logger.setLevel(logging.DEBUG)
|
||||
werkzeug_logger.addHandler(pg_log_handler)
|
||||
werkzeug_logger.addHandler(stream_log_handler)
|
||||
|
||||
log.info("Logging initialized.")
|
||||
|
||||
|
||||
# CREATE FLASK APP
|
||||
app = Flask(
|
||||
__name__,
|
||||
template_folder="../templates",
|
||||
static_folder="../static"
|
||||
)
|
||||
log.info("Flask initialized.")
|
||||
|
||||
|
||||
# BLUEPRINTS
|
||||
app.register_blueprint(errors.bp, url_prefix="/errors")
|
||||
app.register_blueprint(dynamic_routes.bp, url_prefix="/")
|
||||
log.info("Blueprints registered.")
|
||||
|
||||
|
||||
# ROUTES
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html", name=get_name(request))
|
||||
|
||||
@app.route("/toaster")
|
||||
def toaster():
|
||||
return render_template("toaster.html", name=get_name(request))
|
||||
|
||||
@app.route("/terminal")
|
||||
def terminal():
|
||||
return render_template("terminal.html", name=get_name(request))
|
||||
|
||||
|
||||
|
||||
# DEBUG (DONT RUN LIKE THIS IN PROD)
|
||||
if __name__ == "__main__":
|
||||
log.warning(f"RUNNING IN DEBUG MODE DO NOT USE FOR PRODUCTION!")
|
||||
app.run(debug=True)
|
||||
@@ -1,5 +0,0 @@
|
||||
def get_name(req):
|
||||
if req.headers.get("Host") == "proot.uk":
|
||||
return "Toaster"
|
||||
else:
|
||||
return "Alfie King"
|
||||
@@ -1,35 +0,0 @@
|
||||
import psycopg2, logging
|
||||
|
||||
class PgLog(logging.StreamHandler):
|
||||
def __init__(self, host, port, dbname, user, password):
|
||||
super().__init__()
|
||||
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.dbname = dbname
|
||||
self.user = user
|
||||
self.password = password
|
||||
|
||||
self.conn = psycopg2.connect(
|
||||
database = dbname,
|
||||
user = user,
|
||||
password = password,
|
||||
host = host,
|
||||
port = port
|
||||
)
|
||||
|
||||
self.cursor = self.conn.cursor()
|
||||
|
||||
def __del__(self):
|
||||
self.cursor.close()
|
||||
self.conn.close()
|
||||
|
||||
def emit(self, record):
|
||||
self.cursor.execute(
|
||||
f"INSERT INTO logs (level, message) VALUES (%s, %s)",
|
||||
(
|
||||
record.levelname,
|
||||
record.getMessage(),
|
||||
)
|
||||
)
|
||||
self.conn.commit()
|
||||
76
src/templating.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "templating.hpp"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
|
||||
Templating::Templating(const std::string& template_dir)
|
||||
: inja_env(std::filesystem::canonical(template_dir).string()),
|
||||
template_dir(std::filesystem::canonical(template_dir).string())
|
||||
{
|
||||
inja_env.set_search_included_templates_in_files(true);
|
||||
}
|
||||
|
||||
std::string Templating::preprocess_template(const std::string& template_name) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
fs::path abs_template_dir = fs::path(template_dir);
|
||||
fs::path abs_template_file = fs::canonical(abs_template_dir / template_name);
|
||||
|
||||
std::ifstream file(abs_template_file);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Failed to open template file: " + abs_template_file.string());
|
||||
}
|
||||
|
||||
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
|
||||
std::regex extends_regex(R"(\{\%\s*extends\s*(['"])(.+?)\1\s*\%\})");
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_search(content, match, extends_regex)) {
|
||||
std::string quote = match[1].str();
|
||||
std::string original_path = match[2].str();
|
||||
|
||||
if (original_path.find("/") == std::string::npos &&
|
||||
!original_path.empty() &&
|
||||
original_path.front() != '/') {
|
||||
|
||||
fs::path abs_extended_template = fs::canonical(abs_template_dir / original_path);
|
||||
fs::path rel_path = fs::relative(abs_extended_template, abs_template_file.parent_path());
|
||||
|
||||
std::string new_path = rel_path.generic_string();
|
||||
|
||||
content = std::regex_replace(content, extends_regex,
|
||||
"{% extends " + quote + new_path + quote + " %}");
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
crow::response Templating::render_template(const std::string& template_name, const inja::json& data) {
|
||||
try {
|
||||
std::string preprocessed = preprocess_template(template_name);
|
||||
inja::Template tpl = inja_env.parse(preprocessed);
|
||||
std::string rendered = inja_env.render(tpl, data);
|
||||
return crow::response(rendered);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
return crow::response(500, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
crow::response Templating::render_template(const std::string& template_name) {
|
||||
return render_template(template_name, inja::json{});
|
||||
}
|
||||
|
||||
std::string Templating::render_template_string(const std::string& template_name, const inja::json& data) {
|
||||
std::string preprocessed = preprocess_template(template_name);
|
||||
inja::Template tpl = inja_env.parse(preprocessed);
|
||||
return inja_env.render(tpl, data);
|
||||
}
|
||||
|
||||
std::string Templating::render_template_string(const std::string& template_name) {
|
||||
return render_template_string(template_name, inja::json{});
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 965 B |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 3.6 MiB After Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 4.6 MiB After Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 4.6 MiB After Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 3.3 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 3.5 MiB After Width: | Height: | Size: 3.5 MiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 3.5 MiB After Width: | Height: | Size: 3.5 MiB |
|
Before Width: | Height: | Size: 3.3 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 4.0 MiB After Width: | Height: | Size: 4.0 MiB |
|
Before Width: | Height: | Size: 4.5 MiB After Width: | Height: | Size: 4.5 MiB |
|
Before Width: | Height: | Size: 4.7 MiB After Width: | Height: | Size: 4.7 MiB |
@@ -3,6 +3,7 @@ https://cyber.dabamos.de/88x31/anythingbut.gif
|
||||
https://cyber.dabamos.de/88x31/bestdesktop.gif
|
||||
https://kopawz.neocities.org/buttonhoard/buttonsfldr2/diagnosedwithGAY.gif
|
||||
https://kopawz.neocities.org/indexgraphics/buttondecor/ilikecomputer.png
|
||||
https://identity-crisis.carrd.co/assets/images/gallery04/ad4f8d52.jpg?v=4e55d939
|
||||
https://anlucas.neocities.org/best_viewed_with_eyes.gif
|
||||
https://anlucas.neocities.org/html_learn_it_today.gif
|
||||
https://highway.eightyeightthirty.one/badge/5d58a8f32b007d4897db6f862a895a81674fb35f5cc3947fc66595817ca174db
|
||||
@@ -1,6 +1,8 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Disallow: /errors
|
||||
Disallow: /404
|
||||
Disallow: /500
|
||||
Disallow: /400
|
||||
|
||||
Sitemap: https://alfieking.dev/sitemap.xml
|
||||
|
||||
|
||||
@@ -6,4 +6,13 @@
|
||||
<url>
|
||||
<loc>https://alfieking.dev/toaster</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://alfieking.dev/events</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://alfieking.dev/events/paws-n-pistons</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://alfieking.dev/events/crittersmk</loc>
|
||||
</url>
|
||||
</urlset>
|
||||
|
Before Width: | Height: | Size: 4.4 MiB |
|
Before Width: | Height: | Size: 4.9 MiB |
|
Before Width: | Height: | Size: 5.1 MiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 710 B |
|
Before Width: | Height: | Size: 170 B |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 126 B |
|
Before Width: | Height: | Size: 86 B |
|
Before Width: | Height: | Size: 170 B |
|
Before Width: | Height: | Size: 88 B |
|
Before Width: | Height: | Size: 82 B |
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 134 B |
|
Before Width: | Height: | Size: 122 B |
|
Before Width: | Height: | Size: 116 B |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 830 KiB |
@@ -5,24 +5,6 @@
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family:"Scratch";
|
||||
src:url("/static/content/fonts/avali-scratch.otf.woff2") format("woff2");
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family:"Ultrafont";
|
||||
src:url("/static/content/fonts/ultrakill-font.woff2") format("woff2");
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family:"Ultrafont2";
|
||||
src:url("/static/content/fonts/ultrakill-font-2.woff2") format("woff2");
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
:root {
|
||||
--primary-color: #5cdd8b;
|
||||
@@ -35,11 +17,6 @@
|
||||
--font-family: "Space Mono", "serif";
|
||||
--title-font: 'Roboto Mono', sans-serif;
|
||||
--irken-font: 'Irken';
|
||||
--scratch-font: 'Scratch';
|
||||
--ultrafont-font: 'Ultrafont';
|
||||
--smileos2-box: url(/static/content/smileos/SmileOS_2_Box.webp) 17 3 3 fill / 51px 9px 9px;
|
||||
--smileos2-font: 'Ultrafont2';
|
||||
--smileos2-emphasis: #FF4343;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -243,15 +220,6 @@ main section a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.smileos {
|
||||
border-image: var(--smileos2-box);
|
||||
padding: 54px 15px 12px;
|
||||
image-rendering: pixelated;
|
||||
font-size: 1.25rem;
|
||||
font-family: var(--smileos2-font);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#furry {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
@@ -276,14 +244,6 @@ main section a {
|
||||
font-family: var(--irken-font);
|
||||
}
|
||||
|
||||
.scratch {
|
||||
font-family: var(--scratch-font);
|
||||
}
|
||||
|
||||
.ultrafont {
|
||||
font-family: var(--ultrafont-font);
|
||||
}
|
||||
|
||||
#alt-nav {
|
||||
display: none;
|
||||
backdrop-filter: blur(2px) brightness(0.6);
|
||||
@@ -348,41 +308,6 @@ a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--secondary-background-color-but-slightly-transparent);
|
||||
padding: 4px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
#toaster-wave {
|
||||
position: absolute;
|
||||
left: -145px;
|
||||
top: 200px;
|
||||
}
|
||||
|
||||
.webring {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.webring a {
|
||||
text-decoration: none;
|
||||
color: var(--primary-color);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.webring a:hover {
|
||||
font-weight: 900;
|
||||
text-shadow: 0px 0px 10px var(--primary-color-but-slightly-transparent);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1240px) {
|
||||
#toaster-wave {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
@@ -1,23 +1,17 @@
|
||||
.gallery {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gallery .gallery-images {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gallery .gallery-images img {
|
||||
.gallery img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.gallery h2.gallery-date {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.gallery-date {
|
||||
margin: 1rem 0 .25rem 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
@font-face {
|
||||
font-family:"Ultrafont2";
|
||||
src:url("/static/content/fonts/ultrakill-font-2.woff2") format("woff2");
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
aspect-ratio: 4/3;
|
||||
padding: 0;
|
||||
font-family: "Ultrafont2";
|
||||
font-size: 1.2rem;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.smileos-header {
|
||||
height: 9%;
|
||||
border-image: url(/static/content/smileos/SmileOS_2_Header.webp) 3 fill / 9px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 900;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.smileos-header img {
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
border-image: url(/static/content/smileos/SmileOS_2_Content.webp) 1 3 3 fill / 3px 9px 9px;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"logo window"
|
||||
"buttons window";
|
||||
grid-template-columns: 40% 1fr;
|
||||
grid-template-rows: 25% 1fr;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
#smileos-logo {
|
||||
width: 250px;
|
||||
grid-area: logo;
|
||||
margin: auto;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
#terminal-window {
|
||||
height: 100%;
|
||||
grid-area: window;
|
||||
}
|
||||
|
||||
#window-container {
|
||||
border-image: url(/static/content/smileos/SmileOS_2_Content.webp) 1 3 3 fill / 3px 9px 9px;
|
||||
height: 91%;
|
||||
padding: 35px;
|
||||
box-sizing: border-box;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
#window-content {
|
||||
border-image: url(/static/content/smileos/SmileOS_2_inset_panel.webp) 1 fill / 3px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #ff4343;
|
||||
}
|
||||
|
||||
#terminal-buttons {
|
||||
grid-area: buttons;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.terminal-button {
|
||||
border-image: url(/static/content/smileos/SmileOS_2_Button_transparent.png) 2 / 9px;
|
||||
background: url(/static/content/smileos/SmileOS_2_Button_Background.png);
|
||||
background-repeat: repeat-x;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 15px;
|
||||
height: 75px;
|
||||
width: 270px;
|
||||
image-rendering: pixelated;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-family: "Ultrafont2";
|
||||
font-size: 1.2rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.terminal-button:hover {
|
||||
filter: contrast(110%);
|
||||
}
|
||||
|
||||
.terminal-button:active {
|
||||
filter: contrast(125%);
|
||||
}
|
||||
|
||||
#smileos-window-content img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#smileos-restart-music {
|
||||
color: #FF4343;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#smileos-restart-music:hover {
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -81,8 +81,4 @@ ul#toaster-specs li {
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
#toaster-wave {
|
||||
display: none;
|
||||
}
|
||||
@@ -72,33 +72,25 @@ typing();
|
||||
|
||||
// HIDDEN STUFF (shh don't tell anyone >:3)
|
||||
|
||||
let last15Chars = "";
|
||||
let last5Chars = "";
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
last15Chars += event.key;
|
||||
if (last15Chars.includes("furry")) {
|
||||
last5Chars += event.key;
|
||||
if (last5Chars == "furry") {
|
||||
console.log("owo, whats this?");
|
||||
document.getElementById('furry').style.display = 'block';
|
||||
last15Chars = "";
|
||||
}
|
||||
if (last15Chars.includes("irken")) {
|
||||
if (last5Chars == "irken") {
|
||||
console.log("doom doom doom!");
|
||||
document.querySelector(":root").style.setProperty('--font-family', 'Irken');
|
||||
document.querySelector(":root").style.setProperty('--title-font', '1.5em');
|
||||
last15Chars = "";
|
||||
}
|
||||
if (last15Chars.includes("scratch")) {
|
||||
console.log("space chicken");
|
||||
document.querySelector(":root").style.setProperty('--font-family', 'Scratch');
|
||||
document.querySelector(":root").style.setProperty('--title-font', '1em');
|
||||
last15Chars = "";
|
||||
}
|
||||
while (last15Chars.length >= 15) {
|
||||
last15Chars = last15Chars.slice(1);
|
||||
while (last5Chars.length >= 5) {
|
||||
last5Chars = last5Chars.slice(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Spotify API (now lastfm)
|
||||
// Spotify API
|
||||
|
||||
function getSpotify() {
|
||||
fetch('https://api.alfieking.dev/spotify/nowplaying/xz02oolstlvwxqu1pfcua9exz').then(response => {
|
||||
@@ -123,11 +115,10 @@ if (document.getElementById('spotify')) {
|
||||
setInterval(getSpotify, 15000);
|
||||
}
|
||||
|
||||
|
||||
// load buttons
|
||||
|
||||
function loadButtons() {
|
||||
fetch('/static/content/buttons/non_link_buttons.txt').then(response => {
|
||||
fetch('/static/content/other/buttons.txt').then(response => {
|
||||
return response.text();
|
||||
}).then(data => {
|
||||
container = document.getElementById('button-collection');
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// onionring.js is made up of four files - onionring-widget.js (this one!), onionring-index.js, onionring-variables.js and onionring.css
|
||||
// it's licensed under the cooperative non-violent license (CNPL) v4+ (https://thufie.lain.haus/NPL.html)
|
||||
// it was originally made by joey + mord of allium (蒜) house, last updated 2020-11-24
|
||||
|
||||
// === ONIONRING-WIDGET ===
|
||||
//this file contains the code which builds the widget shown on each page in the ring. ctrl+f 'EDIT THIS' if you're looking to change the actual html of the widget
|
||||
|
||||
var tag = document.getElementById(ringID); //find the widget on the page
|
||||
|
||||
thisSite = window.location.href; //get the url of the site we're currently on
|
||||
thisIndex = null;
|
||||
|
||||
// FIX
|
||||
thisSite = thisSite.replace("alfieking.dev", "proot.uk"); // fix domain
|
||||
thisSite = thisSite.replace("http:\/\/127.0.0.1:5000", "https:\/\/proot.uk"); // For debug purposes
|
||||
|
||||
// go through the site list to see if this site is on it and find its position
|
||||
for (i = 0; i < sites.length; i++) {
|
||||
if (thisSite.startsWith(sites[i])) { //we use startswith so this will match any subdirectory, users can put the widget on multiple pages
|
||||
thisIndex = i;
|
||||
break; //when we've found the site, we don't need to search any more, so stop the loop
|
||||
}
|
||||
}
|
||||
|
||||
function randomSite() {
|
||||
otherSites = sites.slice(); //create a copy of the sites list
|
||||
otherSites.splice(thisIndex, 1); //remove the current site so we don't just land on it again
|
||||
randomIndex = Math.floor(Math.random() * otherSites.length);
|
||||
location.href = otherSites[randomIndex];
|
||||
}
|
||||
|
||||
//if we didn't find the site in the list, the widget displays a warning instead
|
||||
if (thisIndex == null) {
|
||||
tag.insertAdjacentHTML('afterbegin', `
|
||||
<table>
|
||||
<tr>
|
||||
<td>This site isn't part of the ${ringName} webring yet 😿</td>
|
||||
</tr>
|
||||
</table>
|
||||
`);
|
||||
}
|
||||
else {
|
||||
//find the 'next' and 'previous' sites in the ring. this code looks complex
|
||||
//because it's using a shorthand version of an if-else statement to make sure
|
||||
//the first and last sites in the ring join together correctly
|
||||
previousIndex = (thisIndex-1 < 0) ? sites.length-1 : thisIndex-1;
|
||||
nextIndex = (thisIndex+1 >= sites.length) ? 0 : thisIndex+1;
|
||||
|
||||
indexText = ""
|
||||
//if you've chosen to include an index, this builds the link to that
|
||||
if (useIndex) {
|
||||
indexText = `<a href='${indexPage}'>index</a> | `;
|
||||
}
|
||||
|
||||
randomText = ""
|
||||
//if you've chosen to include a random button, this builds the link that does that
|
||||
if (useRandom) {
|
||||
randomText = `<a href='javascript:void(0)' onclick='randomSite()'>random</a> | `;
|
||||
}
|
||||
|
||||
//this is the code that displays the widget - EDIT THIS if you want to change the structure
|
||||
tag.insertAdjacentHTML('afterbegin', `
|
||||
<table>
|
||||
<tr>
|
||||
<td class='webring-prev'><a href='${sites[previousIndex]}'>prev</a></td>
|
||||
<td class='webring-info'>This site is part of the ${ringName} webring 😸</br>
|
||||
<span class='webring-links'>
|
||||
${randomText}
|
||||
${indexText}
|
||||
<a href='https://garlic.garden/onionring/'>onionring</a></span></td>
|
||||
<td class='webring-next'><a href='${sites[nextIndex]}'>next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
`);
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
const tips_of_the_day = [
|
||||
`The Revolver deals <span style="color:var(--smileos2-emphasis)">locational damage</span>.<br>A <span style="color:var(--smileos2-emphasis)">headshot</span> deals <span style="color:var(--smileos2-emphasis)">2x</span> damage and a <span style="color:var(--smileos2-emphasis)">limbshot</span> deals <span style="color:var(--smileos2-emphasis)">1.5x</span> damage.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Dash</span>: Fully invincible, costs stamina<br><span style="color:var(--smileos2-emphasis)">Slide</span>: Greater distance, no invincibility<br><span style="color:var(--smileos2-emphasis)">Jump</span>: Quickly out of melee range, less control`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Shotgun parries</span>: A <span style="color:var(--smileos2-emphasis)">point-blank</span> Shotgun shot to the torso right before an enemy attack lands will deal massive damage.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Attack sound cues</span> allow you to keep track of enemies who are off screen.`,
|
||||
`Some enemies make <span style="color:var(--smileos2-emphasis)">idle sounds</span> to make them easier to track.`,
|
||||
`Use the <span style="color:cyan">ATTRACTOR NAILGUN</span>'s magnets to form concentrated <span style="color:var(--smileos2-emphasis)">orbs</span> of nails that can be <span style="color:var(--smileos2-emphasis)">moved</span> around using the pull force of <span style="color:var(--smileos2-emphasis)">other magnets</span>.`,
|
||||
`Enemies <span style="color:var(--smileos2-emphasis)">can hurt</span> other enemy types. With quick thinking and positioning, powerful enemies can turn into powerful weapons.`,
|
||||
`The <span style="color:cyan">ATTRACTOR NAILGUN</span>'s magnets can be attached to enemies to make mobile targets easy to hit with nails.`,
|
||||
`Enemies <span style="color:var(--smileos2-emphasis)">scream</span> when falling from a <span style="color:var(--smileos2-emphasis)">fatal height</span>.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">SLAM BOUNCING</span>: Jump immediately after landing from a <span style="color:var(--smileos2-emphasis)">ground slam</span> to jump higher. The longer the ground slam fall, the higher the bounce.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">RAILCANNON</span> variations all share the same cooldown. Choose wisely which variation best fits the situation.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">SLIDING</span> will retain previous momentum for a short amount of time. Chaining quick <span style="color:var(--smileos2-emphasis)">SLIDE JUMPS</span> after a <span style="color:var(--smileos2-emphasis)">DASH JUMP</span> will give you incredible sustained speed.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Environmental hazards</span> such as harmful liquids will hurt enemies as well.`,
|
||||
`If you're having trouble keeping up with a tough enemy, <span style="color:var(--smileos2-emphasis)">stand back and observe</span>. Every enemy has its <span style="color:var(--smileos2-emphasis)">tells</span> and <span style="color:var(--smileos2-emphasis)">patterns</span> and learning those can be your key to victory.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">HITSCAN</span> weapons can be used to hit the shotgun's <span style="color:cyan">CORE EJECT</span> in mid-air to increase its damage and blast radius.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">POWER-UPS</span> can be stacked.`,
|
||||
`Hitting an enemy with only the <span style="color:var(--smileos2-emphasis)">edge</span> of an <span style="color:var(--smileos2-emphasis)">explosion</span> will launch them without dealing much damage, making it a risky but effective tool against <span style="color:var(--smileos2-emphasis)">Stalkers</span>.`,
|
||||
`Airborne <span style="color:var(--smileos2-emphasis)">coins</span> can be shot with any <span style="color:var(--smileos2-emphasis)">hitscan</span> weapon.`,
|
||||
`Falling <span style="color:var(--smileos2-emphasis)">underwater</span> is slow, but a <span style="color:var(--smileos2-emphasis)">ground slam</span> allows for a quick return to the ground.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Sliding</span> onto water will cause one to <span style="color:var(--smileos2-emphasis)">skip across</span> its surface.`,
|
||||
`If an enemy is <span style="color:var(--smileos2-emphasis)">blessed</span> by an <span style="color:var(--smileos2-emphasis)">Idol</span>, a direct visible connection is formed between the two, allowing one to easily <span style="color:var(--smileos2-emphasis)">track down</span> and destroy the protector.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Explosions</span> deflect <span style="color:var(--smileos2-emphasis)">projectiles</span>.<br><br>If an explosion is caused right from where an enemy shoots a projectile, it can <span style="color:var(--smileos2-emphasis)">backfire</span> and <span style="color:var(--smileos2-emphasis)">hit them</span> instead.`,
|
||||
`The space of a <span style="color:var(--smileos2-emphasis)">large</span> arena can be used to one's advantage. Using the environment to <span style="color:var(--smileos2-emphasis)">break line-of-sight</span> with enemies allows for some breathing room and time to consider <span style="color:var(--smileos2-emphasis)">target prioritization</span>.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">DON'T</span> WASTE STAMINA! Dashing <span style="color:var(--smileos2-emphasis)">needlessly</span> while fighting very <span style="color:var(--smileos2-emphasis)">aggressive foes</span> will quickly cause one to have none left when it is most needed.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Homing projectiles</span> may be more difficult to dodge, but their tracking and slower speed makes them much <span style="color:var(--smileos2-emphasis)">easier</span> to <span style="color:var(--smileos2-emphasis)">parry</span>.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Mannequins</span> can be hard to hit due to their speed, but they lose air control when <span style="color:var(--smileos2-emphasis)">launched</span> or <span style="color:var(--smileos2-emphasis)">shot down</span> from a surface, making them <span style="color:var(--smileos2-emphasis)">unable to move</span> for a short moment.`,
|
||||
`The <span style="color:red">Knuckleblaster</span>'s <span style="color:var(--smileos2-emphasis)">blast wave</span> is also capable of breaking a <span style="color:var(--smileos2-emphasis)">Gutterman's shield</span>, and is much easier to land in a chaotic scenario.`,
|
||||
`A <span style="color:var(--smileos2-emphasis)">direct hit</span> from the <span style="color:red">Knuckleblaster</span> has extremely powerful <span style="color:var(--smileos2-emphasis)">knockback</span>, making it extremely powerful for launching enemies into <span style="color:var(--smileos2-emphasis)">pits</span> and other <span style="color:var(--smileos2-emphasis)">environmental hazards</span>.`,
|
||||
`Didn't expect me, huh?`,
|
||||
`<span style="color:#FF0078">Magenta</span> colored attacks can <span style="color:var(--smileos2-emphasis)">not</span> be dashed through and must be <span style="color:var(--smileos2-emphasis)">avoided entirely</span>.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Blood Puppets</span> do not grant kills or style points, but their <span style="color:var(--smileos2-emphasis)">blood</span> can still <span style="color:var(--smileos2-emphasis)">heal</span>.`,
|
||||
`When facing down <span style="color:var(--smileos2-emphasis)">a difficult foe</span>, it may be beneficial to first get rid of the <span style="color:var(--smileos2-emphasis)">fodder</span> to reduce distractions.`,
|
||||
`Sometimes it may be more beneficial to <span style="color:var(--smileos2-emphasis)">stay at a distance</span> and wait for an opening <span style="color:var(--smileos2-emphasis)">before</span> getting close.`,
|
||||
`If you're having <span style="color:var(--smileos2-emphasis)">trouble</span> with a specific encounter, take a moment to <span style="color:var(--smileos2-emphasis)">weigh your options</span>. <br> There may be some <span style="color:var(--smileos2-emphasis)">trick</span>, <span style="color:var(--smileos2-emphasis)">tool</span> or <span style="color:var(--smileos2-emphasis)">alternative prioritization</span> that will tip the scales in your favor.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">ENEMY STEP</span>: Jump while in mid-air <span style="color:var(--smileos2-emphasis)">near an enemy</span> to jump off the enemy. This resets the amount of available walljumps without needing to land.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">Parries</span> can be used as a powerful healing tool.<br><br>Parrying any enemy projectile or melee attack will <span style="color:red">fully replenish your health</span> up to the hard damage limit.`,
|
||||
`H a v e f u n .`,
|
||||
`If blown too far off the arena, <span style="color:lime">PUMP CHARGE</span>'s overcharge is a good way to get back.`,
|
||||
`<span style="color:var(--smileos2-emphasis)">CHEATS</span> can be enabled in other levels by inputting <span style="color:var(--smileos2-emphasis)">🡡 🡡 🡣 🡣 🡠 🡢 🡠 🡢 B A</span> Enabling cheats will disable ranks`,
|
||||
`You can pick up the cut weapons on the second floor.`
|
||||
]
|
||||
|
||||
|
||||
var click = new Audio('/static/content/smileos/SmileOS2Click.ogx');
|
||||
|
||||
document.getElementById("smileos-about").addEventListener("click", function() {
|
||||
click.play();
|
||||
document.getElementById("smileos-window-title").innerHTML = "About";
|
||||
document.getElementById("smileos-window-content").innerHTML = `
|
||||
<span class="red">SmileOS</span>: is the operating system found on most digital interfaces found throughout
|
||||
<span class="red">Hell</span>. <span class="red">SmileOS 1.0</span> is employed on pannels despite its poor user and developer experience to conserve
|
||||
blood after the war, while <span class="red">SmileOS 2.0</span> is used for terminals requireing higher blood consumption.
|
||||
`;
|
||||
});
|
||||
|
||||
document.getElementById("smileos-snake").addEventListener("click", function() {
|
||||
click.play();
|
||||
document.getElementById("smileos-window-title").innerHTML = "Snake";
|
||||
document.getElementById("smileos-window-content").innerHTML = `
|
||||
<img src="/static/content/smileos/KITR_Build.webp" alt="under construction">
|
||||
`;
|
||||
});
|
||||
|
||||
document.getElementById("smileos-leaderboard").addEventListener("click", function() {
|
||||
click.play();
|
||||
document.getElementById("smileos-window-title").innerHTML = "Leaderboard";
|
||||
document.getElementById("smileos-window-content").innerHTML = `
|
||||
<img src="/static/content/smileos/KITR_Build.webp" alt="under construction">
|
||||
`;
|
||||
});
|
||||
|
||||
document.getElementById("smileos-tip").addEventListener("click", function() {
|
||||
click.play();
|
||||
document.getElementById("smileos-window-title").innerHTML = "Tip of the Day";
|
||||
document.getElementById("smileos-window-content").innerHTML = tips_of_the_day[Math.floor(Math.random() * tips_of_the_day.length)];
|
||||
});
|
||||
|
||||
async function playAudio(url) {
|
||||
return new Promise((resolve) => {
|
||||
const audio = new Audio(url);
|
||||
audio.addEventListener('ended', resolve); // Resolve the promise when audio ends
|
||||
audio.volume = 0.4;
|
||||
audio.play();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async function() {
|
||||
document.getElementById("smileos-window-title").innerHTML = "Tip of the Day";
|
||||
document.getElementById("smileos-window-content").innerHTML = tips_of_the_day[Math.floor(Math.random() * tips_of_the_day.length)];
|
||||
await playAudio('/static/content/smileos/SmileOS2Startup.ogx');
|
||||
|
||||
var music = new Audio('/static/content/smileos/Shopmusic.ogx');
|
||||
music.loop = true;
|
||||
music.volume = 0.2;
|
||||
music.play();
|
||||
});
|
||||
|
||||
document.getElementById("smileos-restart-music").addEventListener("click", async function() {
|
||||
await playAudio('/static/content/smileos/SmileOS2Startup.ogx');
|
||||
|
||||
var music = new Audio('/static/content/smileos/Shopmusic.ogx');
|
||||
music.loop = true;
|
||||
music.volume = 0.2;
|
||||
music.play();
|
||||
});
|
||||
174
static/js/snake.js
Normal file
@@ -0,0 +1,174 @@
|
||||
const canvas = document.getElementById('snakeCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const gridSize = 20;
|
||||
const tileSize = 100;
|
||||
const snakeSize = 60;
|
||||
const foodSize = 80;
|
||||
canvas.width = gridSize * tileSize;
|
||||
canvas.height = gridSize * tileSize;
|
||||
|
||||
let snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }];
|
||||
let direction = { x: 0, y: 0 };
|
||||
let food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) };
|
||||
let score = 0;
|
||||
let gameOver = false;
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// draw grid of checkerboard pattern
|
||||
for (let x = 0; x < gridSize; x++) {
|
||||
for (let y = 0; y < gridSize; y++) {
|
||||
ctx.fillStyle = (x + y) % 2 === 0 ?
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--background-color') :
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--secondary-background-color');
|
||||
ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw snake
|
||||
snake.forEach(segment => {
|
||||
let nextVec = { x: 0, y: 0 };
|
||||
// if there is a segment after the current segment
|
||||
if (snake.indexOf(segment) < snake.length - 1) {
|
||||
const nextSegment = snake[snake.indexOf(segment) + 1];
|
||||
nextVec.x = nextSegment.x - segment.x;
|
||||
nextVec.y = nextSegment.y - segment.y;
|
||||
}
|
||||
|
||||
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--primary-color');
|
||||
if (nextVec.x === 0 && nextVec.y === 0) {
|
||||
ctx.fillRect(
|
||||
segment.x * tileSize + (tileSize - snakeSize) / 2,
|
||||
segment.y * tileSize + (tileSize - snakeSize) / 2,
|
||||
snakeSize,
|
||||
snakeSize
|
||||
);
|
||||
} else if (nextVec.x > 0 || nextVec.y > 0) {
|
||||
ctx.fillRect(
|
||||
segment.x * tileSize + (tileSize - snakeSize) / 2,
|
||||
segment.y * tileSize + (tileSize - snakeSize) / 2,
|
||||
snakeSize + nextVec.x * (tileSize - snakeSize),
|
||||
snakeSize + nextVec.y * (tileSize - snakeSize)
|
||||
);
|
||||
} else {
|
||||
ctx.fillRect(
|
||||
segment.x * tileSize + (tileSize - snakeSize) / 2 + nextVec.x * (tileSize - snakeSize),
|
||||
segment.y * tileSize + (tileSize - snakeSize) / 2 + nextVec.y * (tileSize - snakeSize),
|
||||
snakeSize + Math.abs(nextVec.x) * (tileSize - snakeSize),
|
||||
snakeSize + Math.abs(nextVec.y) * (tileSize - snakeSize)
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Draw food
|
||||
ctx.fillStyle = '#ff4d4d';
|
||||
ctx.fillRect(
|
||||
food.x * tileSize + (tileSize - foodSize) / 2,
|
||||
food.y * tileSize + (tileSize - foodSize) / 2,
|
||||
foodSize,
|
||||
foodSize
|
||||
);
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (gameOver) return;
|
||||
|
||||
// Move snake
|
||||
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
|
||||
|
||||
// Add new head
|
||||
snake.unshift(head);
|
||||
|
||||
// Check for food collision
|
||||
if (head.x === food.x && head.y === food.y) {
|
||||
score += 10; // Increase score
|
||||
placeFood();
|
||||
} else {
|
||||
snake.pop(); // Remove tail if no food eaten
|
||||
}
|
||||
|
||||
// Check for wall collision
|
||||
if (head.x < 0 || head.x >= gridSize || head.y < 0 || head.y >= gridSize) {
|
||||
gameOver = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for self collision
|
||||
for (let i = 1; i < snake.length; i++) {
|
||||
if (head.x === snake[i].x && head.y === snake[i].y) {
|
||||
gameOver = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function placeFood() {
|
||||
do {
|
||||
food.x = Math.floor(Math.random() * gridSize);
|
||||
food.y = Math.floor(Math.random() * gridSize);
|
||||
} while (snake.some(segment => segment.x === food.x && segment.y === food.y));
|
||||
}
|
||||
|
||||
function changeDirection(event) {
|
||||
switch (event.key) {
|
||||
case 'w':
|
||||
if (direction.y === 0) direction = { x: 0, y: -1 };
|
||||
break;
|
||||
case 's':
|
||||
if (direction.y === 0) direction = { x: 0, y: 1 };
|
||||
break;
|
||||
case 'a':
|
||||
if (direction.x === 0) direction = { x: -1, y: 0 };
|
||||
break;
|
||||
case 'd':
|
||||
if (direction.x === 0) direction = { x: 1, y: 0 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Menu to start the game
|
||||
function menu() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--background-color');
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--text-color');
|
||||
ctx.font = '200px Arial';
|
||||
ctx.fillText('Snake Game', canvas.width / 2, canvas.height / 2);
|
||||
ctx.font = '100px Arial';
|
||||
ctx.fillText('Press W/A/S/D to move', canvas.width / 2, canvas.height / 2 + 100);
|
||||
ctx.fillText('Click to start', canvas.width / 2, canvas.height / 2 + 200);
|
||||
|
||||
canvas.addEventListener('click', startGame);
|
||||
}
|
||||
|
||||
function gameLoop() {
|
||||
if (!gameOver) {
|
||||
update();
|
||||
draw();
|
||||
setTimeout(gameLoop, 100);
|
||||
} else {
|
||||
document.removeEventListener('keydown', changeDirection);
|
||||
document.getElementById('score').value = score;
|
||||
alert(`Game Over! Your score: ${score}`);
|
||||
menu();
|
||||
}
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }];
|
||||
direction = { x: 1, y: 0 };
|
||||
food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) };
|
||||
score = 0;
|
||||
gameOver = false;
|
||||
canvas.removeEventListener('click', startGame);
|
||||
document.addEventListener('keydown', changeDirection);
|
||||
gameLoop();
|
||||
}
|
||||
|
||||
menu();
|
||||
@@ -1,78 +0,0 @@
|
||||
//YELLOW TERMINAL
|
||||
|
||||
// onionring.js is made up of four files - onionring-widget.js (this one!), onionring-index.js, onionring-variables.js and onionring.css
|
||||
// it's licensed under the cooperative non-violent license (CNPL) v4+ (https://thufie.lain.haus/NPL.html)
|
||||
// it was originally made by joey + mord of allium (蒜) house, last updated 2020-11-24
|
||||
|
||||
// === ONIONRING-WIDGET ===
|
||||
//this file contains the code which builds the widget shown on each page in the ring. ctrl+f 'EDIT THIS' if you're looking to change the actual html of the widget
|
||||
|
||||
var tag = document.getElementById(ringID); //find the widget on the page
|
||||
|
||||
thisSite = window.location.href; //get the url of the site we're currently on
|
||||
thisIndex = null;
|
||||
|
||||
// FIX
|
||||
thisSite = thisSite.replace("alfieking.dev", "proot.uk"); // fix domain
|
||||
thisSite = thisSite.replace("http:\/\/127.0.0.1:5000", "https:\/\/proot.uk"); // For debug purposes
|
||||
|
||||
// go through the site list to see if this site is on it and find its position
|
||||
for (i = 0; i < sites.length; i++) {
|
||||
if (thisSite.startsWith(sites[i])) { //we use startswith so this will match any subdirectory, users can put the widget on multiple pages
|
||||
thisIndex = i;
|
||||
break; //when we've found the site, we don't need to search any more, so stop the loop
|
||||
}
|
||||
}
|
||||
|
||||
function randomUltraRingSite() {
|
||||
otherSites = sites.slice(); //create a copy of the sites list
|
||||
otherSites.splice(thisIndex, 1); //remove the current site so we don't just land on it again
|
||||
randomIndex = Math.floor(Math.random() * otherSites.length);
|
||||
location.href = otherSites[randomIndex];
|
||||
}
|
||||
|
||||
//if we didn't find the site in the list, the widget displays a warning instead
|
||||
if (thisIndex == null) {
|
||||
tag.insertAdjacentHTML('afterbegin', `
|
||||
<table>
|
||||
<tr>
|
||||
<td>This site isn't part of <a href="https://jack-dawlia.neocities.org/page/shrines/ultrakill/ULTRARING" target='_parent'>${ringName}</a> yet!</td>
|
||||
</tr>
|
||||
</table>
|
||||
`);
|
||||
}
|
||||
else {
|
||||
//find the 'next' and 'previous' sites in the ring. this code looks complex
|
||||
//because it's using a shorthand version of an if-else statement to make sure
|
||||
//the first and last sites in the ring join together correctly
|
||||
previousIndex = (thisIndex-1 < 0) ? sites.length-1 : thisIndex-1;
|
||||
nextIndex = (thisIndex+1 >= sites.length) ? 0 : thisIndex+1;
|
||||
|
||||
indexText = ""
|
||||
//if you've chosen to include an index, this builds the link to that
|
||||
if (useIndex) {
|
||||
indexText = `<a href='${indexPage}' class="textshadow" target='_parent'>[INDEX]</a> | `;
|
||||
}
|
||||
|
||||
randomText = ""
|
||||
//if you've chosen to include a random button, this builds the link that does that
|
||||
if (useRandom) {
|
||||
randomText = `<a href='javascript:void(0)' onclick='randomUltraRingSite()' style="color: red;" class="textshadow" target='_parent'>[RANDOM]</a>`;
|
||||
}
|
||||
|
||||
//this is the code that displays the widget - EDIT THIS if you want to change the structure
|
||||
tag.insertAdjacentHTML('afterbegin', `
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td class='webring-prev'><a href='${sites[previousIndex]}' style="color: red;" class="textshadow" title="[PREV]" target='_parent'><<</a></td>
|
||||
<td class='webring-info'><a href="https://jack-dawlia.neocities.org/page/shrines/ultrakill/ULTRARING" style="color: red;" target='_parent'><img src="https://jack-dawlia.neocities.org/image/ultraring-yellow-terminal.png" alt="This site is part of ULTRARING" title="ULTRARING" style="max-width:100%"></a></br>
|
||||
<span class='webring-links'>
|
||||
${randomText}
|
||||
${indexText}
|
||||
<td class='webring-next'><a href='${sites[nextIndex]}' style="color: red;" title="[NEXT]" target='_parent'>>></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
`);
|
||||
|
||||
}
|
||||
@@ -3,19 +3,19 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{{ name }}'s basement{% endblock %}</title>
|
||||
<link rel="icon" href="{% block icon %}/static/content/{% if name == 'Toaster' %}toaster/Toaster_v1.0_sticker.png{% else %}general_images/icon.webp{% endif %}{% endblock %}">
|
||||
<link rel="stylesheet" href="/static/css/bases/base.css">
|
||||
<title>{% block title %}Alfie's basement{% endblock %}</title>
|
||||
<link rel="icon" href="/static/content/general_images/icon.webp">
|
||||
<link rel="stylesheet" href="/static/css/base.css">
|
||||
<meta name="description" content="{% block description %}server backend survivor{% endblock %}">
|
||||
<meta name="keywords" content="{% block keywords %}Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server, developer, backend, selfhost, homelab{% endblock %}">
|
||||
<meta name="author" content="Alfie King">
|
||||
<meta name="robots" content="all">
|
||||
<meta name="theme-color" content="#63de90" data-react-helmet="true">
|
||||
<meta property="og:site_name" content="{% if name == 'Toaster' %}proot.uk{% else %}alfieking.dev{% endif %}">
|
||||
<meta property="og:url" content="https://{% if name == 'Toaster' %}proot.uk{% else %}alfieking.dev{% endif %}/">
|
||||
<meta property="og:title" content="{{ self.title() }}">
|
||||
<meta property="og:description" content="{{ self.description() }}">
|
||||
<meta property="og:image" content="{% block og_image %}/static/content/{% if name == 'Toaster' %}toaster/Toaster_v1.0_sticker.png{% else %}general_images/icon.webp{% endif %}{% endblock %}">
|
||||
<meta property="og:site_name" content="Alfieking.dev">
|
||||
<meta property="og:url" content="https://alfieking.dev/">
|
||||
<meta property="og:title" content="{% block og-title %}Home - Alfie's basement{% endblock %}">
|
||||
<meta property="og:description" content="{% block og-description %}server backend survivor{% endblock %}">
|
||||
<meta property="og:image" content="{% block og_image %}/static/content/general_images/icon.webp{% endblock %}">
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
@@ -28,7 +28,6 @@
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/toaster">Toaster</a></li>
|
||||
<li><a href="/terminal" class="ultrafont">Terminal</a></li>
|
||||
<li><a href="/events">Events</a></li>
|
||||
<li><a href="https://git.alfieking.dev/acetheking987">Gitea</a></li>
|
||||
<li><a href="https://www.last.fm/user/acetheking987">LastFm</a></li>
|
||||
@@ -42,56 +41,24 @@
|
||||
</section>
|
||||
</nav>
|
||||
<section>
|
||||
<h6 class="irken">heya, try typing "furry", "irken" or "<span class="scratch">scratch</span>" into this page!</h6>
|
||||
<h6 class="irken">heya, try typing "furry" and "irken" into this page!</h6>
|
||||
</section>
|
||||
<section id="buttons">
|
||||
<h1>BUTTONS</h1>
|
||||
<ul>
|
||||
<li><a herf="https://hijpixel.nekoweb.org/"><img src="/static/content/buttons/hijpixel.gif" alt="hijpixel"></a></li>
|
||||
<li><a href="https://lensdeer.neocities.org/"><img src="/static/content/buttons/lensdeer.gif" alt="lensdeer"></a></li>
|
||||
<li><a href="https://emmixis.net/"><img src="/static/content/buttons/emmixis.gif" alt="emmixis"></a></li>
|
||||
<li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></a></li><!-- hotlink on purpose -->
|
||||
<li><a href="https://ne0nbandit.neocities.org/"><img src="/static/content/buttons/ne0nbandit.png" alt="ne0nbandit"></a></li>
|
||||
<li><a href="https://thinliquid.dev"><img src="/static/content/buttons/thnlqd.png" alt="thinliquid"></a></li>
|
||||
<li><a href="https://nekoweb.org/"><img src="/static/content/buttons/nekoweb.gif" alt="nekoweb"></a><!-- button by s1nez.nekoweb.org --></li>
|
||||
<li><a href="https://s1nez.nekoweb.org/"><img src="/static/content/buttons/s1nez.gif" alt="s1nez"></a></li>
|
||||
<li><a href="https://beeps.website"><img src="/static/content/buttons/beeps.gif" alt="beeps"></a></li>
|
||||
<li><a href="https://itsnotstupid.com"><img src="/static/content/buttons/insia.gif" alt="itsnotstupid"></a></li>
|
||||
<li><a href='https://blinkies.cafe'><img src='/static/content/buttons/blinkiescafe.gif' alt='blinkies.cafe | make your own blinkies!'></a></li>
|
||||
<li><a href="https://eightyeightthirty.one"><img src="/static/content/buttons/8831.png" alt="88x31"></a></li>
|
||||
<li><a href="https://neocities.org"><img src="/static/content/buttons/neocities.gif" alt="neocities"></a></li>
|
||||
<li><a href="https://tuxedodragon.art"><img src="/static/content/buttons/tuxedodragon.gif" alt="tuxedodragon"></a></li>
|
||||
<li><a href="https://beepi.ng"><img src="https://beepi.ng/88x31.png" width="88" height="31" alt="unnick"></a></li>
|
||||
<li><a href="https://sneexy.synth.download"><img src="https://synth.download/assets/buttons/sneexy.svg" alt="Sneexy"></a></li>
|
||||
<li><a href="https://kraafter.me/"><img src="https://kraafter.me/assets/img/button.png" alt="Kraafter.me button" title="kraaftersite"></a></li>
|
||||
<li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></a></li>
|
||||
<li><a href="https://ne0nbandit.neocities.org/"><img src="https://ne0nbandit.github.io/assets/img/btn/mine/nbbanner.png" alt="ne0nbandit"></a></li>
|
||||
<li><a href="https://thinliquid.dev"><img src="https://thinliquid.dev/thnlqd.png" alt="thinliquid"></a></li>
|
||||
<li><a href="https://nekoweb.org/"><img src="https://nekoweb.org/assets/buttons/button6.gif" alt="nekoweb"></a><!-- button by s1nez.nekoweb.org --></li>
|
||||
<li><a href="https://s1nez.nekoweb.org/"><img src="https://s1nez.nekoweb.org/BUTTON.gif" alt="s1nez"></a></li>
|
||||
<li><a href="https://beeps.website"><img src="https://beeps.website/assets/images/88x31-d.gif" alt="beeps"></a></li>
|
||||
<li><a href="https://itsnotstupid.com"><img src="https://itsnotstupid.com/pics/button1.gif" alt="itsnotstupid"></a></li>
|
||||
<li><a href='https://blinkies.cafe'><img src='https://blinkies.cafe/b/display/blinkiesCafe-badge.gif' alt='blinkies.cafe | make your own blinkies!'></a></li>
|
||||
<li><a href="https://eightyeightthirty.one"><img src="https://eightyeightthirty.one/88x31.png" alt="88x31"></a></li>
|
||||
<li><a href="https://neocities.org"><img src="https://cyber.dabamos.de/88x31/neocities-now.gif" alt="neocities"></a></li>
|
||||
<li><a href="https://tuxedodragon.art"><img src="https://tuxedodragon.art/tuxedodragon%2088x31.gif" alt="tuxedodragon"></a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<div id='furnix'>
|
||||
<script type="text/javascript" src="https://tapeykatt.neocities.org/furnix/onionring-variables.js"></script>
|
||||
<script type="text/javascript" src="/static/js/furnix_widget.js"></script>
|
||||
</div>
|
||||
</section>
|
||||
<section class="webring">
|
||||
<a href="https://stellophiliac.github.io/roboring">Roboring</a><br>
|
||||
<a href="https://stellophiliac.github.io/roboring/Toaster/previous"><--</a>
|
||||
<a href="https://stellophiliac.github.io/roboring/Toaster/next">--></a>
|
||||
</section>
|
||||
<section>
|
||||
<div id='ultraring'>
|
||||
<script type="text/javascript" src="https://jack-dawlia.neocities.org/page/shrines/ultrakill/ULTRARING/onionring-variables.js"></script>
|
||||
<script type="text/javascript" src="/static/js/ultraring_widget.js"></script>
|
||||
<noscript>
|
||||
This site is part of <a href="https://jack-dawlia.neocities.org/page/shrines/ultrakill/ULTRARING">ULTRARING</a>!
|
||||
</noscript>
|
||||
</div>
|
||||
</section>
|
||||
<section class="webring">
|
||||
<a href="https://keithhacks.cyou/furryring.php">Furryring</a><br>
|
||||
<a href="https://keithhacks.cyou/furryring.php?prev=proot.uk"><--</a>
|
||||
<a href="https://keithhacks.cyou/furryring.php?next=proot.uk">--></a>
|
||||
</section>
|
||||
<iframe width="150" height="450" style="border:none" src="https://dogspit.nekoweb.org/sidelink.html" name="sidelink"></iframe>
|
||||
<section>
|
||||
<pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre>
|
||||
</section>
|
||||
@@ -100,15 +67,12 @@
|
||||
<main id="main">
|
||||
<header id="home">
|
||||
<div class="row">
|
||||
<img src="/static/content/{% if name == 'Toaster' %}toaster/Toaster_v1.0_sticker.png{% else %}general_images/icon.webp{% endif %}">
|
||||
<img src="/static/content/general_images/icon.webp">
|
||||
<div>
|
||||
<h1>{{ name }}</h1>
|
||||
<h1>Alfie King</h1>
|
||||
<h2 id="typing">server backend survivor</h2>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/toaster" id="toaster-wave">
|
||||
<img src="/static/content/toaster/Toaster_v1.1.png" alt="toaster">
|
||||
</a>
|
||||
</header>
|
||||
<nav id="alt-nav">
|
||||
<ul>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{% extends "bases/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}/{{ directory }} - Alfie's basement{% endblock %}
|
||||
{% block description %}server backend survivor{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/static/css/bases/directory.css">
|
||||
<link rel="stylesheet" href="/static/css/directory.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}{{ title }} - Alfie's basement{% endblock %}
|
||||
{% block description %}server backend survivor{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section>
|
||||
{{ markdown|safe }}
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -4,7 +4,7 @@
|
||||
{% block description %}Bad request. The server could not understand the request due to invalid syntax.{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/static/css/errors/400.css">
|
||||
<link rel="stylesheet" href="/static/css/400.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
<section>
|
||||
<h1>404</h1>
|
||||
<p>
|
||||
It seems like the thing you are looking for does not exist or <code>rm -rf</code> itself out of exsistance.
|
||||
Hey so you know that thing you were looking for? Yeah, it doesn't exist. :P
|
||||
<br><br>
|
||||
So why not try going back to the <a href="/">homepage</a>?
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Actual error</h2>
|
||||
<h2>The actual error for the 2 ppl who care</h2>
|
||||
<p>
|
||||
{{ error }}
|
||||
404: {{ requested_url }} not found :3
|
||||
</p>
|
||||
</section>
|
||||
{% endblock %}
|
||||
</section>
|
||||
@@ -4,7 +4,7 @@
|
||||
{% block description %}An unexpected error occurred on the server.{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/static/css/errors/500.css">
|
||||
<link rel="stylesheet" href="/static/css/500.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -14,10 +14,4 @@
|
||||
Oopsie Woopsie! Uwu We made a fucky wucky!! A wittle fucko boingo! The code monkeys at our headquarters are working VEWY HAWD to fix this!
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Actual error</h2>
|
||||
<p>
|
||||
{{ error }}
|
||||
</p>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,16 +0,0 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}{{ code }} - {{ err_name }}{% endblock %}
|
||||
{% block description %}The page you are looking for does not exist.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section>
|
||||
<img src="https://http.cat/images/{{ code }}.jpg" alt="">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Actual error</h2>
|
||||
<p>
|
||||
{{ description }}
|
||||
</p>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,7 +1,10 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}Home - {{ name }}'s basement{% endblock %}
|
||||
{% block title %}Home - Alfie's basement{% endblock %}
|
||||
{% block description %}server backend survivor{% endblock %}
|
||||
{% block og-title %}Home - Alfie's basement{% endblock %}
|
||||
{% block og-description %}server backend survivor{% endblock %}
|
||||
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/static/css/index.css">
|
||||
@@ -11,8 +14,7 @@
|
||||
<section>
|
||||
<h1>A lil bit abt me</h1>
|
||||
<p>
|
||||
<span style="color: yellow; font-size: 0.8rem;">This is a "bit" out of date, will update soon ^^</span><br>
|
||||
Im not good with writing so dont expect much here. I was a student learning c++ and python. I've Done a few projects that i think
|
||||
Im not good with writing so dont expect much here. I am a student who is learning c++ and python. I've Done a few projects that i think
|
||||
are decent enough to show off, so I have put them on this website. I like to mess around with linux and have a few servers that I run. I've
|
||||
been running a server for a few years now, and I have learned a lot from it. I have also switched to linux on my main computer, which has been
|
||||
slightly annoying at times (mainly because one of my most played games' anticheat doesn't support on linux atm. Also, the lack of photoshop is
|
||||
@@ -38,7 +40,7 @@
|
||||
<img src="https://s1nez.nekoweb.org/img/7dcd20d4.gif" alt="">
|
||||
</section>
|
||||
<div class="flex-row">
|
||||
<a href="https://www.last.fm/user/acetheking987" id="spotify-link">
|
||||
<a href="" id="spotify-link">
|
||||
<div id="spotify">
|
||||
<h1 id="spotify-title"></h1>
|
||||
<h2 id="spotify-artist"></h2>
|
||||
@@ -63,17 +65,12 @@
|
||||
<img src="https://adriansblinkiecollection.neocities.org/stamps/e43.gif" alt="">
|
||||
</section>
|
||||
</div>
|
||||
<section class="smileos">
|
||||
<span style="margin: auto;">
|
||||
Try going to the <span style="color: #ff4343;">Terminal</span> for more information
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Projects & stuff</h1>
|
||||
<p>just some projects ive worked on over time</p>
|
||||
<ul>
|
||||
<li>
|
||||
<h2>alfieking.dev/proot.uk</h2>
|
||||
<h2>alfieking.dev</h2>
|
||||
<p>
|
||||
This website is a project that I have been working on for a while now. I have made a few versions of it, but I have
|
||||
never been happy with them. I am quite happy with this version atm since it is more organized and has a design that I
|
||||
@@ -110,24 +107,6 @@
|
||||
<h1>Some News</h1>
|
||||
<h6>(dont expect this to be updated often tho :P)</h6>
|
||||
<ul>
|
||||
<li>
|
||||
<h2>05-03-2026</h2>
|
||||
<p>
|
||||
This is a short post since i plan on reworking these in the next few days, but i had mad a lot of changes to the site. Some are visible and some are not;
|
||||
the bigget change in the new terminal page that needs more features but that is a later me issue. I also redid the backend so making updates are much
|
||||
easier now. I also need to update the main about me and projects sections since they are old and not very good. """hopefully""" i should make a new news post
|
||||
soon when i have reworked the system.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<h2>18-01-2026</h2>
|
||||
<p>
|
||||
:O an update! thats unheard of on this site (aleast its more often than tf2 gets updates). finding motivation to work on things has been painful
|
||||
recently, but im wokring on my mental state a bit so hopefully there will be more updates. I am writing this before i make any major changes but
|
||||
i hope to add a blog or something, or maybe a daily thoughts thing that pings my phone to get me to write something. I also need to rewrite most
|
||||
of the home page as well since its kinda out of date :P
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<h2>28-06-2025</h2>
|
||||
<p>
|
||||
@@ -135,7 +114,7 @@
|
||||
I didn't want to use a framework at first, mainly because I like the simplicity of a static site, but it allows me to use templatiing and makes
|
||||
adding new features easier and more organized. The site is also more interacive now, with a few secrets on some of the pages. I still plan on adding
|
||||
more secrets and features. I also plan on adding a blog section, that I will move this to, so that I can give updates on the site and other things
|
||||
that I find interesting.
|
||||
that I find interesting.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -150,5 +129,4 @@
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<iframe src="https://john.citrons.xyz/embed?ref=alfieking.dev" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}Critters MK - {{ name }}'s basement{% endblock %}
|
||||
{% block title %}Critters MK - Alfie's basement{% endblock %}
|
||||
{% block description %}furry corner{% endblock %}
|
||||
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
|
||||
{% block keywords %}
|
||||
@@ -34,22 +34,12 @@ protogen v1.0, toaster v1.0
|
||||
<p>
|
||||
Here are some photos from the meets I have attended. I will add more as I attend more meets.
|
||||
</p>
|
||||
<h2 class="gallery-date">26th July 2025</h2>
|
||||
<div class="gallery">
|
||||
<h2 class="gallery-date">26th July 2025</h2>
|
||||
<div class="gallery-images">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
|
||||
</div>
|
||||
</div>
|
||||
<div class="gallery">
|
||||
<h2 class="gallery-date">23rd Aug 2025</h2>
|
||||
<div class="gallery-images">
|
||||
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130640362.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130648109.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130659800.jpg" alt="Critters MK">
|
||||
</div>
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}Paws'N'Pistons - {{ name }}'s basement{% endblock %}
|
||||
{% block title %}Paws'N'Pistons - Alfie's basement{% endblock %}
|
||||
{% block description %}furry corner{% endblock %}
|
||||
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
|
||||
{% block keywords %}
|
||||
@@ -42,25 +42,23 @@ protogen v1.0, toaster v1.0
|
||||
ALSO, one of them offered to let me try their fursuit!!! Im now going to speedrun going broke trying to get a fursuit of my own cus of this :3 (I was
|
||||
already planning on getting one, but this just made me want one more).
|
||||
<br>
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_200906329.jpg" alt="me in a fursuit" id="woooooo">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_200906329.jpg" alt="me in a fursuit" id="woooooo">
|
||||
<br>
|
||||
The fursuit belongs to <a href="https://www.tiktok.com/@trickythefox" target="_blank">Tricky the Fox</a>, they are a very chill person and I had a great time talking to them ^w^.
|
||||
<h1>Photos :3</h1>
|
||||
<p>
|
||||
Here are some photos from the meets I have attended. I will add more as I attend more meets.
|
||||
</p>
|
||||
<h2 class="gallery-date">3rd Aug 2025</h2>
|
||||
<div class="gallery">
|
||||
<h2 class="gallery-date">3rd Aug 2025</h2>
|
||||
<div class="gallery-images">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_140629639.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141242090.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_182023562.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_184321576.jpg" alt="Paws'N'Pistons">
|
||||
</div>
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_140629639.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141242090.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_182023562.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_184321576.jpg" alt="Paws'N'Pistons">
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}Toaster - {{ name }}'s basement{% endblock %}
|
||||
{% block title %}Toaster - Alfie's basement{% endblock %}
|
||||
{% block description %}furry corner{% endblock %}
|
||||
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
|
||||
{% block keywords %}
|
||||
@@ -86,19 +86,19 @@ protogen v1.0, toaster v1.0
|
||||
<li>
|
||||
<a href="/events/crittersmk"><b>Critters MK</b></a> - A furmeet in Milton Keynes.
|
||||
<div class="fur-meet-gallery-small">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
|
||||
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
|
||||
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/events/paws-n-pistons"><b>Paws'N'Pistons</b></a> - A furry car meet around the UK.
|
||||
<div class="fur-meet-gallery-small">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
|
||||
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
|
||||
</div>
|
||||
</li>
|
||||
<p>Click on the links to view more photos from each event :3</p>
|
||||
@@ -1,63 +0,0 @@
|
||||
{% extends "bases/base.html" %}
|
||||
|
||||
{% block title %}SmileOS 2.0{% endblock %}
|
||||
{% block description %}SmileOS 2.0{% endblock %}
|
||||
{% block og_image %}static/content/smileos/SmileOS_2_icon_smile.webp{% endblock %}
|
||||
{% block icon %}static/content/smileos/SmileOS_2_icon_smile.webp{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/static/css/terminal.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section id="terminal">
|
||||
<div class="smileos-header">
|
||||
<img src="/static/content/smileos/SmileOS_2_icon_smile.webp" alt="smile">
|
||||
SmileOS 2.0
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_5.png" alt="minimize" style="margin-left: auto;">
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_4.png" alt="maximize">
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_3.png" alt="close">
|
||||
</div>
|
||||
<div id="terminal-container">
|
||||
<img src="/static/content/smileos/SmileOS2.webp" alt="logo" id="smileos-logo">
|
||||
<div id="terminal-buttons">
|
||||
<button class="terminal-button" id="smileos-tip">
|
||||
Tip of the Day
|
||||
</button>
|
||||
<button class="terminal-button" id="smileos-snake">
|
||||
Snake
|
||||
</button>
|
||||
<button class="terminal-button" id="smileos-leaderboard">
|
||||
Leaderboard
|
||||
</button>
|
||||
<button class="terminal-button" id="smileos-about">
|
||||
About
|
||||
</button>
|
||||
</div>
|
||||
<div id="terminal-window">
|
||||
<div class="smileos-header">
|
||||
<img src="/static/content/smileos/SmileOS_2_icon_tip.webp" alt="tip">
|
||||
<span id="smileos-window-title">Tip of the Day</span>
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_5.png" alt="minimize" style="margin-left: auto;">
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_4.png" alt="maximize">
|
||||
<img src="/static/content/smileos/SmileOS_2_top_button_3.png" alt="close">
|
||||
</div>
|
||||
<div id="window-container">
|
||||
<div id="window-content">
|
||||
<span id="smileos-window-content"><span class="red">SLAM BOUNCING</span>: Jump immediately after landing from a <span class="red">ground slam</span> to jump higher. The longer the ground slam fall, the higher the bounce.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<p>
|
||||
Note: this page has background music, you may have to allow the music in the browser and refesh to let it play, or you can try
|
||||
press <a id="smileos-restart-music">this</a> to restart it
|
||||
</p>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/smileos.js"></script>
|
||||
{% endblock %}
|
||||