#stage-discussion
1 messages ยท Page 9 of 1
looks pretty good
for slightly larger than 1:1
anyone feel like eating a cum glazed donut
ill pass
not really
why is that a thing anyways
like why 13
and why is a dozen 12
i guess bakers only deal in prime numbers
"douze" in french stands for 12 
more like douche


forsenmidlyamused
forsenlookingatyousideways
what ever happened to the original OMGScoots
people only use the pajlada one now
$origin OMGScoots
treuks, https://supinic.com/data/origin/detail/368 channel FFZ emote: Crudely drawn version of the original
face, which was a photo of SirScoots's face giving a "Oh really?" look. It used to be a global emote, but was removed because of SirScoots requesting it to be taken down. Added on 2017-02-27. Made by @pomegranateflea.
i asked him if it could be a 7tv global

but does he even own the copyright
we should ask the photographer
for usage rights
that'd be fucked 
rip
guy was ok with it but photographer sued

another forsen global 
i dont think you can own someone's "likeness" 
well idfk how to works 
well yeah rights, but not exclusivity
no not exclusivily
but also why would twitch give a fuck about pajlada
its not like he's a mascot
literally no reason
for them
he's one of the
make pajascoots global 
oh
thats why
he made it a sub emote
taking a global and putting it behind a paywall

cmonBRUH

is there something special i need to make eslint have the same checks as the ci does
stylelint?
dank
nope
had this problem
forever
@daring gale idk did we ever actually come up with a solution for this, it was like this on the trainwrecks site too wasnt it\
like its fucking desynced
github actions uses different rules
than local
which still
makes no sense to me
yeah not sure
maybe make the linter versions fixed
and I dont understand how its even possible in the first place
is there some kind of a way to use stylelint inside of .vue files though
it should by itself
not for css
with volar

and you can run the linter manually
and it'll just spit out the errors across the whole project
just run yarn lint

WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.
You may find that it works just fine, or you may not.
SUPPORTED TYPESCRIPT VERSIONS: >=3.3.1 <4.8.0
YOUR TYPESCRIPT VERSION: 4.9.4
is this meant to happen with the new version on chrome?
first 1-2 lines are like mostly unreadable
@daring gale idk if it was reported but whenever you use : and type emote chat dissapears
you can use this build that has a fix for it
here
oh cool it has autofill preview and tab completion
thanks
wish it had priority in some way like ffz has favorites
do we load the fix the same way as the original file?
just overwrite the folder and reload in extentions
new extension shows emotes as clickable in chat, though obviously it doesn't do anything rn. is it possible that in the future, clicking on an emote in chat types that emote into the user's message box thingy?
/user you mean? that works only for mods. most litely its gonan be an emote preview like ffz
I think he meant clicking the emote would copy and paste the emote name into the chatbox,
so you dont have to manually highlight the emote text then cvPaste
rereading it you might be right
But i think there is other planned feature for clicking emotes, like emote card and link to the emote page
Aware
put "giga" in front of everything

@daring gale

css pixels are not actual pixels
whatever they are
they sure aint responsive
- the srcset code is duplicated in several places. move it into a utility
do i put it in here
- the tooltips rescales after the image loads, so wrap the image in div with defined width/height
yeah make it a file called Image or something then export function imageHostToSrcset(host: ImageHost): string
ye
Do you think a 1/5 box could be usefull aswell?
for the tiny emotes? 
No meaning a 5th of the total width
We currently do 1/2 1/3 1/4 1/6
1/5 can only group with itself tho
Would be like 6/5 units wide
A bit more due to the margin
Would allow for some of the slightly wider than 1x1 emotes to fit more tightly, but wouldnt make it look better most likely
Also, we need another global 1x1 to fill this gap
https://i.imgur.com/o7US9Yt.png
should it be based on pixel dimensions rather than ratio?
in case non-128-pixel-tall emotes become a thing (
)
Well, the ratio is calculated based on how they tile in this grid
So moving the determineRatio isnt really nessesary since its only needed in the emote menu
Everywhere else should just use the actual dimentions
@finite monolith

const ratio = L + youFellOff+ ripbozo;
seems like you just googled this
but they most certainly are
what people online mean when they are referring to this
is that they scale on retina or hidpi displays
or that when you zoom in the px size changes, but thats without saying
em and rem are based on the font size and therefor much more accessable
ie if a user has trouble seeing, they can elect to make the font size larger
so its not completely applicable everywhere but in most places it makes sense
i prefer rem over em though
yeah
em can get confusing fast since if you were to set the font size to 2em that just means 2 times whatever the parent font size was
so it chains up
!.
shirley
that won't crash everything
ok it didn't and it works well
the only problem is that this returns a size that's okay for the actual chat
but not for the display
Just calculate based on the bounding box

