Skip to content

Commit

Permalink
Merge pull request #21 from mogproject/dev
Browse files Browse the repository at this point in the history
v0.0.5
  • Loading branch information
mogproject authored Dec 30, 2024
2 parents bca17d3 + c37e7b8 commit 3dbea42
Show file tree
Hide file tree
Showing 18 changed files with 173 additions and 103 deletions.
6 changes: 3 additions & 3 deletions docs/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.f0ba3973.css",
"main.js": "/static/js/main.27b9f05c.js",
"main.js": "/static/js/main.735e9e9a.js",
"index.html": "/index.html",
"main.f0ba3973.css.map": "/static/css/main.f0ba3973.css.map",
"main.27b9f05c.js.map": "/static/js/main.27b9f05c.js.map"
"main.735e9e9a.js.map": "/static/js/main.735e9e9a.js.map"
},
"entrypoints": [
"static/css/main.f0ba3973.css",
"static/js/main.27b9f05c.js"
"static/js/main.735e9e9a.js"
]
}
Binary file added docs/assets/img/fei-small-back.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/img/fei-small-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="description" content="Feign-Discord CSS Generator"/><meta name="author" content="mogproject"/><link rel="shortcut icon" href="assets/ico/favicon.ico" type="image/x-icon"/><link rel="apple-touch-icon" sizes="57x57" href="assets/ico/apple-touch-icon-57x57.png"/><link rel="apple-touch-icon" sizes="60x60" href="assets/ico/apple-touch-icon-60x60.png"/><link rel="apple-touch-icon" sizes="72x72" href="assets/ico/apple-touch-icon-72x72.png"/><link rel="apple-touch-icon" sizes="76x76" href="assets/ico/apple-touch-icon-76x76.png"/><link rel="apple-touch-icon" sizes="114x114" href="assets/ico/apple-touch-icon-114x114.png"/><link rel="apple-touch-icon" sizes="120x120" href="assets/ico/apple-touch-icon-120x120.png"/><link rel="apple-touch-icon" sizes="144x144" href="assets/ico/apple-touch-icon-144x144.png"/><link rel="apple-touch-icon" sizes="152x152" href="assets/ico/apple-touch-icon-152x152.png"/><link rel="apple-touch-icon" sizes="180x180" href="assets/ico/apple-touch-icon-180x180.png"/><link rel="icon" type="image/png" href="assets/ico/favicon-16x16.png" sizes="16x16"/><link rel="icon" type="image/png" href="assets/ico/favicon-32x32.png" sizes="32x32"/><link rel="icon" type="image/png" href="assets/ico/favicon-96x96.png" sizes="96x96"/><link rel="icon" type="image/png" href="assets/ico/android-chrome-192x192.png" sizes="192x192"/><meta name="msapplication-config" content="/browserconfig.xml"/><meta property="og:site_name" content="Feign-Discord CSS Generator"/><meta property="og:title" content="Feign-Discord CSS Generator"/><meta property="og:image" content="https://feign.mogproject.com/assets/img/snapshot.png"/><meta property="og:description" content="Generate CSS for Feign + Discord Streamkit Overlay with no hassle. This website's customizability, efficient user management, and simplistic UI are must-haves for all Feign streamers."/><meta property="og:url" content="https://feign.mogproject.com"/><meta property="og:type" content="website"/><link rel="manifest" href="manifest.json"/><title>Feign-Discord CSS Generator</title><script defer="defer" src="/static/js/main.27b9f05c.js"></script><link href="/static/css/main.f0ba3973.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="description" content="Feign-Discord CSS Generator"/><meta name="author" content="mogproject"/><link rel="shortcut icon" href="assets/ico/favicon.ico" type="image/x-icon"/><link rel="apple-touch-icon" sizes="57x57" href="assets/ico/apple-touch-icon-57x57.png"/><link rel="apple-touch-icon" sizes="60x60" href="assets/ico/apple-touch-icon-60x60.png"/><link rel="apple-touch-icon" sizes="72x72" href="assets/ico/apple-touch-icon-72x72.png"/><link rel="apple-touch-icon" sizes="76x76" href="assets/ico/apple-touch-icon-76x76.png"/><link rel="apple-touch-icon" sizes="114x114" href="assets/ico/apple-touch-icon-114x114.png"/><link rel="apple-touch-icon" sizes="120x120" href="assets/ico/apple-touch-icon-120x120.png"/><link rel="apple-touch-icon" sizes="144x144" href="assets/ico/apple-touch-icon-144x144.png"/><link rel="apple-touch-icon" sizes="152x152" href="assets/ico/apple-touch-icon-152x152.png"/><link rel="apple-touch-icon" sizes="180x180" href="assets/ico/apple-touch-icon-180x180.png"/><link rel="icon" type="image/png" href="assets/ico/favicon-16x16.png" sizes="16x16"/><link rel="icon" type="image/png" href="assets/ico/favicon-32x32.png" sizes="32x32"/><link rel="icon" type="image/png" href="assets/ico/favicon-96x96.png" sizes="96x96"/><link rel="icon" type="image/png" href="assets/ico/android-chrome-192x192.png" sizes="192x192"/><meta name="msapplication-config" content="/browserconfig.xml"/><meta property="og:site_name" content="Feign-Discord CSS Generator"/><meta property="og:title" content="Feign-Discord CSS Generator"/><meta property="og:image" content="https://feign.mogproject.com/assets/img/snapshot.png"/><meta property="og:description" content="Generate CSS for Feign + Discord Streamkit Overlay with no hassle. This website's customizability, efficient user management, and simplistic UI are must-haves for all Feign streamers."/><meta property="og:url" content="https://feign.mogproject.com"/><meta property="og:type" content="website"/><link rel="manifest" href="manifest.json"/><title>Feign-Discord CSS Generator</title><script defer="defer" src="/static/js/main.735e9e9a.js"></script><link href="/static/css/main.f0ba3973.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
3 changes: 0 additions & 3 deletions docs/static/js/main.27b9f05c.js

