Compare commits

...

67 commits

Author SHA1 Message Date
Sebin Nyshkim
15d487ec6f chore: bump version number 2024-09-03 14:41:04 +02:00
Sebin Nyshkim
d716e192bb build: update packages 2024-09-03 14:41:04 +02:00
Sebin Nyshkim
6aa34c1648 build: update scaffolding to current create-vue template 2024-09-03 14:40:57 +02:00
Sebin Nyshkim
34823665c6 chore: bump version number 2023-11-30 23:18:28 +01:00
Sebin Nyshkim
134e2c79cc fix: wrong order of v-if evaluation 2023-11-30 23:17:49 +01:00
Sebin Nyshkim
b0abfd8311 chore: bump version number 2023-11-30 22:55:32 +01:00
Sebin Nyshkim
61cd15fd5b build: update npm packages 2023-11-30 22:55:05 +01:00
Sebin Nyshkim
f3f94be6ae build: update browserslist definitions 2023-11-30 22:54:18 +01:00
Sebin Nyshkim
61147be693 build: update browserslist definition file 2023-11-30 22:53:41 +01:00
Sebin Nyshkim
6a1474eb52 build: update npm packages 2023-10-19 01:54:10 +02:00
Sebin Nyshkim
f4b1003801 chore: bump version number 2023-09-01 13:13:07 +02:00
Sebin Nyshkim
5d94323bdd feat: update overdrive ref image to new border style 2023-09-01 13:12:30 +02:00
Sebin Nyshkim
d2774e8150 refactor: update vite-imagetools asset link directives
Starting with v5 vite-imagetools has removed shorthands
2023-09-01 13:06:40 +02:00
Sebin Nyshkim
89831a64a2 build: add package.json to list of includes 2023-09-01 13:04:08 +02:00
Sebin Nyshkim
4c8d576f13 build: migrate autoprefixer from CJS require to ES module import 2023-09-01 12:30:33 +02:00
Sebin Nyshkim
0c8a3b0348 build: update scaffolding to current create-vue template 2023-09-01 12:29:06 +02:00
Sebin Nyshkim
0335006ee5 build: update packages to latest versions 2023-09-01 12:28:40 +02:00
Sebin Nyshkim
07bd197c29 refactor: add types for emits 2023-09-01 12:11:51 +02:00
Sebin Nyshkim
a0b2062137 chore: bump version number 2023-07-22 02:15:08 +02:00
Sebin Nyshkim
d5cf84e592 refactor: move buttons and tags to separate components 2023-07-22 02:14:22 +02:00
Sebin Nyshkim
cd9c1d950d feat: add FilterListTag component 2023-07-22 02:12:52 +02:00
Sebin Nyshkim
665f2c6b35 feat: add FilterButton component 2023-07-22 02:12:09 +02:00
Sebin Nyshkim
30a573e9cf feat: reorganize list tag positioning 2023-07-22 01:28:08 +02:00
Sebin Nyshkim
ddde6df30b fix: remove duplicate entry 2023-07-22 01:18:40 +02:00
Sebin Nyshkim
d5703cc274 chore: bump version number 2023-07-21 15:41:23 +02:00
Sebin Nyshkim
778142c4c1 build: update npm packages 2023-07-21 15:41:08 +02:00
Sebin Nyshkim
d984651fc8 feat: update responsive image srcsets, genereate fewer images 2023-07-21 15:40:33 +02:00
Sebin Nyshkim
9a529b62fb feat: update figure cencor size constraints 2023-07-21 15:15:23 +02:00
Sebin Nyshkim
c143956e9f feat: add new RefFigure style 2023-07-21 15:14:56 +02:00
Sebin Nyshkim
120a1a03e3 feat: replace placeholder images with artwork 2023-07-21 15:13:17 +02:00
Sebin Nyshkim
08e01502c5 fix: eliminate unintended side-effects in computed property 2023-07-20 19:15:38 +02:00
Sebin Nyshkim
314255dc31 chore: bump version number 2023-07-18 21:53:14 +02:00
Sebin Nyshkim
1b036d3278 feat: replace DataTable component with new FilteredList component 2023-07-18 21:51:32 +02:00
Sebin Nyshkim
b450849075 feat: expand css color variables 2023-07-18 21:51:14 +02:00
Sebin Nyshkim
f100c524af feat: add FilteredList component 2023-07-18 21:50:06 +02:00
Sebin Nyshkim
d196c1e680 feat: update interface definitions 2023-07-18 21:48:41 +02:00
Sebin Nyshkim
f147510c04 feat: expand Sebin data object 2023-07-18 21:48:18 +02:00
Sebin Nyshkim
6cf6e6d045 chore: bump version number 2023-07-17 14:49:13 +02:00
Sebin Nyshkim
ff665a6cea build: update npm packages 2023-07-17 14:45:00 +02:00
Sebin Nyshkim
a2e2c1f791 fix: wrong open graph meta tag attributes 2023-07-17 14:36:42 +02:00
Sebin Nyshkim
0b4813e285 chore: bump version number 2023-04-03 00:55:46 +02:00
Sebin Nyshkim
4853e1ec63 style: run linter 2023-04-03 00:55:28 +02:00
Sebin Nyshkim
de3862bf77 build: inline postcss config into vite config 2023-04-03 00:29:59 +02:00
Sebin Nyshkim
6094a2a559 feat: update prettier config 2023-04-03 00:29:40 +02:00
Sebin Nyshkim
939610ed61 build: update typescript 2023-04-03 00:03:18 +02:00
Sebin Nyshkim
5ef3d6c0f9 build: add browserslist config 2023-04-02 23:55:44 +02:00
Sebin Nyshkim
35562692e4 build: update tsconfig 2023-04-02 23:55:24 +02:00
Sebin Nyshkim
5f65a341a0 refactor: change how version is read from package.json 2023-04-02 23:46:46 +02:00
Sebin Nyshkim
e3f2e0c256 feat: migrate to native details element for quickfacts component 2023-04-02 23:35:59 +02:00
Sebin Nyshkim
51e72e2021 feat: remove no longer needed modalResultKey inject 2023-04-02 20:08:29 +02:00
Sebin Nyshkim
b8c9d8de17 feat: remove no longer needed isWarn property and injection key 2023-04-02 17:45:08 +02:00
Sebin Nyshkim
cc664a764d feat: move modal out of views and into global app context 2023-04-02 17:42:26 +02:00
Sebin Nyshkim
d0f9434700 feat: migrate to native dialog element for modal component 2023-04-02 17:28:48 +02:00
Sebin Nyshkim
b9fe7113ed feat: extend column styling 2023-04-02 17:27:27 +02:00
Sebin Nyshkim
0e225f95c9 fix: make sure paragraphs in footer are always center aligned 2023-04-02 17:08:38 +02:00
Sebin Nyshkim
8e0756f166 feat: add column and grid styling to button group 2023-04-02 17:07:57 +02:00
Sebin Nyshkim
e67a220223 feat: add props for button styling 2023-04-02 17:07:13 +02:00
Sebin Nyshkim
dd70061798 feat: use buttons instead of list for social links 2023-04-02 17:05:41 +02:00
Sebin Nyshkim
c7444256f1 feat: justify paragraphs, add hyphenation 2023-04-02 17:04:30 +02:00
Sebin Nyshkim
3c8b726d83 refactor: decouple social link styling from fixed elements 2023-04-02 17:03:27 +02:00
Sebin Nyshkim
a670952e15 build: add autoprefixer 2023-04-02 15:47:07 +02:00
Sebin Nyshkim
d6f94c26d4 build: update npm packages 2023-04-02 15:46:46 +02:00
Sebin Nyshkim
62795740b3 chore: bump version number 2023-01-25 19:30:20 +01:00
Sebin Nyshkim
6b0acce446 fix: make sure setActiveImage gets integer value after scroll 2023-01-25 19:28:54 +01:00
Sebin Nyshkim
a0182fe447 chore: add header template for Fur Affinity 2023-01-23 02:02:44 +01:00
Sebin Nyshkim
fe785f6ed3 chore: add header template for Mastodon 2023-01-23 02:02:35 +01:00
Sebin Nyshkim
52d2f12b75 chore: add header template for Twitter 2023-01-23 02:02:25 +01:00
55 changed files with 3653 additions and 6266 deletions

3
.browserslistrc Normal file
View file

@ -0,0 +1,3 @@
defaults
>1% and not dead
last 2 versions

View file

@ -1,15 +1,15 @@
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier",
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: "latest",
},
};
ecmaVersion: 'latest'
}
}

2
.gitignore vendored
View file

@ -26,3 +26,5 @@ coverage
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

View file

@ -1 +1,8 @@
{}
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}

View file

@ -1,3 +1,7 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -0,0 +1,139 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 25vh;
--welcome-header-subline-font-size: 10vh;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%),
radial-gradient(circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
flex: 0 0 50vw;
padding: 0 2vw;
}
.flex > * {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 3vh solid #fff; box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 1 45vw;
margin: 0;
padding: 0 1vw;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -0,0 +1,139 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 6vw;
--welcome-header-subline-font-size: 2vw;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%),
radial-gradient(circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
flex: 0 0 72vw;
}
.flex>* {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 1vw solid #fff;
box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 0 50vw;
margin: 0;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
line-height: 1.75;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -0,0 +1,143 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 8vw;
--welcome-header-subline-font-size: 2.5vw;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(
circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%
),
radial-gradient(
circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%
);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-evenly;
align-items: center;
flex: 0 0 100%;
}
.flex > * {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 1vw solid #fff;
box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 0 60vw;
margin: 0;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
line-height: 1.75;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -17,11 +17,12 @@
<meta name="twitter:description" content="The official reference page for Sebin Nyshkim with picture references and in-depth character descriptions" />
<meta name="twitter:image" content="https://ref.sebin-nyshkim.net/sebin/preview.png" />
<meta name="og:type" content="website" />
<meta name="og:title" content="Sebin Nyshkim - Reference Page" />
<meta name="og:url" content="https://ref.sebin-nyshkim.net/sebin/" />
<meta name="og:image" content="https://ref.sebin-nyshkim.net/sebin/preview.png" />
<meta name="og:description" content="The official reference page for Sebin Nyshkim with picture references and in-depth character descriptions" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Sebin Nyshkim - Reference Page" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://ref.sebin-nyshkim.net/sebin/" />
<meta property="og:image" content="https://ref.sebin-nyshkim.net/sebin/preview.png" />
<meta property="og:description" content="The official reference page for Sebin Nyshkim with picture references and in-depth character descriptions" />
</head>
<body>
<script type="module" src="/src/main.ts"></script>

6940
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,35 +1,38 @@
{
"name": "sebin-reference",
"version": "0.9.1",
"version": "0.10.7",
"private": true,
"scripts": {
"dev": "vite --host",
"build": "run-p type-check build-only",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"vue": "^3.2.45",
"vue-router": "^4.1.6"
"vue": "^3.4.38",
"vue-router": "^4.4.3"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@types/node": "^18.11.18",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.2",
"@vue/tsconfig": "^0.1.3",
"eslint": "^8.32.0",
"eslint-plugin-vue": "^9.9.0",
"@rushstack/eslint-patch": "^1.10.4",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.16.3",
"@vitejs/plugin-vue": "^5.1.3",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.28.0",
"normalize.css": "^8.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.3",
"sass": "^1.57.1",
"typescript": "~4.7.4",
"vite": "^4.0.4",
"vite-imagetools": "^4.0.15",
"vue-tsc": "^1.0.24"
"npm-run-all2": "^6.2.2",
"prettier": "^3.3.3",
"sass": "^1.77.8",
"typescript": "~5.5.0",
"vite": "^5.4.2",
"vite-imagetools": "^6.2.9",
"vue-tsc": "^2.1.4"
}
}

View file

@ -1,63 +1,82 @@
<script setup lang="ts">
import { ref, provide } from "vue";
import { RouterView } from "vue-router";
import { isWarnKey, modalResultKey, nsfwKey, showModalKey } from "@/keys";
import SiteHeader from "@/components/SiteHeader.vue";
import SiteFooter from "@/components/SiteFooter.vue";
import SiteNavigation from "@/components/SiteNavigation.vue";
import pkg from "../package.json";
import { ref, provide } from 'vue'
import { RouterView } from 'vue-router'
import { modalResultKey, nsfwKey, showModalKey } from '@/keys'
import { version } from '../package.json'
import RefModal from '@/components/RefModal.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Button from '@/components/RefButton.vue'
import SiteHeader from '@/components/SiteHeader.vue'
import SiteFooter from '@/components/SiteFooter.vue'
import SiteNavigation from '@/components/SiteNavigation.vue'
const version = pkg.version;
const isNsfw = ref(false)
const isConfirmedHorny = ref(false)
const isNsfw = ref(false);
const isConfirmedHorny = ref(false);
const isWarn = ref(false);
const nsfwmodal = ref<InstanceType<typeof RefModal>>()
const showModal = (): void => {
if (!isConfirmedHorny.value) {
isWarn.value = true;
document.body.classList.add("scroll-lock");
nsfwmodal.value?.showModal()
setTimeout(() => {
isNsfw.value = false;
}, 1);
isNsfw.value = false
}, 1)
} else {
isNsfw.value = !isNsfw.value;
isNsfw.value = !isNsfw.value
}
}
};
const modalResult = (value: boolean): void => {
isNsfw.value = value;
isConfirmedHorny.value = value;
isWarn.value = false;
document.body.classList.remove("scroll-lock");
};
isNsfw.value = value
isConfirmedHorny.value = value
nsfwmodal.value?.close()
}
provide(isWarnKey, isWarn);
provide(modalResultKey, modalResult);
provide(nsfwKey, isNsfw);
provide(showModalKey, showModal);
provide(modalResultKey, modalResult)
provide(nsfwKey, isNsfw)
provide(showModalKey, showModal)
</script>
<template>
<RefModal id="nsfw-warning" ref="nsfwmodal">
<template #heading>
<br />
Whoa, Nelly!
</template>
<template #message>
By enabling NSFW mode you confirm that you are of legal age to view adult content.
</template>
<template #buttons>
<ButtonGroup col>
<Button positive @click.prevent="modalResult(true)"> Yes, show me the goods 👀 </Button>
<Button negative @click.prevent="modalResult(false)"> NO, STAHP 😱 </Button>
</ButtonGroup>
</template>
</RefModal>
<SiteHeader>
<!-- max 500px -->
<picture>
<source
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&avif&quality=75&srcset"
srcset="
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=avif&quality=75&as=srcset
"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
type="image/avif"
/>
<source
srcset="
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&webp&quality=100&srcset
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=webp&quality=100&as=srcset
"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
type="image/webp"
/>
<img
class="nav-logo"
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&png&srcset"
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=png&as=srcset"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
alt="Sebin Avatar"
/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -13,7 +13,6 @@
width: 100%;
max-width: var(--attack-list-max-width);
margin: auto;
padding: 0 var(--container-spacing-right-safe) 0
var(--container-spacing-left-safe);
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
}
</style>

