Initial Release
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
extends _TemplateSpecial
|
||||
block pageHeader
|
||||
meta(name='robots' content='noindex')
|
||||
title suzzy - Page Not Found (404)
|
||||
block pageContent
|
||||
//- User Message
|
||||
img(class='special-banner' src='file:///images/public-nopage.png')
|
||||
p(class='text-header') Page Not Found
|
||||
p(class='text-tip') Should've made a left instead of a right...
|
||||
|
||||
//- User Actions
|
||||
div(class='divider-line')
|
||||
div(class='special-alongside')
|
||||
a(class='default' href='/') Homepage
|
||||
a(class='default' href='javascript:window.history.back()') Go Back
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
each e in relevantArticle.elements
|
||||
case e.type
|
||||
when 'text'
|
||||
p
|
||||
each t in e.items
|
||||
case t.tag
|
||||
when ''
|
||||
| #{t.content}
|
||||
when 'h'
|
||||
| #[span(class='text-hint') #{t.content}]
|
||||
when 'c'
|
||||
| #[span(class='text-code') #{t.content}]
|
||||
when 'a'
|
||||
| #[a(class='link-highlight' target=t.target href=t.href) #{t.content}]
|
||||
when 's'
|
||||
| #[s #{t.content}]
|
||||
when 'b'
|
||||
| #[b #{t.content}]
|
||||
when 'i'
|
||||
| #[i #{t.content}]
|
||||
when 'header'
|
||||
p(class='element-header' id=formatString(e.value)) #{e.value}
|
||||
when 'subheader'
|
||||
p(class='element-subheader' id=formatString(e.value)) #{e.value}
|
||||
when 'quote'
|
||||
p(class='text-quote') > #{e.value}
|
||||
when 'code'
|
||||
div(class='element-code')
|
||||
button(class='default') Copy
|
||||
pre !{e.content}
|
||||
when 'image'
|
||||
div(class='element-gallery')
|
||||
div(class='gallery-item')
|
||||
img(class='special-dropshadow' loading='lazy' src=e.resource alt=e.alt)
|
||||
p #{e.caption}
|
||||
when 'video'
|
||||
div(class='element-gallery')
|
||||
div(class='gallery-item')
|
||||
video(class='special-dropshadow' controls preload='none' poster=e.cover)
|
||||
source(src=e.resource)
|
||||
p #{e.caption}
|
||||
when 'audio'
|
||||
div(class='element-audio special-shadow')
|
||||
audio(preload='auto')
|
||||
//- Audio Metadata
|
||||
div(class='audio-container')
|
||||
p #{e.name}
|
||||
a(class='audio-download' title='Download Track' download=e.resource href=e.resource)
|
||||
img(src='file://icons/icon-download.svg' alt='Icon for Download')
|
||||
//- Audio Controls
|
||||
div(class='audio-container')
|
||||
button(class='audio-button' title='Play/Pause Audio')
|
||||
img(src='file://icons/icon-play.svg' alt='Icon for Play/Pause')
|
||||
input(class='audio-slider' type='range' value='0' disabled)
|
||||
p(class='audio-time') -:--/-:--
|
||||
when 'table'
|
||||
table(class='element-table special-shadow')
|
||||
- var firstRow = e.items.at(0)
|
||||
- var otherRow = e.items.slice(1)
|
||||
thead
|
||||
tr
|
||||
each column in firstRow
|
||||
th #{column}
|
||||
tbody
|
||||
each row in otherRow
|
||||
tr
|
||||
each column in row
|
||||
td #{column}
|
||||
when 'list'
|
||||
ul(class='element-list')
|
||||
each listItem in e.items
|
||||
li • #{listItem}
|
||||
when 'banner'
|
||||
img(class='element-banner' src=e.resource alt=e.alt)
|
||||
when 'beanie'
|
||||
a(href=e.resource download=(e.resource.split('/').at(-1).split('?').at(0)))
|
||||
img(class='element-beanie' src=e.resource alt=e.alt)
|
||||
default
|
||||
- throw "Unknown Type: " + e.type
|
||||
@@ -0,0 +1,67 @@
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1')
|
||||
link(rel='icon' type='image/png' href='file://images/favicon.png')
|
||||
link(rel='stylesheet' href='file://fonts/font-poppins.css')
|
||||
link(rel='stylesheet' href='file://styles/template-global.css')
|
||||
link(rel='stylesheet' href='file://styles/template-modals.css')
|
||||
link(rel='stylesheet' href='file://styles/template-profile.css')
|
||||
meta(property='theme-color' content='#A1A8FF')
|
||||
block pageHeader
|
||||
body
|
||||
noscript
|
||||
style.
|
||||
noscript div {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
noscript p {
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
div.wrapper-layout {
|
||||
display: none;
|
||||
}
|
||||
div
|
||||
p This webpage requires JavaScript to be enabled.
|
||||
a(href='/') Go to Homepage
|
||||
|
||||
div(class='wrapper-layout')
|
||||
div(class='wrapper-navigation')
|
||||
- var PAGE = filename.split('\\').at(-1).split('.').at(0)
|
||||
a(href='/')
|
||||
img(class='navigation-logo' src='file://images/public-logo.png' alt='Logo for suzzy games')
|
||||
a(active=(PAGE === 'index') class='navigation-link' href='/profile')
|
||||
img(src='file://icons/icon-user.svg' alt='Icon for Profile')
|
||||
span Profile
|
||||
a(active=(PAGE === 'security') class='navigation-link' href='/profile/security')
|
||||
img(src='file://icons/icon-lock.svg' alt='Icon for Security')
|
||||
span Security
|
||||
a(active=(PAGE === 'devices') class='navigation-link' href='/profile/devices')
|
||||
img(src='file://icons/icon-mobile.svg' alt='Icon for Devices')
|
||||
span Devices
|
||||
a(active=(PAGE === 'connections') class='navigation-link' href='/profile/connections')
|
||||
img(src='file://icons/icon-plug.svg' alt='Icon for Connections')
|
||||
span Connections
|
||||
a(active=(PAGE === 'applications') class='navigation-link' href='/profile/applications')
|
||||
img(src='file://icons/icon-app.svg' alt='Icon for Applications')
|
||||
span Applications
|
||||
|
||||
div(class='divider-line')
|
||||
a(class='navigation-link' href='/profile/redeem')
|
||||
img(src='file://icons/icon-star.svg' alt='Icon for Redeem Code')
|
||||
span Redeem Code
|
||||
a(class='navigation-link' href='/')
|
||||
img(src='file://icons/icon-exit.svg' alt='Icon for Sign Out')
|
||||
span Sign Out
|
||||
|
||||
div(class='wrapper-content')
|
||||
block pageContent
|
||||
|
||||
script(src='file://scripts/shared-utils.ts')
|
||||
@@ -0,0 +1,15 @@
|
||||
//- Collection Alerts and Errors
|
||||
div(class='collection-alert' id='alert-loading')
|
||||
img(src='file://icons/diagram-loading.svg' alt='Icon for Loading')
|
||||
span Loading #{loading_message ||'Content'}
|
||||
div(class='collection-alert' id='alert-error' hidden)
|
||||
img(src='file://icons/icon-cross.svg' alt='Icon for Cross')
|
||||
span An Error Has Occurred
|
||||
|
||||
if empty_message
|
||||
div(class='collection-alert' id='alert-empty' hidden)
|
||||
img(src=empty_source alt=`Icon for ${empty_alt}`)
|
||||
span #{empty_message}
|
||||
|
||||
//- Collection Items
|
||||
div(class='wrapper-collection')
|
||||
@@ -0,0 +1,66 @@
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
meta(charset='UTF-8')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1.0')
|
||||
link(rel='icon' type='image/png' href='file://images/favicon.png')
|
||||
link(rel='stylesheet' href='file://fonts/font-poppins.css')
|
||||
link(rel='stylesheet' href='file://styles/template-global.css')
|
||||
link(rel='stylesheet' href='file://styles/template-public.css')
|
||||
link(rel='stylesheet' href='file://styles/template-modals.css')
|
||||
meta(property='theme-color' content='#A1A8FF')
|
||||
block pageHeader
|
||||
body
|
||||
//- Navigation Bar
|
||||
div(class='wrapper-navigation')
|
||||
div(class='container-navigation')
|
||||
//- Left-Hand: Site Navigation
|
||||
div(class='navigation-side' id='navigation-left')
|
||||
a(href="/" style="display:grid;" tabindex="0")
|
||||
img(
|
||||
class='navigation-logo'
|
||||
src='file://images/public-logo.png'
|
||||
alt='Logo for suzzy games'
|
||||
)
|
||||
p(class='text-muted') •
|
||||
a(class='text-link' href='/blog') Blog
|
||||
a(class='text-link' href='/library') Library
|
||||
a(class='text-link' href='/projects') Projects
|
||||
//- Right-Hand: User & Site Status
|
||||
div(class='navigation-side' id='navigation-right')
|
||||
a(class='special-shadow' id='navigation-status' href='https://status.suzzygames.com/' title='Server Status')
|
||||
div(id='status-dot' class='status-dot special-pulse')
|
||||
p(id='status-text' class='text-tip') Loading
|
||||
a(id='navigation-profile' class='special-shadow' title='Manage Account')
|
||||
|
||||
//- Content Dividers
|
||||
//- div.divider-navigation: Spacer for Navigation Bar on Desktop
|
||||
//- div.divider-mobile: Line Divider only present on Mobile
|
||||
div(class='divider-navigation')
|
||||
div(class='divider-line divider-mobile')
|
||||
|
||||
//- Escape Content Wrapper for elements that required the full width of the page
|
||||
block pageEscaped
|
||||
|
||||
//- Wrapper for Page Content
|
||||
div(class='wrapper-content')
|
||||
block pageContent
|
||||
|
||||
//- Wrapper for Page Footer
|
||||
div(class='wrapper-footer')
|
||||
div(class='container-footer')
|
||||
div(class='footer-links')
|
||||
a(class='footer-link' target='_blank' href='https://twitter.com/bakonpancakz' title='Twitter Account for bakonpancakz')
|
||||
img(src='file://images/brands/logo-x.png' alt='Logo for X')
|
||||
a(class='footer-link' target='_blank' href='https://discord.gg/invite/bvTCZavXUU' title='Discord Server for suzzy games')
|
||||
img(src='file://images/brands/logo-discord.png' alt='Logo for Discord')
|
||||
a(class='footer-link' target='_blank' href='https://www.roblox.com/groups/10781692' title='ROBLOX Group for suzzy games')
|
||||
img(src='file://images/brands/logo-roblox.png' alt='Logo for Roblox')
|
||||
p(class='text-tip')
|
||||
| © 2021-2024 suzzy games. All Rights Reserved.
|
||||
a(class='text-tip text-muted' href='/challenge-picross' style='text-decoration: none;')
|
||||
| Developed with ♡ by bakonpancakz
|
||||
|
||||
//- Page Scripts
|
||||
script(src='file://scripts/shared-utils.ts')
|
||||
script(src='file://scripts/shared-public.ts')
|
||||
@@ -0,0 +1,17 @@
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1')
|
||||
link(rel='icon' type='image/png' href='file://images/favicon.png')
|
||||
link(rel='stylesheet' href='file://fonts/font-poppins.css')
|
||||
link(rel='stylesheet' href='file://styles/template-global.css')
|
||||
link(rel='stylesheet' href='file://styles/template-modals.css')
|
||||
link(rel='stylesheet' href='file://styles/template-special.css')
|
||||
meta(property='theme-color' content='#A1A8FF')
|
||||
block pageHeader
|
||||
body
|
||||
div(class='wrapper-special')
|
||||
div(class='container-special')
|
||||
block pageContent
|
||||
script(src='file://scripts/shared-utils.ts')
|
||||
block pageEscaped
|
||||
@@ -0,0 +1,182 @@
|
||||
<article
|
||||
id="hello-world"
|
||||
created="Apr 17 2024"
|
||||
categoryId="behind-the-scenes"
|
||||
authorId="bakonpancakz"
|
||||
title="Hello World!"
|
||||
snippet="Breaking the radio silence what has bakonpancakz been up to? And what exactly is a suzzy?"
|
||||
banner="file://blog/hello-world/banner.gif"
|
||||
noindex="false"
|
||||
>
|
||||
<header>Welcome to suzzy games!</header>
|
||||
<text>
|
||||
I made this site to serve as a hub for my game development hobby. There
|
||||
is no theme, there is no incentive, just pure passion and efficient code.
|
||||
I'll be sharing previews, progress, and generally whatever comes to mind.
|
||||
So that's what this site is for! And this post contains a bunch of previews
|
||||
of things I've worked on that <b>might</b> become their own game in the
|
||||
future.
|
||||
</text>
|
||||
<quote>Except for Cart Ride that one was just an update :P</quote>
|
||||
|
||||
<!-- Game: Cart Ride around a Fumo -->
|
||||
<header>Cart Ride Around a Fumo</header>
|
||||
<text>
|
||||
<a href="https://www.roblox.com/games/9987852646/Cart-Ride-Around-a-Fumo">Cart Ride Around a Fumo</a>
|
||||
is my own spin on the cart ride genre that was all over in the olden days
|
||||
of ROBLOX. It's a labor of love with way too much effort put into it, but
|
||||
I like to look back at it and try to match that level of quality for
|
||||
everything I do.
|
||||
</text>
|
||||
<quote>Why Fumos? Because they're funny.</quote>
|
||||
<text>
|
||||
I spent a whole two months on it and again, put way more effort into it
|
||||
than I should have, but that's just how I roll (⌐■_■). I actually got a
|
||||
lot of my cousins to playtest it and everybody had a lot of fun blowing
|
||||
each other up. Which I like to think is what kickstarted my passion.
|
||||
<h>(my origin story)</h>
|
||||
</text>
|
||||
<image
|
||||
caption="Home Sweet Home"
|
||||
alt="Overhead view of the in-game track"
|
||||
resource="file://blog/hello-world/craf-1.jpeg"
|
||||
/>
|
||||
<text>
|
||||
Around ten people play it daily and people are still donating despite
|
||||
its age, so I definitely did something right. (^_^) It even has a
|
||||
couple videos on it, one of <a href="https://www.youtube.com/watch?v=Jjep6xt3PiM">friends just having fun</a>,
|
||||
and a <a href="https://www.youtube.com/watch?v=fyoQxBuR1Mo">super duper edited one</a>.
|
||||
</text>
|
||||
<quote>Thanks guys <3</quote>
|
||||
<text>
|
||||
I actually planned to release a major update for it which would have added
|
||||
cart customization and a track editor. But the update grew too large in
|
||||
scope and is now being developed as its own standalone game.
|
||||
<h>(stay tuned!)</h>
|
||||
</text>
|
||||
<text>
|
||||
It's nothing too interesting in my opinion but here's what one of the
|
||||
menus looked like.
|
||||
</text>
|
||||
<image
|
||||
caption="(Scrapped) Cart Selection Menu"
|
||||
alt="Screenshot of a scrapped concept showcasing cart customization"
|
||||
resource="file://blog/hello-world/craf-2.jpeg"
|
||||
/>
|
||||
|
||||
<!-- Game: Five Nights at Kanye 2 -->
|
||||
<header>Five Nights at Kanye 2</header>
|
||||
<text>
|
||||
The <a href="https://www.roblox.com/games/13051172029/Five-Nights-at-Kanyes-FNAK-CLASSIC">original FNAK</a>
|
||||
was made in only a few hours but my friends really liked the idea so I fleshed it
|
||||
out a bit more and released a <a href="https://www.roblox.com/games/11229358049/Five-Nights-at-Kanyes-FNAK">remastered version</a>
|
||||
just for fun. A few people liked it and sent me messages asking for a second
|
||||
entry so I actually worked on it for a bit.
|
||||
</text>
|
||||
<image
|
||||
caption="Main Menu"
|
||||
alt="Main Menu for Five Nights at Kanyes 2, taking place in a dimly lit restaurant"
|
||||
resource="file://blog/hello-world/fnak-1.jpeg"
|
||||
/>
|
||||
<image
|
||||
caption="Kanye's Mansion (Courtyard)"
|
||||
alt="Wide angle view of the courtyard in Kanye's Mansion"
|
||||
resource="file://blog/hello-world/fnak-2.jpeg"
|
||||
/>
|
||||
<image
|
||||
caption="Kanye's Mansion (Overhead with Layout)"
|
||||
alt="Overhead view of Kanye's Mansion with each room labelled"
|
||||
resource="file://blog/hello-world/fnak-3.jpeg"
|
||||
/>
|
||||
<text>
|
||||
The story I had in mind was that this was a prequel to the first game,
|
||||
and this was the night you broke into Kanye's house to steal DONDA 3
|
||||
for Twitter clout <s>(now called x lol)</s>. Over the course of five
|
||||
nights you <h>(and up to 3 other friends)</h> were supposed to collect
|
||||
story items that would unlock another room after each night.
|
||||
</text>
|
||||
<text>
|
||||
Kanye was also intended to have a better than average AI that would actively
|
||||
hunt you down as you made mistakes. Something as small as leaving a light on
|
||||
would make him suspicious and have him start to slowly but surely hunt you
|
||||
down <h>(working as a soft time limit)</h>.
|
||||
</text>
|
||||
<text>
|
||||
For some added suspense, the music changes as Kanye's suspicious level changes.
|
||||
All the way from clueless to chasing you down. It is based on Kanye's track
|
||||
<a href="https://open.spotify.com/track/3JWiDGQX2eTlFvKj3Yssj3">Closed on Sunday</a>
|
||||
and made by Dakota <h>(he'll get a proper shoutout later!)</h>
|
||||
</text>
|
||||
<audio name="FNAK Stage 1 - We are Here (Arrival)" resource="file://blog/hello-world/FNAK_Stage_1.mp3"/>
|
||||
<audio name="FNAK Stage 2 - Something Isn't Right (Tracking)" resource="file://blog/hello-world/FNAK_Stage_2.mp3"/>
|
||||
<audio name="FNAK Stage 3 - He's Near (Tracking, Close)" resource="file://blog/hello-world/FNAK_Stage_3.mp3"/>
|
||||
<audio name="FNAK Stage 4 - Found you (Chasing)" resource="file://blog/hello-world/FNAK_Stage_4.mp3"/>
|
||||
|
||||
<!-- Game: Project Z -->
|
||||
<header>Project Z</header>
|
||||
<text>
|
||||
Project Z is a <i>player-versus-player, first-person shooter, zombie survival</i>
|
||||
game where you barricade yourself into a room and fight off zombified
|
||||
players for six waves with each wave unlocking new zombie classes and
|
||||
zombie bosses. <h>Did you get all that?</h>
|
||||
</text>
|
||||
<text>
|
||||
I worked on a few systems <h>(UI, Social, Weapons, etc)</h> but never
|
||||
got around to making an actual working prototype to fully test the
|
||||
idea out. Even worse is that changes to ROBLOX suddenly broke my
|
||||
scripts so I can't even show them off except for in this equally
|
||||
terrible quality video.
|
||||
</text>
|
||||
<text>
|
||||
It's definitely a cool idea and I will most likely revisit it in the
|
||||
future and give the love it deserves. This idea actually borrows a ton
|
||||
from the original <a href="https://steamcommunity.com/sharedfiles/filedetails/?id=105462463">Garry's Mod Zombie Survival</a>
|
||||
which I used to play it all the time back in middle school and really
|
||||
wanted to bring the idea to modern audiences.
|
||||
</text>
|
||||
<video
|
||||
caption="Broken Weapons and Sprays"
|
||||
cover="file://blog/hello-world/ProjectZ-Cover.jpeg"
|
||||
resource="file://blog/hello-world/ProjectZ.mp4"
|
||||
/>
|
||||
|
||||
<!-- Section: The Plan -->
|
||||
<header>What now?</header>
|
||||
<text>
|
||||
Well, I'm going back to working on that standalone project I mentioned
|
||||
earlier! It's called Project Monke and you can think of it as Super
|
||||
Monkey Ball and Super Mario Maker put together. It has online services
|
||||
<h>(which is why you can create an account btw)</h> so that should give
|
||||
you an idea of how large of a scope this project has.
|
||||
</text>
|
||||
<text>
|
||||
If you make an account there isn't really a whole lot you can do with it
|
||||
now, except for some profile customization and security related features.
|
||||
I'll be adding comments to the site at a later date, but for now the
|
||||
foundation has been set.
|
||||
</text>
|
||||
<image
|
||||
caption="And for all the nerds out there, the backend is written in Go, the frontend is hand-written PUG+CSS+JS, and served using NGINX, on my personal server (nicknamed miku)"
|
||||
alt="Picture of a computer stuffed in the closest with a Hatsune Miku sticker slapped in the corner"
|
||||
resource="file://blog/hello-world/peak-performance.jpeg"
|
||||
/>
|
||||
|
||||
<!-- Section: Special Thanks -->
|
||||
<header>Special Thanks to Dakota</header>
|
||||
<text>
|
||||
Before I go, I'd also like to share a couple more tracks from Dakota
|
||||
<s>who I have locked in my basement</s> who graciously offered to make
|
||||
music for my projects. He also made the Five Nights at Kanye tracks you
|
||||
heard earlier. <a href="https://soundcloud.com/user-627340075">Check out his Soundcloud!</a> ^_^
|
||||
</text>
|
||||
<audio name="Project Monke - Settings" resource="file://blog/hello-world/ProjectMonke_Settings.mp3"/>
|
||||
<audio name="FNAK - Settings (Original)" resource="file://blog/hello-world/FNAK_Options_Original.mp3"/>
|
||||
<audio name="FNAK - Settings (In-Game)" resource="file://blog/hello-world/FNAK_Options_InGame.mp3"/>
|
||||
<video
|
||||
caption="inside joke :3"
|
||||
cover="file://blog/hello-world/settings-Cover.jpeg"
|
||||
resource="file://blog/hello-world/settings.mp4"
|
||||
/>
|
||||
<quote>p.s. wanna leave an encouraging comment or question? Leave a comment on my twitter!</quote>
|
||||
<quote>p.p.s there's an easter egg hidden somewhere on this site for users, I hope you love picross as much as I do~</quote>
|
||||
</article>
|
||||
@@ -0,0 +1,103 @@
|
||||
<article
|
||||
id="repo-of-knowledge"
|
||||
created="May 12 2024"
|
||||
categoryId="behind-the-scenes"
|
||||
authorId="bakonpancakz"
|
||||
title="Repo of Knowledge"
|
||||
snippet="Fresh paint, building libraries, and starting side-projects (again). Welcome to new suzzy games website!"
|
||||
banner="file://blog/repo-of-knowledge/banner.png"
|
||||
noindex="false"
|
||||
>
|
||||
<!-- Introduction -->
|
||||
<header>A Fresh Coat of Paint</header>
|
||||
<text>
|
||||
<b>Welcome to the new and improved suzzy games website!</b>
|
||||
</text>
|
||||
<text>
|
||||
Absolutely everything on this site has been either upgraded or replaced
|
||||
entirely. The blog system went from janky to proper, pages are now full
|
||||
of content and trivia instead of being half-baked, and a new library was
|
||||
built. <h>More on this later!</h>
|
||||
I dedicated an entire weekend to turn this site from potato to french
|
||||
fry. I absolutely love how it looks now and I hope you do too.
|
||||
</text>
|
||||
<quote>Sometimes I open up the website just to stare at it @_@</quote>
|
||||
<image
|
||||
caption="New and Improved!"
|
||||
alt="A 4 by 4 grid showing the old site on top and the new site design on the bottom"
|
||||
resource="file://blog/repo-of-knowledge/SITE_SHOWCASE.jpg"
|
||||
/>
|
||||
|
||||
<!-- New Feature: oAuth2 -->
|
||||
<header>Introducing oAuth2</header>
|
||||
<text>
|
||||
<b>Are you a developer? Then this chapter is for you!</b> Applications
|
||||
and oAuth2 are now available for everybody! This allows third-party
|
||||
developers to safely access your profile and the game data that
|
||||
<b>you</b> decide to share with them.
|
||||
</text>
|
||||
<text>
|
||||
New features and subsequent documentation on those features will become
|
||||
available for developers in the library.
|
||||
<h>Which brings us to the next topic...</h>
|
||||
</text>
|
||||
<image
|
||||
caption="oAuth2 User Interface (You've seen one of these before right?)"
|
||||
alt="An example oAuth2 prompt asking the user to allow access to certain account permissions"
|
||||
resource="file://blog/repo-of-knowledge/OAUTH2_SHOWCASE.png"
|
||||
/>
|
||||
|
||||
<!-- New Feature: Developer Docs -->
|
||||
<header>Building a Library</header>
|
||||
<text>
|
||||
<a href='/library'>The library</a> is a new section of the suzzy website!
|
||||
It contains legal stuff, branding guidelines, and most importantly
|
||||
documentation for developers. If you're really bored check out the
|
||||
<a href="/library/home/branding" target="_blank">branding article</a>!
|
||||
It contains little bits of trivia on all past suzzy projects.
|
||||
</text>
|
||||
<image
|
||||
caption="Library Homepage (Its Boo!)"
|
||||
alt="A preview for the suzzy games library with the mascot sitting on a bean bag in their room reading a book"
|
||||
resource="file://blog/repo-of-knowledge/LIBRARY_SHOWCASE.png"
|
||||
/>
|
||||
|
||||
<!-- Announcement: New 2D Game Engine -->
|
||||
<header>Introducing BECCA2D</header>
|
||||
<video
|
||||
caption="BECCA2D Splash Screen"
|
||||
resource="file://blog/repo-of-knowledge/BECCA2D_TEASER.mp4"
|
||||
cover="file://blog/repo-of-knowledge/BECCA2D_TEASER_COVER.png"
|
||||
/>
|
||||
<text>
|
||||
<b>Introducing BECCA2D!</b> An <i>in-house 2D Game Engine</i> designed
|
||||
from the ground up to be lightweight, efficient, extensible, and run in
|
||||
Google Chrome. <h>sorry firefox users :p</h>
|
||||
</text>
|
||||
<text>
|
||||
I'm planning on using this engine in a new side-project, a side-scrolling
|
||||
style platformer fangame based on a certain fish vtuber I've taken a liking
|
||||
to recently. This fangame also shares a considerable amount of features with
|
||||
Project Monke, so this will also serve as a personal training ground of sorts.
|
||||
</text>
|
||||
<text>
|
||||
But that's all I'm sharing about this side-project for today! I'll be making
|
||||
a dedicated post on the engine showcasing its features, design, and reasoning
|
||||
soon™
|
||||
</text>
|
||||
|
||||
<!-- Summary -->
|
||||
<header>Epilogue</header>
|
||||
<text>
|
||||
So that's my content dump for the month. Again I'm still working on new
|
||||
stuff and it'll all be done and released eventually
|
||||
<h>gimme like six months or something :P</h>
|
||||
</text>
|
||||
<image
|
||||
caption="ok that's it see you soon™"
|
||||
alt="A man holding the ball standing in front a white board with the words soon trademarked"
|
||||
resource="file://blog/repo-of-knowledge/conclusion.png"
|
||||
/>
|
||||
<quote>p.s. I got a drawing tablet! nothing crazy just a wacom one! expect more doodles all over the site now</quote>
|
||||
<quote>p.p.s still no blog comments btw >.></quote>
|
||||
</article>
|
||||
@@ -0,0 +1,104 @@
|
||||
extends ../_TemplatePublic
|
||||
block pageHeader
|
||||
link(rel='stylesheet' href='file://styles/browser-blog.css')
|
||||
meta(property='og:image' content='file://images/public-logo-og.png')
|
||||
meta(property='og:title' content='suzzy games - blog')
|
||||
meta(property='og:description' content='News and Updates straight from the source.')
|
||||
meta(name='description' content='News and Updates straight from the source.')
|
||||
title suzzy games - blog
|
||||
style.
|
||||
div.divider-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
block pageEscaped
|
||||
div(class='widget-wrapper background-scroll')
|
||||
|
||||
//- Widget: Latest Articles
|
||||
div(class='widget')
|
||||
p(class='text-header') > Latest <
|
||||
div(class='widget-latest-articles')
|
||||
- var recents = articles.slice(0, 4)
|
||||
each article, index in recents
|
||||
div(class='latest-item')
|
||||
img(class='latest-banner special-dropshadow' alt=`Banner Image for Blog Post '${article.info.title}'` src=article.info.banner)
|
||||
div(class='latest-content')
|
||||
p(class='text-headline') #{article.info.title}
|
||||
div(class='latest-info')
|
||||
p(class='text-tip text-muted') #{article.author.name}
|
||||
p(class='text-tip text-muted') • #{formatDate(article.info.created)} •
|
||||
p(class='text-tip text-muted') #{article.category.name}
|
||||
div(class='divider-header')
|
||||
p(class='text-tip') #{article.info.snippet}
|
||||
a(class='text-tip text-muted' href=`/blog/${article.category.id}/${article.info.id}`)
|
||||
| Read More (#{calcReadTime(article.elements)} minutes)
|
||||
|
||||
//- Widget: Latest Controls
|
||||
div(class='widget widget-latest-controls')
|
||||
div(class='latest-spacer')
|
||||
div(class='latest-controls')
|
||||
button(class='default' id='latest-last' aria-label='Last Blog Post') <
|
||||
each _, index in recents
|
||||
div(class='dot-circle' + (index === 0 ? ' dot-active' : ''))
|
||||
button(class='default' id='latest-next' aria-label='Next Blog Post') >
|
||||
script(src='file://scripts/browser-blog.ts')
|
||||
|
||||
block pageContent
|
||||
div(class='main-wrapper')
|
||||
|
||||
//- Browser Filters
|
||||
div(class='main-aside')
|
||||
p(class='text-header') > Browser <
|
||||
a(class=`filter-link ${!relevantCategory ? 'filter-active' : ''}` href='/blog')
|
||||
img(class='filter-icon' alt='Icon for Anything' src='file://blog/category-any.png')
|
||||
p(class='filter-name text-tip') Anything
|
||||
each category in categories
|
||||
a(
|
||||
href=`/blog/${category.id}`
|
||||
class=`filter-link ${relevantCategory && (relevantCategory.id === category.id ? 'filter-active' : '')}`
|
||||
)
|
||||
img(class='filter-icon' alt=`Icon for Category ${category.name}` src=category.icon)
|
||||
p(class='filter-name text-tip') #{category.name}
|
||||
div(class='divider-dashed')
|
||||
|
||||
//- Browser Articles
|
||||
div(class='main-content' role='main')
|
||||
if relevantArticles.length === 0
|
||||
//- No Articles Found
|
||||
div(class='collection-empty')
|
||||
img(aria-hidden='true' alt='Icon for No Posts' src='file://images/public-noposts.png')
|
||||
p(class='text-muted') no blog posts found
|
||||
else
|
||||
//- Article Previews
|
||||
each article, index in relevantArticles
|
||||
a(class='collection-item' href=`/blog/${article.category.id}/${article.info.id}`)
|
||||
img(class='item-banner' alt=`Banner Image for Blog Post ${article.info.title}` src=article.info.banner)
|
||||
div(class='item-content')
|
||||
p(class='text-header') #{article.info.title}
|
||||
div(class='item-info')
|
||||
img(class='filter-icon icon-small' alt=`Icon for Category ${article.category.name}` src=article.category.icon)
|
||||
p(class='text-tip') #{article.category.name}
|
||||
//- img(class='filter-icon icon-small' alt=`Avatar for Author ${article.author.name}` src=article.author.icon)
|
||||
//- p(class='text-tip') #{article.author.name}
|
||||
p(class='text-tip text-muted item-bull') •
|
||||
p(class='text-tip') #{formatDate(article.info.created)}
|
||||
p(class='text-tip text-muted item-bull') •
|
||||
p(class='text-tip') #{calcReadTime(article.elements)} minute read
|
||||
p(class='text-tip text-muted') #{article.info.snippet}
|
||||
|
||||
//- Page Select
|
||||
if relevantArticles.length !== 0
|
||||
div(class='main-wrapper')
|
||||
div(class='main-aside')
|
||||
div(class='main-content' role='main')
|
||||
div(class='collection-pageselect')
|
||||
- var isLastPage = (pageCurrent === 1)
|
||||
- var noNextPage = (pageCurrent === pageTotal)
|
||||
- var BASE_URL = '/blog' + (relevantCategory ? `/${relevantCategory.id}` : '')
|
||||
- var hrefLastPage = BASE_URL + (pageCurrent === 2 ? '' : (isLastPage ? '' : `/${pageCurrent - 1}`))
|
||||
- var hrefNextPage = BASE_URL + (noNextPage ? '' : `/${pageCurrent + 1}` )
|
||||
|
||||
a(class='default text-tip' href=(hrefLastPage) disabled=(isLastPage)) <
|
||||
each _, index in Array(pageTotal)
|
||||
div(class=('dot-circle ' + (index === (pageCurrent-1) ? 'dot-active': '')).trim())
|
||||
a(class='default text-tip' href=(hrefNextPage) disabled=(noNextPage)) >
|
||||
div(class='divider-spacer')
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"itemsPerPage": 8,
|
||||
"authors": [
|
||||
{
|
||||
"id": "bakonpancakz",
|
||||
"name": "bakonpancakz",
|
||||
"icon": "file://blog/author-bakonpancakz.png"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"id": "behind-the-scenes",
|
||||
"name": "Behind The Scenes",
|
||||
"icon": "file://blog/category-bts.png"
|
||||
},
|
||||
{
|
||||
"id": "project-monke",
|
||||
"name": "Project Monke",
|
||||
"icon": "file://blog/category-pm.png"
|
||||
}
|
||||
],
|
||||
"articles": [
|
||||
"04.17.24.Hello World.xml",
|
||||
"05.03.24.Repo of Knowledge.xml"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
extends ../_TemplatePublic
|
||||
block pageHeader
|
||||
- const article = relevantArticle
|
||||
- const author = relevantArticle.author
|
||||
- const category = relevantArticle.category
|
||||
link(rel='stylesheet' href='file://styles/browser-blog.css')
|
||||
link(rel='stylesheet' href='file://styles/template-article.css')
|
||||
meta(property='og:title' content=article.info.title)
|
||||
meta(property='og:description' content=`By ${author.name} on ${formatDate(article.info.created)}\n---\n${article.info.snippet}`)
|
||||
meta(name='description' content=`By ${author.name} on ${formatDate(article.info.created)}\n---\n${article.info.snippet}`)
|
||||
meta(property='og:image' content=`${article.info.banner}?direct=true`)
|
||||
meta(property='twitter:card' content='summary_large_image')
|
||||
title blog | #{article.info.title} (#{category.name})
|
||||
|
||||
block pageContent
|
||||
div(class='main-wrapper')
|
||||
|
||||
//- Layout: Sidebar
|
||||
div(class='main-aside article-chapters')
|
||||
p(class='text-headline') Chapters
|
||||
each element in article.elements
|
||||
if (element.type === 'header')
|
||||
a(href=`#${formatString(element.value)}` class='text-tip') • #{element.value}
|
||||
a(class='text-tip text-muted' href='#') ▲ Back to Top
|
||||
|
||||
//- Mobile Users get a small triangle in the bottom right instead
|
||||
a(class='default mobile-home' href='#home') ▲
|
||||
|
||||
//- Layout: Article
|
||||
div(class='main-content' role='main' id='home')
|
||||
//- Article Headeer
|
||||
img(
|
||||
class='article-banner special-dropshadow'
|
||||
alt=`Banner for ${article.info.title}`
|
||||
src=article.info.banner
|
||||
)
|
||||
p(class='text-hero article-header') #{article.info.title}
|
||||
div(class='article-header')
|
||||
div(class='item-info')
|
||||
img(class='filter-icon' alt=`Icon for Category ${category.name}` src=category.icon)
|
||||
a(class='text-tip' href=`/blog/${category.id}`) #{category.name}
|
||||
p(class='text-tip')
|
||||
| #{formatDate(article.info.created)}
|
||||
p(class='text-tip')
|
||||
| #{calcReadTime(article.elements)} minute read
|
||||
div(class='item-info')
|
||||
img(class='filter-icon' alt=`Avatar for Author ${author.name}` src=author.icon)
|
||||
p(class='text-tip') #{author.name}
|
||||
div(class='divider-line')
|
||||
|
||||
//- Article Content
|
||||
include ../_TemplateArticle
|
||||
|
||||
div(style='height: 64px;')
|
||||
script(src='file://scripts/shared-article.ts')
|
||||
@@ -0,0 +1,57 @@
|
||||
<article
|
||||
id="applications"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="Applications"
|
||||
created="500"
|
||||
snippet="Developer documentation for Applications"
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<header>Introduction</header>
|
||||
<text>
|
||||
Applications allow you to integrate the suzzy API into your projects.
|
||||
You can create and manage them while in the <a href='/profile/applications'>Applications</a>
|
||||
section of your profile.
|
||||
</text>
|
||||
|
||||
<subheader>Application Object</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>id</column>
|
||||
<column>integer</column>
|
||||
<column>Unique Application ID</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>created</column>
|
||||
<column>Date</column>
|
||||
<column>ISO Timestamp of when application was created</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>flags</column>
|
||||
<column>integer</column>
|
||||
<column>the application's public flags</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>name</column>
|
||||
<column>string</column>
|
||||
<column>the application's name</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>description</column>
|
||||
<column>string?</column>
|
||||
<column>the application's description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>icon</column>
|
||||
<column>string?</column>
|
||||
<column>the application's image hash</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,23 @@
|
||||
<article
|
||||
id="changelog"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="Changelog"
|
||||
created="-1"
|
||||
snippet="Changelog for suzzy APIs and Services"
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<header>Notices</header>
|
||||
<text>Important and Breaking changes will be listed below:</text>
|
||||
<list>
|
||||
<item>Nothing to report!</item>
|
||||
</list>
|
||||
<header>History</header>
|
||||
<subheader>Initial Release</subheader>
|
||||
<quote>Date: May 12th 2024</quote>
|
||||
<list>
|
||||
<item>Applications are now generally available</item>
|
||||
<item>suzzy Library now available</item>
|
||||
</list>
|
||||
</article>
|
||||
@@ -0,0 +1,155 @@
|
||||
<article
|
||||
id="oauth2"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="OAuth2"
|
||||
created="400"
|
||||
snippet="Developer documentation for OAuth2"
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<header>Resources</header>
|
||||
<text>
|
||||
suzzy games provides support for OAuth2 allowing applications to
|
||||
use the API for authorization and retrieval of user data.
|
||||
</text>
|
||||
<text>
|
||||
It is recommended you
|
||||
<a href="/library/api/tutorials#creating-an-application">Create an Application</a>
|
||||
and store the given
|
||||
<c>CLIENT_ID</c> and
|
||||
<c>CLIENT_SECRET</c> for later use.
|
||||
</text>
|
||||
<subheader>OAuth2 URLs</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>URL</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>https://suzzygames.com/oauth2</column>
|
||||
<column>Base Authorization URL</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>https://apis.suzzygames.com/v1/oauth2/token</column>
|
||||
<column>Token URL</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>https://apis.suzzygames.com/v1/oauth2/token/revoke</column>
|
||||
<column>Token Revocation URL</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>These endpoints will only accept the content type "application/x-www-form-urlencoded"</quote>
|
||||
<subheader>OAuth2 Scopes</subheader>
|
||||
<text>
|
||||
A list of available scopes, some endpoints will return fields with a
|
||||
<c>null</c> value or return an error if a required scope is unavailable.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Name</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>identify</column>
|
||||
<column>Allows access to /users/@me endpoint</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>email</column>
|
||||
<column>Allows /users/@me endpoint to return the user's email</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>connections</column>
|
||||
<column>Allows access to /users/@me/applications endpoint</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<!-- OAuth2 User Flow -->
|
||||
<header>Authorization Code Grant</header>
|
||||
<text>
|
||||
This is most commonly known as <b>standard OAuth2</b>, where the user
|
||||
follows an Authorization Flow in return for an access code which the
|
||||
application can exchange for the user's access token.
|
||||
</text>
|
||||
<quote>
|
||||
All endpoints expect HTTP Basic Auth using your applications
|
||||
CLIENT_ID as the username and CLIENT_SECRET as the password
|
||||
</quote>
|
||||
|
||||
<subheader>Example Authorization URL</subheader>
|
||||
<code syntax="skip">
|
||||
https://suzzygames.com/oauth2?response_type=code&redirect_uri=https%3A%2F%2Fexample.org&client_id=1273&redirect_uri=https%3A%2F%2Fexample.org&scope=identify%20email&state=1734831153572
|
||||
</code>
|
||||
<text>- <c>response_type</c> must always be code, as it is currently the only supported type.</text>
|
||||
<text>- <c>redirect_uri</c> is one of the Redirect URIs set in your application settings, url encoded.</text>
|
||||
<text>- <c>client_id</c> is your Application ID. </text>
|
||||
<text>- <c>scope</c> is a list of <a href="#oauth2-scopes">OAuth2 Scopes</a> delimited by url encoded spaces <c>(%20)</c>.</text>
|
||||
<text>- <c>state</c> is a unique string that will be returned if set.</text>
|
||||
|
||||
<subheader>Example Redirect URL</subheader>
|
||||
<code syntax="skip">
|
||||
https://example.org?code=9AED9A46641F3E3F489523C643C177BB.oboQpOkOSQJvdYYa4WuPq8J3TaYqNgylfq97sa99DRk&state=1734831153572
|
||||
</code>
|
||||
<text>
|
||||
The <c>code</c> can now be exchanged for a user's access token by
|
||||
making a POST request to the <a href="#oauth2-urls">Token URL</a>
|
||||
with the following parameters:
|
||||
</text>
|
||||
<text>- <c>code</c> - parameter taken from the query string</text>
|
||||
<text>- <c>grant_type</c> - value must be <c>authorization_code</c></text>
|
||||
<text>- <c>redirect_uri</c> - the <c>redirect_uri</c> from the authorization url</text>
|
||||
<text>In response you will be bestowed an <a href="#access-token-response">Access Token Response</a></text>
|
||||
|
||||
<subheader>Access Token Response</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Name</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>access_token</column>
|
||||
<column>string</column>
|
||||
<column>Token to include in authorization header</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>token_type</column>
|
||||
<column>string</column>
|
||||
<column>String to prepend to token in authorization header</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>expires_in</column>
|
||||
<column>number</column>
|
||||
<column>Seconds until access token expires</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>refresh_token</column>
|
||||
<column>string</column>
|
||||
<column>Token to submit when making a refresh request</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>scope</column>
|
||||
<column>string</column>
|
||||
<column>The relevant OAuth2 Scopes for this token (delimited with a space)</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<subheader>Refreshing Access Token</subheader>
|
||||
<text>
|
||||
Once an access token has expired you may refresh it by making a
|
||||
POST request to the <a href="#oauth2-urls">Token URL</a> with
|
||||
the following parameters:
|
||||
</text>
|
||||
<text>- <c>grant_type</c> - value must be <c>refresh_token</c></text>
|
||||
<text>- <c>refresh_token</c> - the user's refresh token</text>
|
||||
<text>In response you will be bestowed a fresh <a href="#access-token-response">Access Token Response</a></text>
|
||||
|
||||
<subheader>Revoking Access Token</subheader>
|
||||
<text>
|
||||
You can revoke an access token by making a POST request to the
|
||||
<a href="#oauth2-urls">Token Revocation URL</a> with the following
|
||||
parameters:
|
||||
</text>
|
||||
<text>- <c>token</c> - the user's access token or refresh token</text>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,108 @@
|
||||
<article
|
||||
id="reference"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="Reference"
|
||||
created="100"
|
||||
snippet="References for suzzy APIs and Services"
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<!-- Server URLs -->
|
||||
<header>Sending Requests</header>
|
||||
<text>
|
||||
All requests to the api should be made to the following URL: <c>https://apis.suzzygames.com/v1/</c>
|
||||
</text>
|
||||
|
||||
<!-- Server Ratelimiting -->
|
||||
<header>Ratelimiting</header>
|
||||
<text>
|
||||
Each response will include headers related to ratelimiting, follow them otherwise
|
||||
the server will automatically reject your request and respond with a
|
||||
<c>429 Too Many Requests</c> error.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Header</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>RateLimit-Limit</column>
|
||||
<column>Request Quota</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>RateLimit-Remaining</column>
|
||||
<column>Requests Remaining</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>RateLimit-Reset</column>
|
||||
<column>Float seconds until Quota Resets</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>
|
||||
Sending too many bad requests too quickly will result in your IP Address
|
||||
being blocked temporarily.
|
||||
</quote>
|
||||
<quote>
|
||||
Frequent abusers will get the ban hammer!
|
||||
</quote>
|
||||
|
||||
<!-- User Assets -->
|
||||
<header>Content URLs</header>
|
||||
<text>
|
||||
User Uploads <h>(Avatars, Banners, etc.)</h> are available at
|
||||
<c>https://content.suzzygames.com/</c> using the following paths:
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Name</column>
|
||||
<column>Path</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>User Avatars</column>
|
||||
<column>/avatars/{user.id}/{user.avatar}/{extension}/{size}</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>User Banners</column>
|
||||
<column>/banners/{user.id}/{user.banner}/{extension}/{size}</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>Image Sizes: Large (192px), Medium (96px), Small (48px)</quote>
|
||||
<quote>Image Extensions: webp, png, gif (if animated)</quote>
|
||||
<quote>Animated images will have their hash begin with "a_"</quote>
|
||||
|
||||
<!-- User Default Assets -->
|
||||
<header>Default Assets</header>
|
||||
<text>
|
||||
Ocasionally users won't have uploaded an avatar, you can use the provided
|
||||
default ones by calculating the index with <c>index = {user.id} % 6</c> and using the follow URL:
|
||||
</text>
|
||||
<text>
|
||||
<c>https://suzzygames.com/assets/images/default-user{index}.png</c>
|
||||
</text>
|
||||
<quote>Signed out users use "default-anon.png" instead</quote>
|
||||
|
||||
<subheader>Default Colors</subheader>
|
||||
<text>
|
||||
Default colors for user profiles are available below:
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Name</column>
|
||||
<column>Color (Hex)</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>Profile Banner</column>
|
||||
<column>#1D1E2E</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>Profile Background</column>
|
||||
<column>#333550</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>Profile Border</column>
|
||||
<column>#282A3F</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,28 @@
|
||||
<article
|
||||
id="tutorials"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="Tutorials"
|
||||
created="200"
|
||||
snippet="Simple tutorials on certain things."
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<header>Creating an Application</header>
|
||||
<text>
|
||||
You can create an application using the <a href="https://suzzygames.com/account/applications">My Applications</a>
|
||||
page in the account management portal. Ensure your application has a
|
||||
memorable name and that you keep its secret key secure and private.
|
||||
</text>
|
||||
<image
|
||||
alt="Click on the Create Application Button"
|
||||
caption="Click on the Create Application Button"
|
||||
resource="file://library/tutorials/applications-step-1.png"
|
||||
/>
|
||||
<image
|
||||
alt="You can then edit your Application by clicking on the Edit Button"
|
||||
caption="You can then edit your Application by clicking on the Edit Button"
|
||||
resource="file://library/tutorials/applications-step-2.png"
|
||||
/>
|
||||
<!-- TODO: IMPROVE OAUTH2 TUTORIAL -->
|
||||
</article>
|
||||
@@ -0,0 +1,212 @@
|
||||
<article
|
||||
id="users"
|
||||
authorId=""
|
||||
categoryId="api"
|
||||
title="Users"
|
||||
created="300"
|
||||
snippet="Developer documentation for Users"
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<!-- User Object Reference -->
|
||||
<header>User Object</header>
|
||||
<text>
|
||||
Fields for a user object and the required oAuth2 Scope to view them.
|
||||
Optional fields <h>(Type ending with ?)</h> or hidden fields <h>(Missing oAuth2 Scope)</h>
|
||||
will have their value set as <c>null</c> instead.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
<column>Required oAuth2 Scope</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>id</column>
|
||||
<column>integer</column>
|
||||
<column>their unique account id</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>created</column>
|
||||
<column>timestamp</column>
|
||||
<column>their account creation timestamp</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>public_flags</column>
|
||||
<column>integer</column>
|
||||
<column>their public flags (badges)</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>username</column>
|
||||
<column>string</column>
|
||||
<column>their username</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>displayname</column>
|
||||
<column>string</column>
|
||||
<column>their displayname</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>subtitle</column>
|
||||
<column>string</column>
|
||||
<column>their pronouns, status, etc.</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>biography</column>
|
||||
<column>string</column>
|
||||
<column>their biography</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>accent_background</column>
|
||||
<column>integer</column>
|
||||
<column>their profile background color</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>accent_banner</column>
|
||||
<column>integer</column>
|
||||
<column>their profile banner color</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>accent_border</column>
|
||||
<column>integer</column>
|
||||
<column>their profile border color</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>avatar</column>
|
||||
<column>string?</column>
|
||||
<column>their avatar image hash</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>banner</column>
|
||||
<column>string?</column>
|
||||
<column>their banner image hash</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>verified</column>
|
||||
<column>boolean</column>
|
||||
<column>has email been verified?</column>
|
||||
<column>identify</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>email</column>
|
||||
<column>string?</column>
|
||||
<column>their email address</column>
|
||||
<column>email</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>Usernames will always be alphanumeric with underscores and between 3-32 characters long</quote>
|
||||
<quote>Usernames may change without warning, use account IDs instead!</quote>
|
||||
<quote>Displaynames and Subtitles are up to 32 characters long</quote>
|
||||
<quote>Biographies are up to 320 chracters long</quote>
|
||||
<quote>Colors are in Decimal Representation</quote>
|
||||
|
||||
<!-- User Public Flags/Badges -->
|
||||
<header>Public Flags</header>
|
||||
<text>
|
||||
Use a <b>Bitwise AND</b> operation in your language of choice to see if a flag is
|
||||
set for a user. Flags are primarily used for badges which are special achievements
|
||||
that were obtainable for a limited time or gifted to specific users.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Value</column>
|
||||
<column>Name</column>
|
||||
<column>Description</column>
|
||||
<column>Obtainable?</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>1 (1 << 0)</column>
|
||||
<column>BADGE_CROWN</column>
|
||||
<column>Reserved for bakonpancakz</column>
|
||||
<column>Never</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>2 (1 << 1)</column>
|
||||
<column>BADGE_VIP</column>
|
||||
<column>Reserved for important users</column>
|
||||
<column>No</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>4 (1 << 2)</column>
|
||||
<column>BADGE_PICROSS</column>
|
||||
<column>Awarded by completing Challenge #1</column>
|
||||
<column>Yes</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>8 (1 << 3)</column>
|
||||
<column>PUBLIC_UNAVAILABLE</column>
|
||||
<column>Account is Unavailable</column>
|
||||
<column>TOS Violation</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>
|
||||
Unavailable accounts, may be banned or deleted.
|
||||
The reasoning will be sent to the account owners email.
|
||||
</quote>
|
||||
|
||||
<!-- GET /users/@me -->
|
||||
<header>Get Current User</header>
|
||||
<text><c>GET /users/@me</c></text>
|
||||
<text>
|
||||
Returns the current user if you have the <c>identify</c> scope, also
|
||||
returns email if you also have the <c>email</c> scope.
|
||||
</text>
|
||||
|
||||
<!-- GET /users/@me/connections -->
|
||||
<header>Get Connections for Current User</header>
|
||||
<text><c>GET /users/@me/connections</c></text>
|
||||
<text>
|
||||
Requires the <c>connections</c> <a href='/library/api/oauth2#oauth2-scopes'>OAuth2 Scope</a>.
|
||||
Returns an array of <a href="#connection-object">Connection</a> Objects the user is actively connected to.
|
||||
</text>
|
||||
<subheader>Connection Object</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>id</column>
|
||||
<column>integer</column>
|
||||
<column>Unique Connection ID</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>created</column>
|
||||
<column>Date</column>
|
||||
<column>ISO Timestamp of when connection was created</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>scopes</column>
|
||||
<column>integer</column>
|
||||
<column>Associated OAuth2 scopes with connection</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>application</column>
|
||||
<column>Application Object</column>
|
||||
<column>An Application Object</column>
|
||||
</row>
|
||||
</table>
|
||||
<text><i>Quick link to</i> <a href="/library/api/applications#application-object">Application Object</a>.</text>
|
||||
|
||||
<!-- GET /users/<user.username> -->
|
||||
<header>Get User by Username </header>
|
||||
<text><c>GET /users/<user.username></c></text>
|
||||
<text>
|
||||
Returns a <a href="#user-object">user object</a> for a given username,
|
||||
doesn't require any authorization.
|
||||
</text>
|
||||
</article>
|
||||
@@ -0,0 +1,64 @@
|
||||
<article
|
||||
id="branding"
|
||||
authorId=""
|
||||
categoryId="home"
|
||||
title="Branding"
|
||||
created="200"
|
||||
snippet="Branding Guidelines for suzzy games"
|
||||
banner=""
|
||||
noindex="true"
|
||||
>
|
||||
<!-- Guidelines -->
|
||||
<header>Usage</header>
|
||||
<text>
|
||||
This page contains high quality versions of promotional assets from most
|
||||
suzzy projects and games. Please use common sense and don't hesistate to
|
||||
<a href="mailto:bakonpancakz@suzzygames.com">contact me</a> if you have any
|
||||
questions.
|
||||
</text>
|
||||
<text>
|
||||
<b>Do not use these assets commercially or for impersonation.</b>
|
||||
</text>
|
||||
<quote>Hint: You can click on any image to download it to your device.</quote>
|
||||
|
||||
<!-- Product: suzzy games -->
|
||||
<header>suzzy games</header>
|
||||
<beanie alt="suzzy games Logo" resource="file://library/branding/suzzy-logo.png?preset=branding" />
|
||||
<beanie alt="suzzy games Icon" resource="file://library/branding/suzzy-icon.png?preset=branding" />
|
||||
<quote>Trivia: The name for our ghost mascot is Boo! You can find them in the logo.</quote>
|
||||
<quote>Trivia: The accent color for suzzy is #A1A8FF and is actually considered to be a light sky blue. Not purple!</quote>
|
||||
|
||||
<!-- Product: BECCA2D -->
|
||||
<header>BECCA2D</header>
|
||||
<text>
|
||||
BECCA2D is a <b>2D Web Game Engine</b> developed by suzzy games and is
|
||||
used in the upcoming <a href="/projects">super marimari_eno</a> fan-game.
|
||||
</text>
|
||||
<beanie alt="BECCA2D Logo" resource="file://library/branding/becca-logo.svg?preset=branding" />
|
||||
<quote>Trivia: BECCA2D is named after my sister, since my nickname for her is Becca.</quote>
|
||||
|
||||
<!-- Product: Project Monke -->
|
||||
<header>Project Monke</header>
|
||||
<text>Project Monke is an upcoming platformer game developed by suzzy games.</text>
|
||||
<beanie alt="PM Game Icon #1" resource="file://library/branding/monke-gameicon.png?preset=branding" />
|
||||
<beanie alt="PM Game Icon #2" resource="file://library/branding/monke-gameicon-initials.png?preset=branding" />
|
||||
<beanie alt="PM Game Logo #1" resource="file://library/branding/monke-logo-text.png?preset=branding" />
|
||||
<beanie alt="PM Game Logo #2" resource="file://library/branding/monke-logo-initials.png?preset=branding" />
|
||||
<beanie alt="PM Promo Art #1" resource="file://library/branding/monke-promo-1.png?preset=branding" />
|
||||
<quote>Trivia: The Polka Dot pattern was inspired by DDLC+ promo art.</quote>
|
||||
|
||||
<!-- Product: Cart Ride around a Fumo -->
|
||||
<header>Cart Ride Around a Fumo</header>
|
||||
<text>
|
||||
Cart Ride around a Fumo is a <a href="https://www.roblox.com/games/9987852646/Cart-Ride-Around-a-Fumo">ROBLOX experience</a> developed by suzzy games.
|
||||
Promo and Game Icon Art drawn by <a href="https://twitter.com/MondaeAkari">@mondaeakari</a>.
|
||||
</text>
|
||||
<beanie alt="CRAF Game Icon #1" resource="file://library/branding/craf-gameicon-1.png?preset=branding" />
|
||||
<beanie alt="CRAF Game Icon #2" resource="file://library/branding/craf-gameicon-2.png?preset=branding" />
|
||||
<beanie alt="CRAF Promo Art #1" resource="file://library/branding/craf-promo-1.png?preset=branding" />
|
||||
<beanie alt="CRAF Promo Art #2" resource="file://library/branding/craf-promo-2.png?preset=branding" />
|
||||
<quote>
|
||||
Trivia: The first icon didn't do so well to bring in new players.
|
||||
Which sucks because I liked it ;-;
|
||||
</quote>
|
||||
</article>
|
||||
@@ -0,0 +1,27 @@
|
||||
<article
|
||||
id="welcome"
|
||||
authorId=""
|
||||
categoryId="home"
|
||||
title="Welcome"
|
||||
created="100"
|
||||
snippet="Welcome to the suzzy Library!"
|
||||
banner=""
|
||||
noindex="true"
|
||||
>
|
||||
<banner resource="file://library/introduction/banner-welcome.png" alt="Welcome Banner" />
|
||||
<subheader>Welcome to the library!</subheader>
|
||||
<text>
|
||||
This site contains documentation and guides intended for developers.
|
||||
You can navigate the website using the links on the side. <h>Or above if you're on mobile!</h>
|
||||
</text>
|
||||
|
||||
<subheader>Heads up!</subheader>
|
||||
<text>
|
||||
Documentation and features are still early in development, you may occasionally
|
||||
encounter an unexpected <c>500 Internal Server Error</c> or find a random typo.
|
||||
</text>
|
||||
<text>
|
||||
Please send bug reports or feature requests to
|
||||
<a href="mailto:bakonpancakz@gmail.com">bakonpancakz@gmail.com</a>
|
||||
</text>
|
||||
</article>
|
||||
@@ -0,0 +1,24 @@
|
||||
<article
|
||||
id="privacy-policy"
|
||||
authorId=""
|
||||
categoryId="legal"
|
||||
title="Privacy Policy"
|
||||
created="999999"
|
||||
snippet="Privacy Policy governing all suzzy services and products"
|
||||
noindex="true"
|
||||
banner=""
|
||||
>
|
||||
<header>Introduction</header>
|
||||
<text>
|
||||
This document entails the general privacy policy, covering all suzzy services.
|
||||
Specific services may override it as necessary — please refer to their respective documents for more information.
|
||||
</text>
|
||||
<text>
|
||||
<c>Last Updated on May 11th 2024</c>
|
||||
</text>
|
||||
|
||||
<header>1. todo</header>
|
||||
<text>
|
||||
<h>here's where i would put my privacy policy. IF I HAD ONE!</h>
|
||||
</text>
|
||||
</article>
|
||||
@@ -0,0 +1,24 @@
|
||||
<article
|
||||
id="terms-of-service"
|
||||
authorId=""
|
||||
categoryId="legal"
|
||||
title="Terms of Service"
|
||||
created="999998"
|
||||
snippet="Terms of Service governing all suzzy services and products"
|
||||
noindex="true"
|
||||
banner=""
|
||||
>
|
||||
<header>Introduction</header>
|
||||
<text>
|
||||
This document entails the general terms of service, covering all suzzy services.
|
||||
Specific services may override it as necessary — please refer to their respective documents for more information.
|
||||
</text>
|
||||
<text>
|
||||
<c>Last Updated on May 11th 2024</c>
|
||||
</text>
|
||||
|
||||
<header>1. todo</header>
|
||||
<text>
|
||||
<h>here's where i would put my terms of service. IF I HAD ONE!</h>
|
||||
</text>
|
||||
</article>
|
||||
@@ -0,0 +1,135 @@
|
||||
<article
|
||||
id="endpoints"
|
||||
authorId=""
|
||||
categoryId="status"
|
||||
title="Endpoints"
|
||||
created="100"
|
||||
snippet=""
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<!-- GET /widget.json -->
|
||||
<header>Get Widget</header>
|
||||
<text><c>GET /widget.json</c></text>
|
||||
<text>
|
||||
Returns a unique <a href="#widget-object">Widget Object</a>. This
|
||||
is the same endpoint use for the widget displayed in the top-right
|
||||
corner of the suzzy games webpage.
|
||||
</text>
|
||||
|
||||
<subheader>Widget Object</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>status</column>
|
||||
<column>string</column>
|
||||
<column>Current status either "online", "degraded", or "down"</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>counter_players_online</column>
|
||||
<column>number?</column>
|
||||
<column>Estimated number of players online</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>This endpoint returns the headers 'X-Refresh' and 'Etag'</quote>
|
||||
|
||||
<!-- GET /status.json -->
|
||||
<header>Get Status</header>
|
||||
<text><c>GET /status.json</c></text>
|
||||
<text>
|
||||
Returns a unique <a href="#status-object">Status Object</a>. Includes
|
||||
the current status, an array of
|
||||
<a href="/library/status/reference#tracker-object">tracker objects</a>,
|
||||
and an array of
|
||||
<a href="/library/status/reference#event-object">event objects</a>
|
||||
which occurred today.
|
||||
</text>
|
||||
<subheader>Status Object</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>status</column>
|
||||
<column>string</column>
|
||||
<column>Current status either "online", "degraded", or "down"</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>trackers</column>
|
||||
<column>Array<Trackers></column>
|
||||
<column>List of Trackers</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>events</column>
|
||||
<column>Array<Events></column>
|
||||
<column>List of Events for Today</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>This endpoint returns the headers 'X-Refresh' and 'Etag'</quote>
|
||||
<text>
|
||||
<b>Notice:</b> This endpoint is compressed with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/gzip_compression">gzip</a>.
|
||||
Your client must support and notify the server that it accepts gzip
|
||||
encoded content via the <c>Accept-Encoding</c> header. Otherwise
|
||||
your request will be rejected with a <c>415 Unsupported Media Type</c>
|
||||
status code.
|
||||
</text>
|
||||
|
||||
<!-- GET /events -->
|
||||
<header>Get Events</header>
|
||||
<text><c>GET /events</c></text>
|
||||
<text>
|
||||
Returns an array of <a href="/library/status/reference#event-object">Event Objects</a>
|
||||
for today. You can request a specific day using the query parameter <c>date</c> in
|
||||
<c>MM/DD/YYYY</c> format <h>(ex. date=06/26/2003)</h>.
|
||||
</text>
|
||||
|
||||
<!-- GET /status.json -->
|
||||
<header>Get Events Summary</header>
|
||||
<text><c>GET /events/summary</c></text>
|
||||
|
||||
<text>
|
||||
Returns a Unique <a href="#summary-object">Summary Object</a> for this month.
|
||||
You can request a specific month using the query parameter <c>date</c> in
|
||||
<c>MM/YYYY</c> format. <h>(ex. date=06/2003)</h>
|
||||
</text>
|
||||
<subheader>Summary Object</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>uptime</column>
|
||||
<column>string</column>
|
||||
<column>Uptime Percentage in Float</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>results</column>
|
||||
<column>...</column>
|
||||
<column>See Description Below</column>
|
||||
</row>
|
||||
</table>
|
||||
<text>
|
||||
The results field is a JSON object with the <b>keys</b> being the <i>day of the month</i>, and it's
|
||||
<b>value</b> being an <i>Array with three integers</i>. Each integer represents how many seconds of
|
||||
<b>Degredation</b>, <b>Downtime</b>, and <b>Maintenance</b> occurred
|
||||
that day, respectively.
|
||||
</text>
|
||||
|
||||
<code syntax="json">
|
||||
{
|
||||
"uptime": "99.99", // Uptime Percent as Float
|
||||
"results": {
|
||||
"0": [0, 0, 3600], // "Day": [Seconds Degraded, Downtime, Maintenance]
|
||||
"12": [300, 0, 0], // Ex. 5 Minutes of Downtime on the 12th day of the month
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</article>
|
||||
@@ -0,0 +1,310 @@
|
||||
<article
|
||||
id="reference"
|
||||
authorId=""
|
||||
categoryId="status"
|
||||
title="Reference"
|
||||
created="0"
|
||||
snippet=""
|
||||
banner=""
|
||||
noindex="false"
|
||||
>
|
||||
<!-- Server URLs -->
|
||||
<header>Sending Requests</header>
|
||||
<text>
|
||||
All requests to the <b>Status Service</b> should be made to the following URL:
|
||||
<c>https://status.suzzygames.com/api/</c>
|
||||
</text>
|
||||
|
||||
<header>Automatic Refreshing</header>
|
||||
<text>
|
||||
This service updates the <a href="/library/status/endpoints#fetch-widget">widget</a>
|
||||
and <a href="/library/status/endpoints#fetch-status">status</a> endpoints
|
||||
every minute.
|
||||
</text>
|
||||
<text>
|
||||
You can use the <c>X-Refresh</c> header to calculate how many float seconds
|
||||
your client should wait before attempting to make another request.
|
||||
</text>
|
||||
<text>
|
||||
This service also returns a <c>ETag</c> header which you can optionally include
|
||||
in the next request. If nothing has changed the service will respond with a
|
||||
<c>304 Not Modified</c> and an <b>empty body</b>.
|
||||
</text>
|
||||
<code syntax="yml">
|
||||
X-Refresh: 12.73 # Seconds until next refresh
|
||||
ETag: 1735594572 # Unique Cache Identifier
|
||||
</code>
|
||||
<quote>
|
||||
Note: The 'X-Refresh' header is randomly offset up to 5 seconds to
|
||||
help mitigate the sudden spike in traffic.
|
||||
</quote>
|
||||
|
||||
<header>Service Unavailable</header>
|
||||
<text>
|
||||
On rare occasions the Service may return a <c>503 Service Unavailable</c>
|
||||
error. This happens when the service has just restarted <h>(usually due to an update)</h>
|
||||
and is doing some digital housekeeping before preparing the <a href="/library/status/endpoints#fetch-widget">widget</a>
|
||||
and <a href="/library/status/endpoints#fetch-status">status</a> endpoints.
|
||||
</text>
|
||||
<text>
|
||||
The error will however return the <c>X-Refresh</c> header and the
|
||||
aforementioned endpoints should become available then.
|
||||
</text>
|
||||
<quote>
|
||||
Note: The status service always returns an empty body when an error occurs.
|
||||
Your client should not attempt to parse any JSON.
|
||||
</quote>
|
||||
|
||||
<header>About Trackers</header>
|
||||
|
||||
<subheader>Tracker Object</subheader>
|
||||
<text>
|
||||
All trackers share the same base fields, but some fields are only
|
||||
included for their respective types.
|
||||
</text>
|
||||
<text>
|
||||
<b>Charts</b> take in values from multiple servers and average them
|
||||
every specified interval compiling it into a <a href="#chart-data-point">Data Point</a>.
|
||||
Charts return the <c>interval</c>, <c>history</c>, and <c>history_length</c> fields.
|
||||
</text>
|
||||
<text>
|
||||
<b>Counters</b> take in individual numbers from multiple servers and accumulate
|
||||
them together as one number. Counters return the <c>value</c> field.
|
||||
</text>
|
||||
<text>
|
||||
<b>Services</b> keep track of multiple servers to ensure they're healthy and operational.
|
||||
If the health check fails their status is changed to either <b>degraded</b> or <b>down</b>
|
||||
generating an event and alerting an engineer.
|
||||
Services return the <c>status</c> field.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>id</column>
|
||||
<column>string</column>
|
||||
<column>Unique Tracker Identifier</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>public</column>
|
||||
<column>boolean</column>
|
||||
<column>Is this tracker public? (Internal)</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>ephemeral</column>
|
||||
<column>boolean</column>
|
||||
<column>Clear tracker data on startup? (Internal)</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>name</column>
|
||||
<column>string</column>
|
||||
<column>User-Friendly name for this tracker</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>description</column>
|
||||
<column>string</column>
|
||||
<column>Description that appears when mouse is hovered over</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>tags</column>
|
||||
<column>Array<string></column>
|
||||
<column>Strings used to categorize this tracker</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>type</column>
|
||||
<column>integer</column>
|
||||
<column>The Type of Tracker</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>value</column>
|
||||
<column>integer?</column>
|
||||
<column>COUNTER: Current Tracker Value</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>status</column>
|
||||
<column>integer?</column>
|
||||
<column>SERVICE: Current Service Status</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>interval</column>
|
||||
<column>integer?</column>
|
||||
<column>CHART: Data Point Interval</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>history_length</column>
|
||||
<column>integer?</column>
|
||||
<column>CHART: Data Point History Length</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>history</column>
|
||||
<column>Array<DataPoint>?</column>
|
||||
<column>CHART: Data Point History</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<subheader>Tracker Types</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Enum</column>
|
||||
<column>Value</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>COUNTER</column>
|
||||
<column>1</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>CHART</column>
|
||||
<column>2</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>SERVICE</column>
|
||||
<column>3</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<subheader>Service Status</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Enum</column>
|
||||
<column>Value</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>HEALTHY</column>
|
||||
<column>0</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>DEGRADED</column>
|
||||
<column>1</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>DOWN</column>
|
||||
<column>2</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<subheader>Chart Data Point</subheader>
|
||||
<text>
|
||||
<b>Data Points</b> are Arrays that contain two integers.
|
||||
The first integer is a timestamp for when the service compiled
|
||||
the data into a point and can be converted into a UNIX Timestamp with
|
||||
<c>TIMESTAMP * (INTERVAL * 60) * 1000</c>. The second integer is the
|
||||
calculated average value.
|
||||
</text>
|
||||
<text>
|
||||
You can then reverse iterate over the <a href="#tracker-object">trackers history field</a>
|
||||
to plot the values on a line chart.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Index</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>0</column>
|
||||
<column>integer</column>
|
||||
<column>Data Timestamp</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>1</column>
|
||||
<column>integer</column>
|
||||
<column>Data Value</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<header>About Events</header>
|
||||
<subheader>Event Object</subheader>
|
||||
<text>
|
||||
Events are generated when downtime is detected or for when downtime is
|
||||
scheduled. They include <b>"helpful"</b> messages either generated by
|
||||
the service itself or personally written by an engineer.
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>id</column>
|
||||
<column>string</column>
|
||||
<column>Unique Event Identifier</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>type</column>
|
||||
<column>integer</column>
|
||||
<column>Event Type</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>affects</column>
|
||||
<column>string</column>
|
||||
<column>The ID of Tracker this event pertains to</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>occurred</column>
|
||||
<column>ISO Timestamp</column>
|
||||
<column>When this event began</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>resolved</column>
|
||||
<column>ISO Timestamp?</column>
|
||||
<column>When this event was resolved</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>messages</column>
|
||||
<column>Array<Message></column>
|
||||
<column>List of Message Objects (Unsorted)</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
<subheader>Event Types</subheader>
|
||||
<table>
|
||||
<row>
|
||||
<column>Enum</column>
|
||||
<column>Value</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>DEGREDATION</column>
|
||||
<column>0</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>DOWNTIME</column>
|
||||
<column>1</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>MAINTENANCE</column>
|
||||
<column>2</column>
|
||||
</row>
|
||||
</table>
|
||||
<quote>Their respective Hex Colors: #f1c40f, #ff005b, #6cc0e0</quote>
|
||||
|
||||
<subheader>Message Object</subheader>
|
||||
<text>
|
||||
These message contain HTML Content. Which usually only use the
|
||||
standard text formatting tags <c><b> <s> <i></c>.
|
||||
</text>
|
||||
<text>
|
||||
<a target="_blank" href="">They may also occasionally include an image tag.</a>
|
||||
</text>
|
||||
<table>
|
||||
<row>
|
||||
<column>Field</column>
|
||||
<column>Type</column>
|
||||
<column>Description</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>created</column>
|
||||
<column>ISO Timestamp</column>
|
||||
<column>When this message was written</column>
|
||||
</row>
|
||||
<row>
|
||||
<column>message</column>
|
||||
<column>string</column>
|
||||
<column>HTML Content</column>
|
||||
</row>
|
||||
</table>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1 @@
|
||||
extends template
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"itemsPerPage": 8,
|
||||
"noBrowser": true,
|
||||
"authors": [
|
||||
{
|
||||
"id": "",
|
||||
"name": "suzzy",
|
||||
"icon": ""
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"id": "home",
|
||||
"name": "Home",
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"id": "legal",
|
||||
"name": "Legal",
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"id": "api",
|
||||
"name": "API",
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"name": "Status",
|
||||
"icon": ""
|
||||
}
|
||||
],
|
||||
"articles": [
|
||||
"home/Welcome.xml",
|
||||
"home/Branding.xml",
|
||||
"legal/Privacy Policy.xml",
|
||||
"legal/Terms of Service.xml",
|
||||
"api/Users.xml",
|
||||
"api/OAuth2.xml",
|
||||
"api/Applications.xml",
|
||||
"api/Reference.xml",
|
||||
"api/Tutorials.xml",
|
||||
"api/Changelog.xml",
|
||||
"status/Reference.xml",
|
||||
"status/Endpoints.xml"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
extends template
|
||||
@@ -0,0 +1,110 @@
|
||||
-
|
||||
// Create Sidebar Categories
|
||||
const t = {}
|
||||
for (const a of articles) {
|
||||
const k = categories.find(c => c.id === a.category.id).name
|
||||
t[k] ? t[k].push(a) : t[k] = [a]
|
||||
}
|
||||
// Sort Sidebar Articles
|
||||
for (const v of Object.values(t)) {
|
||||
v.sort((a, b) => parseInt(a.info.created) - parseInt(b.info.created))
|
||||
}
|
||||
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
meta(charset='UTF-8')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1.0')
|
||||
link(rel='icon' type='image/png' href='file://library/favicon.png')
|
||||
link(rel='stylesheet' href='file://styles/template-global.css')
|
||||
link(rel='stylesheet' href='file://styles/template-article.css')
|
||||
link(rel='stylesheet' href='file://styles/browser-library.css')
|
||||
link(rel='stylesheet' href='file://fonts/font-poppins.css')
|
||||
meta(property='theme-color' content='#A1A8FF')
|
||||
meta(property='og:image' content='file://library/logo-og.png?direct=true')
|
||||
meta(property='og:title' content=`library | ${relevantArticle.category.name} > ${relevantArticle.info.title}`)
|
||||
meta(property='og:description' content=relevantArticle.info.snippet)
|
||||
meta(name='description' content=relevantArticle.info.snippet)
|
||||
title library - #{relevantArticle.info.title} (#{relevantArticle.category.name})
|
||||
body
|
||||
div(class='wrapper-search')
|
||||
div(class='container-search special-dropshadow')
|
||||
|
||||
div(class='search-actions')
|
||||
input(class='search-input' tabindex='-1' type='text' name='Search Library' placeholder='Search Library')
|
||||
button(class='search-close' tabindex='-1') ×
|
||||
|
||||
div(class='search-body')
|
||||
//- Loading Icon
|
||||
div(class='pane' id='loading')
|
||||
img(src='file://icons/diagram-loading.svg' style='width: 64px;')
|
||||
|
||||
//- Error Message
|
||||
div(class='pane' id='error')
|
||||
img(src='file://library/search/search-error.png')
|
||||
span I ran into an issue...
|
||||
p(class='text-tip text-muted') TypeError: Failed to Fetch
|
||||
|
||||
//- First Open/Empty Query
|
||||
div(class='pane' id='help')
|
||||
img(src='file://library/search/search-initial.png')
|
||||
span Can't find something? Let me help you out!
|
||||
p(class='text-tip text-muted') start typing to begin our search
|
||||
|
||||
//- Empty Results
|
||||
div(class='pane' id='empty')
|
||||
img(src='file://library/search/search-empty.png')
|
||||
span I couldn't find anything!
|
||||
p(class='text-tip text-muted') try again with some different keywords
|
||||
|
||||
//- Some Results
|
||||
div(class='pane' id='results')
|
||||
|
||||
div(class='search-footer')
|
||||
p(class='text-tip text-muted')
|
||||
div(style='flex-basis: 100%;')
|
||||
p Close #[span ESC]
|
||||
p Navigate #[span ⬆⬇]
|
||||
p Select #[span ↩]
|
||||
|
||||
|
||||
div(class='wrapper-layout')
|
||||
div(class='layout-navigation background-scroll special-shadow')
|
||||
//- Logo and Search Box
|
||||
a(class='navigation-button' id='skipper' href='#home')
|
||||
| Skip to Content
|
||||
a(href='/')
|
||||
img(
|
||||
class='navigation-logo'
|
||||
alt='Logo for suzzy games'
|
||||
src='file://library/logo-navigation.png'
|
||||
)
|
||||
button(class='navigation-button' id='search-open')
|
||||
| Search Library
|
||||
|
||||
//- Render Sidebar
|
||||
each [categoryName, categoryArticles] of Object.entries(t)
|
||||
p(class='navigation-header') #{categoryName}
|
||||
each someArticle of categoryArticles
|
||||
- var thisLink = `${relevantArticle.category.id}/${relevantArticle.info.id}`
|
||||
- var someLink = `${someArticle.category.id}/${someArticle.info.id}`
|
||||
- var matchLink = (thisLink === someLink)
|
||||
a(class='navigation-link' href=`/library/${someLink}` active=matchLink)
|
||||
| #{someArticle.info.title}
|
||||
if matchLink
|
||||
each element of someArticle.elements
|
||||
if element.type === 'header'
|
||||
a(class='navigation-chapter' href=`#${formatString(element.value)}`)
|
||||
| #{element.value}
|
||||
|
||||
div(class='layout-content' id='home')
|
||||
//- Article Content
|
||||
include ../_TemplateArticle
|
||||
|
||||
//- Mobile Users get a Return to Top Button
|
||||
//- Also includes spacer so content doesn't cover button
|
||||
div(class='layout-spacer')
|
||||
a(class='default layout-return' href='#home') ▲
|
||||
|
||||
script(src='file://scripts/shared-article.ts')
|
||||
script(src='file://scripts/browser-library.ts')
|
||||
@@ -0,0 +1,102 @@
|
||||
extends ../_TemplateProfile
|
||||
block pageHeader
|
||||
title suzzy - Manage Applications
|
||||
block pageContent
|
||||
- var loading_message = 'Applications'
|
||||
- var empty_message = 'No Applications'
|
||||
- var empty_source = 'file://icons/icon-app-none.svg'
|
||||
- var empty_alt = 'No Apps'
|
||||
p(class='text-hero') Applications
|
||||
p(class='text-tip') Create applications that interface with suzzy games and it's users.
|
||||
p(class='text-tip')
|
||||
| Check out the #[a(href='/library' class='text-tip') library]
|
||||
| for documentation on how to develop with suzzy games.
|
||||
div(class='collection-divider')
|
||||
button(class='default wide' id='action-create' hidden)
|
||||
| Create New Application
|
||||
include ../_TemplateProfilePage
|
||||
|
||||
//- //- Template Redirect URL
|
||||
//- div(class='input-redirect' hidden)
|
||||
//- input(
|
||||
//- type='text'
|
||||
//- class='text'
|
||||
//- autocomplete='off'
|
||||
//- maxlength=128
|
||||
//- placeholder='https://example.org/oauth2-redirect'
|
||||
//- required=true
|
||||
//- pattern='^(http|https)://.*'
|
||||
//- )
|
||||
//- button(class='default destructive') Delete
|
||||
|
||||
//- //- Templat Application
|
||||
//- div(class='collection-item special-shadow' id='application-template' hidden)
|
||||
//- //- Application Metadata
|
||||
//- div(class='application-header')
|
||||
//- img(
|
||||
//- id='app-icon'
|
||||
//- aria-hidden='true'
|
||||
//- class='application-icon'
|
||||
//- onload='this.style.opacity=1'
|
||||
//- )
|
||||
//- div(class='application-info')
|
||||
//- p(id='app-name' class='text-header') Name
|
||||
//- p(id='app-desc' class='text-tip') Description
|
||||
//- p(class='text-tip text-muted' id='verified-message' hidden) ★ Verified Application
|
||||
//- button(id='input-edit' class='default') Edit
|
||||
//- //- Application Options
|
||||
//- div(class='application-options options-hidden')
|
||||
//- div(class='divider-line')
|
||||
//- //- Personalization
|
||||
//- p(class='text-header') About
|
||||
//- input(
|
||||
//- id='input-name'
|
||||
//- placeholder='Name'
|
||||
//- autocomplete='off'
|
||||
//- type='text'
|
||||
//- class='text'
|
||||
//- maxlength=32
|
||||
//- )
|
||||
//- textarea(
|
||||
//- id='input-desc'
|
||||
//- placeholder='Description'
|
||||
//- autocomplete='off'
|
||||
//- class='text'
|
||||
//- maxlength=320
|
||||
//- rows=5
|
||||
//- style='max-height:200px;'
|
||||
//- )
|
||||
//- input(
|
||||
//- type='file'
|
||||
//- id='input-icon-file'
|
||||
//- accept='image/jpeg, image/webp, image/gif, image/png'
|
||||
//- hidden
|
||||
//- )
|
||||
//- button(class='default wide' id='input-icon')
|
||||
//- | Upload Icon
|
||||
//- button(class='small text-tip' id='input-icon-remove')
|
||||
//- | Remove Icon
|
||||
|
||||
//- //- Redirects
|
||||
//- div(class='divider-line')
|
||||
//- p(class='text-header') Redirects
|
||||
//- div(id='container-redirects')
|
||||
//- button(class='default wide' id='input-redirect-new')
|
||||
//- | New Redirect
|
||||
//- p(class='text-tip' id='input-clientid') Client ID:
|
||||
|
||||
//- //- Actions
|
||||
//- p(id='status-message')
|
||||
//- button(class='default wide destructive' id='input-discard' disabled)
|
||||
//- | Discard
|
||||
//- button(class='default wide' id='input-save' disabled)
|
||||
//- | Save Changes
|
||||
|
||||
//- //- Danger Zone
|
||||
//- div(class='divider-line')
|
||||
//- button(class='default destructive wide' id='input-reset')
|
||||
//- | Reset Secret Key
|
||||
//- button(class='default destructive wide' id='input-delete')
|
||||
//- | Delete Application
|
||||
|
||||
script(src='file://scripts/profile-applications.ts')
|
||||
@@ -0,0 +1,37 @@
|
||||
extends ../_TemplateProfile
|
||||
block pageHeader
|
||||
title suzzy - Manage Connections
|
||||
block pageContent
|
||||
- var loading_message = 'Connections'
|
||||
- var empty_message = 'No Connections'
|
||||
- var empty_source = 'file://icons/icon-plug-socket.svg'
|
||||
- var empty_alt = 'Disconnect'
|
||||
p(class='text-hero') Connections
|
||||
p(class='text-tip') Manage the connections your account has with applications.
|
||||
p(class='text-tip')
|
||||
| Official Applications are labelled with
|
||||
| #[span(class='text-tip text-muted') (★ Verified Application)]
|
||||
| under their description.
|
||||
div(class='collection-divider')
|
||||
include ../_TemplateProfilePage
|
||||
|
||||
//- //- Template Scope
|
||||
//- div(class='scope' id='scope-template' hidden)
|
||||
//- div(class='dot-green')
|
||||
//- span Scope Description
|
||||
|
||||
//- //- Template Item
|
||||
//- div(class='collection-item special-shadow' id='application-template' hidden)
|
||||
//- div(class='application-header')
|
||||
//- img(aria-hidden='true' class='application-icon' onload='this.style.opacity=1')
|
||||
//- div(class='application-info')
|
||||
//- p(class='text-header') Name
|
||||
//- p(class='text-tip') Description
|
||||
//- p(class='text-tip text-muted' id='verified-message' hidden) ★ Verified Application
|
||||
//- p(class='text-error' id='error-message')
|
||||
//- button(class='default destructive') Disconnect
|
||||
//- div(class='text-box')
|
||||
//- p(class='text-tip') This application can:
|
||||
//- div(class='scopes')
|
||||
|
||||
script(src='file://scripts/profile-connections.ts')
|
||||
@@ -0,0 +1,30 @@
|
||||
extends ../_TemplateProfile
|
||||
block pageHeader
|
||||
title suzzy - Manage Devices
|
||||
block pageContent
|
||||
- var loading_message = 'Devices'
|
||||
- var empty_message = 'No Devices'
|
||||
- var empty_source = 'file://icons/icon-app-none.svg'
|
||||
- var empty_alt = 'Devices'
|
||||
p(class='text-hero') Devices
|
||||
p(class='text-tip') Here's a list of devices that are currently logged in with your account.
|
||||
p(class='text-tip') If you see a device you don't recognize, log it out and change your password immediately.
|
||||
div(class='collection-divider')
|
||||
include ../_TemplateProfilePage
|
||||
|
||||
//- //- Template Item
|
||||
//- div(class='item-device collection-item special-shadow' id='device-template' hidden)
|
||||
//- div(class='device-icon')
|
||||
//- img(aria-hidden='true' src='/assets/images/icons/icon-desktop.svg' alt='Icon for Desktop')
|
||||
//- div(class='device-info')
|
||||
//- div(class='info-alongside')
|
||||
//- p(id='browser') Chrome on Windows 10
|
||||
//- p(id='me' class='text-tip text-muted' hidden) (This Device)
|
||||
//- div(class='info-alongside')
|
||||
//- p(id='location') Modesto, United States
|
||||
//- p(id='lastseen' class='text-tip text-muted') 3 hours ago
|
||||
//- p(class='text-error' id='error-message')
|
||||
//- button(class='device-action')
|
||||
//- img(src='/assets/images/icons/icon-cross.svg' alt='Icon for Cross')
|
||||
|
||||
script(src='file://scripts/profile-devices.ts')
|
||||
@@ -0,0 +1,96 @@
|
||||
extends ../_TemplateProfile
|
||||
block pageHeader
|
||||
title suzzy - Manage Profile
|
||||
block pageContent
|
||||
- var loading_message = 'Profile'
|
||||
p(class='text-hero') Profile
|
||||
p(class='text-tip') Personalize your profile to make it uniquely yours!
|
||||
p(class='text-tip') Animated Avatars and Banners are supported! Uploads up to 8MB are allowed.
|
||||
div(class='collection-divider')
|
||||
include ../_TemplateProfilePage
|
||||
|
||||
//- div(class='profile-options text-nopad')
|
||||
//- //- About Section
|
||||
//- p(class='text-header') About Me
|
||||
//- input(
|
||||
//- type='text'
|
||||
//- id='input-displayname'
|
||||
//- class='text'
|
||||
//- placeholder='Displayname'
|
||||
//- maxlength=32
|
||||
//- )
|
||||
//- input(
|
||||
//- type='text'
|
||||
//- id='input-subtitle'
|
||||
//- class='text'
|
||||
//- placeholder='Subtitle'
|
||||
//- maxlength=32
|
||||
//- )
|
||||
//- textarea(
|
||||
//- id='input-bio'
|
||||
//- class='text'
|
||||
//- placeholder='Biography'
|
||||
//- rows=3
|
||||
//- maxlength=320
|
||||
//- style='max-height:200px;'
|
||||
//- )
|
||||
|
||||
//- //- Images Section
|
||||
//- p(class='text-header') Images
|
||||
//- input(
|
||||
//- type='file'
|
||||
//- id='input-avatar-file'
|
||||
//- accept='image/jpeg, image/webp, image/gif, image/png'
|
||||
//- hidden
|
||||
//- )
|
||||
//- input(
|
||||
//- type='file'
|
||||
//- id='input-banner-file'
|
||||
//- accept='image/jpeg, image/webp, image/gif, image/png'
|
||||
//- hidden
|
||||
//- )
|
||||
//- button(class='default wide' id='button-avatar')
|
||||
//- | Upload Avatar
|
||||
//- button(class='small text-tip' id='button-avatar-remove')
|
||||
//- | Remove Avatar
|
||||
//- button(class='default wide' id='button-banner')
|
||||
//- | Upload Banner
|
||||
//- button(class='small text-tip' id='button-banner-remove')
|
||||
//- | Remove Banner
|
||||
|
||||
//- //- Colors Section
|
||||
//- p(class='text-header') Accents
|
||||
//- div(class='widget-container')
|
||||
//- div(class='widget-color')
|
||||
//- label(class='text-tip' for='input-banner') Banner
|
||||
//- input(id='input-banner' type='color' class='color-preview')
|
||||
//- div(class='widget-color')
|
||||
//- label(class='text-tip' for='input-border') Border
|
||||
//- input(id='input-border' type='color' class='color-preview')
|
||||
//- div(class='widget-color')
|
||||
//- label(class='text-tip' for='input-background') Background
|
||||
//- input(id='input-background' type='color' class='color-preview')
|
||||
|
||||
//- //- Actions Section
|
||||
//- div(class='divider-line')
|
||||
//- p(id='profile-status')
|
||||
//- button(class='default wide destructive' id='button-cancel' disabled)
|
||||
//- | Discard
|
||||
//- button(class='default wide' id='button-submit' disabled)
|
||||
//- | Save Changes
|
||||
|
||||
//- //- Preview
|
||||
//- div(class='profile-container special-shadow')
|
||||
//- div(id='profile-banner')
|
||||
//- div(class='profile-header')
|
||||
//- img(id='profile-avatar' alt='My Avatar')
|
||||
//- div(id='profile-badges')
|
||||
//- div(class='profile-about text-nopad')
|
||||
//- div(class='info-alongside')
|
||||
//- p(id='profile-displayname')
|
||||
//- p(id='profile-username')
|
||||
//- p(id='profile-subtitle' class='text-tip')
|
||||
//- div(class='divider-line' id='profile-divider' hidden)
|
||||
//- pre(id='profile-bio' class='text-tip')
|
||||
|
||||
script(src='file://scripts/profile-index.ts')
|
||||
@@ -0,0 +1,57 @@
|
||||
extends ../_TemplateProfile
|
||||
block pageHeader
|
||||
title suzzy - Manage Account
|
||||
block pageContent
|
||||
- var loading_message = 'Account'
|
||||
p(class='text-hero') Account
|
||||
p(class='text-tip') Welcome to your account's security settings.
|
||||
p(class='text-tip') Here, you can manage various security options to help protect your account.
|
||||
div(class='collection-divider')
|
||||
include ../_TemplateProfilePage
|
||||
|
||||
//- div(id='security-wrapper' hidden)
|
||||
//- //- Email Address
|
||||
//- p(class='text-header') Email Address
|
||||
//- p(class='text-tip' id='preview-email' aria-live='polite')
|
||||
//- | Current Email Address:
|
||||
//- p(class='text-error' id='error-email')
|
||||
//- div(class='collection-wrapper')
|
||||
//- button(class='default' id='email-reveal')
|
||||
//- | Reveal Email Address
|
||||
//- button(class='default' id='email-edit')
|
||||
//- | Edit Email Address
|
||||
//- button(class='default' id='email-resend' hidden)
|
||||
//- | Resend Verification Email
|
||||
//- div(class='divider-spacer')
|
||||
|
||||
//- //- Password
|
||||
//- p(class='text-header') Password
|
||||
//- p(class='text-tip') Change your account password, doing so will sign you out on all other devices.
|
||||
//- button(class='default' id='password-change')
|
||||
//- | Change Password
|
||||
//- div(class='divider-spacer')
|
||||
|
||||
//- //- Multi-Factor
|
||||
//- p(class='text-header') Multi-Factor Authentication (MFA)
|
||||
//- p(class='text-tip') Use an Authenticator App to add an extra layer of security to your account.
|
||||
//- p(class='text-error' id='error-mfa')
|
||||
//- div(class='collection-wrapper')
|
||||
//- button(class='default' id='mfa-setup-start' hidden)
|
||||
//- | Setup Authenticator App
|
||||
//- button(class='default destructive' id='mfa-setup-remove' hidden)
|
||||
//- | Remove Authenticator App
|
||||
//- button(class='default' id='mfa-recovery-view' hidden)
|
||||
//- | View Recovery Codes
|
||||
//- button(class='default destructive' id='mfa-recovery-regen' hidden)
|
||||
//- | Generate New Codes
|
||||
//- div(class='divider-spacer')
|
||||
|
||||
//- //- Account Deletion
|
||||
//- div(class='divider-spacer')
|
||||
//- p(class='text-header') Danger Zone
|
||||
//- p(class='text-tip') Buttons that will cause major changes to your account.
|
||||
//- p(class='text-error' id='error-danger')
|
||||
//- button(class='default destructive' id='danger-deleteaccount')
|
||||
//- | Request Account Deletion
|
||||
|
||||
script(src='file://scripts/profile-security.ts')
|
||||
@@ -0,0 +1,187 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
meta(name='robots' content='noindex')
|
||||
title Secret Challenge - Picross!
|
||||
// Was bored and I love picross puzzles. Enjoy this little minigame.
|
||||
// This is also a one-time thing! There are no more easter eggs that give out badges!
|
||||
|
||||
block pageEscaped
|
||||
script(src='file://scripts/shared-utils.ts')
|
||||
script(src='file://scripts/challenge-picross.ts')
|
||||
|
||||
block pageContent
|
||||
// In case you're wondering I sampled my keyboard for the audio.
|
||||
// Also no you cannot mute it, now suffer.
|
||||
audio(hidden src='file://audio/picross_2.mp3' id='set')
|
||||
audio(hidden src='file://audio/picross_1.mp3' id='release')
|
||||
|
||||
p(class='text-header') Secret Challenge: Picross!
|
||||
p(class='text-tip') Solve this puzzle to earn the picross badge for your profile.
|
||||
p(class='text-tip text-muted') Controls: Left click to fill, right click to mark.
|
||||
|
||||
// thank you gzip for savin bandwidth
|
||||
div(class='special-picross')
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint') 3
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint') 7
|
||||
p(class='picross-hint') 5
|
||||
p(class='picross-hint') 5
|
||||
p(class='picross-hint') 4
|
||||
p(class='picross-hint') 8
|
||||
p(class='picross-hint') 3
|
||||
p(class='picross-hint') 2
|
||||
p(class='picross-hint') 2
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 3
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint') 1
|
||||
p(class='picross-hint') 1
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 5
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 2
|
||||
p(class='picross-hint') 2
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 3
|
||||
p(class='picross-hint') 1
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 5
|
||||
p(class='picross-hint') 1
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 8
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 7
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
div(class='picross-row')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint')
|
||||
p(class='picross-hint') 5
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
button(class='picross-button' dynamic)
|
||||
|
||||
//- User Actions
|
||||
div(class='divider-line')
|
||||
p(class='text-tip' id='time-spent') Time Spent: 00:00:00
|
||||
div(class='special-alongside')
|
||||
// NEVER GIVE UP!!!
|
||||
a(dynamic class='default' target='_blank' href='https://www.youtube.com/watch?v=KxGRhd_iWuE&t=2s' onclick='this.onclick=()=>{ alert("quitter..."); window.location.assign("/") }') I Give Up...
|
||||
a(dynamic class='default' id='done') Check it!
|
||||
@@ -0,0 +1,28 @@
|
||||
extends ../_TemplatePublic
|
||||
block pageHeader
|
||||
link(rel='stylesheet' href=`file://styles/public-homepage.css`)
|
||||
meta(property='og:title' content='suzzy games')
|
||||
meta(property='og:description' content='The official suzzy games website.')
|
||||
meta(name='description' content='The official suzzy games website.')
|
||||
meta(property='og:image' content='file://images/public-logo-og.png')
|
||||
title suzzy games
|
||||
block pageEscaped
|
||||
//- Widget: Hero
|
||||
div(class='widget widget-hero-wrapper')
|
||||
div(class='widget-hero')
|
||||
p(class='text-hero') Welcome!
|
||||
p
|
||||
| suzzy games is a personal project from the mind of
|
||||
| #[a(target='_blank' href='https://twitter.com/bakonpancakz') bakonpancakz]
|
||||
i
|
||||
p(class='text-muted text-tip') ❝There is no theme, there is no incentive, just pure passion and efficient code❞
|
||||
div(class='divider-spacer')
|
||||
p All projects are stuck in development hell until they suddenly aren't
|
||||
i
|
||||
p(class='text-tip')
|
||||
| Check out the #[a(class='text-tip' href='/blog') blog] to see what im up to
|
||||
| or play some old #[a(class='text-tip' href='/projects') projects]
|
||||
div(class='divider-spacer')
|
||||
p(class='text-tip text-muted' id='birthday')
|
||||
| Active since May 13th, 2021
|
||||
script(src='file://scripts/public-homepage.ts')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Login
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-index.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Reset Password
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-passwordreset.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Update Password
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-passwordupdate.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
@@ -0,0 +1,105 @@
|
||||
extends ../_TemplatePublic
|
||||
block pageHeader
|
||||
link(rel='stylesheet' href='file://styles/public-projects.css')
|
||||
meta(property='og:title' content='suzzy games - projects')
|
||||
meta(property='og:description' content='Projects from over the years.')
|
||||
meta(name='description' content='Projects from over the years.')
|
||||
meta(property='og:image' content='https://suzzygames.com/assets/images/og-logo.png')
|
||||
title suzzy games - projects
|
||||
block pageEscaped
|
||||
-
|
||||
const PROJECT_MANIFEST = [
|
||||
{
|
||||
accent: '#ff9d2f',
|
||||
brightness: 0.75,
|
||||
background: 'file://projects/monke/background.jpeg',
|
||||
name: 'Project Monke',
|
||||
state: 'In Development',
|
||||
platforms: ['desktop', 'mobile'],
|
||||
images: [
|
||||
{ label: 'Promo Banner', url: 'file://projects/monke/image-1.jpeg' },
|
||||
],
|
||||
description: [
|
||||
'Can only be explained as Super Monkey Ball and Super Mario Maker in one.',
|
||||
'Check the blog for news!',
|
||||
],
|
||||
actions: [
|
||||
{ label: 'View Blog Posts', url: '/blog/project-monke', target: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
accent: '#91defd',
|
||||
brightness: 0.75,
|
||||
name: 'Cart Ride Around a Fumo',
|
||||
background: 'file://projects/craf/background.jpeg',
|
||||
platforms: ['desktop', 'mobile'],
|
||||
state: '2021',
|
||||
images: [
|
||||
{ label: 'Promo Artwork #1', url: 'file://projects/craf/image-1.jpeg' },
|
||||
{ label: 'Promo Artwork #2', url: 'file://projects/craf/image-2.jpeg' },
|
||||
],
|
||||
description: [
|
||||
'My own spin on the classic ROBLOX cart ride genre.',
|
||||
'Centered around fumos for no specific reason.',
|
||||
'Warning: Contains explosions',
|
||||
],
|
||||
actions: [
|
||||
{ label: 'Play on ROBLOX', url: 'https://www.roblox.com/games/9987852646/Cart-Ride-Around-a-Fumo', target: '_blank' },
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
//- Layout: Header
|
||||
div(class='wrapper-widget-hero')
|
||||
div(class='widget-hero')
|
||||
p(class='text-hero') > Projects <
|
||||
p All of my projects in reverse chronological order (a.k.a. new to old)
|
||||
|
||||
//- Layout: Projects
|
||||
each p in PROJECT_MANIFEST
|
||||
div(class='widget widget-project' style=`--accent: ${p.accent}; --brightness: ${p.brightness}; --background: url('${p.background}');`)
|
||||
|
||||
//- Stack div elements with background underneath the foreground
|
||||
//- Image will be darkened using 'brightness' css variable
|
||||
div(class='project-background')
|
||||
div(class='project-foreground')
|
||||
|
||||
//- Project: Metadata
|
||||
div(class='project-content')
|
||||
|
||||
//- Name, Platforms, Descriptions
|
||||
div(class='project-info')
|
||||
div(class='project-header')
|
||||
p(class='text-header') #{p.name}
|
||||
div(class='project-platforms')
|
||||
if p.platforms.find(p => p === 'desktop')
|
||||
img(class='platform-icon' alt='Icon for Desktop Devices' src='file://icons/icon-computer.svg')
|
||||
if p.platforms.find(p => p === 'mobile')
|
||||
img(class='platform-icon' alt='Icon for Mobile Devices' src='file://icons/icon-mobile.svg')
|
||||
p • #{p.state}
|
||||
|
||||
div(class='divider-line' style='background-color: var(--accent);')
|
||||
div(class='project-description')
|
||||
each s in p.description
|
||||
p #{s}
|
||||
|
||||
//- Screenshots
|
||||
div(class='project-gallery')
|
||||
div(class='project-gallery-upper')
|
||||
button(class='project-gallery-button' id='last') <
|
||||
div(class='project-gallery-scroll')
|
||||
each i in p.images
|
||||
img(class='gallery-image' alt=`${p.name} - ${i.label}` src=i.url)
|
||||
button(class='project-gallery-button' id='next') >
|
||||
|
||||
div(class='project-content project-lower')
|
||||
div(class='project-actions')
|
||||
each a in p.actions
|
||||
a(class='default wide' target=a.target href=a.url) #{a.label}
|
||||
|
||||
//- Screenshot Gallery Controls
|
||||
div(class='project-gallery-actions')
|
||||
each _, i in p.images
|
||||
div(class=`gallery-dot${i===0 ? ' gallery-dot-active' : ''}`)
|
||||
|
||||
script(src='file://scripts/public-projects.ts')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Signup
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-signup.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Verify Email
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-verifyemail.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../_TemplateSpecial
|
||||
block pageHeader
|
||||
title suzzy games - Verify Login
|
||||
block pageEscaped
|
||||
script(src='file://scripts/login-verifylogin.ts')
|
||||
img(class='special-corner' src='file://images/login-globe.png')
|
||||
Reference in New Issue
Block a user