22 Commits

Author SHA1 Message Date
4b99a1c26e Fix oversights in bg renderer
So it turns out the performance improvements were completelty neglected
because my code is bad. The buffer wasn't getting rendered to the canvas
in the best way, and there were too many particles for smaller screens.
I have now added a simple math equasion to the init function that
decides how many particles are needed based on the display size. It
still needs a lot of tweaking, and a more complex function is probably
necessary for good results. I'm still trying to get this background to
not suck and actually look good.
2025-04-02 19:49:37 -07:00
2ce9e6955f Bump version to v1.2.1 2025-04-02 18:56:24 -07:00
a3a774b964 Change particle color and ammount 2025-03-31 20:08:30 -07:00
ac3d579254 Massive performance improvement in background rendering
Turns out the performance bottleneck was actually rendering the
gradients every frame, so they are now rendering to a buffer when the
page loads once and that buffer is being rendered as an image every
frame. No functionality has been changed; but it runs so much faster and
is much more efficient on mobile devices.
2025-03-31 19:59:16 -07:00
db0ed8cb42 Add page metadata for each page and enable prettier-plugin-svelte 2025-03-31 16:36:32 -07:00
2c21504279 Add prettier-plugin-svelte 2025-03-31 16:11:31 -07:00
4b05bb519e Bump package.json version to the right number 2025-03-31 15:54:51 -07:00
e7aba82655 Welcome, Prettier. 2025-03-31 15:51:57 -07:00
bf419426cf About page: add more text 2025-03-18 21:33:02 -07:00
fe14fd46e1 Colormatic Studios page: fix redundant and hard-coded values 2025-03-18 20:46:41 -07:00
a651520669 Zakarya page: Revamp and overhaul 2025-03-18 20:42:55 -07:00
679cdc078f Fix panel border in dark theme 2025-03-18 19:31:55 -07:00
5f52d9ec4d BG: remove gradient breathing effect
This was causing some rendering bugs, and I didn't want it anyways.
2025-03-18 17:24:24 -07:00
765b3542d1 Move custom styling and scripting into pages
The Zakarya page is a work in progress
2025-03-18 17:10:59 -07:00
6177d407d2 BG: fix particle rotation axis 2025-03-18 17:00:42 -07:00
3332d4ab89 Proper DPI scaling for the background canvas 2025-03-13 19:43:12 -07:00
13960ad144 Fixup main page 2025-03-13 11:09:20 -07:00
2587ddd721 Change bg shapes to SVGs and add more complex shapes 2025-03-13 10:46:04 -07:00
0cb18c2103 README: download directions should include "cd" command 2025-03-11 10:20:12 -07:00
1a81d748df Add "under construction" panel 2025-03-10 12:07:42 -07:00
514b413281 Embed bg canvas style to Svelte component 2025-03-10 11:29:27 -07:00
6cbbe07371 Migrate background animation to a Svelte component 2025-03-10 11:25:36 -07:00
27 changed files with 1731 additions and 949 deletions

49
.prettierrc.json Normal file
View File

@ -0,0 +1,49 @@
{
"plugins": ["prettier-plugin-svelte"],
"singleQuote": false,
"tabWidth": 2,
"useTabs": false,
"htmlWhitespaceSensitivity": "ignore",
"overrides": [
{
"files": "*.html",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.scss",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.json",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.svelte",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.js",
"options": {
"useTabs": true
}
},
{
"files": "*.ts",
"options": {
"useTabs": true
}
}
]
}

View File