View file

@ -1,5 +1,14 @@
<script setup lang="ts">
interface Props {
col?: boolean
grid?: boolean
}
defineProps<Props>()
</script>
<template>
<div class="btn-group">
<div class="btn-group" :class="{ col: col, grid: grid }">
<slot></slot>
</div>
</template>
@ -10,6 +19,27 @@
flex-flow: row wrap;
justify-content: space-evenly;
&.col {
flex-flow: column nowrap;
gap: 1.5rem;
margin: 1rem 0;
> * {
margin: 0;
}
}
&.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1rem 0;
> * {
margin: 0;
}
}
> * {
flex: var(--button-group-flex);
margin: 1rem 0;

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import type { ColorDict } from "@/interfaces";
import type { ColorDict } from '@/interfaces'
interface Props {
colors: ColorDict[];
colors: ColorDict[]
}
defineProps<Props>();
defineProps<Props>()
</script>
<template>
@ -21,10 +21,7 @@ defineProps<Props>();
<tr class="color-table__row" v-for="(color, idx) in colors" :key="idx">
<td class="color-table__cell name">{{ color.name }}</td>
<td class="color-table__cell value">{{ color.value }}</td>
<td
class="color-table__cell color"
:style="{ 'background-color': color.value }"
></td>
<td class="color-table__cell color" :style="{ 'background-color': color.value }"></td>
</tr>
</tbody>
</table>

View file

@ -1,21 +1,17 @@
<script setup lang="ts">
interface Props {
headings: string[];
data: string[][];
headings: string[]
data: string[][]
}
defineProps<Props>();
defineProps<Props>()
</script>
<template>
<table class="data-table">
<thead class="data-table__head">
<tr class="data-table__row">
<th
class="data-table__heading"
v-for="(heading, idx) in headings"
:key="idx"
>
<th class="data-table__heading" v-for="(heading, idx) in headings" :key="idx">
{{ heading }}
</th>
</tr>

View file

@ -0,0 +1,161 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Ratings } from '@/interfaces'
interface Props {
modelValue: number[]
name?: string
value: Ratings
}
interface Emits {
(e: 'update:modelValue', value: number[]): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const checked = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
<template>
<div class="filter-button">
<input
class="filter-button__input"
type="checkbox"
:name="name"
:id="Ratings[value].toLowerCase()"
:value="value"
v-model="checked"
/>
<label
:for="Ratings[value].toLowerCase()"
class="filter-button__label"
:class="[Ratings[value].toLowerCase()]"
>
{{ Ratings[value] }}
</label>
</div>
</template>
<style lang="scss">
.filter-button {
flex: 1 1 0;
&__input {
display: none;
}
&__input:checked + &__label {
top: 0.25rem;
box-shadow: 0 0.25rem 0 0 var(--color-button-box-shadow);
&.love {
box-shadow: 0 0.25rem 0 0 var(--theme-c-love-dark);
}
&.yes {
box-shadow: 0 0.25rem 0 0 var(--theme-c-yes-dark);
}
&.maybe {
box-shadow: 0 0.25rem 0 0 var(--theme-c-maybe-dark);
}
&.no {
box-shadow: 0 0.25rem 0 0 var(--theme-c-no-dark);
}
}
&__label {
display: block;
position: relative;
top: 0;
background-color: var(--color-button);
font-weight: 700;
text-decoration: none;
text-align: center;
margin: 0.5rem 0;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
box-shadow: 0 0.5rem 0 0 var(--color-button-box-shadow);
transition: all 0.1s ease-out;
&:hover {
cursor: pointer;
top: -0.25rem;
box-shadow: 0 0.75rem 0 0 var(--color-button-box-shadow);
}
&:active {
top: 0.25rem;
box-shadow: 0 0.25rem 0 0 var(--color-button-box-shadow);
}
&.love {
background-color: var(--theme-c-love);
box-shadow: 0 0.5rem 0 0 var(--theme-c-love-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-love-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-love-dark);
}
}
&.yes {
background-color: var(--theme-c-yes);
box-shadow: 0 0.5rem 0 0 var(--theme-c-yes-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-yes-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-yes-dark);
}
}
&.maybe {
background-color: var(--theme-c-maybe);
box-shadow: 0 0.5rem 0 0 var(--theme-c-maybe-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-maybe-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-maybe-dark);
}
}
&.no {
background-color: var(--theme-c-no);
box-shadow: 0 0.5rem 0 0 var(--theme-c-no-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-no-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-no-dark);
}
}
}
}
</style>

View file

@ -0,0 +1,77 @@
<script setup lang="ts">
interface Props {
type: string
}
defineProps<Props>()
</script>
<template>
<span class="filter-list__tag" :class="type.toLowerCase()">
<span>{{ type }}</span>
</span>
</template>
<style lang="scss">
.filter-list {
&__tag {
flex: 0 0 0;
span {
display: block;
font-size: 0.75rem;
font-weight: bold;
text-align: center;
background: rgba(#f5f5f5, 0.7);
border: 1px solid #f5f5f5;
border-radius: 1em;
padding: 0 0.5em;
}
&.love span {
background: var(--theme-c-love);
border: 1px solid var(--theme-c-love-dark);
}
&.yes span {
background: var(--theme-c-yes);
border: 1px solid var(--theme-c-yes-dark);
}
&.maybe span {
background: var(--theme-c-maybe);
border: 1px solid var(--theme-c-maybe-dark);
}
&.no span {
background: var(--theme-c-no);
border: 1px solid var(--theme-c-no-dark);
}
&.category {
flex: 0 0 3rem;
}
&.receive {
flex: 0 0 3.125rem;
span {
background: var(--theme-c-receive);
border: 1px solid var(--theme-c-receive);
}
}
&.give {
flex: 0 0 2.125rem;
span {
background: var(--theme-c-give);
border: 1px solid var(--theme-c-give);
}
}
}
}
</style>

View file

@ -0,0 +1,127 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { Ratings, Role } from '@/interfaces'
import type { Kink } from '@/interfaces'
import FilterButton from '@/components/FilterButton.vue'
import FilterListTag from '@/components/FilterListTag.vue'
interface Props {
data: Kink[]
}
const props = defineProps<Props>()
const filterOptions = ref<number[]>([])
const filteredItems = computed(() =>
[...props.data]
.sort((a, b) => a.rating - b.rating)
.filter((kink) => filterOptions.value.some((filterNum) => kink.rating === filterNum))
)
</script>
<template>
<div class="filter-list">
<div class="filter-list__filters">
<FilterButton name="rating" :value="Ratings.Love" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.Yes" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.Maybe" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.No" v-model="filterOptions" />
</div>
<div class="filter-list__list-container">
<template v-if="filterOptions.length > 0">
<ul class="filter-list__list">
<li v-for="(item, idx) in filteredItems" :key="idx" class="filter-list__item">
<FilterListTag
v-if="filterOptions.length > 1"
class="category"
:type="Ratings[item.rating]"
/>
<span class="filter-list__item-name">
<span>{{ item.name }}</span>
</span>
<FilterListTag
v-if="((item.role ?? 0) & Role.Receive) === Role.Receive"
:type="Role[Role.Receive]"
/>
<FilterListTag
v-if="((item.role ?? 0) & Role.Give) === Role.Give"
:type="Role[Role.Give]"
/>
</li>
</ul>
</template>
<template v-else>
<p class="filter-list__intro-msg">Select one of the categories above</p>
</template>
</div>
</div>
</template>
<style lang="scss">
.filter-list {
background: var(--quickfacts-background);
border-radius: 1rem;
box-shadow: var(--container-box-shadow);
overflow: hidden;
&__options {
display: flex;
gap: 1rem;
margin: 0;
padding: 0;
list-style: none;
}
&__filters {
display: flex;
gap: 0.75rem;
border-collapse: collapse;
padding: 0.5rem 0.75rem;
}
&__intro-msg {
font-size: 2rem;
font-weight: bold;
font-style: italic;
text-align: center;
hyphens: none;
}
&__list-container {
border-top: 0.125rem solid var(--color-quickfacts-border);
border-collapse: collapse;
}
&__list {
max-height: 30rem;
margin: 0;
padding: 0;
overflow: scroll;
}
&__item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.875rem;
&:hover {
background: rgba(#000, 0.3);
}
}
&__item-name {
flex: 1 0 0;
line-height: 2;
}
}
</style>

View file

@ -1,20 +1,18 @@
<script setup lang="ts">
import { ref } from "vue";
interface Props {
cols?: number
}
const isExpanded = ref(false);
const toggle = (): void => {
isExpanded.value = !isExpanded.value;
};
defineProps<Props>()
</script>
<template>
<div class="quickfacts" :class="{ open: isExpanded }">
<h3 class="quickfacts__head" @click.prevent="toggle">Quickfacts</h3>
<div class="quickfacts__list">
<details class="quickfacts">
<summary class="quickfacts__head">Quickfacts</summary>
<div class="quickfacts__list" :class="[`cols-${cols}`]">
<slot></slot>
</div>
</div>
</details>
</template>
<style lang="scss">
@ -29,11 +27,12 @@ const toggle = (): void => {
box-shadow: var(--container-box-shadow);
overflow: hidden;
transition: 0.3s all ease-in-out;
&:before {
display: block;
content: "";
content: '';
position: absolute;
top: 1.375rem;
right: 1.375rem;
@ -48,31 +47,39 @@ const toggle = (): void => {
}
}
&.open:before {
&[open]:before {
transform: rotate(0deg);
}
&.open & {
&__list {
max-height: 25rem;
border-top: 0.125rem solid var(--color-quickfacts-border);
padding: 1.5rem;
}
}
&__head {
font-family: var(--font-family-headings);
font-size: 1.125rem;
list-style: none;
margin: 0;
border: 0;
padding: 0.75rem 1.5rem;
transition: 0.3s all ease-in-out;
cursor: pointer;
&::-webkit-details-marker {
display: none;
}
}
&__list {
max-height: 0rem;
padding: 0 1.5rem;
transition: 0.3s all ease-in-out;
border-top: 0.125rem solid var(--color-quickfacts-border);
padding: 1.5rem;
&.cols-2 ul {
columns: var(--quickfacts-cols-double);
}
&.cols-3 ul {
columns: var(--quickfacts-cols-triple);
}
&.cols-4 ul {
columns: var(--quickfacts-cols-quadruple);
}
ul {
margin: 0;

View file

@ -1,14 +1,21 @@
<script setup lang="ts">
interface Props {
href?: string;
download?: boolean | any;
positive?: boolean
negative?: boolean
href?: string
download?: boolean | any
}
defineProps<Props>();
defineProps<Props>()
</script>
<template>
<a class="btn" :href="href" :[download]="download">
<a
class="btn"
:class="{ positive: positive, negative: negative }"
:href="href"
:[download]="download"
>
<slot></slot>
</a>
</template>

View file

@ -1,32 +1,33 @@
<script setup lang="ts">
import { inject } from "vue";
import { nsfwKey, showModalKey } from "@/keys";
import RefToggle from "@/components/RefToggle.vue";
import { inject } from 'vue'
import { nsfwKey, showModalKey } from '@/keys'
import RefToggle from '@/components/RefToggle.vue'
interface Props {
polaroidBorder?: boolean;
dropshadow?: boolean;
nsfw?: boolean;
id: string;
cornerText?: boolean
polaroidBorder?: boolean
dropshadow?: boolean
nsfw?: boolean
id: string
}
const isNsfw = inject<boolean>(nsfwKey, false);
const showModal = inject<Function>(showModalKey, Function);
const isNsfw = inject<boolean>(nsfwKey, false)
const showModal = inject<Function>(showModalKey, Function)
defineProps<Props>();
defineProps<Props>()
</script>
<template>
<figure class="figure">
<div
class="figure__border"
:class="{ 'figure__border--polaroid': polaroidBorder }"
:class="{
'figure__border--polaroid': polaroidBorder,
'figure__border--cornertext': cornerText
}"
>
<template v-if="!nsfw || isNsfw">
<div
class="figure__image"
:class="{ 'figure__image--dropshadow': dropshadow }"
>
<div class="figure__image" :class="{ 'figure__image--dropshadow': dropshadow }">
<slot name="img"></slot>
</div>
</template>
@ -54,18 +55,14 @@ defineProps<Props>();
</div>
</template>
<figcaption class="figure__meta">
<template v-if="!nsfw || isNsfw">
<figcaption class="figure__meta">
<div class="caption">
<slot name="caption"></slot>
</div>
<div class="copyright">© <slot name="copyright"></slot></div>
</template>
<template v-else>
<p>😳 2 hot 4 u 🍆</p>
</template>
</figcaption>
</template>
</div>
</figure>
</template>
@ -79,8 +76,7 @@ defineProps<Props>();
text-align: center;
margin: 1em auto;
padding: 0 var(--container-spacing-right-safe) 0
var(--container-spacing-left-safe);
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
&__border {
display: flex;
@ -100,8 +96,42 @@ defineProps<Props>();
}
}
&__border--cornertext {
position: relative;
}
&__border--cornertext img,
&__border--cornertext &__cencor {
margin: 1rem 0;
border-radius: 1rem;
filter: drop-shadow(0 0 0.625rem black);
}
&__border--cornertext &__meta {
position: absolute;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
font-size: 0.75rem;
margin: 0 0 1.35rem 0;
border-radius: 1em 0 1rem 0;
padding: 0.25rem 0.75rem;
.caption,
.copyright {
display: inline;
}
.caption {
margin: 0 0.125rem 0 0;
}
}
&__border--polaroid &__meta {
font-family: "Permanent Marker", fantasy;
font-family: 'Permanent Marker', fantasy;
color: var(--color-figure-polaroid-text);
max-width: 35rem;

View file

@ -1,76 +1,68 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { debounce } from "@/helpers";
import { ref, onMounted } from 'vue'
import { debounce } from '@/helpers'
const activeImage = ref(0);
const images = ref<Element[]>([]);
const element = document.createElement("div");
const galleryViewport = ref<HTMLElement>(element);
const galleryItemWidth = ref<number>(1);
const activeImage = ref(0)
const images = ref<Element[]>([])
const element = document.createElement('div')
const galleryViewport = ref<HTMLElement>(element)
const galleryItemWidth = ref<number>(1)
const resizeObserverCallback = (entries: ResizeObserverEntry[]): void => {
for (const entry of entries) {
galleryItemWidth.value = entry.contentRect.width;
galleryItemWidth.value = entry.contentRect.width
}
}
};
const resizeObserver = new ResizeObserver(
debounce(resizeObserverCallback, 1000)
);
const resizeObserver = new ResizeObserver(debounce(resizeObserverCallback, 1000))
const setActiveImage = (index: number): void => {
activeImage.value = index;
activeImage.value = index
galleryViewport.value.scrollTo({
left: galleryItemWidth.value * index,
behavior: "smooth",
});
};
behavior: 'smooth'
})
}
const getActiveImage = (gallery: HTMLElement, itemWidth: number): number => {
return gallery.scrollLeft / itemWidth;
};
return gallery.scrollLeft / itemWidth
}
const prev = (): void => {
if (activeImage.value > 0) {
galleryViewport.value.scrollBy({
left: galleryItemWidth.value * -1,
behavior: "smooth",
});
behavior: 'smooth'
})
}
}
};
const next = (): void => {
if (activeImage.value < images.value.length - 1) {
galleryViewport.value.scrollBy({
left: galleryItemWidth.value,
behavior: "smooth",
});
behavior: 'smooth'
})
}
}
};
const onScroll = (): void => {
const newImg = getActiveImage(galleryViewport.value, galleryItemWidth.value);
setActiveImage(newImg);
};
const newImg = Math.floor(getActiveImage(galleryViewport.value, galleryItemWidth.value))
setActiveImage(newImg)
}
onMounted(() => {
resizeObserver.observe(galleryViewport.value);
images.value = Array.from(galleryViewport.value.children);
galleryItemWidth.value =
galleryViewport.value.scrollWidth / images.value.length;
galleryViewport.value.addEventListener("scroll", debounce(onScroll, 100));
});
resizeObserver.observe(galleryViewport.value)
images.value = Array.from(galleryViewport.value.children)
galleryItemWidth.value = galleryViewport.value.scrollWidth / images.value.length
galleryViewport.value.addEventListener('scroll', debounce(onScroll, 500))
})
</script>
<template>
<div class="gallery">
<div class="gallery__images">
<a
href="#"
class="gallery__prev"
@click.prevent="prev()"
v-show="activeImage > 0"
></a>
<a href="#" class="gallery__prev" @click.prevent="prev()" v-show="activeImage > 0"></a>
<a
href="#"
class="gallery__next"