if your max-width is 8rem just do (8rem*height)/width
I guess that wouldnt work very well for narrow emotes
hmm

ideally
i just need to show a 3x or a 4x
based on how big the bounding box is
this is the value used for the actual chat emotes
i could probably just pass in a size var into this to make the tooltip emotes of a size -1
so they would be bigger
but it feels kinda donk
i'm 
I believe the function might give incorrect values in some cases right now aswell
since we map all emote types to the ActiveEmote
But we dont have a guarantee that they have sizes 1, 2, 3, 4
7tv emotes do, but the other providers might now
before
especially for the special cases of
emotes only having size 1
so being just 16x16
i need to get the size that's the closest to the bounding box size
and i'm a bit clueless
on how i can do that
You could probably replace the ```ts
${i + 1}x
with ```ts
`${f.name.charAt()}x`
Since all the filenames are formated like 1x or 1.0 or 1
what the fuck do i do
I guess the proper way would be to implement different reducers for each provider
there's no guarantee the file names are gonna keep having a number
ffz file names don't have a number
Different reducers it is then
for 7TV it's simple the width/Height values are provided
for the rest
just set a fixed size then fit the image in it
twitch global sizes

32 72 98?


not many ffz wides exist and no one uses bttv wide emotes so just default it to a square if it's non-7tv
BAND
does bttv let you do wide emotes now
yes
i feel like i remember him adding that
same time he added his version of the event api
yeah a couple months back just before night went on twitter to bitch about 7tv
these fucks are so bad i copied their shit


i guess i can try just forcing the emotes to a specific height
that would make their size a good size
We talked about calculating emote dimensions in the sharedworker
But probably wont be a thing for at least a little while
i thought about it but like
Would require the worker to dl all the emotes
itd require sending a network request to download every emote ahead of time
perhaps with wasm it would be possible to download only the headers
but thats dank territory
I think i need to change some stuff on the Emote component aswell
rust in the extension
Since the v-if unload happens on the same tick as the srcSet gets set to ""
So the img request is actually never canceled
Which renders the intersection observer kinda useless

with wasm you cant download anything
nice
you need to message pass to a js glue script
to access
any api
thats why it sucks
and is super slow

Lets make v4.0.0 right now 
also
why are we concerned about image dimensions
we know the image dimensions
atleast the aspect
the aspect should be identical
Not for other providers?
of 7TV emotes

we dont have to follow the images version of 4x or whatever multiple
we just say the height is always 3 times the height of 1x
and force the image into that box
yes
not neccissarily
we know the aspect too
because we have the original 1x image
already downloaded
(ideally)
No?
yes its a hover card
i suppose yea
you cant hover something thats not there
so we know the exact aspect ratio
we just need to scale it
and force whatever higher res image we download
to be that scaled size we expected
even if its a different multiple
this is better anyways
You could, if your internet is slow enough i guess 
yea

just use the ratio of the 1x emote to force the tooltip to that ratio beforehand

We could go 1 step further tho
yeah
Since it would also be nice to know the emote dimentions before inserting them into the chat
To avoid any popin

you can only do that with 7tv though
which is fine
easy fix tho
offload to the user
give users an option
image popin the first time they see an emote
or delay rendering
if you think you have fast enough internet
that youd just rather wait the additional ms to download
before you see anything

i think
therefore i am
yes this is fine
Yea, like the emote menu
unless it's 7tv and has dimensions in api
so yeah
apply the same thing as in the emote menu for chat
then it looks clean for slow internet ppl
also im thinking of defaulting the emote menu to static
and animating only on hover
or animating only on hover, in a radius around the cursor
request amount dont matter with media
We are already doing that @finite monolith
no he's being stupid
yes
and making a bad joke about foviated rendering
i am
yeah i'll fix the api , i dont rly like the static_name property tho
static_nam
we should
drop that
completely
and do like twitch does
with a templated format
yea
just specify somewhere in the api what the template is
not hardcoded
then you dont even need an image property
because it can be assumed that
if an emote really doenst have an image
the request will just fail
i mean other than that the ImageHost is fine i believe
with a known error
its rarely neccissary
to enumerate
because you know before hand
what you will need
whats so hard about it
yust set a ref on the img tag in ChatEmote and extract the width/height values
4me
then when the tooltip is called you pass those values as props
multiply by 3
done
no way that was so easy
yea do that then @finite monolith set a onload listener on the img tag in ChatEmote
and assign the width/height values to refs that are passed as props to the tooltip
yea store them in refs, should be easy to do
okay egg
maybe we should use naturalWidth
idk @daring gale do we ever restrict the size of emotes in chat
or do we always follow the image size
if its the latter than regular width should be fine
There is no max size
SubHype
let's not restrict size so we can be the last bastion of hope and fun next time people find an exploit to upload big emotes