@ -1,4 +1,5 @@
# Colormatic Website
[colormatic.org](https://colormatic.org)
This project uses SvelteKit along with TypeScript and Sass. It's configured for static site generation (SSG) and prerendering at compile time to create a simple static website for Nginx to serve, with very little client-side rendering (CSR).
@ -6,21 +7,37 @@ This project uses SvelteKit along with TypeScript and Sass. It's configured for
The Colormatic website is developed with accordance to modern web standards, however a legacy website will be available in the future for older/less capable browsers.
To download the project, run:
```
git clone git@git.colormatic.org:ColormaticStudios/Colormatic-Website.git
cd Colormatic-Website
npm install
```
You can run the project locally with:
```
npm run dev
```
Or you can build the project for release with:
```
npm run build
```
After the project has been built, you can preview the release build with:
```
npm run preview
```
Bootstrap Icons are licensed under the [MIT](https://opensource.org/license/MIT) license.
Before submitting a push or pull request, run:
```
npm run format
```
To format your code according to the project code format. Remember to never fight the formatter.
[Bootstrap Icons](https://icons.getbootstrap.com/) are licensed under the [MIT](https://opensource.org/license/MIT) license.

View File

@ -1,26 +1,29 @@
{
"name": "colormatic-website",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"sass": "^1.83.4",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"typescript": "^5.0.0",
"vite": "^6.0.0"
},
"dependencies": {
"bootstrap-icons": "^1.11.3"
}
"name": "colormatic-website",
"version": "1.2.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"format": "prettier -w .",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"sass": "^1.83.4",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"typescript": "^5.0.0",
"vite": "^6.0.0"
},
"dependencies": {
"bootstrap-icons": "^1.11.3"
}
}

334
src/component/bg.svelte Normal file
View File

@ -0,0 +1,334 @@
<script lang="ts">
import { canvasDpiScaler } from "../script/canvas_dpi_scaler.ts";
import { onMount } from "svelte";
let canvas: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D;
let dark_theme = false;
let time_scale = 1;
let particlesArray: Array<Particle> = [];
let gradientsArray: Array<Gradient> = [];
let particleImages = {
// This is horrible code
circle: {} as HTMLImageElement,
square: {} as HTMLImageElement,
triangle: {} as HTMLImageElement,
star: {} as HTMLImageElement,
wavyCircle: {} as HTMLImageElement,
};
onMount(() => {
canvas = document.getElementById("bg-canvas") as HTMLCanvasElement;
ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
particleImages.circle = new Image() as HTMLImageElement;
particleImages.circle.src = "/img/bg-shapes/circle.svg";
particleImages.square = new Image() as HTMLImageElement;
particleImages.square.src = "/img/bg-shapes/square.svg";
particleImages.triangle = new Image() as HTMLImageElement;
particleImages.triangle.src = "/img/bg-shapes/triangle.svg";
particleImages.star = new Image() as HTMLImageElement;
particleImages.star.src = "/img/bg-shapes/star.svg";
particleImages.wavyCircle = new Image() as HTMLImageElement;
particleImages.wavyCircle.src = "/img/bg-shapes/wavy-circle.svg";
if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
dark_theme = true;
}
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", (event) => {
dark_theme = event.matches;
for (let i = 0; i < gradientsArray.length; i++) {
let gradient = gradientsArray[i];
gradient.color = getRandomColor();
gradient.prepareBuffer();
}
});
resize();
init();
animate();
window.addEventListener("resize", resize);
});
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvasDpiScaler(canvas, ctx);
}
const clamp = (val: number, min: number, max: number) =>
Math.min(Math.max(val, min), max);
class Entity {
x: number;
y: number;
speedX: number;
speedY: number;
growthSpeed: number;
constructor() {
this.x = Math.random() * window.innerWidth;
this.y = Math.random() * window.innerHeight;
this.speedX = (Math.random() - 0.5) * 0.2; // -0.1 to 0.1
this.speedY = (Math.random() - 0.5) * 0.2;
this.growthSpeed = Math.random() * 0.02 + 0.01; // 0.01 to 0.03
}
update() {
this.x += this.speedX * time_scale;
this.y += this.speedY * time_scale;
// Reverse direction if particle hits edge
if (this.x <= 0 || this.x >= window.innerWidth) {
this.speedX = -this.speedX;
}
this.x = clamp(0, this.x, window.innerWidth);
if (this.y <= 0 || this.y >= window.innerHeight) {
this.speedY = -this.speedY;
}
this.y = clamp(0, this.y, window.innerHeight);
}
}
class Shape {
// Reference implementation for Shape
draw(angle: number, size: number) {
return;
}
}
class Circle extends Shape {
draw(angle: number, size: number) {
let image = particleImages.circle;
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
}
class Square extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
let image = particleImages.square;
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
}
class Triangle extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
let image = particleImages.triangle;
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
}
class Star extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
let image = particleImages.star;
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
}
class WaveyCircle extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
let image = particleImages.wavyCircle;
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
}
class Particle extends Entity {
shape: Shape;
angle: number;
rotationSpeed: number;
size: number;
originalSize: number;
constructor() {
super();
this.shape = new [Circle, Square, Triangle, Star, WaveyCircle][
Math.floor(Math.random() * 5)
](); // A very strange but effective way to pick a random shape
this.angle = Math.random() * 360;
this.rotationSpeed = Math.random() * 2 - 1; // -1 to 1
this.originalSize = Math.random() * 8 + 8; // 8 to 16
this.size = this.originalSize;
}
update() {
super.update();
this.angle += this.rotationSpeed * time_scale;
// Breathing effect: oscillate size
this.size += this.growthSpeed * time_scale;
if (
this.size >= this.originalSize * 1.25 ||
this.size <= this.originalSize * 0.75
) {
this.growthSpeed = -this.growthSpeed; // Reverse growth direction
}
}
draw() {
ctx.save();
// The source images are black, so we are inverting them
// different amounts to get different shades of gray
ctx.filter = dark_theme ? "invert(0.15)" : "invert(0.8)";
// Draw center of rotation
// ctx.beginPath();
// ctx.arc(this.x, this.y, 2, 0, 2 * Math.PI);
// ctx.fill();
ctx.translate(this.x, this.y);
ctx.scale(this.size / 10, this.size / 10);
this.shape.draw(this.angle, this.size);
ctx.restore();
}
}
function getRandomColor() {
if (dark_theme) {
let r = Math.floor(Math.random() * 255 - 100);
let b = Math.floor(Math.random() * 255 - 100);
let g = Math.floor(Math.random() * 255 - 100);
return `rgb(${r}, ${g}, ${b})`;
} else {
let r = Math.floor(Math.random() * 100 + 155);
let g = Math.floor(Math.random() * 100 + 155);
let b = Math.floor(Math.random() * 100 + 155);
return `rgb(${r}, ${g}, ${b})`;
}
}
class Gradient extends Entity {
radius: number;
color: string;
alpha: number;
renderingBuffer: HTMLCanvasElement;
constructor() {
super();
this.radius = Math.random() * 500 + 300;
this.color = getRandomColor();
this.alpha = Math.random() * 0.5 + 0.5; // Initial alpha between 0.5 and 1
this.renderingBuffer = document.createElement(
"canvas",
) as HTMLCanvasElement;
// One-shot buffer adjustment
this.renderingBuffer.width = this.radius * 2;
this.renderingBuffer.height = this.radius * 2;
// canvasDpiScaler(
// this.renderingBuffer,
// this.renderingBuffer.getContext("2d") as CanvasRenderingContext2D,
// );
this.prepareBuffer();
}
prepareBuffer() {
let bctx = this.renderingBuffer.getContext(
"2d",
) as CanvasRenderingContext2D;
bctx.clearRect(
0,
0,
this.renderingBuffer.width,
this.renderingBuffer.height,
);
const gradient = ctx.createRadialGradient(
this.radius,
this.radius,
0,
this.radius,
this.radius,
this.radius,
);
gradient.addColorStop(0, this.color);
if (dark_theme) {
gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);
} else {
gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
}
bctx.globalAlpha = this.alpha;
bctx.fillStyle = gradient;
bctx.beginPath();
bctx.arc(this.radius, this.radius, this.radius, 0, Math.PI * 2);
bctx.closePath();
bctx.fill();
}
draw() {
ctx.save();
ctx.translate(this.x - this.radius, this.y - this.radius);
ctx.drawImage(this.renderingBuffer, 0, 0);
ctx.restore();
}
}
function init() {
/*/
* Calculate the proper amount of particles
* 25920 is our constant, equal to x in (1080*1920)/x = 80
* Because the subjectively correct amount of particles for a 1080p
* display is 80, so to calculate the proper amount for any window size,
* just do (width * height) / 25920
/*/
let particleCount = (window.innerWidth * window.innerHeight) / 25920;
particlesArray = [];
for (let i = 0; i < particleCount; i++) {
particlesArray.push(new Particle());
}
gradientsArray = [];
for (let i = 0; i < 10; i++) {
gradientsArray.push(new Gradient());
}
}
function animate() {
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
for (let i_gradient = 0; i_gradient < gradientsArray.length; i_gradient++) {
let gradient = gradientsArray[i_gradient];
gradient.update();
gradient.draw();
}
for (let i_particle = 0; i_particle < particlesArray.length; i_particle++) {
let particle = particlesArray[i_particle];
particle.update();
particle.draw();
}
requestAnimationFrame(animate);
}
</script>
<canvas id="bg-canvas"></canvas>
<style>
canvas#bg-canvas {
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
</style>

View File

@ -1,7 +1,37 @@
<footer>
<p>© 2025 Colormatic Studios, All Rights Reserved.</p>
<p>
<a href="mailto:support@colormatic.org">support@colormatic.org</a> |
<a href="mailto:support@colormatic.org">support@colormatic.org</a>
|
<a href="mailto:support@colormatic.org">contact@colormatic.org</a>
</p>
</footer>
<style lang="scss">
@use "../style/global.scss";
footer {
display: flex;
justify-content: space-between;
border-top: solid 1px global.$text-color;
width: 95%;
padding: 4px;
margin: 0 auto;
}
footer p {
color: global.$text-color;
padding: 4px 10%;
}
@media screen and (max-width: global.$mobile-width) {
footer {
flex-direction: column;
}
footer p {
text-align: center;
padding: 4px;
margin: 4px;
}
}
</style>

View File