View file

@ -1,100 +1,98 @@
<script setup lang="ts">
import { inject } from "vue";
import { modalResultKey } from "@/keys";
import Button from "@/components/RefButton.vue";
import { ref } from 'vue'
const modalResult = inject(modalResultKey, Function);
interface Props {
id: string
}
defineProps<Props>()
const modal = ref<HTMLDialogElement>()
const showModal = () => {
modal.value?.showModal()
document.body.inert = true
document.body.classList.add('scroll-lock')
}
const close = () => {
modal.value?.close()
document.body.inert = false
document.body.classList.remove('scroll-lock')
}
defineExpose({ showModal, close })
</script>
<template>
<div class="modal">
<div class="modal__background"></div>
<dialog :id="id" class="modal" ref="modal">
<form method="dialog" class="modal__content">
<h2 class="modal__heading">
<slot name="heading"></slot>
</h2>
<div class="modal__message">
<div>
<h2><slot name="heading"></slot></h2>
<p><slot name="message"></slot></p>
<slot name="message"></slot>
</div>
<div class="modal__buttons">
<Button
class="modal__button positive"
@click.prevent="modalResult(true)"
>
<slot name="yes"></slot>
</Button>
<Button
class="modal__button negative"
@click.prevent="modalResult(false)"
>
<slot name="no"></slot>
</Button>
</div>
</div>
</div>
<slot name="buttons"></slot>
</div>
</form>
</dialog>
</template>
<style lang="scss">
.modal {
display: flex;
flex-flow: row nowrap;
justify-content: center;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
text-align: center;
padding: 2rem;
backdrop-filter: blur(1rem);
background-color: rgba(0, 0, 0, 0.5);
overflow: auto;
z-index: 9001;
&__background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
&__message {
flex: 0 1 30rem;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-content: center;
background: var(--modal-background);
color: var(--color-text);
width: var(--modal-width);
margin: auto;
border: 0.25rem solid var(--color-modal-border);
border-radius: 1rem;
padding: 1rem;
z-index: 9002;
overflow: auto;
animation: fade-in 1s;
&::backdrop {
backdrop-filter: blur(1rem);
background-color: rgba(0, 0, 0, 0.5);
animation: fade-in 1s;
}
&__content {
display: flex;
flex-flow: column nowrap;
justify-content: center;
text-align: center;
gap: 1.5rem;
> * {
flex: 0 1 100%;
flex: 1 1 auto;
}
}
&__buttons {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
align-items: center;
&__heading {
margin: 1.875rem 0 0 0;
}
&__button {
flex: 0 1 100%;
margin: 0.75em 0;
&__message {
flex: 1 1 100%;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
</style>

View file

@ -1,23 +1,27 @@
<script setup lang="ts">
import { computed } from "vue";
import { computed } from 'vue'
interface Props {
modelValue: boolean;
id: string;
name?: string;
modelValue: boolean
id: string
name?: string
}
const props = defineProps<Props>();
const emit = defineEmits(["update:modelValue"]);
interface Emits {
(e: 'update:modelValue', value: boolean): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const checked = computed({
get() {
return props.modelValue;
return props.modelValue
},
set(value) {
emit("update:modelValue", value);
},
});
emit('update:modelValue', value)
}
})
</script>
<template>
@ -37,9 +41,8 @@ const checked = computed({
<style lang="scss">
.toggle {
font-family: "apple color emoji", "noto color emoji", "segoe ui emoji",
"android emoji", "emojisymbols", "emojione mozilla", "twemoji mozilla",
"segoe ui symbol";
font-family: 'apple color emoji', 'noto color emoji', 'segoe ui emoji', 'android emoji',
'emojisymbols', 'emojione mozilla', 'twemoji mozilla', 'segoe ui symbol';
padding: 0.5em;
@ -84,7 +87,7 @@ const checked = computed({
&:before,
&:after {
content: "";
content: '';
position: absolute;
left: 0;
height: 1.1em;

View file

@ -14,6 +14,7 @@
text-align: center;
p {
text-align: center;
margin: 0;
+ p {

View file

@ -1,16 +1,12 @@
<script setup lang="ts">
import { RouterLink } from "vue-router";
import router from "@/router";
import { RouterLink } from 'vue-router'
import router from '@/router'
</script>
<template>
<nav class="nav">
<ul class="nav__list">
<li
class="nav__item"
v-for="(route, idx) in router.options.routes"
:key="idx"
>
<li class="nav__item" v-for="(route, idx) in router.options.routes" :key="idx">
<RouterLink class="nav__link" :to="route.path">
{{ route.name }}
</RouterLink>
@ -75,7 +71,7 @@ import router from "@/router";
&:before,
&:after {
content: "";
content: '';
position: absolute;
bottom: 0;

View file

@ -5,21 +5,21 @@
<picture>
<source
srcset="
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&avif&quality=75&withoutEnlargement&srcset
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 280px, (min-width: 80em) 240px, (min-width: 35em) 200px, 180px"
type="image/avif"
/>
<source
srcset="
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&webp&quality=100&withoutEnlargement&srcset
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 280px, (min-width: 80em) 240px, (min-width: 35em) 200px, 180px"
type="image/webp"
/>
<img
srcset="
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&png&withoutEnlargement&srcset
@/assets/sebin-smug-icon.png?w=180;200;240;280;350;400;480;0&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 280px, (min-width: 80em) 240px, (min-width: 35em) 200px, 180px"
alt="Sebin Avatar"
@ -68,7 +68,7 @@
&__mainline,
&__subline {
font-family: "Exo", sans-serif;
font-family: 'Exo', sans-serif;
text-align: center;
font-style: italic;
margin: 0;

View file

@ -1,76 +1,67 @@
const debounce = (fn: Function, delay: number = 300): any => {
let timer = 0;
let timer = 0
const debounced = (...args: any[]): void => {
if (!args) args = [];
clearTimeout(timer);
if (!args) args = []
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(fn, args);
}, delay);
};
fn.apply(fn, args)
}, delay)
}
return debounced;
};
return debounced
}
const getClientLocale = (): string => {
return navigator.languages.length > 0 ? navigator.languages[0] : "en-US";
};
return navigator.languages.length > 0 ? navigator.languages[0] : 'en-US'
}
const getAge = (dateOfBirth: Date): number => {
const today = new Date();
const today = new Date()
const thisYear = today.getFullYear();
const thisMonth = today.getMonth();
const thisDay = today.getDate();
const thisYear = today.getFullYear()
const thisMonth = today.getMonth()
const thisDay = today.getDate()
const dobYear = dateOfBirth.getFullYear();
const dobMonth = dateOfBirth.getMonth();
const dobDay = dateOfBirth.getDate();
const dobYear = dateOfBirth.getFullYear()
const dobMonth = dateOfBirth.getMonth()
const dobDay = dateOfBirth.getDate()
let age = thisYear - dobYear;
let age = thisYear - dobYear
if (thisMonth < dobMonth) age--;
if (thisMonth === dobMonth && thisDay < dobDay) age--;
if (thisMonth < dobMonth) age--
if (thisMonth === dobMonth && thisDay < dobDay) age--
return age;
};
return age
}
const toImperial = (cm: number): string => {
const realFeet = (cm * 0.3937) / 12;
const feet = Math.floor(realFeet);
const inches = Math.round((realFeet - feet) * 12);
const realFeet = (cm * 0.3937) / 12
const feet = Math.floor(realFeet)
const inches = Math.round((realFeet - feet) * 12)
return `${feet}'${inches}"`;
};
return `${feet}'${inches}"`
}
const toInch = (cm: number): string => {
return `${Math.round(cm / 2.45)} in`;
};
return `${Math.round(cm / 2.45)} in`
}
const toLbs = (kg: number): number => {
const nearExact = kg / 0.45359237;
const lbs = Math.floor(nearExact);
const nearExact = kg / 0.45359237
const lbs = Math.floor(nearExact)
return lbs;
};
return lbs
}
const toFahrenheit = (celsius: number): number => {
return celsius * 1.8 + 32;
};
return celsius * 1.8 + 32
}
const dateFormat = new Intl.DateTimeFormat(getClientLocale(), {
year: "numeric",
month: "long",
day: "2-digit",
});
year: 'numeric',
month: 'long',
day: '2-digit'
})
export {
debounce,
getClientLocale,
getAge,
toImperial,
toInch,
toLbs,
toFahrenheit,
dateFormat,
};
export { debounce, getClientLocale, getAge, toImperial, toInch, toLbs, toFahrenheit, dateFormat }

View file

@ -1,12 +1,25 @@
interface ColorDict {
name: string;
value: string;
name: string
value: string
}
interface Kink {
name: string;
receive: boolean;
give: boolean;
name: string
rating: number
role?: Role
}
export type { ColorDict, Kink };
export enum Ratings {
Love,
Yes,
Maybe,
No
}
export enum Role {
Give = 1,
Receive = 2,
Both = Give | Receive
}
export type { ColorDict, Kink }

View file

@ -1,6 +1,5 @@
import type { InjectionKey, Ref } from "vue";
import type { InjectionKey, Ref } from 'vue'
export const isWarnKey: InjectionKey<Ref<boolean>> = Symbol("isWarnKey");
export const nsfwKey: InjectionKey<Ref<boolean>> = Symbol("nsfwKey");
export const showModalKey: InjectionKey<Function> = Symbol("showModalKey");
export const modalResultKey: InjectionKey<Function> = Symbol("modalResultKey");
export const nsfwKey: InjectionKey<Ref<boolean>> = Symbol('nsfwKey')
export const showModalKey: InjectionKey<Function> = Symbol('showModalKey')
export const modalResultKey: InjectionKey<Function> = Symbol('modalResultKey')

View file

@ -1,12 +1,12 @@
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import "normalize.css";
import "@/scss/main.scss";
import 'normalize.css'
import '@/scss/main.scss'
const app = createApp(App);
const app = createApp(App)
app.use(router);
app.use(router)
app.mount("body");
app.mount('body')

View file

@ -1,43 +1,43 @@
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "@/views/HomeView.vue";
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
scrollBehavior() {
return { top: 0, behavior: "smooth" };
return { top: 0, behavior: 'smooth' }
},
routes: [
{
path: "/",
name: "home",
component: HomeView,
path: '/',
name: 'home',
component: HomeView
},
{
path: "/general",
name: "general",
component: () => import("@/views/GeneralView.vue"),
path: '/general',
name: 'general',
component: () => import('@/views/GeneralView.vue')
},
{
path: "/anatomy",
name: "anatomy",
component: () => import("@/views/AnatomyView.vue"),
path: '/anatomy',
name: 'anatomy',
component: () => import('@/views/AnatomyView.vue')
},
{
path: "/clothing",
name: "clothing",
component: () => import("@/views/ClothingView.vue"),
path: '/clothing',
name: 'clothing',
component: () => import('@/views/ClothingView.vue')
},
{
path: "/abilities",
name: "abilities",
component: () => import("@/views/AbilitiesView.vue"),
path: '/abilities',
name: 'abilities',
component: () => import('@/views/AbilitiesView.vue')
},
{
path: "/overdrive",
name: "overdrive",
component: () => import("@/views/OverdriveView.vue"),
},
],
});
path: '/overdrive',
name: 'overdrive',
component: () => import('@/views/OverdriveView.vue')
}
]
})
export default router;
export default router