I remember that day 
just thinking because width will be wrong if the size was restricted
lets intentionally restrict the size in the tooltip so you can see it better though

like if you imagine the width was restricted to 32px and the emote was wider, img.height would be wrong, the aspect would be right but we couldnt just multiply by 3 to get our size
.naturalHeight always represents the actual image size though pretty sure
me on my way to put a gigantic emote in my personal set that only i can use because i manually uploaded it to the cdn


you can just get a huge badge
technically you could but you'd have to swap out the set details every time
fourtf does that yea

yeah ive seen that fucking badge
actual internet terrorist

wdym 
was referring to this
le epic admin troll
although it's artificially limited in the sense that personal sets have restrictions
nah i meant like even more le epic troll
like you can only update a given personal slot once an hour atm

like using a random collection of emotes from anywhere on the site in any message at will 
oh 
Basically a /clear in any chat 
ant no way
Anyone know why the different twitch sub plans are named like Prime, 1000, 2000, 3000 ?
"Maybe we need a tier 1.5 in the future" 
floating point tiers
Well i've just assumed that 1000 is tier 1
$js "0.3 - 0.1"
treuks, 0.3 - 0.1
feelsdonkman
0.2 
$js 0.2 + 0.1
treuks, 0.30000000000000004
there we go
pretty sure its because of the way badges and perks are layed out
wdym
ie teir 3 20 month sub badge is 3020
ahh
Pft. I have a 3060 and it's way faster 
i have a 1030 
3080 
"You manage your money better than me" 
true 
Could have sold it for 2.5x the price tho
4060 will probably outperform a 3070 for the price of a 3060
waiting = free performance
I could've sold for like 2x the price
Not managing my money better, just poor 

how do i use the vue @onload directive
i cant figure out how i can get the emote size
on load
onload is in when the img has finished loading?
<img has an @ load i believe
Mind sending what your code looks like now?
uhh
i can send the entire chat emote file

what
i'm in a discord server??????????????????
<template>
<div class="emote-box">
<img
v-if="srcSet"
ref="imgRef"
class="chat-emote"
:srcset="srcSet"
:alt="emote.name"
:class="{ blur: hideUnlisted && emote.data?.listed === false }"
@click="openCard"
@load="let height = `NaM`;"
@mouseenter="show(imgRef)"
@mouseleave="hide()"
/>
<template v-for="(e, index) of emote.overlaid" :key="index">
<img
class="chat-emote zero-width-emote"
:class="{ blur: hideUnlisted && e.data?.listed === false }"
:srcset="getSrcSet(e)"
:alt="' ' + e.name"
/>
</template>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from "vue";
import { useConfig } from "@/composable/useSettings";
import { useTooltip } from "@/composable/useTooltip";
import { tools } from "@/site/twitch.tv/modules/chat/ChatBackend";
import ChatEmoteTooltip from "@/site/twitch.tv/modules/chat/components/ChatEmoteTooltip.vue";
const props = withDefaults(
defineProps<{
emote: SevenTV.ActiveEmote;
imageFormat?: SevenTV.ImageFormat;
unload?: boolean;
}>(),
{ unload: false, imageFormat: "WEBP" },
);
const srcSet = computed(() => (props.unload ? "" : getSrcSet(props.emote)));
function getSrcSet(emote: SevenTV.ActiveEmote) {
const host = emote.data?.host ?? { url: "", files: [] };
const format = host.files.some((fi) => fi.format === props.imageFormat) ? props.imageFormat : host.files[0]?.format;
return host.files
.filter((f) => f.format === format)
.map((f, i) => `${host.url}/${f.name} ${i + 1}x`)
.join(", ");
}
const imgRef = ref<HTMLElement>();
const { show, hide } = useTooltip(ChatEmoteTooltip, {
emote: props.emote,
width: Number,
height: Number,
});
there we go
Change this
const imgRef = ref<HTMLElement>();
to
const imgRef = ref<HTMLImageElement>();
define a function, with Event as argument, then set @load="onImageLoaded" (your func name)
then define 2 refs
const width = ref(0);
const height = ref(0);```
Do we even need the onload here?
in onImageLoaded, grab evt.target (which should be a HTMLImageElement)
Cant we just use the naturalWidth directly?
you cannot, the image width will be 0 if its not loaded
Yes, but it will be loaded when we hover right?
not necessarily
doesnt matter onload is better here
we don't need a permanent ref to the image
we only care about extracting its size once
its just a proxied value
So the setter and getter triggers side effects which lets vue have its reactivity
In the script you have to use asd.value to get or set
but in the <template it does it automatically
do i use the natural sizes
regular sizes are fine here
Probably dosnt matter
but yeah dont actually hold a ref to the image, just take evt.target in the onload event
we already hold a ref to the image
what for?
const target = event.target as HTMLImageElement;```
oh nice
not a huge fan of the show() and hide() thing when it could just be setting v-tooltip on the img tag
true
seems right yea, do an additional check here
if (!(ev.target instanceof HTMLImageElement)) return;```
actually im not sure about the performance of instanceof
maybe @unkempt hill knows
a null check is fine too i think
oh yeah
realistically it cannot be anything other than null or an image element
so instance check might be overkill
I mean, this is literally the same, since the values get updated once the img loads anyway ```ts
const { show, hide } = useTooltip(ChatEmoteTooltip, {
emote: props.emote,
width: imgRef.value.width,
height: imgRef.value.height,
});
And we already have the ref