@ -29,11 +29,13 @@
class="git-icon"
target="_blank"
rel="noopener noreferrer"
aria-label="Colormatic Git"><i class="bi bi-git"></i></a
>
<button on:click={toggleModalMenu} class="menu-button" aria-label="menu"
><i class="bi bi-list"></i></button
aria-label="Colormatic Git"
>
<i class="bi bi-git"></i>
</a>
<button on:click={toggleModalMenu} class="menu-button" aria-label="menu">
<i class="bi bi-list"></i>
</button>
</div>
</nav>
@ -46,9 +48,9 @@ Svelte modal example, https://svelte.dev/playground/modal
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
<span on:click={modalMenuProcessClick} id="pages" class="modalbg hidden">
<div>
<button on:click={toggleModalMenu} class="close" aria-label="Close"
><i class="bi bi-x"></i></button
>
<button on:click={toggleModalMenu} class="close" aria-label="Close">
<i class="bi bi-x"></i>
</button>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/zakarya">Zakarya</a></li>
@ -57,17 +59,211 @@ Svelte modal example, https://svelte.dev/playground/modal
<a
href="https://git.colormatic.org"
target="_blank"
rel="noopener noreferrer">Colormatic Git</a
rel="noopener noreferrer"
>
Colormatic Git
</a>
</li>
<li>
<a
href="https://auth.colormatic.org"
target="_blank"
rel="noopener noreferrer">Colormatic ID</a
rel="noopener noreferrer"
>
Colormatic ID
</a>
</li>
<li><a href="/about">About</a></li>
</ul>
</div>
</span>
<style lang="scss">
@use "../style/global.scss";
nav {
display: grid;
grid-template-columns: 1fr min-content 1fr;
align-items: center;
padding: 12px;
border-bottom: solid 1px global.$text-color;
z-index: 1;
margin: 0 auto;
width: 95%;
box-sizing: border-box;
overflow-wrap: anywhere;
}
nav .nav-left {
justify-self: left;
grid-column: 1;
}
nav .nav-center {
justify-self: center;
grid-column: 2;
}
nav .nav-right {
justify-self: right;
grid-column: 3;
}
nav ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
}
nav ul li {
display: grid;
justify-items: center;
}
nav a,
nav button {
padding: 0 8px;
color: global.$text-color;
text-decoration: none;
display: flex;
cursor: pointer;
align-items: center;
}
nav a.title {
font-size: 140%;
font-weight: bold;
}
nav img.colormatic-logo {
width: auto;
height: 40px;
padding: 4px;
}
nav button.menu-button {
background: none;
border: none;
}
nav .menu-button i {
font-size: 230%;
/*/
* Ugly hack to account for the fact that the menu icon is off-center
* (Bootstrap please fix)
/*/
transform: translateY(-1px);
}
nav .git-icon i {
font-size: 140%;
}
nav div.inline {
display: flex;
}
@media screen and (max-width: global.$mobile-width) {
nav {
padding: 6px 0;
}
nav .git-icon i {
font-size: 150%;
}
nav ul.responsive-hidden {
display: none;
}
}
/*/
* Navigation modal section
/*/
span.modalbg.hidden {
display: none;
}
span.modalbg {
position: fixed;
z-index: 1;
padding: 0;
margin: auto;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
span.modalbg div {
width: 50ch;
margin: 100px auto;
padding: 16px;
color: global.$text-color;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
background-color: #ffffffbb;
backdrop-filter: blur(5px);
animation-name: modal-animate-in;
animation-duration: 0.4s;
}
@keyframes modal-animate-in {
from {
transform: translate(0px, -300px);
opacity: 0;
}
to {
transform: translate(0px, 0px);
opacity: 1;
}
}
span.modalbg div button.close {
float: right;
width: min-content;
background: none;
border: none;
outline: none;
cursor: pointer;
font-size: 200%;
color: global.$text-color;
}
span.modalbg div ul {
list-style-type: none;
margin: 0;
padding: 0;
}
span.modalbg div ul li {
margin: 18px 12px;
}
span.modalbg div ul li a {
color: global.$text-color;
padding: 8px;
text-decoration: none;
font-size: 120%;
}
@media screen and (max-width: global.$mobile-width) {
span.modalbg div {
width: 30ch;
}
}
@media (prefers-color-scheme: dark) {
span.modalbg div {
background-color: #000000bb;
}
}
</style>

View File

@ -1,20 +1,17 @@
<script lang="ts">
import "../style/main.scss";
import "../style/nav.scss";
import "bootstrap-icons/font/bootstrap-icons.css";
import Navbar from "../component/navbar.svelte";
import Footer from "../component/footer.svelte";
import { createBackground } from "../script/bg.ts";
import { onMount } from "svelte";
onMount(createBackground);
import Bg from "../component/bg.svelte";
</script>
<svelte:head>
<link rel="icon" href="/img/colormatic_logo.svg" />
</svelte:head>
<Bg />
<Navbar />
<slot />

View File

@ -2,17 +2,17 @@
import { onMount } from "svelte";
onMount(() => {
var arrow = document.getElementById("scroll-arrow");
let arrow = document.getElementById("scroll-arrow") as HTMLDivElement;
if (arrow) {
// Arrow is not null
window.addEventListener("scroll", (e: Event) => {
if (window.scrollY != 0) {
if (!(arrow as HTMLElement).classList.contains("scroll-arrow-hide")) {
(arrow as HTMLElement).classList.add("scroll-arrow-hide");
if (!arrow.classList.contains("scroll-arrow-hide")) {
arrow.classList.add("scroll-arrow-hide");
}
} else {
if ((arrow as HTMLElement).classList.contains("scroll-arrow-hide")) {
(arrow as HTMLElement).classList.remove("scroll-arrow-hide");
if (arrow.classList.contains("scroll-arrow-hide")) {
arrow.classList.remove("scroll-arrow-hide");
}
}
});
@ -22,6 +22,24 @@
<svelte:head>
<title>Colormatic</title>
<meta
name="description"
content="Colormatic is a non-profit project by Zakarya dedicated to creation."
/>
<meta name="keywords" content="Open Source, Non Profit" />
<link rel="canonical" href="https://colormatic.org" />
<meta property="og:title" content="Colormatic" />
<meta
property="og:description"
content="Colormatic is a non-profit project by Zakarya dedicated to creation."
/>
<meta
property="og:image"
content="https://colormatic.org/img/colormatic_logo.svg"
/>
<meta property="og:url" content="https://colormatic.org" />
<meta property="og:type" content="website" />
</svelte:head>
<main>
@ -41,8 +59,10 @@
<a
href="https://git.colormatic.org/ColormaticStudios/quality-godot-first-person"
target="_blank"
rel="noopener noreferrer">Quality First Person Controller</a
rel="noopener noreferrer"
>
Quality First Person Controller
</a>
</h1>
<p>An actually good first person controller for the Godot Engine.</p>
@ -52,11 +72,63 @@
<a
href="https://git.colormatic.org/ColormaticStudios/godot-bson"
target="_blank"
rel="noopener noreferrer">BSON for Godot</a
rel="noopener noreferrer"
>
BSON for Godot
</a>
</h1>
<p>A BSON serializer/deserializer for the Godot Engine</p>
</div>
<spacer></spacer>
<div class="hero panel">
<h1>
<i class="bi bi-tools" style="padding-right: 12px;"></i>
This website is under construction.
</h1>
<p>
Check up on progress and changes at <a
href="https://git.colormatic.org/ColormaticStudios/Colormatic-Website"
target="_blank"
rel="noopener noreferrer"
>
ColormaticStudios/Colormatic-Website
</a>
.
</p>
</div>
</main>
<spacer></spacer>
<style lang="scss">
@use "../style/global.scss";
main div.brand-heading {
padding: 12%;
width: 60%;
}
main div.brand-heading h1 {
font-size: 300%;
}
main div.heading {
font-size: 250%;
text-align: center;
padding: 12px;
}
@media screen and (max-width: global.$mobile-width) {
main div.brand-heading {
padding: 38% 12px;
text-align: center;
width: initial;
}
main div.heading {
font-size: 200%;
}
}
</style>

View File

@ -1,5 +1,23 @@
<svelte:head>
<title>Colormatic - About</title>
<meta
name="description"
content="Colormatic is a non-profit project by Zakarya dedicated to creation."
/>
<meta name="keywords" content="Open Source, Non Profit" />
<link rel="canonical" href="https://colormatic.org/about/" />
<meta property="og:title" content="Colormatic - About" />
<meta
property="og:description"
content="Colormatic is a non-profit project by Zakarya dedicated to creation."
/>
<meta
property="og:image"
content="https://colormatic.org/img/colormatic_logo.svg"
/>
<meta property="og:url" content="https://colormatic.org/about/" />
<meta property="og:type" content="website" />
</svelte:head>
<spacer></spacer>
@ -8,12 +26,19 @@
<div class="hero panel">
<h1>Colormatic: A non-profit project for creation.</h1>
<p class="justify">
Colormatic is a non-profit project for creating a curated collection of
sub-projects that match a high-quality, high attention to detail standard.
Colormatic is a non-profit project from Zakarya for creating a curated
collection of sub-projects that match a high-quality, high attention to
detail standard.
</p>
<p class="justify">
Colormatic Studios is a creative studio dedicated to giving life to these
maximum effort projects.
Colormatic is still in the early stages, so expect many things to change
in the near future.
</p>
<p class="justify">
Colormatic Studios is a creative studio dedicated to giving life to
Colormatic's projects. We are currently just a small group of passionate
volunteers working to build inspiring, intuitive and innovative creative
works.
</p>
</div>
</main>

View File

@ -1,9 +1,32 @@
<script lang="ts">
import "../../style/studios.scss";
</script>
<svelte:head>
<title>Colormatic Studios</title>
<meta
name="description"
content="Colormatic Studios is a creative studio dedicated to giving life to
Colormatic's projects. We are currently just a small group of passionate
volunteers working to build inspiring, intuitive and innovative creative
works."
/>
<meta
name="keywords"
content="Open Source, Not for Profit, Game Development, World Building"
/>
<link rel="canonical" href="https://colormatic.org/studios/" />
<meta property="og:title" content="Colormatic Studios" />
<meta
property="og:description"
content="Colormatic Studios is a creative studio dedicated to giving life to
Colormatic's projects. We are currently just a small group of passionate
volunteers working to build inspiring, intuitive and innovative creative
works."
/>
<meta
property="og:image"
content="https://colormatic.org/img/colormatic_logo.svg"
/>
<meta property="og:url" content="https://colormatic.org/studios/" />
<meta property="og:type" content="website" />
</svelte:head>
<main>
@ -15,8 +38,10 @@
<a
href="https://git.colormatic.org/ColormaticStudios/quality-godot-first-person"
target="_blank"
rel="noopener noreferrer">Quality First Person Controller</a
rel="noopener noreferrer"
>
Quality First Person Controller
</a>
</h1>
<div class="project-grid-box-contents">
<img
@ -31,8 +56,10 @@
<a
href="https://git.colormatic.org/ColormaticStudios/godot-bson"
target="_blank"
rel="noopener noreferrer">BSON for Godot</a
rel="noopener noreferrer"
>
BSON for Godot
</a>
</h1>
<div class="project-grid-box-contents">
<img
@ -78,22 +105,28 @@
<a
href="https://mastodon.social/@colormaticstudios"
target="_blank"
rel="noopener noreferrer">Mastodon</a
rel="noopener noreferrer"
>
Mastodon
</a>
</li>
<li>
<a
href="https://www.instagram.com/colormaticstudios/"
target="_blank"
rel="noopener noreferrer">Instagram</a
rel="noopener noreferrer"
>
Instagram
</a>
</li>
<li>
<a
href="https://www.youtube.com/@colormaticstudios"
target="_blank"
rel="noopener noreferrer">Youtube</a
rel="noopener noreferrer"
>
Youtube
</a>
</li>
</ul>
<ul class="linktree">
@ -101,22 +134,28 @@
<a
href="https://git.colormatic.org/ColormaticStudios"
target="_blank"
rel="noopener noreferrer">Colormatic Git</a
rel="noopener noreferrer"
>
Colormatic Git
</a>
</li>
<li>
<a
href="https://github.com/ColormaticStudios"
target="_blank"
rel="noopener noreferrer">GitHub</a
rel="noopener noreferrer"
>
GitHub
</a>
</li>
<li>
<a
href="https://bsky.app/profile/colormaticstudios.bsky.social"
target="_blank"
rel="noopener noreferrer">Bluesky</a
rel="noopener noreferrer"
>
Bluesky
</a>
</li>
</ul>
</div>
@ -124,3 +163,91 @@
</main>
<spacer></spacer>
<style lang="scss">
@use "../../style/global.scss";
div.cs-title {
background-image: url("/img/colormatic_banner.svg");
background-size: cover;
background-repeat: no-repeat;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
}
div.cs-title h1 {
color: white;
background-color: #00000088;
padding: 28px 38px;
border-radius: 16px;
font-size: 300%;
box-shadow: 1px 1px 8px #00000033;
backdrop-filter: blur(5px);
}
div.project-grid-container {
display: flex;
width: 80%;
margin-left: auto;
margin-right: auto;
flex-wrap: wrap;
justify-content: center;
}
@media screen and (max-width: global.$mobile-width) {
div.project-grid-container {
width: 90%;
}
div.cs-title {
height: 200px;
}
div.cs-title h1 {
font-size: 200%;
}
}
div.project-grid-container div.project-grid-box {
flex: 1;
margin: 16px;
padding: 16px;
min-width: 40%;
max-width: 50%;
}
div.project-grid-container div.project-grid-box h1 {
text-align: center;
}
div.project-grid-container div.project-grid-box h1 a {
color: global.$text-color;
}
div.project-grid-container
div.project-grid-box
div.project-grid-box-contents {
/* Yes, this absurdly long element selector is a joke */
display: flex;
}
div.project-grid-container div.project-grid-box img {
max-width: 120px;
max-height: 150px;
margin: 12px;
border-radius: 8px;
}
@media screen and (max-width: global.$mobile-width) {
div.project-grid-container div.project-grid-box {
min-width: 90%;
max-width: 90%;
}
div.project-grid-container div.project-grid-box img {
max-width: 100px;
}
}
</style>

View File

@ -1,7 +1,4 @@
<script lang="ts">
import { getParam, getVideo } from "../../script/video.ts";
import "../../style/video.scss";
import { onMount } from "svelte";
onMount(() => {
@ -12,10 +9,98 @@
getVideo(channel, video);
}
});
const BASEURL = "https://files.colormatic.org/";
export function getParam(paramName: string) {
var params = new URLSearchParams(window.location.search);
let t_param = params.get(paramName);
return t_param ? t_param : ""; // Return empty string if null
}
async function getJSON(url: string) {
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = response.json();
return data;
}
export function getVideo(cname: string, vname: string) {
var videoplayer = document.getElementById("videoplayer") as HTMLElement;
var videotitle = document.getElementById("videotitle") as HTMLElement;
var videodescription = document.getElementById(
"videodescription",
) as HTMLElement;
var videodownload = document.getElementById("videodownload") as HTMLElement;
var sourcedownload = document.getElementById(
"sourcedownload",
) as HTMLElement;
getJSON(BASEURL + cname + "/videos/data/" + vname + ".json")
.then((data) => {
let videoURL =
BASEURL +
cname +
"/videos/raw/" +
data.video_file +
"." +
data.video_format;
videoplayer.setAttribute(
"poster",
BASEURL + cname + "/videos/thumbnail/" + data.thumbnail,
);
var videosource = document.createElement("source");
videosource.setAttribute("src", videoURL);
videosource.setAttribute("type", "video/" + data.video_format);
videoplayer.appendChild(videosource);
document.title = data.title;
videotitle.innerText = data.title;
data.description.forEach((iter: number) => {
// TODO: Detect if one of these lines contains a link and if so, make it a link
videodescription.appendChild(
document.createTextNode(iter.toString()),
);
videodescription.appendChild(document.createElement("br"));
});
videodownload.setAttribute(
"href",
BASEURL +
cname +
"/videos/raw/" +
data.video_file +
"." +
data.video_format,
);
videodownload.setAttribute(
"download",
data.video_file + "." + data.video_format,
);
sourcedownload.setAttribute(
"href",
BASEURL +
cname +
"/videos/source/" +
data.source_file +
"." +
data.source_format,
);
sourcedownload.setAttribute(
"download",
data.source_file + "." + data.source_format,
);
})
.catch((error) => {
videotitle.innerText = "Failed to load video.";
console.error(error);
});
}
</script>
<svelte:head>
<title>Video Player</title>
<meta property="og:type" content="video" />
</svelte:head>
<spacer></spacer>
@ -46,3 +131,115 @@
</main>
<spacer></spacer>
<style lang="scss">
@use "../../style/global.scss";
div.video.container {
display: flex;
color: global.$text-color;
width: 90%;
margin: 16px auto 16px auto;
border: solid 1px #00000033;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
padding: 16px;
background-color: #ffffff22;
backdrop-filter: blur(3px);
}
div.video.container video#videoplayer {
flex-grow: 1;
border-radius: 12px;
height: auto;
max-width: 55%;
}
div.video.container div.videoobjects {
display: grid;
padding: 24px;
}
div.video.container div.videodetails h1#videotitle {
padding: 0 12px;
}
div.dropdown-container {
display: flex;
flex-direction: column-reverse;
}
div.video.container div.download-dropdown {
position: relative;
display: inline-block;
padding: 12px;
width: 25px;
height: 25px;
background-color: #21afff;
box-shadow: 1px 1px 8px #00000033;
border-radius: 50px;
transition-duration: 0.35s;
font-size: 120%;
text-align: center;
}
div.video.container div.download-dropdown:hover {
box-shadow: 1px 1px 8px #00000088;
}
div.video.container div.download-dropdown div.dropdown-content {
display: none;
position: absolute;
font-size: 80%;
min-width: 160px;
background-color: #edeeee;
box-shadow: 1px 1px 8px #00000033;
border-radius: 8px;
text-align: center;
}
div.video.container div.download-dropdown:hover div.dropdown-content {
display: block;
}
div.video.container div.download-dropdown div.dropdown-content ul {
list-style-type: none;
padding-left: 0;
}
div.video.container div.download-dropdown div.dropdown-content ul li {
padding: 4px;
cursor: pointer;
}
div.video.container div.download-dropdown div.dropdown-content ul li:hover {
background-color: #dcdfdf;
}
div.video.container div.download-dropdown div.dropdown-content ul li a {
text-decoration: none;
color: global.$text-color;
}
@media screen and (max-width: global.$mobile-width) {
div.video.container {
display: block;
}
div.video.container video#videoplayer {
width: 100%;
max-width: none;
}
div.video.container div.download-dropdown {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 12px;
}
}
@media (prefers-color-scheme: dark) {
div.video.container div.download-dropdown div.dropdown-content {
background-color: #444444;
}
}
</style>

View File

@ -1,43 +1,91 @@
<svelte:head>
<title>Colormatic - Zakarya</title>
<meta
name="description"
content="I am a software and game developer, I run Colormatic and Colormatic
Studios, and I primarily study computer science, psychology, and
linguistics."
/>
<link rel="canonical" href="https://colormatic.org/zakarya/" />
<meta property="og:title" content="Colormatic - Zakarya" />
<meta
property="og:description"
content="I am a software and game developer, I run Colormatic and Colormatic
Studios, and I primarily study computer science, psychology, and
linguistics."
/>
<meta
property="og:image"
content="https://colormatic.org/img/zakarya-icon.svg"
/>
<meta property="og:url" content="https://colormatic.org/zakarya/" />
<meta property="og:type" content="website" />
</svelte:head>
<main>
<img class="banner" src="/img/zakarya-banner.png" alt="Zakarya Banner" />
<span class="name-title">Zakarya</span>
<div class="hero panel">
<h1>Links:</h1>
<ul class="linktree">
<li>
<a
href="https://mstdn.party/@zakarya"
target="_blank"
rel="noopener noreferrer">Mastodon</a
>
</li>
<li>
<a
href="https://ko-fi.com/zakarya"
target="_blank"
rel="noopener noreferrer">Ko-fi</a
>
</li>
<li>
<a
href="https://www.youtube.com/@czakarya"
target="_blank"
rel="noopener noreferrer">Youtube</a
>
</li>
<li>
<a
href="https://github.com/CZakarya"
target="_blank"
rel="noopener noreferrer">GitHub</a
>
</li>
<!--<li><a href="https://www.reddit.com/user/CZakarya/" target="_blank" rel="noopener noreferrer">Reddit</a></li>-->
</ul>
<div class="hero panel profile">
<div class="nameplate">
<img
src="/img/zakarya-icon.png"
class="zakarya-icon"
alt="Zakarya Icon"
/>
<span class="name-title">Zakarya</span>
</div>
<p>
I am a software and game developer, I run Colormatic and Colormatic
Studios, and I primarily study computer science, psychology, and
linguistics.
<br />
I have an intrinsic urge to create, and that's what Colormatic is all about.
My works include world building, music, videos, 3D modeling, video games, websites,
programs, and more.
</p>
<div class="linktree-container">
<ul class="linktree">
<li>
<a
href="https://mstdn.party/@zakarya"
target="_blank"
rel="noopener noreferrer"
>
Mastodon
</a>
</li>
<li>
<a
href="https://ko-fi.com/zakarya"
target="_blank"
rel="noopener noreferrer"
>
Ko-fi
</a>
</li>
<li>
<a
href="https://www.youtube.com/@czakarya"
target="_blank"
rel="noopener noreferrer"
>
Youtube
</a>
</li>
<li>
<a
href="https://github.com/CZakarya"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</a>
</li>
<!--<li><a href="https://www.reddit.com/user/CZakarya/" target="_blank" rel="noopener noreferrer">Reddit</a></li>-->
</ul>
</div>
</div>
<div class="hero panel">
@ -66,3 +114,101 @@
</main>
<spacer></spacer>
<style lang="scss">
@use "../../style/global.scss";
main img.banner {
display: block;
width: 70%;
margin: 32px auto 32px auto;
border: solid 1px #00000033;
border-radius: 16px;
box-shadow: 1px 1px 8px #00000033;
}
main div.profile {
display: flex;
flex-wrap: wrap;
align-items: center;
}
main div.profile div.nameplate {
flex-grow: 1;
display: flex;
flex-direction: column;
}
main div.profile div.nameplate img.zakarya-icon {
width: 100px;
border-radius: 16px;
margin: 8px auto;
display: block;
}
main div.profile div.nameplate span.name-title {
font-size: 200%;
}
main div.profile p {
font-size: 120%;
max-width: 50%;
padding: 16px;
margin: 12px;
height: fit-content;
text-align: left;
/* text-align: justify;
text-justify: auto; */
border-radius: 16px;
border: solid 1px;
border-color: #383c3f33; // Same as text color but with alpha
}
main div.profile div.linktree-container {
flex-grow: 1;
}
main div.profile div.linktree-container ul.linktree {
width: 100%;
}
@media screen and (max-width: global.$mobile-width) {
main img.banner {
width: 95%;
border-radius: 12px;
margin: 24px auto;
}
main div.profile p {
max-width: unset;
}
main div.profile div.linktree-container ul.linktree {
width: 60%;
}
main div.profile div.nameplate {
flex-direction: row;
align-items: end;
justify-content: center;
}
main div.profile div.nameplate img.zakarya-icon {
height: 1.25em;
width: auto;
font-size: 170%;
margin: 0px 12px;
border-radius: 10px;
}
main div.profile div.nameplate span.name-title {
font-size: 170%;
}
}
@media (prefers-color-scheme: dark) {
main div.profile p {
border-color: #ffffff55;
}
}
</style>

View File

@ -1,271 +0,0 @@
/*/
* Wrapping this entire program into a function isn't ideal,
* but it's the only way I can figure out how to start this
* when the page finishes loading. (svelte onMount function)
/*/
export function createBackground() {
let canvas = document.createElement("canvas") as HTMLCanvasElement;
let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
canvas.classList.add("bg-canvas");
document.body.appendChild(canvas);
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
let dark_theme = false;
if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
dark_theme = true;
}
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", (event) => {
dark_theme = event.matches;
gradientsArray.forEach((gradient: Gradient) => {
gradient.color = getRandomColor();
});
});
let particlesArray: Array<Particle> = [];
const clamp = (val: number, min: number, max: number) =>
Math.min(Math.max(val, min), max);
class Entity {
x: number;
y: number;
size: number;
originalSize: number;
speedX: number;
speedY: number;
growthSpeed: number;
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = (Math.random() * 5 + 1) * 1.5;
this.originalSize = this.size;
this.speedX = (Math.random() - 0.5) * 0.2;
this.speedY = (Math.random() - 0.5) * 0.2;
this.growthSpeed = Math.random() * 0.02 + 0.01;
}
update() {
this.x += this.speedX;
this.y += this.speedY;
// Reverse direction if particle hits edge
if (this.x <= 0 || this.x >= canvas.width) {
this.speedX = -this.speedX;
}
this.x = clamp(0, this.x, canvas.width);
if (this.y <= 0 || this.y >= canvas.height) {
this.speedY = -this.speedY;
}
this.y = clamp(0, this.y, canvas.height);
// Breathing effect: oscillate size
this.size += this.growthSpeed;
if (
this.size >= this.originalSize * 1.5 ||
this.size <= this.originalSize * 0.5
) {
this.growthSpeed = -this.growthSpeed; // Reverse growth direction
}
}
}
function roundRect(
x: number,
y: number,
width: number,
height: number,
radius: number,
) {
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(
x + width,
y + height,
x + width - radius,
y + height,
);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
function roundTriangle(size: number, radius: number) {
const x1 = 0,
y1 = 0;
const x2 = size,
y2 = 0;
const x3 = size / 2,
y3 = size / 1.375;
const midX1 = (x1 + x2) / 2;
const midY1 = (y1 + y2) / 2;
const midX2 = (x2 + x3) / 2;
const midY2 = (y2 + y3) / 2;
const midX3 = (x3 + x1) / 2;
const midY3 = (y3 + y1) / 2;
ctx.arcTo(x2, y2, midX2, midY2, radius);
ctx.arcTo(x3, y3, midX3, midY3, radius);
ctx.arcTo(x1, y1, midX1, midY1, radius);
}
class Shape {
draw(angle: number, size: number) {
return;
}
}
class Circle extends Shape {
draw(angle: number, size: number) {
ctx.beginPath();
ctx.arc(0, 0, size / 2, 0, Math.PI * 2);
ctx.closePath();
}
}
class Square extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
ctx.beginPath();
roundRect(-size / 2, -size / 2, size, size, size / 5);
ctx.closePath();
}
}
class Triangle extends Shape {
draw(angle: number, size: number) {
ctx.rotate((angle * Math.PI) / 180);
ctx.beginPath();
roundTriangle(size * 2, size / 5);
ctx.closePath();
}
}
class Particle extends Entity {
shape: Shape;
angle: number;
rotationSpeed: number;
constructor() {
super();
this.shape = new [Circle, Square, Triangle][
Math.floor(Math.random() * 3)
](); // A very strange but effective way to pick a random shape
this.angle = Math.random() * 360;
this.rotationSpeed = Math.random() * 2 - 1;
}
update() {
super.update();
this.angle += this.rotationSpeed;
}
draw() {
ctx.fillStyle = dark_theme ? "#333" : "#bbb";
ctx.save();
ctx.translate(this.x, this.y);
this.shape.draw(this.angle, this.size);
ctx.fill();
ctx.restore();
}
}
function getRandomColor() {
if (dark_theme) {
const r = Math.floor(Math.random() * 255 - 100);
const b = Math.floor(Math.random() * 255 - 100);
const g = Math.floor(Math.random() * 255 - 100);
return `rgb(${r}, ${g}, ${b})`;
} else {
const r = Math.floor(Math.random() * 100 + 155);
const g = Math.floor(Math.random() * 100 + 155);
const b = Math.floor(Math.random() * 100 + 155);
return `rgb(${r}, ${g}, ${b})`;
}
}
class Gradient extends Entity {
radius: number;
color: string;
alpha: number;
dAlpha: number;
constructor() {
super();
this.radius = Math.random() * 500 + 300;
this.color = getRandomColor();
this.alpha = Math.random() * 0.5 + 0.5; // Initial alpha between 0.5 and 1
this.dAlpha = (Math.random() - 0.5) * 0.01;
}
draw() {
const gradient = ctx.createRadialGradient(
this.x,
this.y,
0,
this.x,
this.y,
this.radius,
);
gradient.addColorStop(0, this.color);
if (dark_theme) {
gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);
} else {
gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
}
ctx.globalAlpha = this.alpha;
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1.0;
}
}
let gradientsArray: Array<Gradient> = [];
function init() {
particlesArray = [];
for (let i = 0; i < 100; i++) {
particlesArray.push(new Particle());
}
gradientsArray = [];
for (let i = 0; i < 10; i++) {
gradientsArray.push(new Gradient());
}
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
gradientsArray.forEach((gradient) => {
gradient.update();
gradient.draw();
});
particlesArray.forEach((particle) => {
particle.update();
particle.draw();
});
requestAnimationFrame(animate);
}
resize();
init();
animate();
window.addEventListener("resize", resize);
}