View file

@ -1,4 +1,4 @@
@import "fontfaces";
@import 'fontfaces';
/* theme colors */
:root {
@ -28,6 +28,18 @@
--theme-c-white: #ffffff;
--theme-c-black: #000000;
--theme-c-love: #e00f60;
--theme-c-yes: #2faf2a;
--theme-c-maybe: #daa520;
--theme-c-no: #8b0000;
--theme-c-receive: #448dc9;
--theme-c-give: #4a7d91;
--theme-c-love-dark: #9b0a41;
--theme-c-yes-dark: #1f771c;
--theme-c-maybe-dark: #997416;
--theme-c-no-dark: #530000;
--theme-c-dull-red-translucent: #c64c35bf;
--theme-c-indian-yellow-translucent: #eda958bf;
--theme-c-dusky-blue-translucent: #4b608fbf;
@ -100,8 +112,8 @@
/* general purpose variables */
:root {
--font-family-copy: "Dosis", sans-serif;
--font-family-headings: "Zilla Slab", sans-serif;
--font-family-copy: 'Dosis', sans-serif;
--font-family-headings: 'Zilla Slab', sans-serif;
--font-size: 18px;
--font-size-h1: 3rem;
@ -128,11 +140,17 @@
--page-background: var(--theme-b-page-background-light);
--header-background: var(--theme-b-navigation-background-light);
--header-margin: 1rem var(--container-spacing-right-safe) 1rem
var(--container-spacing-left-safe);
--header-margin: 1rem var(--container-spacing-right-safe) 1rem var(--container-spacing-left-safe);
--navigation-justify-content: flex-start;
--quickfacts-background: var(--theme-b-page-background-light);
--quickfacts-cols-double: auto;
--quickfacts-cols-triple: auto;
--quickfacts-cols-quadruple: auto;
--modal-background: var(--theme-b-modal-background-light);
--modal-width: 100%;
--welcome-header-headings-flex-basis: 100%;
--welcome-header-headings-margin: 1.5rem 0 0 0;
--welcome-header-mainline-font-size: 2rem;
@ -165,8 +183,7 @@
--social-links-flex-flow: row wrap;
--social-links-flex: 1 1 50%;
--footer-padding: var(--container-spacing-top-safe) 0
var(--container-spacing-bottom-safe) 0;
--footer-padding: var(--container-spacing-top-safe) 0 var(--container-spacing-bottom-safe) 0;
}
/* semantic color variables for this project */
@ -207,18 +224,25 @@
--font-size-h2: 2.25rem;
--font-size-h3: 1.5rem;
--navigation-justify-content: center;
--modal-width: 30rem;
--welcome-header-headings-flex-basis: 23rem;
--welcome-header-headings-margin: 0;
--welcome-header-mainline-font-size: var(--font-size-h1);
--quickfacts-cols-double: 2 auto;
--quickfacts-cols-triple: 3 auto;
--quickfacts-cols-quadruple: 4 auto;
--section-max-width: 34rem;
--button-group-flex: 0 0 auto;
--table-cell-padding: 0.5rem 1rem;
--figure-cencor-width: 20rem;
--figure-cencor-height: 20rem;
--figure-cencor-width: max(50vw, 20rem);
--figure-cencor-height: max(50vh, 30rem);
--gallery-size: 1.5rem;
--gallery-arrow-position: 2rem;

View file

@ -97,6 +97,8 @@ h3 {
p {
margin: 1rem 0;
text-align: justify;
hyphens: auto;
}
a {
@ -111,35 +113,8 @@ blockquote {
padding: 1rem;
}
ul {
margin: 1rem 0;
&.col-2 {
columns: 2 auto;
}
&.col-3 {
columns: 3 auto;
}
&.col-4 {
columns: 4 auto;
}
&.social {
display: flex;
flex-flow: var(--social-links-flex-flow);
justify-content: space-evenly;
margin: 1rem 0;
padding: 0;
list-style: none;
li {
flex: var(--social-links-flex);
padding: 0.25rem;
text-align: center;
.social {
> * {
&:before {
margin: 0 0.375rem 0 0;
}
@ -161,7 +136,6 @@ ul {
}
}
}
}
table {
border-collapse: collapse;

View file

@ -1,51 +1,82 @@
export const firstName = "Sebin",
middleName = "Antario",
lastName = "Nyshkim",
dateOfBirth = new Date("1993-10-17"),
gender = "male ♂️",
orientation = "gay",
position = "vers, prefers top",
import { Ratings, Role } from '@/interfaces'
export const firstName = 'Sebin',
middleName = 'Antario',
lastName = 'Nyshkim',
dateOfBirth = new Date('1993-10-17'),
gender = 'male ♂️',
orientation = 'gay',
position = 'vers, prefers top',
height = 210, // cm
weight = 124, // kg
tailLength = 104, // cm
wingspan = 417, // cm
colors = {
hairPrimary: "#4b608f",
hairSecondary: "#6684c0",
eyes: "#31c215",
scalesPrimary: "#c64c35",
scalesSecondary: "#eda958",
eyebrows: "#eda958",
tailspikes: "#7f4539",
horns: "#413a3a",
claws: "#413a3a",
nipples: "#413a3a",
penis: "#413a3a",
hairPrimary: '#4b608f',
hairSecondary: '#6684c0',
eyes: '#31c215',
scalesPrimary: '#c64c35',
scalesSecondary: '#eda958',
eyebrows: '#eda958',
tailspikes: '#7f4539',
horns: '#413a3a',
claws: '#413a3a',
nipples: '#413a3a',
penis: '#413a3a'
},
hobbies = ["working out", "travels", "camping", "video games", "tech"],
hobbies = ['working out', 'travels', 'camping', 'video games', 'tech'],
penis = {
shape: "humanoid",
type: "grower",
special: "ridged, no foreskin",
shape: 'humanoid',
type: 'grower',
special: 'ridged, no foreskin',
size: 20, // cm
girth: 5, // cm
girth: 5 // cm
},
kinks = [
{ name: "Oral", receive: true, give: true },
{ name: "Anal", receive: true, give: true },
{ name: "Facial", receive: true, give: true },
{ name: "Creampie", receive: true, give: true },
{ name: "Bukkake", receive: true, give: true },
{ name: "Biting", receive: true, give: true },
{ name: "Nipple Play", receive: true, give: true },
{ name: "Rough", receive: true, give: true },
{ name: "Toys", receive: true, give: true },
{ name: "Frotting", receive: true, give: true },
{ name: "Muscle Worship", receive: true, give: true },
{ name: "Filled Condoms", receive: true, give: true },
{ name: "Growth/Macro", receive: true, give: true },
{ name: "Size Difference", receive: true, give: true },
{ name: "Underwear", receive: true, give: true },
{ name: "Chubbies", receive: true, give: true },
];
{ name: 'Absorption', rating: Ratings.No },
{ name: 'Anal', rating: Ratings.Love, role: Role.Both },
{ name: 'Auto-Fellatio', rating: Ratings.Yes },
{ name: 'Biting', rating: Ratings.Yes, role: Role.Both },
{ name: 'Bukkake', rating: Ratings.Yes, role: Role.Give },
{ name: 'Chastity', rating: Ratings.No },
{ name: 'Chubby', rating: Ratings.Maybe },
{ name: 'Clothed Sex', rating: Ratings.Yes },
{ name: 'Cock Slapping', rating: Ratings.Yes, role: Role.Give },
{ name: 'Coiling', rating: Ratings.Maybe, role: Role.Give },
{ name: 'Competition', rating: Ratings.Maybe, role: Role.Give },
{ name: 'Creampie', rating: Ratings.Yes, role: Role.Give },
{ name: 'Crushing (Living/Objects)', rating: Ratings.No },
{ name: 'Cum From Mouth/Nose', rating: Ratings.Yes, role: Role.Give },
{ name: 'Cum Inflation (Light/Medium)', rating: Ratings.Yes },
{ name: 'Deep-throat', rating: Ratings.Yes, role: Role.Receive },
{ name: 'Dirty Talking', rating: Ratings.Yes },
{ name: 'Excessive Cum', rating: Ratings.Love, role: Role.Both },
{ name: 'Face-Fucking', rating: Ratings.Yes, role: Role.Give },
{ name: 'Facial', rating: Ratings.Yes, role: Role.Give },
{ name: 'Feet', rating: Ratings.No },
{ name: 'Filled Condoms', rating: Ratings.Yes },
{ name: 'Foreplay', rating: Ratings.Yes, role: Role.Both },
{ name: 'Frotting', rating: Ratings.Yes },
{ name: 'Gangbangs', rating: Ratings.Yes },
{ name: 'Growth', rating: Ratings.Love, role: Role.Receive },
{ name: 'Handjobs', rating: Ratings.Yes, role: Role.Both },
{ name: 'Hotdogging', rating: Ratings.Yes, role: Role.Give },
{ name: 'Kissing', rating: Ratings.Yes, role: Role.Both },
{ name: 'Macro', rating: Ratings.Love },
{ name: 'Milking', rating: Ratings.Yes },
{ name: 'Muscle Growth', rating: Ratings.Love, role: Role.Both },
{ name: 'Muscle Worship', rating: Ratings.Yes, role: Role.Both },
{ name: 'Nipple Play', rating: Ratings.Yes, role: Role.Both },
{ name: 'Oral', rating: Ratings.Love, role: Role.Both },
{ name: 'Rough', rating: Ratings.Yes, role: Role.Both },
{ name: 'Sheath Play', rating: Ratings.Yes, role: Role.Both },
{ name: 'Size Difference', rating: Ratings.Love },
{ name: 'Slime/Goo Characters', rating: Ratings.Yes },
{ name: 'Spanking', rating: Ratings.Maybe, role: Role.Give },
{ name: 'Tailsex', rating: Ratings.Yes, role: Role.Both },
{ name: 'Toys', rating: Ratings.Yes, role: Role.Both },
{ name: 'Underwear', rating: Ratings.Love },
{ name: 'Unsanitary', rating: Ratings.No },
{ name: 'Verbal Abuse', rating: Ratings.Maybe, role: Role.Give },
{ name: 'Vore', rating: Ratings.No }
]

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import AttackItem from "@/components/AttackItem.vue";
import AttackList from "@/components/AttackList.vue";
import AttackItem from '@/components/AttackItem.vue'
import AttackList from '@/components/AttackList.vue'
</script>
<template>
@ -8,8 +8,8 @@ import AttackList from "@/components/AttackList.vue";
<h1>{{ $route.name }}</h1>
<p>
Since Sebin is a fire dragon there's a myriad of abilities he has at his
disposal to defend himself.
Since Sebin is a fire dragon there's a myriad of abilities he has at his disposal to defend
himself.
</p>
</section>
@ -24,21 +24,21 @@ import AttackList from "@/components/AttackList.vue";
<picture>
<source
srcset="
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;960;1920;1330;1680&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;960;1920;1330;1680&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&png&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-fire_breath-hires.png?w=640;960;1920;1330;1680&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
alt="Sebin Fire Breath"
@ -48,12 +48,10 @@ import AttackList from "@/components/AttackList.vue";
</template>
<template #name>Fire Breath</template>
<template #desc>
Like most fire dragons, Sebin can breathe fire. In order to do this, he
takes a deep breath to enrich the oxygen in his lungs with gases, which,
together with special glands in his mouth, produce a combustible
mixture. The resulting jet of fire, reaching several hundred degrees
Celsius, spreads out on its way to its target, scorching everything in
its path.
Like most fire dragons, Sebin can breathe fire. In order to do this, he takes a deep breath
to enrich the oxygen in his lungs with gases, which, together with special glands in his
mouth, produce a combustible mixture. The resulting jet of fire, reaching several hundred
degrees Celsius, spreads out on its way to its target, scorching everything in its path.
</template>
</AttackItem>
@ -63,21 +61,21 @@ import AttackList from "@/components/AttackList.vue";
<picture>
<source
srcset="
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;960;1920;1330;1680&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;960;1920;1330;1680&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&png&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-flame_toss-hires.png?w=640;960;1920;1330;1680&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
alt="Sebin Fire Breath"
@ -87,11 +85,10 @@ import AttackList from "@/components/AttackList.vue";
</template>
<template #name>Flame Toss</template>
<template #desc>
By spitting fire into his hands, Sebin can form it into a ball and use
it as a projectile. His scales are fireproof and can withstand the high
temperatures. Due to their high concentration, the projectiles explode
upon impact. By combining two fireballs the explosion radius increases
dramatically.
By spitting fire into his hands, Sebin can form it into a ball and use it as a projectile.
His scales are fireproof and can withstand the high temperatures. Due to their high
concentration, the projectiles explode upon impact. By combining two fireballs the explosion
radius increases dramatically.
</template>
</AttackItem>
@ -101,21 +98,21 @@ import AttackList from "@/components/AttackList.vue";
<picture>
<source
srcset="
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;960;1920;1330;1680&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;960;1920;1330;1680&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&png&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-kindled_fist-hires.png?w=640;960;1920;1330;1680&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
alt="Sebin Kindled Fist"
@ -125,10 +122,9 @@ import AttackList from "@/components/AttackList.vue";
</template>
<template #name>Kindled Fist</template>
<template #desc>
Apart from throwing projectiles, Sebin can also use the fireballs to
wrap his fists in fire. This allows him to inflict severe burns on his
opponent with each blow. In addition, he can release the fire from his
fists with aimed blows and hurl it at his opponents.
Apart from throwing projectiles, Sebin can also use the fireballs to wrap his fists in fire.
This allows him to inflict severe burns on his opponent with each blow. In addition, he can
release the fire from his fists with aimed blows and hurl it at his opponents.
</template>
</AttackItem>
@ -138,21 +134,21 @@ import AttackList from "@/components/AttackList.vue";
<picture>
<source
srcset="
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;960;1920;1330;1680&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;960;1920;1330;1680&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;400;480;560;1280;800;960;1120;1920;1200;1330;1680&png&withoutEnlargement&srcset
@/assets/refs/attacks/sebin-burning_twister-hires.png?w=640;960;1920;1330;1680&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 560px, (min-width: 80em) 480px, (min-width: 45em) 400px, 640px"
alt="Sebin Burning Twister"
@ -162,9 +158,8 @@ import AttackList from "@/components/AttackList.vue";
</template>
<template #name>Burning Twister</template>
<template #desc>
A technique used in aerial combat, Sebin uses his fire breath to engulf
his body in flames while spinning to become a fire tornado that singes
opponents.
A technique used in aerial combat, Sebin uses his fire breath to engulf his body in flames
while spinning to become a fire tornado that singes opponents.
</template>
</AttackItem>
</AttackList>

View file

@ -1,59 +1,42 @@
<script setup lang="ts">
import { inject } from "vue";
import { isWarnKey, nsfwKey, showModalKey } from "@/keys";
import type { ColorDict } from "@/interfaces";
import { tailLength, wingspan, penis, colors } from "@/sebin";
import { toImperial, toFahrenheit } from "@/helpers";
import RefToggle from "@/components/RefToggle.vue";
import RefModal from "@/components/RefModal.vue";
import RefGallery from "@/components/RefGallery.vue";
import RefFigure from "@/components/RefFigure.vue";
import ColorTable from "@/components/ColorTable.vue";
import DataTable from "@/components/DataTable.vue";
import QuickFacts from "@/components/QuickFacts.vue";
import { inject } from 'vue'
import { nsfwKey, showModalKey } from '@/keys'
import type { ColorDict } from '@/interfaces'
import { tailLength, wingspan, penis, colors } from '@/sebin'
import { toImperial, toFahrenheit } from '@/helpers'
import RefToggle from '@/components/RefToggle.vue'
import RefGallery from '@/components/RefGallery.vue'
import RefFigure from '@/components/RefFigure.vue'
import ColorTable from '@/components/ColorTable.vue'
import DataTable from '@/components/DataTable.vue'
import QuickFacts from '@/components/QuickFacts.vue'
const sebinColors: ColorDict[] = [
{ name: "Scales", value: colors.scalesPrimary },
{ name: "Chest, Wings (front)", value: colors.scalesSecondary },
{ name: "Hair", value: colors.hairPrimary },
{ name: "Hair Streaks (optional)", value: colors.hairSecondary },
{ name: "Eyes", value: colors.eyes },
{ name: "Facial Spikes", value: colors.eyebrows },
{ name: "Horns/Claws/Nipples", value: colors.horns },
{ name: "Tail Spikes", value: colors.tailspikes },
];
{ name: 'Scales', value: colors.scalesPrimary },
{ name: 'Chest, Wings (front)', value: colors.scalesSecondary },
{ name: 'Hair', value: colors.hairPrimary },
{ name: 'Hair Streaks (optional)', value: colors.hairSecondary },
{ name: 'Eyes', value: colors.eyes },
{ name: 'Facial Spikes', value: colors.eyebrows },
{ name: 'Horns/Claws/Nipples', value: colors.horns },
{ name: 'Tail Spikes', value: colors.tailspikes }
]
const sebinPenisHeadings = ["Key", "Value"];
const sebinPenisHeadings = ['Key', 'Value']
const sebinPenisData = [
["Shape", penis.shape],
["Type", penis.type],
["Special Traits", penis.special],
["Color", colors.penis],
["Length", `${penis.size} cm (${toImperial(penis.size)})`],
["Girth", `${penis.girth} cm (${toImperial(penis.girth)})`],
];
['Shape', penis.shape],
['Type', penis.type],
['Special Traits', penis.special],
['Color', colors.penis],
['Length', `${penis.size} cm (${toImperial(penis.size)})`],
['Girth', `${penis.girth} cm (${toImperial(penis.girth)})`]
]
const isNsfw = inject<boolean>(nsfwKey, false);
const isWarn = inject<boolean>(isWarnKey, false);
const showModal = inject<Function>(showModalKey, Function);
const isNsfw = inject<boolean>(nsfwKey, false)
const showModal = inject<Function>(showModalKey, Function)
</script>
<template>
<RefModal v-show="isWarn">
<template #heading>
<br />
Whoa, Nelly!
</template>
<template #message>
By enabling NSFW mode you confirm that you are of legal age to view adult
content.
</template>
<template #yes>Yes, show me the goods 👀</template>
<template #no>NO, STAHP 😱</template>
</RefModal>
<section>
<h1>{{ $route.name }}</h1>
</section>
@ -64,7 +47,7 @@ const showModal = inject<Function>(showModalKey, Function);
<picture v-if="isNsfw">
<source
srcset="
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -78,7 +61,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<source
srcset="
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -92,7 +75,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<img
srcset="
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&png&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-NSFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -109,7 +92,7 @@ const showModal = inject<Function>(showModalKey, Function);
<picture v-else>
<source
srcset="
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -123,7 +106,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<source
srcset="
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -137,7 +120,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<img
srcset="
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&png&withoutEnlargement&srcset
@/assets/refs/sebin-ref-body-SFW.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;2880;3240;3360&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -154,11 +137,7 @@ const showModal = inject<Function>(showModalKey, Function);
</template>
<template #caption>
<RefToggle
id="sebin-fullbody-ref"
v-model="isNsfw"
@click.prevent="showModal()"
>
<RefToggle id="sebin-fullbody-ref" v-model="isNsfw" @click.prevent="showModal()">
<template #off>😇</template>
<template #on>😈</template>
</RefToggle>
@ -174,32 +153,27 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<ColorTable :colors="sebinColors" />
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>Bipedal plantigrade</li>
<li>Red and yellow scales</li>
<li>Yellow scales under chin, torso, underside of tail</li>
<li>Athletic to body builder physique</li>
<li>Sharp, black claws on fingers and toes</li>
<li>Brown blunt spikes running over back and top-side of tail</li>
<li>
Tail about {{ tailLength / 100 }} meter ({{ toImperial(tailLength) }})
in length
</li>
<li>Tail about {{ tailLength / 100 }} meter ({{ toImperial(tailLength) }}) in length</li>
</ul>
</QuickFacts>
<p>
As the offspring of a union between human and dragon, Sebin is a bipedal
plantigrade. The majority of his body is covered in red scales. A strip of
yellow scales runs from the underside of his jaw, extending down his chest
through his legs to the underside of the tip of his tail. The scales on
his chest are characterized by a special toughness to better protect vital
organs. He also has an athletic to muscular physique that he continuously
tends to keep in shape. Finger and toe tips are armed with sharp, black
claws, which serve him equally as tools and weapons. Brown spines run from
head to spine to tip of tail, though they are too blunt to pose a risk of
injury. His tail is about
As the offspring of a union between human and dragon, Sebin is a bipedal plantigrade. The
majority of his body is covered in red scales. A strip of yellow scales runs from the
underside of his jaw, extending down his chest through his legs to the underside of the tip of
his tail. The scales on his chest are characterized by a special toughness to better protect
vital organs. He also has an athletic to muscular physique that he continuously tends to keep
in shape. Finger and toe tips are armed with sharp, black claws, which serve him equally as
tools and weapons. Brown spines run from head to spine to tip of tail, though they are too
blunt to pose a risk of injury. His tail is about
{{ tailLength / 100 }} meters ({{ toImperial(tailLength) }}) in length.
</p>
</section>
@ -207,11 +181,9 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<h2>Wings</h2>
<QuickFacts>
<ul class="col-2">
<li>
Wingspan {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }})
</li>
<QuickFacts :cols="2">
<ul>
<li>Wingspan {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }})</li>
<li>Closed when on the ground</li>
<li>Function like a second pair of arms</li>
<li>Pointy talon on end of "hand"</li>
@ -219,17 +191,14 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
Sebin's wings have a span of about {{ wingspan / 100 }} meters ({{
toImperial(wingspan)
}}). They function very much like a second pair of arms: two
interconnected limbs that form a bendable arm, at the end of which sits a
hand-like structure, adorned with a talon in exchange for a thumb, with a
sturdy membrane stretched between its long fingers. On solid ground, he
keeps his wings closed so as not to accidentally bump into anything with
them. Sebin also pays a lot of attention to his wings when working out, so
that they can keep carrying him reliably through the air. Though, he only
travels short to medium distances through the air before he has to take a
rest - as long as the airspace in the area has been declared open for wing
Sebin's wings have a span of about {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }}).
They function very much like a second pair of arms: two interconnected limbs that form a
bendable arm, at the end of which sits a hand-like structure, adorned with a talon in exchange
for a thumb, with a sturdy membrane stretched between its long fingers. On solid ground, he
keeps his wings closed so as not to accidentally bump into anything with them. Sebin also pays
a lot of attention to his wings when working out, so that they can keep carrying him reliably
through the air. Though, he only travels short to medium distances through the air before he
has to take a rest - as long as the airspace in the area has been declared open for wing
bearers.
</p>
</section>
@ -244,7 +213,7 @@ const showModal = inject<Function>(showModalKey, Function);
<picture>
<source
srcset="
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -258,7 +227,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<source
srcset="
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -272,7 +241,7 @@ const showModal = inject<Function>(showModalKey, Function);
/>
<img
srcset="
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&png&withoutEnlargement&srcset
@/assets/refs/sebin-ref-expressions.png?w=480;720;1080;1280;1440;1600;1920;2240;960;2160;2560;0&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 2240px,
(min-width: 100em) 1920px,
@ -294,8 +263,8 @@ const showModal = inject<Function>(showModalKey, Function);
</RefFigure>
<section>
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>Round pupils, green iris</li>
<li>Yellow spikes for eyebrows</li>
<li>Yellow spikes on cheeks</li>
@ -308,69 +277,65 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
Despite what one might expect with reptilians, Sebin's pupils are rounded
instead of slit-shaped. Yellow spikes running above his eyelids serve as
eyebrows. These spikes are also found along his jaw bone. Two pointed,
slightly curved, black horns protrude from his head. He usually wears his
medium-length, blue hair loose. His long, pointed ears are very flexible,
allowing him to hear sounds around him without having to turn his head.
They are also used for non-verbal communication, to express emotions
through body language. His hearing perceives a wider range of frequencies,
making it superior to that of a human. His jaws are equipped with
razor-sharp teeth that effortlessly sink into anything he manages to bite,
be it nourishment or adversaries. Embedded between them lies his tongue,
which is typically pointed for reptilians. Glands in his throat produce a
mixture which he uses to spit fire, which can reach up to around 100 °C
({{ toFahrenheit(100) }} °F).
Despite what one might expect with reptilians, Sebin's pupils are rounded instead of
slit-shaped. Yellow spikes running above his eyelids serve as eyebrows. These spikes are also
found along his jaw bone. Two pointed, slightly curved, black horns protrude from his head. He
usually wears his medium-length, blue hair loose. His long, pointed ears are very flexible,
allowing him to hear sounds around him without having to turn his head. They are also used for
non-verbal communication, to express emotions through body language. His hearing perceives a
wider range of frequencies, making it superior to that of a human. His jaws are equipped with
razor-sharp teeth that effortlessly sink into anything he manages to bite, be it nourishment
or adversaries. Embedded between them lies his tongue, which is typically pointed for
reptilians. Glands in his throat produce a mixture which he uses to spit fire, which can reach
up to around 100 °C ({{ toFahrenheit(100) }} °F).
</p>
</section>
<section>
<h2>Upper Body</h2>
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>Strong upper body</li>
<li>Big pecs</li>
<li>Defined abs</li>
<li>Black nipples</li>
<li>
Any muscle mass from athletic to body builder is fine, with a
preference towards body builder
Any muscle mass from athletic to body builder is fine, with a preference towards body
builder
</li>
</ul>
</QuickFacts>
<p>
At the age of 17, Sebin gradually began to keep his body in shape on a
regular basis. His favorite exercises include weightlifting (with both
dumbbells and barbells), lat pulldown, leg press and cable curls. He works
out three days a week with one day off between training days, rotating the
body regions he trains each day.
At the age of 17, Sebin gradually began to keep his body in shape on a regular basis. His
favorite exercises include weightlifting (with both dumbbells and barbells), lat pulldown, leg
press and cable curls. He works out three days a week with one day off between training days,
rotating the body regions he trains each day.
</p>
</section>
<RefFigure id="sebin-upper-body-ref" polaroidBorder>
<RefFigure id="sebin-upper-body-ref" cornerText>
<!-- max 3617px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/upper-body-ref.png?w=400;500;600;700;800;1000;1200;1500;1800&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/upper-body-ref.png?w=400;700;1000;1200;1500;1800&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/upper-body-ref.png?w=400;500;600;700;800;1000;1200;1500;1800&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/upper-body-ref.png?w=400;700;1000;1200;1500;1800&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/upper-body-ref.png?w=400;500;600;700;800;1000;1200;1500;1800&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/upper-body-ref.png?w=400;700;1000;1200;1500;1800&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
alt="Sebin's upper body closeup"
@ -386,10 +351,9 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<p>
Sebin is very concerned with an even distribution of muscle mass, but pays
particular attention to his back, chest and arms. A strong chest with
strong arms helps to throw fire projectiles as far as possible. A strong
back guarantees a longer stay in the air.
Sebin is very concerned with an even distribution of muscle mass, but pays particular
attention to his back, chest and arms. A strong chest with strong arms helps to throw fire
projectiles as far as possible. A strong back guarantees a longer stay in the air.
</p>
</section>
@ -398,27 +362,27 @@ const showModal = inject<Function>(showModalKey, Function);
</section>
<RefGallery>
<RefFigure id="sebin-muscle-ref12" polaroidBorder>
<RefFigure id="sebin-muscle-ref12" cornerText>
<!-- max 1964px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref12.png?w=290;640;770;900;580;1280;1540;1800;870;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref12.png?w=290;770;900;580;1280;1540;1700;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 900px, (min-width: 80em) 770px, (min-width: 35em) 640px, 290px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref12.png?w=290;640;770;900;580;1280;1540;1800;870;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref12.png?w=290;770;900;580;1280;1540;1700;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 900px, (min-width: 80em) 770px, (min-width: 35em) 640px, 290px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref12.png?w=290;640;770;900;580;1280;1540;1800;870;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref12.png?w=290;770;900;580;1280;1540;1700;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 900px, (min-width: 80em) 770px, (min-width: 35em) 640px, 290px"
alt="Sebin flexing"
@ -431,27 +395,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/KidRhinoBoy">Chirros</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref1" polaroidBorder nsfw>
<RefFigure id="sebin-muscle-ref1" cornerText nsfw>
<!-- max 2480px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref1.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref1.png?w=400;700;1000;1200;1500;1800;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref1.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref1.png?w=400;700;1000;1200;1500;1800;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref1.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref1.png?w=400;700;1000;1200;1500;1800;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
alt="Sebin beckons"
@ -464,27 +428,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/GrisserArt">Grisser</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref2" polaroidBorder>
<RefFigure id="sebin-muscle-ref2" cornerText>
<!-- max 2953px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref2.png?w=415;625;750;875;1250;1500;1750;1875;2250;2625&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref2.png?w=415;625;875;1250;1500;1750;2250;2625&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 875px, (min-width: 80em) 750px, (min-width: 35em) 625px, 415px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref2.png?w=415;625;750;875;1250;1500;1750;1875;2250;2625&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref2.png?w=415;625;875;1250;1500;1750;2250;2625&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 875px, (min-width: 80em) 750px, (min-width: 35em) 625px, 415px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref2.png?w=415;625;750;875;1250;1500;1750;1875;2250;2625&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref2.png?w=415;625;875;1250;1500;1750;2250;2625&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 875px, (min-width: 80em) 750px, (min-width: 35em) 625px, 415px"
alt="Sebin jamming out to some tunes"
@ -497,27 +461,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/artvalentinapaz">Valentina Paz</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref3" polaroidBorder>
<RefFigure id="sebin-muscle-ref3" cornerText>
<!-- max 4961px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref3.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref3.png?w=400;800;1000;1200;1500;1800;2100&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref3.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref3.png?w=400;800;1000;1200;1500;1800;2100&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref3.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref3.png?w=400;800;1000;1200;1500;1800;2100&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
alt="Sebin flexing"
@ -527,32 +491,30 @@ const showModal = inject<Function>(showModalKey, Function);
</template>
<template #caption>Sebin flexing</template>
<template #copyright>
<a href="https://www.furaffinity.net/user/Marsel-Defender">
Marsel-Defender
</a>
<a href="https://www.furaffinity.net/user/Marsel-Defender"> Marsel-Defender </a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref4" polaroidBorder nsfw>
<RefFigure id="sebin-muscle-ref4" cornerText nsfw>
<!-- max 3000px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref4.png?w=400;700;840;980;800;1400;1680;1960;1200;2100;2520;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref4.png?w=400;980;1400;1680;1960;2100;2520;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 980px, (min-width: 80em) 840px, (min-width: 35em) 700px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref4.png?w=400;700;840;980;800;1400;1680;1960;1200;2100;2520;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref4.png?w=400;980;1400;1680;1960;2100;2520;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 980px, (min-width: 80em) 840px, (min-width: 35em) 700px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref4.png?w=400;700;840;980;800;1400;1680;1960;1200;2100;2520;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref4.png?w=400;980;1400;1680;1960;2100;2520;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 980px, (min-width: 80em) 840px, (min-width: 35em) 700px, 400px"
alt="Sebin soaping up"
@ -565,27 +527,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/O_reowoof">(o)reo</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref5" polaroidBorder nsfw>
<RefFigure id="sebin-muscle-ref5" cornerText nsfw>
<!-- max 2000px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref5.jpg?w=415;525;630;735;830;1050;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref5.jpg?w=415;735;1050;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 735px, (min-width: 80em) 630px, (min-width: 35em) 525px, 415px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref5.jpg?w=415;525;630;735;830;1050;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref5.jpg?w=415;735;1050;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 735px, (min-width: 80em) 630px, (min-width: 35em) 525px, 415px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref5.jpg?w=415;525;630;735;830;1050;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref5.jpg?w=415;735;1050;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 735px, (min-width: 80em) 630px, (min-width: 35em) 525px, 415px"
alt="Sebin bulging out"
@ -598,27 +560,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://www.furaffinity.net/user/sexmuffin">SexMuffin</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref6" polaroidBorder nsfw>
<RefFigure id="sebin-muscle-ref6" cornerText nsfw>
<!-- max 1500px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref6.png?w=400;545;655;765;800;1090;1310;1200;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref6.png?w=400;765;1090;1310;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref6.png?w=400;545;655;765;800;1090;1310;1200;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref6.png?w=400;765;1090;1310;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref6.png?w=400;545;655;765;800;1090;1310;1200;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref6.png?w=400;765;1090;1310;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
alt="Sebin showing you his rings"
@ -631,27 +593,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/tehknuxlight">Knuxlight</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref7" polaroidBorder>
<RefFigure id="sebin-muscle-ref7" cornerText>
<!-- max 1240px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1240px, (min-width: 80em) 1190px, (min-width: 35em) 995px, 415px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1240px, (min-width: 80em) 1190px, (min-width: 35em) 992px, 415px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref7.tiff?w=415;995;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1240px, (min-width: 80em) 1190px, (min-width: 35em) 992px, 415px"
alt="Sebin ready to throw down"
@ -664,27 +626,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://www.furaffinity.net/user/shonuff44">ShoNuff44</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref8" polaroidBorder>
<RefFigure id="sebin-muscle-ref8" cornerText>
<!-- max 1245px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 80em) 1200px, (min-width: 35em) 1000px, 415px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 80em) 1200px, (min-width: 35em) 1000px, 415px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref8.png?w=415;1000;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 80em) 1200px, (min-width: 35em) 1000px, 415px"
alt="Sebin looking aloof (but chill)"
@ -697,27 +659,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/UsurpThem">Usurp</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref9" polaroidBorder>
<RefFigure id="sebin-muscle-ref9" cornerText>
<!-- max 2550px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;880;1120;800;1470;1760;2240;1200;2205;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;1470;1760;2240;1200;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1120px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;880;1120;800;1470;1760;2240;1200;2205;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;1470;1760;2240;1200;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1120px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;880;1120;800;1470;1760;2240;1200;2205;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref9.jpg?w=400;735;1470;1760;2240;1200;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 1120px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
alt="Sebin getting out of the pool"
@ -730,27 +692,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://www.furaffinity.net/user/j-cock">j-cock</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref10" polaroidBorder nsfw>
<RefFigure id="sebin-muscle-ref10" cornerText nsfw>
<!-- max 2421px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref10.jpg?w=380;425;510;600;760;850;1020;1200;1140;1275;1530;1800&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref10.jpg?w=380;600;850;1275;1530;1800&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 600px, (min-width: 80em) 510px, (min-width: 35em) 425px, 380px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref10.jpg?w=380;425;510;600;760;850;1020;1200;1140;1275;1530;1800&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref10.jpg?w=380;600;850;1275;1530;1800&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 600px, (min-width: 80em) 510px, (min-width: 35em) 425px, 380px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref10.jpg?w=380;425;510;600;760;850;1020;1200;1140;1275;1530;1800&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref10.jpg?w=380;600;850;1275;1530;1800&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 600px, (min-width: 80em) 510px, (min-width: 35em) 425px, 380px"
alt="Sebin getting frisky on the train"
@ -763,27 +725,27 @@ const showModal = inject<Function>(showModalKey, Function);
<a href="https://twitter.com/Wintech3112">Winty</a>
</template>
</RefFigure>
<RefFigure id="sebin-muscle-ref11" polaroidBorder>
<RefFigure id="sebin-muscle-ref11" cornerText>
<!-- max 3184px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/muscle/muscle-ref11.png?w=400;545;655;765;800;1090;1210;1530;1200;1635;1965;2295&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref11.png?w=400;765;1200;1635;1965;2295&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/muscle/muscle-ref11.png?w=400;545;655;765;800;1090;1210;1530;1200;1635;1965;2295&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref11.png?w=400;765;1200;1635;1965;2295&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/muscle/muscle-ref11.png?w=400;545;655;765;800;1090;1210;1530;1200;1635;1965;2295&png&withoutEnlargement&srcset
@/assets/refs/muscle/muscle-ref11.png?w=400;765;1200;1635;1965;2295&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 765px, (min-width: 80em) 655px, (min-width: 35em) 545px, 400px"
alt="Sebin getting ready to lift"
@ -808,21 +770,17 @@ const showModal = inject<Function>(showModalKey, Function);
<template #img>
<picture>
<source
srcset="
@/assets/refs/sebin-ref-penis.png?w=480;720;0&avif&quality=75&srcset
"
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&format=avif&quality=75&as=srcset"
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/sebin-ref-penis.png?w=480;720;0&webp&quality=100&srcset
"
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&format=webp&quality=100&as=srcset"
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
type="image/webp"
/>
<img
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&png&srcset"
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&format=png&as=srcset"
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
alt="Sebin's manly parts"
loading="lazy"
@ -840,28 +798,24 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<DataTable :headings="sebinPenisHeadings" :data="sebinPenisData" />
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>Human-shaped with ridges</li>
<li>Ring-like sheath surrounding shaft</li>
<li>
Extends from sheath when erect, lives inside sheath when not erect
</li>
<li>Extends from sheath when erect, lives inside sheath when not erect</li>
<li>External balls</li>
</ul>
</QuickFacts>
<p>
Despite his reptilian appearance, Sebin has nipples, a feature of the
human side of his family. Furthermore, his external testicles represent
another humanized feature. Where relatives of his ilk possess a slit in
which the penis lies protectively, Sebin possesses a pouch-like sheath
from which the tip of the penis protrudes slightly. The shape of his
shaft is predominantly humanoid, but it is surrounded by ridges and has
no equivalent of a foreskin. When aroused, the coal-black shaft swells
and pushes out of the sheath until fully erect, the sheath wrapping
around the root of the shaft like a ring. However, he can also push it
out in a flaccid state, e.g. when needing to pass water.
Despite his reptilian appearance, Sebin has nipples, a feature of the human side of his
family. Furthermore, his external testicles represent another humanized feature. Where
relatives of his ilk possess a slit in which the penis lies protectively, Sebin possesses a
pouch-like sheath from which the tip of the penis protrudes slightly. The shape of his shaft
is predominantly humanoid, but it is surrounded by ridges and has no equivalent of a
foreskin. When aroused, the coal-black shaft swells and pushes out of the sheath until fully
erect, the sheath wrapping around the root of the shaft like a ring. However, he can also
push it out in a flaccid state, e.g. when needing to pass water.
</p>
</section>
</template>
@ -871,16 +825,12 @@ const showModal = inject<Function>(showModalKey, Function);
<h2>But, wait! There's more...</h2>
<p>
Sebin like you haven't seen him yet! Flip the switch to reveal his
naughty secrets. If you dare...! Don't say I didn't warn you!!
Sebin like you haven't seen him yet! Flip the switch to reveal his naughty secrets. If you
dare...! Don't say I didn't warn you!!
</p>
<p>
<RefToggle
id="sebin-manly-bits"
v-model="isNsfw"
@click.prevent="showModal()"
>
<RefToggle id="sebin-manly-bits" v-model="isNsfw" @click.prevent="showModal()">
<template #off>😇</template>
<template #on>😈</template>
</RefToggle>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import RefFigure from "@/components/RefFigure.vue";
import RefGallery from "@/components/RefGallery.vue";
import RefFigure from '@/components/RefFigure.vue'
import RefGallery from '@/components/RefGallery.vue'
</script>
<template>
@ -9,27 +9,27 @@ import RefGallery from "@/components/RefGallery.vue";
</section>
<RefGallery>
<RefFigure id="casual-outfit" polaroidBorder>
<RefFigure id="casual-outfit" cornerText>
<!-- max 1876px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/casual/fullbody.png?w=400;650;780;910;800;1300;1560;1820;1200;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/clothes/casual/fullbody.png?w=400;780;910;1300;1560;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 910px, (min-width: 80em) 780px, (min-width: 35em) 650px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/clothes/casual/fullbody.png?w=400;650;780;910;800;1300;1560;1820;1200;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/clothes/casual/fullbody.png?w=400;780;910;1300;1560;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 910px, (min-width: 80em) 780px, (min-width: 35em) 650px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/clothes/casual/fullbody.png?w=400;650;780;910;800;1300;1560;1820;1200;0&png&withoutEnlargement&srcset
@/assets/refs/clothes/casual/fullbody.png?w=400;780;910;1300;1560;0&format=png&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 910px, (min-width: 80em) 780px, (min-width: 35em) 650px, 400px"
alt="Sebin in his casual outfit"
@ -38,37 +38,32 @@ import RefGallery from "@/components/RefGallery.vue";
</picture>
</template>
<template #caption>
<p>Sebin in his casual outfit</p>
<p>
Black tank top, flannell shirt, shorts (w/ dangling bands), sneakers
</p>
</template>
<template #caption>Sebin in his casual outfit</template>
<template #copyright>
<a href="https://twitter.com/coffeerelated">coffeerelated</a>
</template>
</RefFigure>
<RefFigure id="sebin-winter-outfit" polaroidBorder>
<RefFigure id="sebin-winter-outfit" cornerText>
<!-- max 1470px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/cold/fullbody.png?w=400;655;785;915;800;1310;1200;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/clothes/cold/fullbody.png?w=400;785;915;1310;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 915px, (min-width: 80em) 785px, (min-width: 35em) 655px, 400px"
/>
<source
srcset="
@/assets/refs/clothes/cold/fullbody.png?w=400;655;785;915;800;1310;1200;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/clothes/cold/fullbody.png?w=400;785;915;1310;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 915px, (min-width: 80em) 785px, (min-width: 35em) 655px, 400px"
/>
<img
srcset="
@/assets/refs/clothes/cold/fullbody.png?w=400;655;785;915;800;1310;1200;0&jpg&withoutEnlargement&srcset
@/assets/refs/clothes/cold/fullbody.png?w=400;785;915;1310;0&format=jpg&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 915px, (min-width: 80em) 785px, (min-width: 35em) 655px, 400px"
alt="Sebin in his cold weather outfit"
@ -77,35 +72,32 @@ import RefGallery from "@/components/RefGallery.vue";
</picture>
</template>
<template #caption>
<p>Sebin in his cold weather outfit</p>
<p>Winter coat, scarf, zip hoodie, jeans, winter boots</p>
</template>
<template #caption>Sebin in his cold weather outfit</template>
<template #copyright>
<a href="https://twitter.com/lara_belem_">Lara Belém</a>
</template>
</RefFigure>
<RefFigure id="sebin-workout-outfit-fullbody" polaroidBorder>
<RefFigure id="sebin-workout-outfit-fullbody" cornerText>
<!-- max 1758px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/workout/fullbody.png?w=400;535;640;745;800;1070;1280;1490;1200;1605;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/clothes/workout/fullbody.png?w=400;640;800;1070;1280;1490;1605;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 745px, (min-width: 80em) 639px, (min-width: 35em) 532px, 400px"
/>
<source
srcset="
@/assets/refs/clothes/workout/fullbody.png?w=400;535;640;745;800;1070;1280;1490;1200;1605;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/clothes/workout/fullbody.png?w=400;640;800;1070;1280;1490;1605;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 745px, (min-width: 80em) 639px, (min-width: 35em) 532px, 400px"
/>
<img
srcset="
@/assets/refs/clothes/workout/fullbody.png?w=400;535;640;745;800;1070;1280;1490;1200;1605;0&jpg&withoutEnlargement&srcset
@/assets/refs/clothes/workout/fullbody.png?w=400;640;800;1070;1280;1490;1605;0&format=jpg&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 745px, (min-width: 80em) 639px, (min-width: 35em) 532px, 400px"
alt="Sebin in his workout outfit (fullbody)"
@ -114,38 +106,32 @@ import RefGallery from "@/components/RefGallery.vue";
</picture>
</template>
<template #caption>
<p>Sebin in his workout outfit</p>
<p>
<strong>Full body:</strong> Snapback hat, tank top, fingerless gloves,
shorts, sneakers
</p>
</template>
<template #caption>Sebin in his workout outfit (full body)</template>
<template #copyright>
<a href="https://twitter.com/turquoize_art">Atlas</a>
</template>
</RefFigure>
<RefFigure id="sebin-workout-outfit-close" polaroidBorder>
<RefFigure id="sebin-workout-outfit-close" cornerText>
<!-- max 2480px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/workout/closeup.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/clothes/workout/closeup.png?w=400;600;800;1000;1200;1400;1800;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500x, 400px"
/>
<source
srcset="
@/assets/refs/clothes/workout/closeup.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/clothes/workout/closeup.png?w=400;600;800;1000;1200;1400;1800;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
/>
<img
srcset="
@/assets/refs/clothes/workout/closeup.png?w=400;500;600;700;800;1000;1200;1400;1500;1800;2100&jpg&withoutEnlargement&srcset
@/assets/refs/clothes/workout/closeup.png?w=400;600;800;1000;1200;1400;1800;0&format=jpg&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
alt="Sebin in his workout outfit (close-up)"
@ -154,98 +140,83 @@ import RefGallery from "@/components/RefGallery.vue";
</picture>
</template>
<template #caption>
<p>Sebin in his workout outfit</p>
<p>
<strong>Close-up:</strong> Snapback hat, headphones, tank top,
fingerless gloves, shorts, smartwatch
</p>
</template>
<template #caption>Sebin in his workout outfit (close-up)</template>
<template #copyright>
<a href="https://twitter.com/purpledragonrei">Rei</a>
</template>
</RefFigure>
<RefFigure id="sebin-tracksuit-pants" polaroidBorder>
<!-- max 961px -->
<RefFigure id="sebin-tracksuit-pants" nsfw cornerText>
<!-- max 1656px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/lazy/pants.jpg?w=400;500;600;700;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/fullbody.png?w=400;850;1210;1460;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
sizes="(min-width: 120em) 850px, (min-width: 80em) 730px, (min-width: 35em) 605px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/clothes/lazy/pants.jpg?w=400;500;600;700;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/fullbody.png?w=400;850;1210;1460;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
sizes="(min-width: 120em) 850px, (min-width: 80em) 730px, (min-width: 35em) 605px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/clothes/lazy/pants.jpg?w=400;500;600;700;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/fullbody.png?w=400;850;1210;1460;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 400px"
sizes="(min-width: 120em) 850px, (min-width: 80em) 730px, (min-width: 35em) 605px, 400px"
alt="Tracksuit pants"
loading="lazy"
/>
</picture>
</template>
<template #caption>
<p>Tracksuit pants</p>
<p>
Sebin likes to wear comfortable clothes at home when he doesn't need
to leave the house or is enjoying some leisure time after work or on
weekends.
</p>
</template>
<template #caption>Sebin in leisure tracksuit pants</template>
<!-- <template #copyright></template> -->
<template #copyright>
<a href="https://twitter.com/leolynx86">Leolynx</a>
</template>
</RefFigure>
<RefFigure id="sebin-topless" polaroidBorder>
<!-- max 333px -->
<RefFigure id="sebin-topless" cornerText>
<!-- max 2119px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/clothes/lazy/undies.jpg?w=0&avif&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/undies.png?w=400;880;1028;1470;1760;0&format=avif&withoutEnlargement&as=srcset
"
sizes="333px"
sizes="(min-width: 120em) 1028px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/clothes/lazy/undies.jpg?w=0&webp&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/undies.png?w=400;880;1028;1470;1760;0&format=webp&withoutEnlargement&as=srcset
"
sizes="333px"
sizes="(min-width: 120em) 1028px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/clothes/lazy/undies.jpg?w=0&withoutEnlargement&srcset
@/assets/refs/clothes/lazy/undies.png?w=400;880;1028;1470;1760;0&withoutEnlargement&as=srcset
"
sizes="333px"
sizes="(min-width: 120em) 1028px, (min-width: 80em) 880px, (min-width: 35em) 735px, 400px"
alt="Shorts"
loading="lazy"
/>
</picture>
</template>
<template #caption>
<p>Topless w/ jockstrap/boxer briefs</p>
<p>
For even more comfort, Sebin tends to forgoe pants completely and save
on laundry by only wearing the absolute necessary.
</p>
</template>
<template #caption>Sebin in his favorite boxers</template>
<!-- <template #copyright></template> -->
<template #copyright>
<a href="https://twitter.com/Retroslime69">Retroslime69</a>
</template>
</RefFigure>
</RefGallery>
</template>

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { inject } from "vue";
import { inject } from 'vue'
import {
firstName,
middleName,
@ -13,65 +13,37 @@ import {
tailLength,
wingspan,
hobbies,
kinks,
} from "@/sebin";
import { dateFormat, getAge, toImperial, toLbs } from "@/helpers";
import { isWarnKey, nsfwKey, showModalKey } from "@/keys";
import type { Kink } from "@/interfaces";
import DataTable from "@/components/DataTable.vue";
import QuickFacts from "@/components/QuickFacts.vue";
import RefToggle from "@/components/RefToggle.vue";
import RefModal from "@/components/RefModal.vue";
kinks
} from '@/sebin'
import { dateFormat, getAge, toImperial, toLbs } from '@/helpers'
import { nsfwKey, showModalKey } from '@/keys'
import DataTable from '@/components/DataTable.vue'
import QuickFacts from '@/components/QuickFacts.vue'
import RefToggle from '@/components/RefToggle.vue'
import FilteredList from '@/components/FilteredList.vue'
const generalHeadings = ["Key", "Value"];
const generalHeadings = ['Key', 'Value']
const generalData = [
["Full Name", `${firstName} ${middleName} ${lastName} `],
[
"Date of Birth",
`${dateFormat.format(dateOfBirth)} (${getAge(dateOfBirth)})`,
],
["Sex/Gender", gender],
["Height", `${height} cm (${toImperial(height)})`],
["Weight", `${weight} kg (${toLbs(weight)} lbs)`],
["Tail Length", `${tailLength / 100} m (${toImperial(tailLength)})`],
["Wingspan", `${wingspan / 100} m (${toImperial(wingspan)})`],
];
['Full Name', `${firstName} ${middleName} ${lastName} `],
['Date of Birth', `${dateFormat.format(dateOfBirth)} (${getAge(dateOfBirth)})`],
['Sex/Gender', gender],
['Height', `${height} cm (${toImperial(height)})`],
['Weight', `${weight} kg (${toLbs(weight)} lbs)`],
['Tail Length', `${tailLength / 100} m (${toImperial(tailLength)})`],
['Wingspan', `${wingspan / 100} m (${toImperial(wingspan)})`]
]
const nsfwHeadings = ["Key", "Value"];
const nsfwHeadings = ['Key', 'Value']
const nsfwData = [
["Orientation", orientation],
["Position", position],
];
['Orientation', orientation],
['Position', position]
]
const kinksHeadings = ["Kink", "Receive", "Give"];
const kinksData = kinks.map((kink: Kink): string[] => {
const receive = kink.receive ? "✅" : "🚫";
const give = kink.give ? "✅" : "🚫";
return [kink.name, receive, give];
});
const isNsfw = inject<boolean>(nsfwKey, false);
const isWarn = inject<boolean>(isWarnKey, false);
const showModal = inject<Function>(showModalKey, Function);
const isNsfw = inject<boolean>(nsfwKey, false)
const showModal = inject<Function>(showModalKey, Function)
</script>
<template>
<RefModal v-show="isWarn">
<template #heading>
<br />
Whoa, Nelly!
</template>
<template #message>
By enabling NSFW mode you confirm that you are of legal age to view adult
content.
</template>
<template #yes>Yes, show me the goods 👀</template>
<template #no>NO, STAHP 😱</template>
</RefModal>
<section>
<h1>{{ $route.name }}</h1>
@ -81,8 +53,8 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<h2>Personality</h2>
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>warm-hearted</li>
<li>caring</li>
<li>quick to offer help</li>
@ -95,46 +67,42 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
Sebin is a warm-hearted guy who cares a lot about the well-being of his
loved ones. Bad vibes rarely escape him and he offers his help without
hesitation. He also won't avoid difficult conversations in the process.
Not being able to help a friend in need is synonymous with failing them, a
realization that can leave him feeling uneasy long after the fact.
Sebin is a warm-hearted guy who cares a lot about the well-being of his loved ones. Bad vibes
rarely escape him and he offers his help without hesitation. He also won't avoid difficult
conversations in the process. Not being able to help a friend in need is synonymous with
failing them, a realization that can leave him feeling uneasy long after the fact.
</p>
<p>
At the same time, he is very open and honest about his feelings. He does
not mince words and finds clear words when speaking his mind.
Unfortunately, Sebin sometimes forgets his good manners in the heat of the
moment, once he gets invested into a quarrel especially when it comes to
topics that are near and dear to his heart. Anyone looking to have a bad
time can try their luck at pissing him off even once. This includes an
equally vulgar vocabulary. It is not uncommon to hear him swear.
At the same time, he is very open and honest about his feelings. He does not mince words and
finds clear words when speaking his mind. Unfortunately, Sebin sometimes forgets his good
manners in the heat of the moment, once he gets invested into a quarrel especially when it
comes to topics that are near and dear to his heart. Anyone looking to have a bad time can try
their luck at pissing him off even once. This includes an equally vulgar vocabulary. It is not
uncommon to hear him swear.
</p>
<p>
Nevertheless, Sebin strives to put his best foot forward at all times. He
is of the sociable type and likes to laugh a lot, as he is easily amused.
Sometimes to a degree where it can become very childish and immature very
quickly.
Nevertheless, Sebin strives to put his best foot forward at all times. He is of the sociable
type and likes to laugh a lot, as he is easily amused. Sometimes to a degree where it can
become very childish and immature very quickly.
</p>
<p>
Physical strength is not the only thing that plays a big role for Sebin.
He is of a firm believe that a healthy body must also have a healthy mind
in order to find a balance. But he only came to this realization at the
end of a rocky road. While a setback in the past could easily throw him
off track, today he stands much more firmly in life. Not only for his own
sake, but also to be a kind of anchor for others. He always keeps his
cool, so he can be a tower of strenth for others.
Physical strength is not the only thing that plays a big role for Sebin. He is of a firm
believe that a healthy body must also have a healthy mind in order to find a balance. But he
only came to this realization at the end of a rocky road. While a setback in the past could
easily throw him off track, today he stands much more firmly in life. Not only for his own
sake, but also to be a kind of anchor for others. He always keeps his cool, so he can be a
tower of strenth for others.
</p>
</section>
<section>
<h2>Hobbies</h2>
<QuickFacts>
<ul class="col-4">
<QuickFacts :cols="4">
<ul>
<li v-for="(hobby, idx) in hobbies" :key="idx">
{{ hobby }}
</li>
@ -142,26 +110,24 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
Sebin is passionate about his hobbies. If he notices even the smallest
spark of interest in his hobbies you should bring a lot of time, as he
will chew your ear off first. Patience is known to be a virtue one
unknown to this dragon.
Sebin is passionate about his hobbies. If he notices even the smallest spark of interest in
his hobbies you should bring a lot of time, as he will chew your ear off first. Patience is
known to be a virtue one unknown to this dragon.
</p>
<p>
When he indulges in his hobbies, he does so with devotion. Every move has
to be right and everything has to be in perfect harmony. Once he is in his
flow, he must not be disturbed, otherwise he can sometimes become quite
eccentric in expressing his dismay of being disrupted, possibly losing a
very important train of thought.
When he indulges in his hobbies, he does so with devotion. Every move has to be right and
everything has to be in perfect harmony. Once he is in his flow, he must not be disturbed,
otherwise he can sometimes become quite eccentric in expressing his dismay of being disrupted,
possibly losing a very important train of thought.
</p>
</section>
<section>
<h2>Food &amp; Drink</h2>
<QuickFacts>
<ul class="col-4">
<QuickFacts :cols="4">
<ul>
<li>sweets</li>
<li>savory food</li>
<li>spicy food</li>
@ -178,21 +144,19 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
Sebin's day starts with a strong cup of black coffee and sandwiches. He's
also a massive sweet tooth which sounds like a big detriment to his
fitness routine. That's because it is and it's often very hard for him to
resist.
Sebin's day starts with a strong cup of black coffee and sandwiches. He's also a massive sweet
tooth which sounds like a big detriment to his fitness routine. That's because it is and it's
often very hard for him to resist.
</p>
<p>
Besides snacking, Sebin also likes to eat hearty and savory things. He
doesn't disdain a cheese platter with a wide selection, nor a medium-rare
steak.
Besides snacking, Sebin also likes to eat hearty and savory things. He doesn't disdain a
cheese platter with a wide selection, nor a medium-rare steak.
</p>
<p>
Sebin rarely says no to a good beer with friends, just as he rarely says
no to a bar tour to try new and interesting cocktails.
Sebin rarely says no to a good beer with friends, just as he rarely says no to a bar tour to
try new and interesting cocktails.
</p>
</section>
@ -202,8 +166,8 @@ const showModal = inject<Function>(showModalKey, Function);
<DataTable :headings="nsfwHeadings" :data="nsfwData" />
<QuickFacts>
<ul class="col-2">
<QuickFacts :cols="2">
<ul>
<li>Supremely horny</li>
<li>Confident, knows what he's got</li>
<li>Dominant lover, likes it rough but is no brute</li>
@ -215,20 +179,19 @@ const showModal = inject<Function>(showModalKey, Function);
</QuickFacts>
<p>
But above all Sebin is a very naughty hornball. He knows what he's got
and he's not afraid to flaunt it. He is a generally dominant lover who
likes to have it rough. But he is not lacking in tenderness. He
considers himself somewhat of a "service top", who doesn't only have his
own fun in mind. His job is only done if he's benn able to satisfy.
However, that doesn't mean that he doesn't let others have their fun
with him too from time to time. It always depends on his playmates,
which makes him effectively a switch. He loves to wear bottomless
jockstraps and boxer briefs to direct the attention of onlookers exactly
where he wants it. After all he is well endowed enough to peddle it
around.
But above all Sebin is a very naughty hornball. He knows what he's got and he's not afraid
to flaunt it. He is a generally dominant lover who likes to have it rough. But he is not
lacking in tenderness. He considers himself somewhat of a "service top", who doesn't only
have his own fun in mind. His job is only done if he's benn able to satisfy. However, that
doesn't mean that he doesn't let others have their fun with him too from time to time. It
always depends on his playmates, which makes him effectively a switch. He loves to wear
bottomless jockstraps and boxer briefs to direct the attention of onlookers exactly where he
wants it. After all he is well endowed enough to peddle it around.
</p>
<DataTable class="kinks" :headings="kinksHeadings" :data="kinksData" />
<h3>Kinks</h3>
<FilteredList :data="kinks" />
</template>
<template v-else>