Yea, super nice
i dont like this tho
generally the tooltip composable isnt ideal
it can just be a directive
i'll make that change later, keep it with an onload listener for future proofing
yeah vue 3 and the composition api let you write way less code to do things
But the 1x is always like 16px right
if youre trying to get at some constant its not going to work
Nah what I'm saying is
28*

uh, how will this work for high resolution stuff?
what high resolution stuff
Nah, im overthinking i believe
Like if the chat is using 3x emotes?

Will just setting the image size in the img tag work
welcome to vue 3

react copers are afraid of this channel



what does this do
life expectancy raised by 10 years
sets the width and height in css to that of a reactive value
react brain 

they dont have reactive values
everything has to go through predefined states only accessible inside the component
Pure functional "programming"
im sure you can do that with some fucking library with 3 weekly downloads
๐ holy fuck the cope is unreal
i never said that was a good thing โ
keep having fun with your entire component tree rerendering once you update one prop 

the thing about react is it was created at a time where the DOM performance was really really bad
so back then it made sense
but how it achieved what it did with its "virtual dom" was banking on the idea that they can just do a lot of calculations outside the DOM, and only issue dom mutations for things that did change
however this is a very primitive strategy
youre still gonna have hundreds or thousands of internal rerenders, which these days have not much difference with just mutating the DOM this many times
ya
frameworks have gotten smarter since the days of react
its a matter of time until facebook completely abandons it
Clueless
i like how workers can create caches that will withstand a nuclear bomb
the metaphorical nuclear bomb being when the user clears their cache the normal way
you have to go all the way to application tab -> storage and tick the thing at the very bottom in the devtools to clear it 
Even if โdisk-cache-dir and โmedia-cache-dir are both set to a tmpfs directory?
Legacy cosmetics v2 support added
its cached to absolute hell though
i dont even know long
probably until you reset your entire goddamn pc 

๐ค CAAAAAAACHE
i think i'll
like
add a button to clear the legacy cosmetics cache
but never actually clear it automatically
cause theres honestly 0 need to. its just there for the transitory period until all clients are updated
CATSH
I can't wait until everyone sees me using my heckin personal emotes

I just have to sit and be filled with 
when a situation happens where an emote is perfect but xqc is dumb and doesn't have the emote 
add a random usernamd and prefix to the popup though, to make it look like a sub emote

people can't get mad at 7tv then
elis emotes in xqc chat