View File

@ -0,0 +1,44 @@
// Credit: https://github.com/cmpolis/canvas-dpi-scaler
// Based on: http://www.html5rocks.com/en/tutorials/canvas/hidpi/
interface ExtendedCanvasRenderingContext2D extends CanvasRenderingContext2D {
webkitBackingStorePixelRatio?: number;
mozBackingStorePixelRatio?: number;
msBackingStorePixelRatio?: number;
oBackingStorePixelRatio?: number;
backingStorePixelRatio?: number;
}
export function canvasDpiScaler(
canvas: HTMLCanvasElement,
context: ExtendedCanvasRenderingContext2D,
) {
if (!canvas || !context) {
throw new Error("Must pass in `canvas` and `context`.");
}
var width =
canvas.width || // attr, eg: <canvas width='400'>
canvas.clientWidth; // keep existing width
var height = canvas.height || canvas.clientHeight;
var deviceRatio = window.devicePixelRatio || 1;
var bsRatio =
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
var ratio = deviceRatio / bsRatio;
// Adjust canvas if ratio =/= 1
if (deviceRatio !== bsRatio) {
canvas.width = Math.round(width * ratio);
canvas.height = Math.round(height * ratio);
canvas.style.width = width + "px";
canvas.style.height = height + "px";
context.scale(ratio, ratio);
}
return ratio;
}