View file

@ -1,33 +1,16 @@
<script setup lang="ts">
import { inject } from "vue";
import { isWarnKey, nsfwKey, showModalKey } from "@/keys";
import RefToggle from "@/components/RefToggle.vue";
import RefModal from "@/components/RefModal.vue";
import WelcomeHeader from "@/components/WelcomeHeader.vue";
import ButtonGroup from "@/components/ButtonGroup.vue";
import Button from "@/components/RefButton.vue";
import { inject } from 'vue'
import { nsfwKey, showModalKey } from '@/keys'
import RefToggle from '@/components/RefToggle.vue'
import WelcomeHeader from '@/components/WelcomeHeader.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Button from '@/components/RefButton.vue'
const isNsfw = inject<boolean>(nsfwKey, false);
const isWarn = inject<boolean>(isWarnKey, false);
const showModal = inject<Function>(showModalKey, Function);
const isNsfw = inject<boolean>(nsfwKey, false)
const showModal = inject<Function>(showModalKey, Function)
</script>
<template>
<RefModal v-show="isWarn">
<template #heading>
<br />
Whoa, Nelly!
</template>
<template #message>
By enabling NSFW mode you confirm that you are of legal age to view adult
content.
</template>
<template #yes>Yes, show me the goods 👀</template>
<template #no>NO, STAHP 😱</template>
</RefModal>
<WelcomeHeader>
<template #main>Sebin Nyshkim</template>
<template #sub>Character Reference Page</template>
@ -35,46 +18,33 @@ const showModal = inject<Function>(showModalKey, Function);
<section>
<h3>Welcome to Sebin's Ref Page</h3>
<p>
On this page your can learn all about Sebin, your friendly neighborhood
dragon!
</p>
<p>On this page your can learn all about Sebin, your friendly neighborhood dragon!</p>
<p>
I started this page to have a single point of truth with all the info
artists I commission can possibly need. If you're missing some crucial
info, or you would like to give me some general feedback about this page,
feel free to reach out!
I started this page to have a single point of truth with all the info artists I commission can
possibly need. If you're missing some crucial info, or you would like to give me some general
feedback about this page, feel free to reach out!
</p>
<ul class="social">
<li class="twitter">
<a href="https://twitter.com/SebinNyshkim">Twitter</a>
</li>
<li class="mastodon">
<a href="https://meow.social/@SebinNyshkim" rel="me">Mastodon</a>
</li>
<li class="telegram">
<a href="https://t.me/SebinNyshkim">Telegram</a>
</li>
<li class="furaffinity">
<a href="https://www.furaffinity.net/user/sonofdragons">
<ButtonGroup grid class="social">
<Button href="https://twitter.com/SebinNyshkim" class="twitter"> Twitter </Button>
<Button href="https://meow.social/@SebinNyshkim" class="mastodon" rel="me"> Mastodon </Button>
<Button href="https://t.me/SebinNyshkim" class="telegram"> Telegram </Button>
<Button href="https://www.furaffinity.net/user/sonofdragons" class="furaffinity">
Fur Affinity
</a>
</li>
</ul>
</Button>
</ButtonGroup>
<blockquote>
<strong>Note:</strong> This page is still under heavy construction, as
indicated by the 0.x.x version number in the footer. I'm continously
updating the site and adding details and information to it. In case you
run into something weird, definitely let me know!
<strong>Note:</strong> This page is still under heavy construction, as indicated by the 0.x.x
version number in the footer. I'm continously updating the site and adding details and
information to it. In case you run into something weird, definitely let me know!
</blockquote>
<h3>Complete Ref Sheet</h3>
<p>
Just here to fetch the ref sheet? Click the button with the ref sheet you
need and get started!
Just here to fetch the ref sheet? Click the button with the ref sheet you need and get
started!
</p>
<ButtonGroup>

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
// import AttackItem from "@/components/AttackItem.vue";
// import AttackList from "@/components/AttackList.vue";
import RefFigure from "@/components/RefFigure.vue";
import RefFigure from '@/components/RefFigure.vue'
</script>
<template>
@ -9,27 +9,27 @@ import RefFigure from "@/components/RefFigure.vue";
<h1>Overdrive Form</h1>
</section>
<RefFigure id="overdrive-ref" polaroidBorder>
<RefFigure id="overdrive-ref" cornerText>
<!-- max 1080px -->
<template #img>
<picture>
<source
srcset="
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&avif&quality=75&withoutEnlargement&srcset
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&format=avif&quality=75&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 450px"
type="image/avif"
/>
<source
srcset="
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&webp&quality=100&withoutEnlargement&srcset
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&format=webp&quality=100&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 450px"
type="image/webp"
/>
<img
srcset="
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&jpg&quality=95&withoutEnlargement&srcset
@/assets/refs/sebin-overdrive_ref-hires.jpg?w=450;500;600;900;0&format=jpg&quality=95&withoutEnlargement&as=srcset
"
sizes="(min-width: 120em) 700px, (min-width: 80em) 600px, (min-width: 35em) 500px, 450px"
alt="Sebin in Overdrive"
@ -45,34 +45,30 @@ import RefFigure from "@/components/RefFigure.vue";
<section>
<p>
Sebin can enter an Overdrive Form which greatly increases his strength and
abilities but it comes at a cost.
Sebin can enter an Overdrive Form which greatly increases his strength and abilities but it
comes at a cost.
</p>
<p>
He enters Overdrive by engulfing himself in a pillar of flames which
transforms his exterior physique. During Overdrive transformation his hair
ignites and flickers with blue flames. The corners of his eyes flicker
with long green flames. His arms and legs become part carbon black and are
crossed by several glowing veins which pulsate like flowing lava. Fire in
this form burns several degrees hotter than usual because his body becomes
a living blast furnace, which is why his limbs have to be of more
fire-proof material to withstand the increased heat.
He enters Overdrive by engulfing himself in a pillar of flames which transforms his exterior
physique. During Overdrive transformation his hair ignites and flickers with blue flames. The
corners of his eyes flicker with long green flames. His arms and legs become part carbon black
and are crossed by several glowing veins which pulsate like flowing lava. Fire in this form
burns several degrees hotter than usual because his body becomes a living blast furnace, which
is why his limbs have to be of more fire-proof material to withstand the increased heat.
</p>
<p>
To complete the transformation he inhales the flames from the pillar
surrounding him which heats up his body from within. Even if Sebin is a
fire dragon who can sustain high degrees of heat he is essentially
overheating himself from the inside. Because of this he can't maintain
this form for more than a few hours before he does permanent damage to his
own body.
To complete the transformation he inhales the flames from the pillar surrounding him which
heats up his body from within. Even if Sebin is a fire dragon who can sustain high degrees of
heat he is essentially overheating himself from the inside. Because of this he can't maintain
this form for more than a few hours before he does permanent damage to his own body.
</p>
<p>
Direct body contact with Sebin during overdrive causes 3rd degree burns as
he emits an extreme temperature, although less than he keeps inside his
body. His immediate surroundings are likely to burn or melt.
Direct body contact with Sebin during overdrive causes 3rd degree burns as he emits an extreme
temperature, although less than he keeps inside his body. His immediate surroundings are
likely to burn or melt.
</p>
<h2>Attacks</h2>
@ -88,75 +84,69 @@ import RefFigure from "@/components/RefFigure.vue";
<tr>
<td>Fire Breath (improved)</td>
<td>
The reach of Sebin's Fire Breath increases as well as the frequency
at which he can fire shots from his mouth.
The reach of Sebin's Fire Breath increases as well as the frequency at which he can fire
shots from his mouth.
</td>
</tr>
<tr>
<td>Flame Toss (improved)</td>
<td>
Overdrive Form eliminates the need for Sebin to spit fire into his
palms. It instead enables him to fire the shots directly from the
palm palm of his hands, as the firey veins crossing his arms act as
an orifice to do so. The explosion radius of the burning projectiles
that explode on impact is greatly increased.
Overdrive Form eliminates the need for Sebin to spit fire into his palms. It instead
enables him to fire the shots directly from the palm palm of his hands, as the firey
veins crossing his arms act as an orifice to do so. The explosion radius of the burning
projectiles that explode on impact is greatly increased.
</td>
</tr>
<tr>
<td>Kindled Fist (improved)</td>
<td>
As his arms and legs are infused with fire his punches and kicks
exert trails of flames while doing so. Landing a punch or kick sears
enemies.
As his arms and legs are infused with fire his punches and kicks exert trails of flames
while doing so. Landing a punch or kick sears enemies.
</td>
</tr>
<tr>
<td>Searing Discus</td>
<td>
Overdrive allows Sebin to form rings of fire by igniting flames from
his fingertips and swirling them in a circle motion. He can use them
for both close quarters or ranged combat.
Overdrive allows Sebin to form rings of fire by igniting flames from his fingertips and
swirling them in a circle motion. He can use them for both close quarters or ranged
combat.
</td>
</tr>
<tr>
<td>Combustion Flare</td>
<td>
Clinking both of his wrists against each other like flints unleashes
a devestating fire blast from both of his fire-infused hands. A
secure foothold is needed to prevent Sebin from being thrown back by
the recoil of the attack. Using this technique in the air is
Clinking both of his wrists against each other like flints unleashes a devestating fire
blast from both of his fire-infused hands. A secure foothold is needed to prevent Sebin
from being thrown back by the recoil of the attack. Using this technique in the air is
therefore highly risky.
</td>
</tr>
<tr>
<td>Blazing Pandemonium</td>
<td>
A heavy impact into the ground from a great height with both fists,
tearing deep cracks in the ground around the impact crater. Combined
with
A heavy impact into the ground from a great height with both fists, tearing deep cracks
in the ground around the impact crater. Combined with
<strong><em>Kindled Fist</em></strong>
the heat in Sebin's arms are forced through the newly created
furrows, transforming the scene into an inferno.
the heat in Sebin's arms are forced through the newly created furrows, transforming the
scene into an inferno.
</td>
</tr>
<tr>
<td>Scorching Edge</td>
<td>
A fiery blade towering several meters into the air that Sebin sends
careening towards his enemies from his fire-infused legs with a
backflip kick, leaving a swath of destruction in its wake. Upon
impact the force of the attack is distributed sideways.
A fiery blade towering several meters into the air that Sebin sends careening towards
his enemies from his fire-infused legs with a backflip kick, leaving a swath of
destruction in its wake. Upon impact the force of the attack is distributed sideways.
</td>
</tr>
<tr>
<td>Circling Fire Shield</td>
<td>
A rather defensive technique. By spinning around with stretched out
arms Sebin creates fire balls, which he usually hurls towards
enemies, that circle around his body diagonally. They act as a
shield while he can still move his arms relatively freely. Enemies
would be well advised to keep their distance to this spinning
shield, as the fire balls will still explode on contact.
A rather defensive technique. By spinning around with stretched out arms Sebin creates
fire balls, which he usually hurls towards enemies, that circle around his body
diagonally. They act as a shield while he can still move his arms relatively freely.
Enemies would be well advised to keep their distance to this spinning shield, as the
fire balls will still explode on contact.
</td>
</tr>
</tbody>

14
tsconfig.app.json Normal file
View file

@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["globals.d.ts", "env.d.ts", "src/**/*", "src/**/*.vue", "package.json"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

View file

@ -1,8 +0,0 @@
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}

View file

@ -1,16 +1,11 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"files": [],
"references": [
{
"path": "./tsconfig.config.json"
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

20
tsconfig.node.json Normal file
View file

@ -0,0 +1,20 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"globals.d.ts",
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

23
vite.config.mts Normal file
View file

@ -0,0 +1,23 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import { imagetools } from 'vite-imagetools'
import autoprefixer from 'autoprefixer'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
base: '/sebin/',
plugins: [vue(), imagetools()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
devSourcemap: true,
postcss: {
plugins: [autoprefixer({})]
}
}
})

View file

@ -1,19 +0,0 @@
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import { imagetools } from "vite-imagetools";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
base: "/sebin/",
plugins: [vue(), imagetools()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
css: {
devSourcemap: true,
},
});