This file was deleted.

1 change: 0 additions & 1 deletion docs/static/js/main.27b9f05c.js.map

This file was deleted.

3 changes: 3 additions & 0 deletions docs/static/js/main.735e9e9a.js

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions docs/static/js/main.735e9e9a.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "feign-discord",
"version": "0.0.4",
"version": "0.0.5",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.7.2",
Expand Down
Binary file added public/assets/img/fei-small-back.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/img/fei-small-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DiscordUsers } from "./components/sections/DiscordUsers";
import { FeignPlayers } from "./components/sections/FeignPlayers";
import { Preview } from "./components/sections/Preview";
import { buildCSS } from "./models/CSSBuilder";
import { buildFeignImageCSS } from "./models/FeignImageCSS";
import { buildFeignImageCss } from "./models/FeignImageCss";
import { OBSSettings } from "./components/sections/OBSSettings";
import { DiscordVoiceChannel } from "./components/sections/DiscordVoiceChannel";
import { ViewSettingsPane } from "./components/sections/ViewSettingsPane";
Expand Down Expand Up @@ -164,7 +164,7 @@ export default function App() {
</Container>
</ConfContext.Provider>
<style>{buildCSS(feignPlayers, viewSettings)}</style>
<style>{buildFeignImageCSS()}</style>
<style>{buildFeignImageCss()}</style>
<hr />
<Footer />
</>
Expand Down
4 changes: 2 additions & 2 deletions src/components/sections/OBSSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { Container, Row, Col, InputGroup, Form, Alert, Button } from "react-bootstrap";
import { ConfContext } from "../../models/Context";
import { buildCSS } from "../../models/CSSBuilder";
import { buildFeignImageCSS } from "../../models/FeignImageCSS";
import { buildFeignImageCss } from "../../models/FeignImageCss";
import { CopyButton } from "../buttons/CopyButton";
import FileSaver from "../../io/FileSaver";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
Expand All @@ -17,7 +17,7 @@ export function OBSSettings() {
const { feignPlayers, serverID, channelID, viewSettings } = React.useContext(ConfContext);
const isValid = feignPlayers.some((user) => user !== '');

const content = buildCSS(feignPlayers, viewSettings) + "\n" + buildFeignImageCSS();
const content = buildCSS(feignPlayers, viewSettings) + "\n" + buildFeignImageCss();

const obsURL = `https://streamkit.discord.com/overlay/voice/${serverID}/${channelID}`;
const obsWidth = 1772 + viewSettings.fei.interval * 12; // should support up to 13 users
Expand Down
188 changes: 122 additions & 66 deletions src/models/CSSBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,16 @@ function hex2rgba(hex: string, alpha: number): string {
return `rgba(${colors},${alpha})`;
}

function animationString(settings: AnimationSettings, prefix: string): string {
function animationString(flash: boolean, jump: boolean, flash_suffix: string, prefix: string): string {
const ret = [
[`${prefix}flash`, settings.flash],
["jump", settings.jump],
].reduce((acc, [t, enabled]) => {
if (!enabled) return acc;
const delimiter = acc === "" ? "" : ",";
return acc + delimiter + `750ms infinite alternate ease-in-out speak-${t}`;
}, "");
flash ? [`${prefix}speak-flash${flash_suffix}`] : [],
jump ? [`${prefix}speak-jump`] : [],
].flat().join(',');
return ret === "" ? "none" : ret;
}

const glowFilter = (x: number, c: string) => {
const prefix = `drop-shadow(0 0 ${x}px ${c}) brightness(100%) `;
const glowFilter = (prefix: string, x: number, c: string) => {
const infix = ` drop-shadow(0 0 ${x}px ${c}) `;
const suffix = [
[2, 2],
[-2, -2],
Expand All @@ -29,7 +25,7 @@ const glowFilter = (x: number, c: string) => {
]
.map(([i, j]) => `drop-shadow(${i}px ${j}px 0px ${c})`)
.join(" ");
return prefix + suffix;
return prefix + infix + suffix;
};

export function buildCSS(feignPlayers: string[], settings: ViewSettings): string {
Expand All @@ -39,73 +35,132 @@ export function buildCSS(feignPlayers: string[], settings: ViewSettings): string
const now = new Date().toISOString();
const prefix = `/* CSS built on https://feign.mogproject.com (v${APP_VERSION}). ${now}. */\n\n`;

const fei = feignPlayers.flatMap((id: string, i: number) =>
id === ""
? []
: [
// Character
`.voice_state[data-userid="${id}"]::after {`,
` background-image: var(--feign-icon-${FEI_COLORS[i]});`,
` background-size: ${settings.getFeiWidth()}px ${settings.getFeiHeight()}px;`,
" display: inline-block;",
' content: "";',
` width: ${settings.getFeiWidth()}px;`,
` height: ${settings.getFeiHeight()}px;`,
" border-radius: 0;",
" filter: brightness(65%);",
" text-align: center;",
` margin-top: ${settings.getFeiMarginTop()}px;`,
" position: relative;",
" top: 0px;",
settings.fei.mirror ? " -webkit-transform: scaleX(-1);" : "",
settings.fei.mirror ? " transform: scaleX(-1);" : "",
" z-index: 1",
"}",

// Animation
`.wrapper_speaking[data-userid="${id}"]::after {`,
` animation: ${animationString(settings.fei.speaking, "")};`,
" animation-fill-mode: forwards;",
" filter: brightness(100%);",
"}",
]
);
const feiBack = [
// Character
`.voice_state::before {`,
` background-image: var(--feign-icon-bg);`,
` background-size: ${settings.getFeiWidth()}px ${settings.getFeiHeight()}px;`,
" display: inline-block;",
' content: "";',
` width: ${settings.getFeiWidth()}px;`,
` height: ${settings.getFeiHeight()}px;`,
` filter: var(--d-default);`,
" text-align: center;",
` margin-top: ${settings.getFeiMarginTop()}px;`,
" position: absolute;",
" top: 0px;",
settings.fei.mirror ? " -webkit-transform: scaleX(-1);" : "",
settings.fei.mirror ? " transform: scaleX(-1);" : "",
" z-index: 1",
"}",

const animJumpFei = (settings.fei.speaking.jump || settings.avatar.speaking.jump)
? ["@keyframes speak-jump { 0% {top: 0px;} 50% {top: -20px;} 100% {top: 0px;} }"] : [];
// Animation
`.wrapper_speaking::before {`,
` animation-name: ${animationString(settings.fei.speaking.flash, settings.fei.speaking.jump, "-default", '')};`,
" animation-duration: 750ms;",
" animation-timing-function: ease-in-out;",
" animation-delay: 0s;",
" animation-iteration-count: infinite;",
" animation-direction: alternate;",
" animation-fill-mode: forwards;",
` filter: var(--f-default);`,
"}",
];

const animFlashFei = settings.fei.speaking.flash
? [
"@keyframes speak-flash {",
` 0% {filter:${glowFilter(2, settings.fei.speaking.flashColor)};}`,
` 50% {filter:${glowFilter(glowAmount, settings.fei.speaking.flashColor)};}`,
` 100% {filter:${glowFilter(2, settings.fei.speaking.flashColor)};}`,
"}",
]
: [];

const animFlashAvatar = settings.avatar.speaking.flash
? [
"@keyframes speak-avatar-flash {",
` 0% {filter:${glowFilter(2, settings.avatar.speaking.flashColor)};}`,
` 50% {filter:${glowFilter(glowAmount, settings.avatar.speaking.flashColor)};}`,
` 100% {filter:${glowFilter(2, settings.avatar.speaking.flashColor)};}`,
const feiFront = [
`.voice_state::after {`,
` background-image: var(--feign-icon-fg);`,
` background-size: ${settings.getFeiWidth()}px ${settings.getFeiHeight()}px;`,
" display: inline-block;",
' content: "";',
` width: ${settings.getFeiWidth()}px;`,
` height: ${settings.getFeiHeight()}px;`,
" filter: brightness(65%);",
" text-align: center;",
` margin-top: ${settings.getFeiMarginTop()}px;`,
" position: absolute;",
" top: 0px;",
settings.fei.mirror ? " -webkit-transform: scaleX(-1);" : "",
settings.fei.mirror ? " transform: scaleX(-1);" : "",
" z-index: 1",
"}",

// Animation
`.wrapper_speaking::after {`,
` animation-name: ${animationString(false, settings.fei.speaking.jump, "", '')};`,
" animation-duration: 750ms;",
" animation-timing-function: ease-in-out;",
" animation-delay: 0s;",
" animation-iteration-count: infinite;",
" animation-direction: alternate;",
" animation-fill-mode: forwards;",
" filter: brightness(100%);",
"}",
];

function createFlashKeyFrames(anim: AnimationSettings, suffix: string) {
if (!anim.flash) return [];
const prefix = suffix === 'avatar' ? 'brightness(100%)' : `var(--f-${suffix})`;
const varSuffix = suffix === 'avatar' ? '-a' : '';
return [
`@keyframes speak-flash-${suffix} {` +
`0% {filter:${prefix} var(--shadow-sm${varSuffix});}` +
`50% {filter:${prefix} var(--shadow-lg${varSuffix});}` +
`100% {filter:${prefix} var(--shadow-sm${varSuffix});}` +
"}",
]
: [];
];
}

function feiSpecific(id: string, colorIndex: number) {
if (id === '') return [];
const color = FEI_COLORS[colorIndex];
const character = [`.voice_state[data-userid="${id}"]::before {filter:var(--d-${color});}`];
const animation = [
`.wrapper_speaking[data-userid="${id}"]::before {` +
`animation-name: ${animationString(settings.fei.speaking.flash, settings.fei.speaking.jump, `-${color}`, '')};` +
`filter: var(--f-${color});` +
'}',
];
const keyframes = createFlashKeyFrames(settings.fei.speaking, color);
return [...character, ...animation, ...keyframes];
}

const fei = feignPlayers.flatMap((id: string, i: number) => feiSpecific(id, i));

// shadow settings
const shadowDefs = [
settings.fei.speaking.flash ? [
` --shadow-sm:${glowFilter('', 2, settings.fei.speaking.flashColor)};`,
` --shadow-lg:${glowFilter('', glowAmount, settings.fei.speaking.flashColor)};`,
] : [],
settings.avatar.speaking.flash ? [
` --shadow-sm-a:${glowFilter('', 2, settings.avatar.speaking.flashColor)};`,
` --shadow-lg-a:${glowFilter('', glowAmount, settings.avatar.speaking.flashColor)};`,
] : [],
].flat();
const shadowDefsSection = shadowDefs ? [':root {', ...shadowDefs, '}'] : [];

// jump animation
const animJump = (settings.fei.speaking.jump || settings.avatar.speaking.jump)
? ["@keyframes speak-jump { 0% {top: 0px;} 50% {top: -20px;} 100% {top: 0px;} }"] : [];

const animFlashFei = createFlashKeyFrames(settings.fei.speaking, 'default');

// avatar flash
const animFlashAvatar = createFlashKeyFrames(settings.avatar.speaking, 'avatar');

const animation = [...animJumpFei, ...animFlashFei, ...animFlashAvatar];
const animation = [...animJump, ...animFlashFei, ...animFlashAvatar, ...shadowDefsSection];

const avatarRadius =
{ [AvatarShape.Circle]: 50, [AvatarShape.RoundedRectangle]: 12, [AvatarShape.Rectangle]: 0 }[settings.avatar.shape] ?? 0;

const usernameOpacity = 0.95;

const avatarAnimation = [` animation: ${animationString(settings.avatar.speaking, "avatar-")};`, " animation-fill-mode: forwards;"];
const avatarAnimation = [` animation: ${animationString(settings.avatar.speaking.flash, settings.avatar.speaking.jump, "-avatar", '750ms infinite alternate ease-in-out ')};`];

const data = [
".voice_states {display: flex; flex-wrap: nowrap; margin: 0px 15px 0px 15px; padding: 0;}",
`.voice_state {height: auto; margin: 0 ${settings.fei.interval}px 0 0; display: flex; flex-direction: column;}`,
`.voice_state {height: auto; margin: 0 ${settings.fei.interval}px 0 0; display: flex; flex-direction: column; flex: 0 0 ${settings.getFeiWidth()}px; position: relative;}`,

// Avatar image
".voice_avatar {",
Expand All @@ -126,6 +181,7 @@ export function buildCSS(feignPlayers: string[], settings: ViewSettings): string
` border-color: ${settings.avatar.speaking.outline ? settings.avatar.speaking.outlineColor : "transparent"} !important;`,
" filter: brightness(100%);",
...avatarAnimation,
" animation-fill-mode: forwards;",
"}",

// User name
Expand Down Expand Up @@ -155,7 +211,7 @@ export function buildCSS(feignPlayers: string[], settings: ViewSettings): string
];
return (
prefix +
[...fei, ...animation, ...data]
[...feiBack, ...feiFront, ...fei, ...animation, ...data]
.map((s) => s.trim())
.filter((s) => s)
.join("\n")
Expand Down
50 changes: 35 additions & 15 deletions src/models/FeignImageCSS.tsx

Large diffs are not rendered by default.

8 changes: 1 addition & 7 deletions src/models/ViewSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,7 @@ export class ViewSettings {

// Margins (relative to their parent nodes).
getFeiMarginTop(): number {
if (this.username.show) {
return this.getFeiTopRelative() - this.getUsernameBottomRelative();
} else if (this.avatar.show) {
return this.getFeiTopRelative() - this.getAvatarBottomRelative();
} else {
return this.getAvatarMarginTop() - this.getAvatarTopRelative();
}
return this.getFeiTopRelative() - this.getTopElementRelative() + ViewSettings.DEFAULT_TOP_MARGIN;
}
getAvatarMarginTop(): number { return ViewSettings.DEFAULT_TOP_MARGIN + this.getAvatarTopRelative() - this.getTopElementRelative(); }
getUsernameMarginTop(): number {
Expand Down

0 comments on commit 3dbea42

Please sign in to comment.