Merge pull request 'django' (#1) from django into master
Reviewed-on: #1
207
.gitignore
vendored
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[codz]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
#uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
#poetry.toml
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||||
|
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||||
|
#pdm.lock
|
||||||
|
#pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# pixi
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||||
|
#pixi.lock
|
||||||
|
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||||
|
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||||
|
.pixi
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.envrc
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Abstra
|
||||||
|
# Abstra is an AI-powered process automation framework.
|
||||||
|
# Ignore directories containing user credentials, local state, and settings.
|
||||||
|
# Learn more at https://abstra.io/docs
|
||||||
|
.abstra/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||||
|
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||||
|
# you could uncomment the following to ignore the entire vscode folder
|
||||||
|
# .vscode/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# Cursor
|
||||||
|
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
||||||
|
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
||||||
|
# refer to https://docs.cursor.com/context/ignore-files
|
||||||
|
.cursorignore
|
||||||
|
.cursorindexingignore
|
||||||
|
|
||||||
|
# Marimo
|
||||||
|
marimo/_static/
|
||||||
|
marimo/_lsp/
|
||||||
|
__marimo__/
|
BIN
db.sqlite3
Normal file
22
manage.py
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shrinkinminkin.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
137
requirements.txt
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
appdirs==1.4.4
|
||||||
|
argcomplete==3.1.4
|
||||||
|
attrs==23.2.0
|
||||||
|
beautifulsoup4==4.12.3
|
||||||
|
blinker==1.7.0
|
||||||
|
bottle==0.12.25
|
||||||
|
Brlapi==0.8.5
|
||||||
|
Brotli==1.1.0
|
||||||
|
certifi==2023.11.17
|
||||||
|
chardet==5.2.0
|
||||||
|
click==8.1.6
|
||||||
|
colorama==0.4.6
|
||||||
|
command-not-found==0.3
|
||||||
|
configobj==5.0.8
|
||||||
|
contourpy==1.0.7
|
||||||
|
cryptography==41.0.7
|
||||||
|
cupshelpers==1.0
|
||||||
|
cycler==0.11.0
|
||||||
|
dbus-python==1.3.2
|
||||||
|
decorator==5.1.1
|
||||||
|
defer==1.0.6
|
||||||
|
defusedxml==0.7.1
|
||||||
|
deprecation==2.0.7
|
||||||
|
dill==0.3.8
|
||||||
|
distro==1.9.0
|
||||||
|
docker==5.0.3
|
||||||
|
eyed3==0.9.7
|
||||||
|
filelock==3.13.1
|
||||||
|
filetype==1.2.0
|
||||||
|
fonttools==4.46.0
|
||||||
|
fs==2.4.16
|
||||||
|
Glances==3.4.0.3
|
||||||
|
gyp==0.1
|
||||||
|
html2text==2024.2.26
|
||||||
|
httplib2==0.20.4
|
||||||
|
idna==3.6
|
||||||
|
ifaddr==0.2.0
|
||||||
|
IMDbPY==2021.4.18
|
||||||
|
influxdb==5.3.1
|
||||||
|
kiwisolver==0.0.0
|
||||||
|
launchpadlib==1.11.0
|
||||||
|
lazr.restfulclient==0.14.6
|
||||||
|
lazr.uri==1.0.6
|
||||||
|
libevdev==0.5
|
||||||
|
libvirt-python==10.0.0
|
||||||
|
louis==3.29.0
|
||||||
|
lxml==5.2.1
|
||||||
|
lz4==4.0.2+dfsg
|
||||||
|
Mako==1.3.2.dev0
|
||||||
|
Markdown==3.5.2
|
||||||
|
markdown-it-py==3.0.0
|
||||||
|
MarkupSafe==2.1.5
|
||||||
|
matplotlib==3.6.3
|
||||||
|
mdurl==0.1.2
|
||||||
|
mpmath==0.0.0
|
||||||
|
msgpack==1.0.3
|
||||||
|
multiprocess==0.70.16
|
||||||
|
mutagen==1.46.0
|
||||||
|
nemo-emblems==6.4.0
|
||||||
|
netaddr==0.8.0
|
||||||
|
netifaces==0.11.0
|
||||||
|
nicotine-plus==3.2.9
|
||||||
|
numpy==1.26.4
|
||||||
|
oauthlib==3.2.2
|
||||||
|
onboard==1.4.1
|
||||||
|
packaging==24.0
|
||||||
|
PAM==0.4.2
|
||||||
|
pexpect==4.9.0
|
||||||
|
pillow==10.2.0
|
||||||
|
pipx==1.4.3
|
||||||
|
platformdirs==4.2.0
|
||||||
|
ply==3.11
|
||||||
|
psutil==5.9.8
|
||||||
|
ptyprocess==0.7.0
|
||||||
|
pulsemixer==1.5.1
|
||||||
|
pyasn1==0.4.8
|
||||||
|
pyasyncore==1.0.2
|
||||||
|
pycairo==1.25.1
|
||||||
|
pycryptodomex==3.20.0
|
||||||
|
pycups==2.0.1
|
||||||
|
pycurl==7.45.3
|
||||||
|
pyelftools==0.30
|
||||||
|
Pygments==2.17.2
|
||||||
|
PyGObject==3.48.2
|
||||||
|
PyICU==2.12
|
||||||
|
pyinotify==0.9.6
|
||||||
|
PyJWT==2.7.0
|
||||||
|
PyNaCl==1.5.0
|
||||||
|
pyparsing==3.1.1
|
||||||
|
pyparted==3.12.0
|
||||||
|
pypng==0.20231004.0
|
||||||
|
pysmi==0.3.4
|
||||||
|
pysnmp==4.4.12
|
||||||
|
pystache==0.6.0
|
||||||
|
python-apt==2.7.7+ubuntu4
|
||||||
|
python-dateutil==2.8.2
|
||||||
|
python-debian==0.1.49+ubuntu2
|
||||||
|
python-gnupg==0.5.2
|
||||||
|
python-magic==0.4.27
|
||||||
|
python-xlib==0.33
|
||||||
|
pytz==2024.1
|
||||||
|
pyudev==0.24.0
|
||||||
|
pyxdg==0.28
|
||||||
|
PyYAML==6.0.1
|
||||||
|
qrcode==7.4.2
|
||||||
|
ranger-fm==1.9.3
|
||||||
|
repolib==2.2.1
|
||||||
|
requests==2.31.0
|
||||||
|
requests-file==1.5.1
|
||||||
|
rich==13.7.1
|
||||||
|
SciPy==1.11.4
|
||||||
|
setproctitle==1.3.3
|
||||||
|
setuptools==68.1.2
|
||||||
|
six==1.16.0
|
||||||
|
soupsieve==2.5
|
||||||
|
sympy==1.12
|
||||||
|
systemd-python==235
|
||||||
|
tinycss2==1.2.1
|
||||||
|
tldextract==3.1.2
|
||||||
|
typing_extensions==4.10.0
|
||||||
|
ubuntu-drivers-common==0.0.0
|
||||||
|
ufoLib2==0.16.0
|
||||||
|
ufw==0.36.2
|
||||||
|
ujson==5.9.0
|
||||||
|
unicodedata2==15.1.0
|
||||||
|
Unidecode==1.3.8
|
||||||
|
urllib3==2.0.7
|
||||||
|
userpath==1.9.1
|
||||||
|
wadllib==1.3.6
|
||||||
|
webencodings==0.5.1
|
||||||
|
websocket-client==1.7.0
|
||||||
|
websockets==10.4
|
||||||
|
wheel==0.42.0
|
||||||
|
xdg==5
|
||||||
|
xkit==0.0.0
|
||||||
|
xlrd==2.0.1
|
||||||
|
yt-dlp==2024.4.9
|
0
shrinkinminkin/__init__.py
Normal file
16
shrinkinminkin/asgi.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
ASGI config for shrinkinminkin project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shrinkinminkin.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
130
shrinkinminkin/settings.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
"""
|
||||||
|
Django settings for shrinkinminkin project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 5.2.3.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'django-insecure-)z5-$t&%njx^$4wrsq4+@#oybrssf_z*1(p9t(^o2v!2nkybab'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['localhost', 'localhost:8000', '127.0.0.1']
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'web',
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'shrinkinminkin.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'shrinkinminkin.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = 'static/'
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
STATICFILES_DIRS = [BASE_DIR / 'static',]
|
||||||
|
STORAGES = {
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
13
shrinkinminkin/urls.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
|
from web.views import index, album, socials, mailing_list
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', index, name='index'),
|
||||||
|
path('album/', album, name='album'),
|
||||||
|
path('album.html/', album, name='album'),
|
||||||
|
path('socials/', socials, name='socials'),
|
||||||
|
path('socials.html/', socials, name='socials'),
|
||||||
|
path('mailing_list/', mailing_list, name='mailing_list'),
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
]
|
16
shrinkinminkin/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
WSGI config for shrinkinminkin project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shrinkinminkin.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
7
static/css/bootstrap.min.css
vendored
Normal file
70
static/css/style.css
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
@font-face { font-family: Virgo; src: url('../fonts/virgo.ttf'); }
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #189ccf;
|
||||||
|
font-family: Virgo, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-img {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
width: 150px;
|
||||||
|
padding-right: 10px;
|
||||||
|
display: inline;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#band-img-1 {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive-iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navi-link {
|
||||||
|
color: #ff0000;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navi-link:hover {
|
||||||
|
opacity: 70%;
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-container {
|
||||||
|
color: #20d582;
|
||||||
|
background-color: #8220d5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
BIN
static/fonts/nabla.ttf
Normal file
BIN
static/fonts/virgo.ttf
Normal file
BIN
static/img/album_release_header.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/band_1.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
static/img/band_banner.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
static/img/bugman_sticker.png
Normal file
After Width: | Height: | Size: 242 KiB |
BIN
static/img/members.png
Normal file
After Width: | Height: | Size: 5.7 MiB |
BIN
static/img/shrinkin_minkin_album_header.png
Normal file
After Width: | Height: | Size: 47 KiB |
7
static/js/bootstrap.min.js
vendored
Normal file
2
static/js/p5.min.js
vendored
Normal file
230
static/js/sketch.js
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
let myFont;
|
||||||
|
function preload() {
|
||||||
|
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = createCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = createCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
canvas.parent('shrinkin-sketch')
|
||||||
|
}
|
||||||
|
|
||||||
|
function windowResized() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
constructor(x, y, r) {
|
||||||
|
this.position = new p5.Vector(x, y);
|
||||||
|
this.velocity = p5.Vector.random2D();
|
||||||
|
this.velocity.mult(3);
|
||||||
|
this.r = r;
|
||||||
|
this.m = r * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.position.add(this.velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBoundaryCollision() {
|
||||||
|
if (this.position.x > width - this.r) {
|
||||||
|
this.position.x = width - this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.x < this.r) {
|
||||||
|
this.position.x = this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.y > height - this.r) {
|
||||||
|
this.position.y = height - this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
} else if (this.position.y < this.r) {
|
||||||
|
this.position.y = this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollision(other) {
|
||||||
|
// Get distances between the balls components
|
||||||
|
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||||
|
|
||||||
|
// Calculate magnitude of the vector separating the balls
|
||||||
|
let distanceVectMag = distanceVect.mag();
|
||||||
|
|
||||||
|
// Minimum distance before they are touching
|
||||||
|
let minDistance = this.r + other.r;
|
||||||
|
|
||||||
|
if (distanceVectMag < minDistance) {
|
||||||
|
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||||
|
let d = distanceVect.copy();
|
||||||
|
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||||
|
other.position.add(correctionVector);
|
||||||
|
this.position.sub(correctionVector);
|
||||||
|
|
||||||
|
// get angle of distanceVect
|
||||||
|
let theta = distanceVect.heading();
|
||||||
|
// precalculate trig values
|
||||||
|
let sine = sin(theta);
|
||||||
|
let cosine = cos(theta);
|
||||||
|
|
||||||
|
/* bTemp will hold rotated ball this.positions. You
|
||||||
|
just need to worry about bTemp[1] this.position*/
|
||||||
|
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
/* this ball's this.position is relative to the other
|
||||||
|
so you can use the vector between them (bVect) as the
|
||||||
|
reference point in the rotation expressions.
|
||||||
|
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||||
|
automatically to 0.0, which is what you want
|
||||||
|
since b[1] will rotate around b[0] */
|
||||||
|
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||||
|
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||||
|
|
||||||
|
// rotate Temporary velocities
|
||||||
|
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||||
|
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||||
|
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||||
|
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||||
|
|
||||||
|
/* Now that velocities are rotated, you can use 1D
|
||||||
|
conservation of momentum equations to calculate
|
||||||
|
the final this.velocity along the x-axis. */
|
||||||
|
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[0].x =
|
||||||
|
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[0].y = vTemp[0].y;
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[1].x =
|
||||||
|
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[1].y = vTemp[1].y;
|
||||||
|
|
||||||
|
// hack to avoid clumping
|
||||||
|
bTemp[0].x += vFinal[0].x;
|
||||||
|
bTemp[1].x += vFinal[1].x;
|
||||||
|
|
||||||
|
/* Rotate ball this.positions and velocities back
|
||||||
|
Reverse signs in trig expressions to rotate
|
||||||
|
in the opposite direction */
|
||||||
|
// rotate balls
|
||||||
|
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||||
|
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||||
|
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||||
|
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||||
|
|
||||||
|
// update balls to screen this.position
|
||||||
|
other.position.x = this.position.x + bFinal[1].x;
|
||||||
|
other.position.y = this.position.y + bFinal[1].y;
|
||||||
|
|
||||||
|
this.position.add(bFinal[0]);
|
||||||
|
|
||||||
|
// update velocities
|
||||||
|
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||||
|
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||||
|
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||||
|
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display(friend1, friend2) {
|
||||||
|
this.update()
|
||||||
|
noStroke();
|
||||||
|
fill('#ff0000');
|
||||||
|
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||||
|
this.checkBoundaryCollision()
|
||||||
|
this.checkCollision(friend1)
|
||||||
|
this.checkCollision(friend2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logo {
|
||||||
|
constructor() {
|
||||||
|
this.yOffset = 0
|
||||||
|
this.up = false
|
||||||
|
this.textSize = 36
|
||||||
|
this.bounceDepth = 10
|
||||||
|
this.speed = 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
display() {
|
||||||
|
fill('#20d582');
|
||||||
|
textFont(myFont);
|
||||||
|
|
||||||
|
if (windowWidth/6 > 120) {
|
||||||
|
textSize(120);
|
||||||
|
} else {
|
||||||
|
textSize(windowWidth/6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||||
|
} else {
|
||||||
|
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bounce()
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce() {
|
||||||
|
if (!this.up) {
|
||||||
|
if (this.yOffset <= this.bounceDepth) {
|
||||||
|
this.yOffset = this.yOffset + this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset > this.bounceDepth) {
|
||||||
|
this.up = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.yOffset > 0) {
|
||||||
|
this.yOffset = this.yOffset - this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset < 0) {
|
||||||
|
this.up = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ball1 = new Ball(100, 400, 20)
|
||||||
|
let ball2 = new Ball(700, 400, 80)
|
||||||
|
let ball3 = new Ball(0, 200, 60)
|
||||||
|
let logo = new Logo()
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
background('#209bd0');
|
||||||
|
|
||||||
|
|
||||||
|
ball1.display(ball2, ball3)
|
||||||
|
ball2.display(ball1, ball3)
|
||||||
|
ball3.display(ball1, ball2)
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
ball2.r = 40;
|
||||||
|
ball3.r = 30;
|
||||||
|
} else {
|
||||||
|
ball2.r = 80;
|
||||||
|
ball3.r = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo.display()
|
||||||
|
|
||||||
|
}
|
227
static/js/sketch_export.js
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
let myFont;
|
||||||
|
function preload() {
|
||||||
|
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
var canvas = createCanvas(1200, 400);
|
||||||
|
canvas.parent('shrinkin-sketch')
|
||||||
|
createLoop({duration:120, gif:true})
|
||||||
|
}
|
||||||
|
|
||||||
|
function windowResized() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
constructor(x, y, r) {
|
||||||
|
this.position = new p5.Vector(x, y);
|
||||||
|
this.velocity = p5.Vector.random2D();
|
||||||
|
this.velocity.mult(3);
|
||||||
|
this.r = r;
|
||||||
|
this.m = r * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.position.add(this.velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBoundaryCollision() {
|
||||||
|
if (this.position.x > width - this.r) {
|
||||||
|
this.position.x = width - this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.x < this.r) {
|
||||||
|
this.position.x = this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.y > height - this.r) {
|
||||||
|
this.position.y = height - this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
} else if (this.position.y < this.r) {
|
||||||
|
this.position.y = this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollision(other) {
|
||||||
|
// Get distances between the balls components
|
||||||
|
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||||
|
|
||||||
|
// Calculate magnitude of the vector separating the balls
|
||||||
|
let distanceVectMag = distanceVect.mag();
|
||||||
|
|
||||||
|
// Minimum distance before they are touching
|
||||||
|
let minDistance = this.r + other.r;
|
||||||
|
|
||||||
|
if (distanceVectMag < minDistance) {
|
||||||
|
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||||
|
let d = distanceVect.copy();
|
||||||
|
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||||
|
other.position.add(correctionVector);
|
||||||
|
this.position.sub(correctionVector);
|
||||||
|
|
||||||
|
// get angle of distanceVect
|
||||||
|
let theta = distanceVect.heading();
|
||||||
|
// precalculate trig values
|
||||||
|
let sine = sin(theta);
|
||||||
|
let cosine = cos(theta);
|
||||||
|
|
||||||
|
/* bTemp will hold rotated ball this.positions. You
|
||||||
|
just need to worry about bTemp[1] this.position*/
|
||||||
|
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
/* this ball's this.position is relative to the other
|
||||||
|
so you can use the vector between them (bVect) as the
|
||||||
|
reference point in the rotation expressions.
|
||||||
|
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||||
|
automatically to 0.0, which is what you want
|
||||||
|
since b[1] will rotate around b[0] */
|
||||||
|
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||||
|
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||||
|
|
||||||
|
// rotate Temporary velocities
|
||||||
|
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||||
|
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||||
|
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||||
|
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||||
|
|
||||||
|
/* Now that velocities are rotated, you can use 1D
|
||||||
|
conservation of momentum equations to calculate
|
||||||
|
the final this.velocity along the x-axis. */
|
||||||
|
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[0].x =
|
||||||
|
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[0].y = vTemp[0].y;
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[1].x =
|
||||||
|
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[1].y = vTemp[1].y;
|
||||||
|
|
||||||
|
// hack to avoid clumping
|
||||||
|
bTemp[0].x += vFinal[0].x;
|
||||||
|
bTemp[1].x += vFinal[1].x;
|
||||||
|
|
||||||
|
/* Rotate ball this.positions and velocities back
|
||||||
|
Reverse signs in trig expressions to rotate
|
||||||
|
in the opposite direction */
|
||||||
|
// rotate balls
|
||||||
|
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||||
|
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||||
|
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||||
|
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||||
|
|
||||||
|
// update balls to screen this.position
|
||||||
|
other.position.x = this.position.x + bFinal[1].x;
|
||||||
|
other.position.y = this.position.y + bFinal[1].y;
|
||||||
|
|
||||||
|
this.position.add(bFinal[0]);
|
||||||
|
|
||||||
|
// update velocities
|
||||||
|
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||||
|
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||||
|
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||||
|
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display(friend1, friend2) {
|
||||||
|
this.update()
|
||||||
|
noStroke();
|
||||||
|
fill('#ff0000');
|
||||||
|
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||||
|
this.checkBoundaryCollision()
|
||||||
|
this.checkCollision(friend1)
|
||||||
|
this.checkCollision(friend2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logo {
|
||||||
|
constructor() {
|
||||||
|
this.yOffset = 0
|
||||||
|
this.up = false
|
||||||
|
this.textSize = 36
|
||||||
|
this.bounceDepth = 10
|
||||||
|
this.speed = 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
display() {
|
||||||
|
fill('#20d582');
|
||||||
|
textFont(myFont);
|
||||||
|
|
||||||
|
if (windowWidth/6 > 120) {
|
||||||
|
textSize(120);
|
||||||
|
} else {
|
||||||
|
textSize(windowWidth/6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||||
|
} else {
|
||||||
|
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bounce()
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce() {
|
||||||
|
if (!this.up) {
|
||||||
|
if (this.yOffset <= this.bounceDepth) {
|
||||||
|
this.yOffset = this.yOffset + this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset > this.bounceDepth) {
|
||||||
|
this.up = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.yOffset > 0) {
|
||||||
|
this.yOffset = this.yOffset - this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset < 0) {
|
||||||
|
this.up = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ball1 = new Ball(100, 400, 20)
|
||||||
|
let ball2 = new Ball(700, 400, 80)
|
||||||
|
let ball3 = new Ball(0, 200, 60)
|
||||||
|
let logo = new Logo()
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
background('#209bd0');
|
||||||
|
|
||||||
|
|
||||||
|
ball1.display(ball2, ball3)
|
||||||
|
ball2.display(ball1, ball3)
|
||||||
|
ball3.display(ball1, ball2)
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
ball2.r = 40;
|
||||||
|
ball3.r = 30;
|
||||||
|
} else {
|
||||||
|
ball2.r = 80;
|
||||||
|
ball3.r = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo.display()
|
||||||
|
|
||||||
|
}
|
0
web/__init__.py
Normal file
6
web/admin.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from web.models import MailingList
|
||||||
|
|
||||||
|
admin.site.register(MailingList)
|
||||||
|
|
||||||
|
# Register your models here.
|
6
web/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class WebConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'web'
|
27
web/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 5.2.3 on 2025-06-29 21:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MailingList',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True, null=True)),
|
||||||
|
('active', models.BooleanField(default=True)),
|
||||||
|
('email', models.EmailField(max_length=254)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
web/migrations/__init__.py
Normal file
BIN
web/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
web/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
14
web/models.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class BaseModel(models.Model):
|
||||||
|
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
|
||||||
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class MailingList(BaseModel):
|
||||||
|
email = models.EmailField(max_length=254, blank=False, null=False)
|
7
web/static/css/bootstrap.min.css
vendored
Normal file
69
web/static/css/style.css
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
@font-face { font-family: Virgo; src: url('../fonts/virgo.ttf'); }
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #189ccf;
|
||||||
|
font-family: Virgo, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-img {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
width: 150px;
|
||||||
|
padding-right: 10px;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#band-img-1 {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive-iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navi-link {
|
||||||
|
color: #ff0000;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navi-link:hover {
|
||||||
|
opacity: 70%;
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-container {
|
||||||
|
color: #20d582;
|
||||||
|
background-color: #8220d5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
BIN
web/static/fonts/nabla.ttf
Normal file
BIN
web/static/fonts/virgo.ttf
Normal file
BIN
web/static/img/album_release_header.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
web/static/img/band_1.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
web/static/img/band_banner.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
web/static/img/bugman_sticker.png
Normal file
After Width: | Height: | Size: 242 KiB |
BIN
web/static/img/members.png
Normal file
After Width: | Height: | Size: 5.7 MiB |
BIN
web/static/img/shrinkin_minkin_album_header.png
Normal file
After Width: | Height: | Size: 47 KiB |
7
web/static/js/bootstrap.min.js
vendored
Normal file
2
web/static/js/p5.min.js
vendored
Normal file
230
web/static/js/sketch.js
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
let myFont;
|
||||||
|
function preload() {
|
||||||
|
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = createCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = createCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
canvas.parent('shrinkin-sketch')
|
||||||
|
}
|
||||||
|
|
||||||
|
function windowResized() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
constructor(x, y, r) {
|
||||||
|
this.position = new p5.Vector(x, y);
|
||||||
|
this.velocity = p5.Vector.random2D();
|
||||||
|
this.velocity.mult(3);
|
||||||
|
this.r = r;
|
||||||
|
this.m = r * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.position.add(this.velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBoundaryCollision() {
|
||||||
|
if (this.position.x > width - this.r) {
|
||||||
|
this.position.x = width - this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.x < this.r) {
|
||||||
|
this.position.x = this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.y > height - this.r) {
|
||||||
|
this.position.y = height - this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
} else if (this.position.y < this.r) {
|
||||||
|
this.position.y = this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollision(other) {
|
||||||
|
// Get distances between the balls components
|
||||||
|
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||||
|
|
||||||
|
// Calculate magnitude of the vector separating the balls
|
||||||
|
let distanceVectMag = distanceVect.mag();
|
||||||
|
|
||||||
|
// Minimum distance before they are touching
|
||||||
|
let minDistance = this.r + other.r;
|
||||||
|
|
||||||
|
if (distanceVectMag < minDistance) {
|
||||||
|
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||||
|
let d = distanceVect.copy();
|
||||||
|
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||||
|
other.position.add(correctionVector);
|
||||||
|
this.position.sub(correctionVector);
|
||||||
|
|
||||||
|
// get angle of distanceVect
|
||||||
|
let theta = distanceVect.heading();
|
||||||
|
// precalculate trig values
|
||||||
|
let sine = sin(theta);
|
||||||
|
let cosine = cos(theta);
|
||||||
|
|
||||||
|
/* bTemp will hold rotated ball this.positions. You
|
||||||
|
just need to worry about bTemp[1] this.position*/
|
||||||
|
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
/* this ball's this.position is relative to the other
|
||||||
|
so you can use the vector between them (bVect) as the
|
||||||
|
reference point in the rotation expressions.
|
||||||
|
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||||
|
automatically to 0.0, which is what you want
|
||||||
|
since b[1] will rotate around b[0] */
|
||||||
|
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||||
|
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||||
|
|
||||||
|
// rotate Temporary velocities
|
||||||
|
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||||
|
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||||
|
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||||
|
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||||
|
|
||||||
|
/* Now that velocities are rotated, you can use 1D
|
||||||
|
conservation of momentum equations to calculate
|
||||||
|
the final this.velocity along the x-axis. */
|
||||||
|
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[0].x =
|
||||||
|
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[0].y = vTemp[0].y;
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[1].x =
|
||||||
|
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[1].y = vTemp[1].y;
|
||||||
|
|
||||||
|
// hack to avoid clumping
|
||||||
|
bTemp[0].x += vFinal[0].x;
|
||||||
|
bTemp[1].x += vFinal[1].x;
|
||||||
|
|
||||||
|
/* Rotate ball this.positions and velocities back
|
||||||
|
Reverse signs in trig expressions to rotate
|
||||||
|
in the opposite direction */
|
||||||
|
// rotate balls
|
||||||
|
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||||
|
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||||
|
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||||
|
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||||
|
|
||||||
|
// update balls to screen this.position
|
||||||
|
other.position.x = this.position.x + bFinal[1].x;
|
||||||
|
other.position.y = this.position.y + bFinal[1].y;
|
||||||
|
|
||||||
|
this.position.add(bFinal[0]);
|
||||||
|
|
||||||
|
// update velocities
|
||||||
|
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||||
|
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||||
|
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||||
|
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display(friend1, friend2) {
|
||||||
|
this.update()
|
||||||
|
noStroke();
|
||||||
|
fill('#ff0000');
|
||||||
|
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||||
|
this.checkBoundaryCollision()
|
||||||
|
this.checkCollision(friend1)
|
||||||
|
this.checkCollision(friend2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logo {
|
||||||
|
constructor() {
|
||||||
|
this.yOffset = 0
|
||||||
|
this.up = false
|
||||||
|
this.textSize = 36
|
||||||
|
this.bounceDepth = 10
|
||||||
|
this.speed = 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
display() {
|
||||||
|
fill('#20d582');
|
||||||
|
textFont(myFont);
|
||||||
|
|
||||||
|
if (windowWidth/6 > 120) {
|
||||||
|
textSize(120);
|
||||||
|
} else {
|
||||||
|
textSize(windowWidth/6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||||
|
} else {
|
||||||
|
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bounce()
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce() {
|
||||||
|
if (!this.up) {
|
||||||
|
if (this.yOffset <= this.bounceDepth) {
|
||||||
|
this.yOffset = this.yOffset + this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset > this.bounceDepth) {
|
||||||
|
this.up = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.yOffset > 0) {
|
||||||
|
this.yOffset = this.yOffset - this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset < 0) {
|
||||||
|
this.up = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ball1 = new Ball(100, 400, 20)
|
||||||
|
let ball2 = new Ball(700, 400, 80)
|
||||||
|
let ball3 = new Ball(0, 200, 60)
|
||||||
|
let logo = new Logo()
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
background('#209bd0');
|
||||||
|
|
||||||
|
|
||||||
|
ball1.display(ball2, ball3)
|
||||||
|
ball2.display(ball1, ball3)
|
||||||
|
ball3.display(ball1, ball2)
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
ball2.r = 40;
|
||||||
|
ball3.r = 30;
|
||||||
|
} else {
|
||||||
|
ball2.r = 80;
|
||||||
|
ball3.r = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo.display()
|
||||||
|
|
||||||
|
}
|
227
web/static/js/sketch_export.js
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
let myFont;
|
||||||
|
function preload() {
|
||||||
|
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
var canvas = createCanvas(1200, 400);
|
||||||
|
canvas.parent('shrinkin-sketch')
|
||||||
|
createLoop({duration:120, gif:true})
|
||||||
|
}
|
||||||
|
|
||||||
|
function windowResized() {
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 200);
|
||||||
|
} else {
|
||||||
|
var canvas = resizeCanvas(windowWidth, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
constructor(x, y, r) {
|
||||||
|
this.position = new p5.Vector(x, y);
|
||||||
|
this.velocity = p5.Vector.random2D();
|
||||||
|
this.velocity.mult(3);
|
||||||
|
this.r = r;
|
||||||
|
this.m = r * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.position.add(this.velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBoundaryCollision() {
|
||||||
|
if (this.position.x > width - this.r) {
|
||||||
|
this.position.x = width - this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.x < this.r) {
|
||||||
|
this.position.x = this.r;
|
||||||
|
this.velocity.x *= -1;
|
||||||
|
} else if (this.position.y > height - this.r) {
|
||||||
|
this.position.y = height - this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
} else if (this.position.y < this.r) {
|
||||||
|
this.position.y = this.r;
|
||||||
|
this.velocity.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollision(other) {
|
||||||
|
// Get distances between the balls components
|
||||||
|
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||||
|
|
||||||
|
// Calculate magnitude of the vector separating the balls
|
||||||
|
let distanceVectMag = distanceVect.mag();
|
||||||
|
|
||||||
|
// Minimum distance before they are touching
|
||||||
|
let minDistance = this.r + other.r;
|
||||||
|
|
||||||
|
if (distanceVectMag < minDistance) {
|
||||||
|
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||||
|
let d = distanceVect.copy();
|
||||||
|
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||||
|
other.position.add(correctionVector);
|
||||||
|
this.position.sub(correctionVector);
|
||||||
|
|
||||||
|
// get angle of distanceVect
|
||||||
|
let theta = distanceVect.heading();
|
||||||
|
// precalculate trig values
|
||||||
|
let sine = sin(theta);
|
||||||
|
let cosine = cos(theta);
|
||||||
|
|
||||||
|
/* bTemp will hold rotated ball this.positions. You
|
||||||
|
just need to worry about bTemp[1] this.position*/
|
||||||
|
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
/* this ball's this.position is relative to the other
|
||||||
|
so you can use the vector between them (bVect) as the
|
||||||
|
reference point in the rotation expressions.
|
||||||
|
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||||
|
automatically to 0.0, which is what you want
|
||||||
|
since b[1] will rotate around b[0] */
|
||||||
|
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||||
|
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||||
|
|
||||||
|
// rotate Temporary velocities
|
||||||
|
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||||
|
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||||
|
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||||
|
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||||
|
|
||||||
|
/* Now that velocities are rotated, you can use 1D
|
||||||
|
conservation of momentum equations to calculate
|
||||||
|
the final this.velocity along the x-axis. */
|
||||||
|
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[0].x =
|
||||||
|
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[0].y = vTemp[0].y;
|
||||||
|
|
||||||
|
// final rotated this.velocity for b[0]
|
||||||
|
vFinal[1].x =
|
||||||
|
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||||
|
(this.m + other.m);
|
||||||
|
vFinal[1].y = vTemp[1].y;
|
||||||
|
|
||||||
|
// hack to avoid clumping
|
||||||
|
bTemp[0].x += vFinal[0].x;
|
||||||
|
bTemp[1].x += vFinal[1].x;
|
||||||
|
|
||||||
|
/* Rotate ball this.positions and velocities back
|
||||||
|
Reverse signs in trig expressions to rotate
|
||||||
|
in the opposite direction */
|
||||||
|
// rotate balls
|
||||||
|
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||||
|
|
||||||
|
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||||
|
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||||
|
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||||
|
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||||
|
|
||||||
|
// update balls to screen this.position
|
||||||
|
other.position.x = this.position.x + bFinal[1].x;
|
||||||
|
other.position.y = this.position.y + bFinal[1].y;
|
||||||
|
|
||||||
|
this.position.add(bFinal[0]);
|
||||||
|
|
||||||
|
// update velocities
|
||||||
|
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||||
|
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||||
|
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||||
|
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display(friend1, friend2) {
|
||||||
|
this.update()
|
||||||
|
noStroke();
|
||||||
|
fill('#ff0000');
|
||||||
|
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||||
|
this.checkBoundaryCollision()
|
||||||
|
this.checkCollision(friend1)
|
||||||
|
this.checkCollision(friend2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logo {
|
||||||
|
constructor() {
|
||||||
|
this.yOffset = 0
|
||||||
|
this.up = false
|
||||||
|
this.textSize = 36
|
||||||
|
this.bounceDepth = 10
|
||||||
|
this.speed = 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
display() {
|
||||||
|
fill('#20d582');
|
||||||
|
textFont(myFont);
|
||||||
|
|
||||||
|
if (windowWidth/6 > 120) {
|
||||||
|
textSize(120);
|
||||||
|
} else {
|
||||||
|
textSize(windowWidth/6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||||
|
} else {
|
||||||
|
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||||
|
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bounce()
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce() {
|
||||||
|
if (!this.up) {
|
||||||
|
if (this.yOffset <= this.bounceDepth) {
|
||||||
|
this.yOffset = this.yOffset + this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset > this.bounceDepth) {
|
||||||
|
this.up = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.yOffset > 0) {
|
||||||
|
this.yOffset = this.yOffset - this.speed
|
||||||
|
}
|
||||||
|
if (this.yOffset < 0) {
|
||||||
|
this.up = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ball1 = new Ball(100, 400, 20)
|
||||||
|
let ball2 = new Ball(700, 400, 80)
|
||||||
|
let ball3 = new Ball(0, 200, 60)
|
||||||
|
let logo = new Logo()
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
background('#209bd0');
|
||||||
|
|
||||||
|
|
||||||
|
ball1.display(ball2, ball3)
|
||||||
|
ball2.display(ball1, ball3)
|
||||||
|
ball3.display(ball1, ball2)
|
||||||
|
|
||||||
|
if (windowWidth <= 480) {
|
||||||
|
ball2.r = 40;
|
||||||
|
ball3.r = 30;
|
||||||
|
} else {
|
||||||
|
ball2.r = 80;
|
||||||
|
ball3.r = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo.display()
|
||||||
|
|
||||||
|
}
|
41
web/templates/album.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% block 'content' %}
|
||||||
|
<div class="container">
|
||||||
|
<center>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<h5>Listen to our first album Tyrannizing Harmonics Everywhere!!</h5>
|
||||||
|
<br>
|
||||||
|
<div style="margin: 0 auto; max-width: 600px;">
|
||||||
|
<iframe style="border: 0; width: 100%; height: 439px;" src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=large/bgcol=ffffff/linkcol=0687f5/artwork=small/transparent=true/" seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a target="_blank" href="https://open.spotify.com/album/4imchLIIQnfFfrxcy0bQ3l">
|
||||||
|
<button type="button" class="btn btn-light link">Spotify</button><br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">
|
||||||
|
<button type="button" class="btn btn-light link">Bandcamp</button><br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.youtube.com/watch?v=hwaWr7GQ09M&list=OLAK5uy_mr2CAlUomJZIEd3Y0_vIiguRz80bXNmwI">
|
||||||
|
<button type="button" class="btn btn-light link">YouTube</button><br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://music.apple.com/us/album/tyrannizing-harmonics/1814317803" style="display:none;">
|
||||||
|
<button type="button" class="btn btn-light link">Apple Music</button><br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.pandora.com/artist/shrinkin-minkin/tyrannizing-harmonics/AL3j4zhrhJbf4cP">
|
||||||
|
<button type="button" class="btn btn-light link">Pandora</button><br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.instagram.com/shrinkinminkin/">
|
||||||
|
<button type="button" class="btn btn-light link">Follow us on Instagram</button><br>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
{% include 'mailing_list.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
We hope you enjoy our ad free listening experience! Please visit our socials and like and subscribe to support us!
|
||||||
|
</center>
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
45
web/templates/base.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Shrinkin-Minkin</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
|
||||||
|
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||||
|
</head>
|
||||||
|
<body style="padding: 0px; margin: 0px;">
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-success alert-dismissible fade show"
|
||||||
|
role="alert"
|
||||||
|
style="max-width:400px;
|
||||||
|
position: fixed;
|
||||||
|
bottom:0;
|
||||||
|
right: 0;
|
||||||
|
margin:20px">
|
||||||
|
{{ message }}
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">X</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
<center>
|
||||||
|
<a href="{% url 'index' %}">
|
||||||
|
<img src="{% static 'img/album_release_header.png' %}"
|
||||||
|
alt=""
|
||||||
|
class="header-img">
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
</center>
|
||||||
|
{% block 'content' %}{% endblock %}
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||||
|
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
||||||
|
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
||||||
|
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
</body>
|
123
web/templates/index.html
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% block 'content' %}
|
||||||
|
<div>
|
||||||
|
<center>
|
||||||
|
<a href="#listen">
|
||||||
|
<button type="button" class="btn btn-light nav-link">listen</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="#watch">
|
||||||
|
<button type="button" class="btn btn-light nav-link">watch</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="#book">
|
||||||
|
<button type="button" class="btn btn-light nav-link">book us</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{% url 'socials' %}">
|
||||||
|
<button type="button" class="btn btn-light nav-link">social</button>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid pt-2 mt-3">
|
||||||
|
|
||||||
|
<div class="row pb-4">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<center>
|
||||||
|
<img id="band-img-1" class="img-fluid" src="{% static 'img/members.png' %}" alt="" style="margin-bottom: 20px; width:100%; height: auto; max-width: 840px;">
|
||||||
|
|
||||||
|
<div style="margin-top:30px; margin-bottom: 20px;">
|
||||||
|
{% include 'mailing_list.html' %}
|
||||||
|
</div>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6" style="padding:30px; background-color: #54b879;">
|
||||||
|
<h1>About Us:</h1>
|
||||||
|
<p>
|
||||||
|
<b>SHRINKIN-MINKIN</b> thrives on the fringes of genre, violating the confines of classification.
|
||||||
|
Founded in 2022 by singer/guitarists Dominic DiTaranto and Michael Heinfling;
|
||||||
|
SHRINKIN-MINKIN blends Rock, Funk, Jazz, Punk, infused with creative improvisation and FX landscape.
|
||||||
|
The NJ based 5-piece is <i>tight</i>. Technical, Playful, and dripping with thirst-quenching satire.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Their musical multiplicity allows SHRINKIN-MINKIN to fit into any lineup.
|
||||||
|
Their songs range from the Funk, Rock, Hip Hop, Gospel fusion of "GLOP";
|
||||||
|
to Post-Punk anthems like "Industry Rock" and the comical love-lament of "Butter Queen".
|
||||||
|
Songs that are guaranteed to get asses convulsing in rhythmic fervor.
|
||||||
|
More discerning listeners can relax and watch the band trade solos on "Down Polypore Wood".
|
||||||
|
Add in Alternative ballads, Blues tracks, and even a Psychedelic-Waltz and you will begin to scratch
|
||||||
|
the surface of what SHRINKIN-MINKIN has to offer.
|
||||||
|
<br><br>
|
||||||
|
<a href="#book">Book Us</a> now to support or headline!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Members:</b>
|
||||||
|
<br>Dominic DiTaranto - Guitar/Vocals/Synth
|
||||||
|
<br>Michael Heinfling - Guitar/Vocals
|
||||||
|
<br>Charlie Misch - Keyboard/Synth
|
||||||
|
<br>B.S. Ashford - Bass
|
||||||
|
<br>Recon Paul - Drums
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Recommended if you like:</b>
|
||||||
|
Frank Zappa,
|
||||||
|
King Crimson,
|
||||||
|
Talking Heads,
|
||||||
|
David Bowie,
|
||||||
|
Mahavishnu Orchestra,
|
||||||
|
Phish,
|
||||||
|
Miles Davis,
|
||||||
|
The Stooges,
|
||||||
|
Funkadelic,
|
||||||
|
John Coltrane,
|
||||||
|
The Stranglers,
|
||||||
|
The Damned,
|
||||||
|
Weather Report,
|
||||||
|
The Cars
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 id="listen">Listen:</h1>
|
||||||
|
<center>
|
||||||
|
<iframe style="border: 0; max-width: 350px; height: 753px;" src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=large/bgcol=ffffff/linkcol=de270f/transparent=true/" seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||||
|
</center>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<h1 id="watch">Watch Us Live:</h1>
|
||||||
|
<div class="iframe-container">
|
||||||
|
|
||||||
|
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/7Dbg5MuOgbY?si=qW3dw8QY4a8sHqbX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/4Cx1_LMJRzM?si=fS9EuyczsNvsJuSb&start=42" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/R3fo-k2_wfM?si=Foz0OaTK6GC5psKo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-5 mb-5 p-5">
|
||||||
|
<h1 id="book">Book Us:</h1>
|
||||||
|
<br>
|
||||||
|
Email: shrinkinminkin<span style="font-family: monospace;">@</span>gmail.com <br>
|
||||||
|
Phone: 732-895-5253
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<img class="footer-image" src="{% static 'img/bugman_sticker.png' %}" alt="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
8
web/templates/mailing_list.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="card p-2" style="margin-bottom:10px;">
|
||||||
|
<form action="/mailing_list/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<label for="email">Join Our Mailing List:</label>
|
||||||
|
<input type="email" id="email" name="email" placeholder="your@email.com" style="font-family: monospace;">
|
||||||
|
<input type="submit" class="btn btn-success" value="JOIN">
|
||||||
|
</form>
|
||||||
|
</div>
|
44
web/templates/socials.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% block 'content' %}
|
||||||
|
<div class="container">
|
||||||
|
<center>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<iframe style="border: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 42px"
|
||||||
|
src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=small/bgcol=ffffff/linkcol=0687f5/transparent=true/"
|
||||||
|
seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||||
|
<a target="_blank" href="{% url 'album' %}">
|
||||||
|
<button type="button" class="btn btn-success link">Listen To Our Album!</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.instagram.com/shrinkinminkin/">
|
||||||
|
<button type="button" class="btn btn-light link">Instagram</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://shrinkin-minkin.bandcamp.com/">
|
||||||
|
style="margin-bottom:10px;" <button type="button" class="btn btn-light link">Bandcamp</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.youtube.com/channel/UCCmRKeoqtHC9G1X-yvuUG7A">
|
||||||
|
<button type="button" class="btn btn-light link">YouTube</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.shrinkinminkin.com/">
|
||||||
|
<button type="button" class="btn btn-light link">For Promoters And Venues</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.bonfire.com/store/shrinkin-minkin/">
|
||||||
|
<button type="button" class="btn btn-danger link">Merch</button>
|
||||||
|
<br>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</center>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
3
web/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
33
web/views.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from web.models import MailingList
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def index(request):
|
||||||
|
return render(request, 'index.html')
|
||||||
|
|
||||||
|
|
||||||
|
def album(request):
|
||||||
|
return render(request, 'album.html')
|
||||||
|
|
||||||
|
|
||||||
|
def socials(request):
|
||||||
|
return render(request, 'socials.html')
|
||||||
|
|
||||||
|
|
||||||
|
def mailing_list(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
referer = request.META['HTTP_REFERER'][:-1].split('/')[-1].split('.')[0]
|
||||||
|
email = request.POST.get('email')
|
||||||
|
|
||||||
|
if email:
|
||||||
|
exists = MailingList.objects.filter(email=email).first()
|
||||||
|
if not exists:
|
||||||
|
m = MailingList(
|
||||||
|
email=email
|
||||||
|
)
|
||||||
|
m.save()
|
||||||
|
messages.add_message(request, messages.INFO, "Nice! Thanks for joining our mailing list!")
|
||||||
|
|
||||||
|
return redirect(referer)
|