It would be nice if 7TV showed the active 7TV users in the chat , so that I can do the math on 7TV viewers - current viewers = Plebs that won't get my emote enabled super doper funny money comment.
it should not be horrible
ive never tested
but theoretically its like barely any check
its just looking at the prototype
probably slightly worse the more inheritance you have
but we need to do this check anyways, or we should rather, because typescript is correct
when it says that target isnt always going to be the element you expect it to be
i dont think onload bubbles but there are other conditions i beleive where target might be incorrect, it could also just be null
and an instanceof check does both of those
@unkempt hill for mapping user IDs to messages, can we actually use a WeakMap here 
im trying to think of a way
to avoid doing iterations when handling a user getting timed out/banned
to modify the message properties
for what purpose?
you cant iterate a weakmap
yeah not to iterate
but b asically
the event for a timeout only gives us a user id
so we need to map user ids to messages
weakmap is basically just equivalent to setting a symbol'ed prop
on an object
except
it doesnt need to be an object
weakmap needs a pointer right
yeah
as the key
you still need referential access
to the object to retrieve its value
i think a regular map is fine
and not really any more overhead
we just need to keep it in sync
when we flush messages
flush the indexes too
yeah but it's mapped to user ids
so when the buffer clears old messages we'd need to iterate
im not sure i really see what the issue is
oh you mean like that
just do two maps then 
like a jagged array but a map
Wasnt the idea that we dont want to iterate
And we'd need one that has a message id as the key to handle deletions
no matter how you do it, you always know what you removed
and one that has userid's to handle bans/timeouts
you could keep message ids sort of like how i did the usermap in the trainwrecks site
We want to make this more efficient basically https://github.com/SevenTV/ExtensionV3/blob/eacf2d28d6f7b9051f9d7d1ef32e6087f245a476/src/site/twitch.tv/modules/chat/ChatController.vue#L250
cant you just keep two synced arrays and a map
wdym
like just keep a map of user ids to message ids and a map of message ids to message objects
when you flush the message buffer take all the messages ids you just removed
and remove them from the map of their user
you know exactly what messages you remove when you flush, so you should know what users those were from
iterating 10 messages is better
than iterating all of the messages
every time you want to delete
flushUserCache() {
if (this.seenUsers.indexed.length < 60) return;
const index = this.seenUsers.indexed;
const map = this.seenUsers.users;
const removed = index.splice(0, index.length - 31);
for (const id of removed) {
map.delete(id);
}
for (let i = 0; i < index.length; i++) {
const stale = map.get(index[i]);
if (stale) {
stale[0] = i;
}
}
},
updateUserCache(user: ChatUser) {
this.flushUserCache();
const stale = this.seenUsers.users.get(user.id);
if (stale) {
const index = stale[0];
this.seenUsers.indexed.splice(index, 1);
}
const index = this.seenUsers.indexed.push(user.id) - 1;
this.seenUsers.users.set(user.id, [index, user]);
},
},
``` this concept but without the index part
We also have the issue of the scrollBuffer
When the scrollbuffer overflows it never calls a flush tho
why do we let the scroll buffer overflow on its own?
just do the same thing then there
when we splice
grab the message objects we removed
lookup their users in the user table
and delete them from that set
so the structs are like
Map(UserID, Set(MessageID))
Map(MessageID, Set(Message))
Message[]
where the messages in the set
are referentially equal
to the messages in the array
yeah that should change actually, that should be a Map(MessageID, Index)
and we just keep it in sync
like the above code does for seen users
so message[] is the only place messages actually are stored in their full form
when we lookup we just grab index so we can splice out of the array
and delete from map
when we flush we just lookup in each of our maps, and delete, we have to order them though in a good way
to avoid having to reindex
every time we flush

if you reverse that maybe its better, so the map is the source of truth for the messages and the array is just the order
no reindexing issue then
so
Map(UserID, Set(MessageID))
Map(MessageID, Message)
MessageID[]
then when you flush the messages you retrieve from the map what you just removed, pull off the user and grab its message id set, and remove the message id from it
Uh, we use the Message[] for the chat-list
well then reindexing is unavoidable
you have to iterate
at some point
you will need to iterate
you could i suppose make messages like a node tree
just a big linked list
no reindexing or ordering problems
because you just pop out and update references
rendering then sucks though
because you must do it in order
you cant say give me message 100
but does vue even render like this?
if not then probably not a problem no?
im pretty sure it just needs an iterator
so like i mean
head = &Message
length = int
ids = Map(ID, &Message)
Message {
previous: &Message,
next: &Message,
user: &User,
contents: {}
}
User {
messages: &Message[],
}
ignore the heavy mixed language pseudo code
then when you want to delete a message by id
you just grab the message object
and update the previous node's next pointer
to your next pointer
or you can do this for as many messages as you'd like
if you want to delete an entire users messages, just do that for all of them
when you want to flush just start at head
and remove X nodes
you need to keep a length counter
somewhere
making an iterator is not a problem if thats what vue needs
in this structure the only thing that needs iteration is the user message map
but that will in all likelyhood be very small
comparitively
@daring gale I think this makes sense no?

thats if we can actually get vue to render this
but I think vue always renders from top to bottom
anyways
so
probably not a big deal
vue takes in any iteratable iirc
so a generator function should work just fine
that walks the nodes
so also to clarify here I mean for this to completely replace
the message list array
with a linked list
reindexing, poping, and deletions then are non issues
because we can store direct pointers to the nodes
and update their ancestors and children
without ever needing to iterate the whole thing
How would we use it together with the messageBuffer and scrollBuffer?
eliminate the scroll buffer and message buffer
just keep a different "head"
for the scroll
and then when we want to append
just set the tails parent
to the head of the scroll
when flushing we just go to the message head
and compare our length count
Think you would be able to implement this in a 10th of the time it would take me 
and remove however many nodes
we need to
its kind of like the same way git works sort of, if that helps to visualize it
where branches are just different head nodes
@eternal iron keep the iteration on mod messages for now tbh
we can look into this later
Thinking the same
Also just gonna ignore the scroll buffer for now
Worst case is that someone sees a message that should have been removed 
whats scroll buffer?
oh that
yea
oh like as in those dont get updated by mod actions if chat is paused?
correct
ok thats fine
just for beta though right
yeah
So much stuff that needs to be done 
just add a ticket on clickup so we remember
we're past much of the biggest tasks
@unkempt hill where the emojis 
๐ญ ๐น ๐ฅ ๐
nice emojis
yeah @teal knoll where are the emojis
๐
๐ right here
@eternal iron i think for card opener functions we might have to come back to the initial solution with the dummy message
Depends, we might be able to hook something
needs to be a bit more intelegent though
like we need to keep the message around
because eventually
twitch's native
can overflow
if too many fallback messages render
Is the dummy message so that twitch creates a msg instance we can hook?
so we need to keep its rendered instance and move it around
but i mightve been doing it wrong
in our hooked render func
I wonder how the merge into my branch is gonna look 


why merge back into your branch?
its gonna conflict pretty sure
Mine will probably have conflicts with master after this
fix conflicts when you merge to master
Wont that result in 2 commits on master?
Merge master into your branch I guess?
not if you do it properly
merge commits are commits
they usually are meant to contain the conflict fixes
in themselves
and then they have two parents
one to the original head
and another to your branch
github wont let you do it this way though
if you merge through gui
Make them look good

i was gonna mention, add the base style with the border and background blur to the base tooltip style
then replicate a somewhat similar layout
badge title and provider logo
or actually eh no provider logo
badge name would say it
just the image and the title
Lets make an option for the paint to cover the entire message when doing /me 
Imagine animated paints then 
Speaking of epilepsy
Do you think it would make sense to disable animations and make them work on hover if you have reduced motions enabled
yes but
i think we need to more consider
the animated emotes option in native twitch
that should take precidence
as well as ffz's option
maybe just an or is sufficient here
Oh fuck
any of the above being limited motion
That's a dank idea
should mean we should do that as well
Hooking the twitch option should be trivial
Yea
Truee
I think i commented saying that i should do that instead
how was the merge
Mereg
I should make it into an emote when I get the time to
mer-ge 
FFmpega TeaTime
The prop is on the same thing i hooked earlier for primaryColor and ReadableColors 

make it an emote
a git logo
with a ge face
i guess we should also add in mod icons later
just to make it look exactly like normal chat
...but the slider 
slider is pog but i can already see it
angry jannies coming into the discord
asking
where the FUCK is my permaban button

true mod slider should probably be a separate module
altho
we need to do like

i guess we could add slots in various places
for other modules to hook onto
yeah just like a namespace key modular hook system
core:message
then addons who make their own hooks
can be addon:hookname
yea
The slider benefits from wrapping the chatline tho
But it dosnt need to be solved that way
yeah thats why we can use vue <slot />
It does
place named <slot /> in various places where it might be useful for other modules to add content

Its part of the code right now since it was easy to port
can be moved later
explicit next();
compost bin
I feel like the useChatApi should be changed a bit in the future
Right now it feels like we bind anything and everything there
Which makes it return a lot of stuff we dont need
yeah it could be broken up a bit
useChatMessages, useChatStates, useEmotes