View File

@ -1,86 +0,0 @@
const BASEURL = "https://files.colormatic.org/";
export function getParam(paramName: string) {
var params = new URLSearchParams(window.location.search);
let t_param = params.get(paramName);
return t_param ? t_param : ""; // Return empty string if null
}
async function getJSON(url: string) {
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText);
const data = response.json();
return data;
}
export function getVideo(cname: string, vname: string) {
var videoplayer = document.getElementById("videoplayer") as HTMLElement;
var videotitle = document.getElementById("videotitle") as HTMLElement;
var videodescription = document.getElementById(
"videodescription",
) as HTMLElement;
var videodownload = document.getElementById("videodownload") as HTMLElement;
var sourcedownload = document.getElementById(
"sourcedownload",
) as HTMLElement;
getJSON(BASEURL + cname + "/videos/data/" + vname + ".json")
.then((data) => {
let videoURL =
BASEURL +
cname +
"/videos/raw/" +
data.video_file +
"." +
data.video_format;
videoplayer.setAttribute(
"poster",
BASEURL + cname + "/videos/thumbnail/" + data.thumbnail,
);
var videosource = document.createElement("source");
videosource.setAttribute("src", videoURL);
videosource.setAttribute("type", "video/" + data.video_format);
videoplayer.appendChild(videosource);
document.title = data.title;
videotitle.innerText = data.title;
data.description.forEach((iter: number) => {
// TODO: Detect if one of these lines contains a link and if so, make it a link
videodescription.appendChild(
document.createTextNode(iter.toString()),
);
videodescription.appendChild(document.createElement("br"));
});
videodownload.setAttribute(
"href",
BASEURL +
cname +
"/videos/raw/" +
data.video_file +
"." +
data.video_format,
);
videodownload.setAttribute(
"download",
data.video_file + "." + data.video_format,
);
sourcedownload.setAttribute(
"href",
BASEURL +
cname +
"/videos/source/" +
data.source_file +
"." +
data.source_format,
);
sourcedownload.setAttribute(
"download",
data.source_file + "." + data.source_format,
);
})
.catch((error) => {
videotitle.innerText = "Failed to load video.";
console.error(error);
});
}

View File

@ -19,13 +19,6 @@ body {
color: global.$text-color;
}
canvas.bg-canvas {
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
spacer {
display: block;
margin-top: 8%;
@ -59,32 +52,18 @@ div.divider {
div.panel {
color: global.$text-color;
border: solid 1px #00000033;
border: solid 1px;
border-color: #00000033;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
background-color: #ffffff22;
backdrop-filter: blur(5px);
}
main div.brand-heading {
padding: 12%;
width: 60%;
}
main div.brand-heading h1 {
font-size: 300%;
}
main div.heading {
font-size: 250%;
text-align: center;
padding: 12px;
}
main span.name-title {
display: block;
font-size: 550%;
text-align: center;
@media (prefers-color-scheme: dark) {
div.panel {
border-color: #ffffff33;
}
}
main div.hero {
@ -94,6 +73,15 @@ main div.hero {
text-align: center;
}
@media screen and (max-width: global.$mobile-width) {
spacer {
margin-top: 24%;
}
main div.hero {
width: 80%;
}
}
main div#scroll-arrow {
text-align: center;
font-size: 200%;
@ -113,23 +101,6 @@ main div#scroll-arrow.scroll-arrow-hide {
opacity 0.25s ease-out;
}
@media screen and (max-width: global.$mobile-width) {
spacer {
margin-top: 24%;
}
main div.brand-heading {
padding: 38% 12px;
text-align: center;
width: initial;
}
main div.heading {
font-size: 200%;
}
main div.hero {
width: 80%;
}
}
main div.hero h1 a {
color: global.$text-color;
}
@ -137,12 +108,12 @@ main div.hero h1 a {
p.justify {
text-align: justify;
text-justify: auto;
margin-left: auto;
margin-right: auto;
}
main div.hero p.justify {
width: 60%;
margin-left: auto;
margin-right: auto;
}
main div.hero ul {
@ -150,21 +121,7 @@ main div.hero ul {
margin-right: auto;
}
main img.banner {
display: block;
width: 70%;
margin: 32px auto 32px auto;
border: solid 1px #00000033;
border-radius: 16px;
box-shadow: 1px 1px 8px #00000033;
}
@media screen and (max-width: global.$mobile-width) {
main img.banner {
width: 95%;
border-radius: 12px;
margin: 24px auto 24px auto;
}
main div.hero p.justify {
width: 100%;
}
@ -253,28 +210,3 @@ ul.videolist li a span {
img.pixelart {
image-rendering: pixelated;
}
footer {
display: flex;
justify-content: space-between;
border-top: solid 1px global.$text-color;
width: 95%;
padding: 4px;
margin: 0 auto;
}
footer p {
color: global.$text-color;
padding: 4px 10%;
}
@media screen and (max-width: global.$mobile-width) {
footer {
flex-direction: column;
}
footer p {
text-align: center;
padding: 4px;
margin: 4px;
}
}

View File

@ -1,186 +0,0 @@
@use "global.scss";
nav {
display: grid;
grid-template-columns: 1fr min-content 1fr;
align-items: center;
padding: 12px;
border-bottom: solid 1px global.$text-color;
z-index: 1;
margin: 0 auto;
width: 95%;
box-sizing: border-box;
overflow-wrap: anywhere;
}
nav .nav-left {
justify-self: left;
grid-column: 1;
}
nav .nav-center {
justify-self: center;
grid-column: 2;
}
nav .nav-right {
justify-self: right;
grid-column: 3;
}
nav ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
}
nav ul li {
display: grid;
justify-items: center;
}
nav a,
nav button {
padding: 0 8px;
color: global.$text-color;
text-decoration: none;
display: flex;
cursor: pointer;
align-items: center;
}
nav a.title {
font-size: 140%;
font-weight: bold;
}
nav img.colormatic-logo {
width: auto;
height: 40px;
padding: 4px;
}
nav button.menu-button {
background: none;
border: none;
}
nav .menu-button i {
font-size: 230%;
transform: translateY(-1px);
/*/
* Ugly hack to account for the fact that the menu icon is off-center
* (Bootstrap please fix)
/*/
}
nav .git-icon i {
font-size: 140%;
}
nav div.inline {
display: flex;
}
@media screen and (max-width: global.$mobile-width) {
nav {
padding: 6px 0;
}
nav .git-icon i {
font-size: 150%;
}
nav ul.responsive-hidden {
display: none;
}
}
/*/
* Navigation modal section
/*/
span.modalbg.hidden {
display: none;
}
span.modalbg {
position: fixed;
z-index: 1;
padding: 0;
margin: auto;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
span.modalbg div {
width: 50ch;
margin: 100px auto;
padding: 16px;
color: global.$text-color;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
background-color: #ffffffbb;
backdrop-filter: blur(5px);
animation-name: modal-animate-in;
animation-duration: 0.4s;
}
@keyframes modal-animate-in {
from {
transform: translate(0px, -300px);
opacity: 0;
}
to {
transform: translate(0px, 0px);
opacity: 1;
}
}
span.modalbg div button.close {
float: right;
width: min-content;
background: none;
border: none;
outline: none;
cursor: pointer;
font-size: 200%;
color: global.$text-color;
}
span.modalbg div ul {
list-style-type: none;
margin: 0;
padding: 0;
}
span.modalbg div ul li {
margin: 18px 12px;
}
span.modalbg div ul li a {
color: global.$text-color;
padding: 8px;
text-decoration: none;
font-size: 120%;
}
@media screen and (max-width: global.$mobile-width) {
span.modalbg div {
width: 30ch;
}
}
@media (prefers-color-scheme: dark) {
span.modalbg div {
background-color: #000000bb;
}
}

View File

@ -1,90 +0,0 @@
@use "global.scss";
div.cs-title {
background-image: url("/img/colormatic_banner.svg");
background-size: cover;
background-repeat: no-repeat;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
}
div.cs-title h1 {
color: white;
background-color: #00000088;
padding: 28px 38px;
border-radius: 16px;
font-size: 300%;
box-shadow: 1px 1px 8px #00000033;
backdrop-filter: blur(5px);
}
div.project-grid-container {
display: flex;
width: 80%;
margin-left: auto;
margin-right: auto;
flex-wrap: wrap;
justify-content: center;
}
@media screen and (max-width: global.$mobile-width) {
div.project-grid-container {
width: 90%;
}
div.cs-title {
height: 200px;
}
div.cs-title h1 {
font-size: 200%;
}
}
div.project-grid-container div.project-grid-box {
flex: 1;
color: #383c3f;
margin: 16px;
border: solid 1px #00000033;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
padding: 16px;
color: global.$text-color;
min-width: 40%;
max-width: 50%;
background-color: #ffffff22;
backdrop-filter: blur(3px);
}
div.project-grid-container div.project-grid-box h1 {
text-align: center;
}
div.project-grid-container div.project-grid-box h1 a {
color: global.$text-color;
}
div.project-grid-container div.project-grid-box div.project-grid-box-contents {
/* Yes, this absurdly long element selector is a joke */
display: flex;
}
div.project-grid-container div.project-grid-box img {
max-width: 120px;
max-height: 150px;
margin: 12px;
border-radius: 8px;
}
@media screen and (max-width: global.$mobile-width) {
div.project-grid-container div.project-grid-box {
min-width: 90%;
max-width: 90%;
}
div.project-grid-container div.project-grid-box img {
max-width: 100px;
}
}

View File

@ -1,109 +0,0 @@
@use "global.scss";
div.video.container {
display: flex;
color: global.$text-color;
width: 90%;
margin: 16px auto 16px auto;
border: solid 1px #00000033;
border-radius: 8px;
box-shadow: 1px 1px 8px #00000033;
padding: 16px;
background-color: #ffffff22;
backdrop-filter: blur(3px);
}
div.video.container video#videoplayer {
flex-grow: 1;
border-radius: 12px;
height: auto;
max-width: 55%;
}
div.video.container div.videoobjects {
display: grid;
padding: 24px;
}
div.video.container div.videodetails h1#videotitle {
padding: 0 12px;
}
div.dropdown-container {
display: flex;
flex-direction: column-reverse;
}
div.video.container div.download-dropdown {
position: relative;
display: inline-block;
padding: 12px;
width: 25px;
height: 25px;
background-color: #21afff;
box-shadow: 1px 1px 8px #00000033;
border-radius: 50px;
transition-duration: 0.35s;
font-size: 120%;
text-align: center;
}
div.video.container div.download-dropdown:hover {
box-shadow: 1px 1px 8px #00000088;
}
div.video.container div.download-dropdown div.dropdown-content {
display: none;
position: absolute;
font-size: 80%;
min-width: 160px;
background-color: #edeeee;
box-shadow: 1px 1px 8px #00000033;
border-radius: 8px;
text-align: center;
}
div.video.container div.download-dropdown:hover div.dropdown-content {
display: block;
}
div.video.container div.download-dropdown div.dropdown-content ul {
list-style-type: none;
padding-left: 0;
}
div.video.container div.download-dropdown div.dropdown-content ul li {
padding: 4px;
cursor: pointer;
}
div.video.container div.download-dropdown div.dropdown-content ul li:hover {
background-color: #dcdfdf;
}
div.video.container div.download-dropdown div.dropdown-content ul li a {
text-decoration: none;
color: global.$text-color;
}
@media screen and (max-width: global.$mobile-width) {
div.video.container {
display: block;
}
div.video.container video#videoplayer {
width: 100%;
max-width: none;
}
div.video.container div.download-dropdown {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 12px;
}
}
@media (prefers-color-scheme: dark) {
div.video.container div.download-dropdown div.dropdown-content {
background-color: #444444;
}
}

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="10"
height="10"
viewBox="0 0 2.6458332 2.6458334"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="circle.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="5.9860924"
inkscape:cx="28.14858"
inkscape:cy="23.805179"
inkscape:window-width="1251"
inkscape:window-height="991"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0529166"
id="path1"
cx="1.3229166"
cy="1.3229166"
r="1.3229166" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="10"
height="10"
viewBox="0 0 2.6458332 2.6458334"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="square.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="5.9860924"
inkscape:cx="28.232107"
inkscape:cy="23.805179"
inkscape:window-width="1251"
inkscape:window-height="991"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0529166"
id="rect1"
width="2.6458333"
height="2.6458333"
x="0"
y="0"
ry="0.42333332" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="10"
height="10"
viewBox="0 0 2.6458332 2.6458334"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="star.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="40.911253"
inkscape:cx="6.1474529"
inkscape:cy="6.0741234"
inkscape:window-width="1251"
inkscape:window-height="991"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect2"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="path2"
inkscape:flatsided="false"
sodipodi:sides="4"
sodipodi:cx="6.614583"
sodipodi:cy="6.614583"
sodipodi:r1="6.6176233"
sodipodi:r2="2.301954"
sodipodi:arg1="-0.029738439"
sodipodi:arg2="0.75565972"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 11.23738,7.1337824 10.28189,7.4772235 A 4.1661509,4.1661509 133.29611 0 0 7.6936896,10.224128 L 7.4076518,11.198344 A 0.6904665,0.6904665 178.29611 0 1 6.0953836,11.23738 L 5.7519425,10.28189 A 4.1661509,4.1661509 43.296113 0 0 3.0050377,7.6936896 L 2.0308224,7.4076518 A 0.6904665,0.6904665 88.296113 0 1 1.9917861,6.0953836 l 0.95549,-0.3434411 A 4.1661509,4.1661509 133.29611 0 0 5.5354765,3.0050377 L 5.8215142,2.0308224 a 0.6904665,0.6904665 178.29611 0 1 1.3122682,-0.039036 l 0.3434411,0.95549 a 4.1661509,4.1661509 43.296113 0 0 2.7469045,2.5882004 l 0.974216,0.2860377 a 0.6904665,0.6904665 88.296113 0 1 0.03904,1.3122682 z"
inkscape:transform-center-x="-0.014052847"
inkscape:transform-center-y="-0.068859274"
inkscape:path-effect="#path-effect3"
transform="matrix(0.26043146,0,0,0.25804465,-0.39972889,-0.39606549)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="10"
height="10"
viewBox="0 0 2.6458332 2.6458334"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="triangle.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="18.89041"
inkscape:cx="8.9198698"
inkscape:cy="10.243293"
inkscape:window-width="1251"
inkscape:window-height="991"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect2"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
d="M 2.1166666,13.229167 H 11.1125 a 1.2220542,1.2220542 119.99992 0 0 1.058329,-1.833084 L 7.6729215,3.6055279 a 1.2220656,1.2220656 180 0 0 -2.1166765,0 L 1.0583382,11.396083 a 1.2220543,1.2220543 60.000077 0 0 1.0583284,1.833084 z"
id="path2"
sodipodi:nodetypes="cccc"
inkscape:path-effect="#path-effect2"
inkscape:original-d="M 0,13.229167 H 13.229167 L 6.6145832,1.7724437 Z"
transform="matrix(0.23128026,0,0,0.23128026,-0.20690571,-0.55319007)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="10"
height="10"
viewBox="0 0 2.6458332 2.6458334"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="wavy-circle.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="46.528727"
inkscape:cx="5.0398972"
inkscape:cy="5.3945168"
inkscape:window-width="1251"
inkscape:window-height="991"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1 @ F,0,0,1,0,1.2277634,0,1"
radius="6"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect2"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1 @ F,0,0,1,0,2.1166666,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill:#000000;stroke-width:0.264583"
id="path1"
inkscape:flatsided="false"
sodipodi:sides="8"
sodipodi:cx="6.614583"
sodipodi:cy="6.614583"
sodipodi:r1="6.6146464"
sodipodi:r2="5.3311768"
sodipodi:arg1="-1.5707963"
sodipodi:arg2="-1.1780972"
inkscape:rounded="0.4"
inkscape:randomized="0"
d="M 6.6145832,-6.3419342e-5 C 7.6740846,-6.3390953e-5 7.6758845,1.2837643 8.6547362,1.689218 9.6335879,2.0946717 10.542664,1.1881411 11.291844,1.9373218 c 0.749181,0.7491807 -0.157349,1.6582566 0.248104,2.6371083 0.405454,0.9788517 1.689281,0.9806516 1.689281,2.0401531 0,1.0595014 -1.283827,1.0613013 -1.689281,2.040153 -0.405454,0.9788517 0.501077,1.8879278 -0.248104,2.6371078 -0.74918,0.749181 -1.6582564,-0.157349 -2.6371081,0.248104 -0.9788517,0.405454 -0.9806516,1.689281 -2.0401531,1.689281 -1.0595014,0 -1.0613012,-1.283827 -2.0401529,-1.689281 C 3.5955782,11.134494 2.6865022,12.041025 1.9373215,11.291844 1.1881409,10.542664 2.0946715,9.6335876 1.6892179,8.6547359 1.2837642,7.6758842 -6.3447731e-5,7.6740843 -6.3419342e-5,6.6145828 -6.3390953e-5,5.5550814 1.2837643,5.5532816 1.689218,4.5744299 2.0946717,3.5955782 1.1881411,2.6865022 1.9373218,1.9373215 2.6865025,1.1881409 3.5955784,2.0946715 4.5744301,1.6892179 5.5532818,1.2837642 5.5550817,-6.3447731e-5 6.6145832,-6.3419342e-5 Z"
transform="matrix(0.20000288,0,0,0.20000288,-5.0735291e-5,1.2684051e-5)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
static/img/zakarya-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

View File

@ -1,20 +1,20 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@ -1,6 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit()]
plugins: [sveltekit()],
});