Changing Colors
The site uses CSS custom properties (variables) for easy theme customization.
Color Variables
Open styles.css and modify the :root selector:
:root {
--sub : #828282 ; /* Subdued/secondary color */
--main : #000000 ; /* Main/primary color */
}
Light Theme (Current)
Dark Theme
Colorful Theme
:root {
--sub : #828282 ;
--main : #000000 ;
}
body {
color : #000000 ;
background-color : #ffffff ;
}
:root {
--sub : #999999 ;
--main : #ffffff ;
}
body {
color : #ffffff ;
background-color : #0a0a0a ;
}
a {
color : #ffffff ;
}
:root {
--sub : #8b7fc7 ;
--main : #5a4a9f ;
}
body {
color : #2d2645 ;
background-color : #faf9fc ;
}
a {
color : #5a4a9f ;
}
Customize the footer link buttons:
.ftr {
font-size : 12 px ;
padding : 4 px 7 px ;
border-radius : 7 px ;
background-color : #b8b8b8 ; /* Button background */
color : #ffffff ; /* Button text */
text-decoration : none ;
margin-left : 3 px ;
}
/* Hover effect */
.ftr:hover {
background-color : #a0a0a0 ;
transition : background-color 0.2 s ease ;
}
Ensure sufficient color contrast for accessibility. Aim for at least 4.5:1 ratio for normal text and 3:1 for large text.
Updating Typography
The site uses a custom font stack with Host Grotesk as the primary typeface.
Changing the Primary Font
Option 1: Use a Different Local Font
body {
font-family : 'YourFontName' , -apple-system , BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, Adwaita Sans, Cantarell, Ubuntu, roboto, noto, helvetica , arial , sans-serif ;
}
Option 2: Use Google Fonts
Add Font Link
In index.html <head>: < link rel = "preconnect" href = "https://fonts.googleapis.com" >
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
< link href = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap" rel = "stylesheet" >
Update CSS
In styles.css : body {
font-family : 'Inter' , sans-serif ;
}
Option 3: Use System Fonts Only
body {
font-family : -apple-system , BlinkMacSystemFont, 'Segoe UI' , Roboto, Helvetica , Arial , sans-serif ;
}
Font Size Adjustments
body {
font-size : 20 px ; /* Base size */
}
/* Make text smaller */
body {
font-size : 16 px ;
}
/* Make text larger */
body {
font-size : 24 px ;
}
/* Responsive sizing */
body {
font-size : clamp ( 16 px , 2.5 vw , 20 px );
}
Understanding the Font Stack
The current font stack: font-family : 'Host Grotesk', -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, Adwaita Sans, Cantarell, Ubuntu, roboto, noto, helvetica, arial, sans-serif ;
Fallback order:
Host Grotesk (custom web font)
-apple-system (macOS/iOS system font)
BlinkMacSystemFont (Chrome on macOS)
avenir next / avenir (macOS)
segoe ui (Windows)
helvetica neue (macOS/iOS)
Adwaita Sans (Linux GNOME)
Cantarell (Linux)
Ubuntu (Linux Ubuntu)
roboto, noto (Android)
helvetica, arial (universal fallbacks)
sans-serif (system default)
Adding Custom Fonts
Add Font Files
Place font files in /fonts/ directory: /fonts/
YourFont-Regular.woff2
YourFont-Regular.woff
YourFont-Bold.woff2
YourFont-Bold.woff
Declare @font-face
In styles.css : @font-face {
font-family : 'YourFont' ;
src : url ( '/fonts/YourFont-Regular.woff2' ) format ( 'woff2' ),
url ( '/fonts/YourFont-Regular.woff' ) format ( 'woff' );
font-style : normal ;
font-weight : 400 ;
font-display : swap ;
}
@font-face {
font-family : 'YourFont' ;
src : url ( '/fonts/YourFont-Bold.woff2' ) format ( 'woff2' ),
url ( '/fonts/YourFont-Bold.woff' ) format ( 'woff' );
font-style : normal ;
font-weight : 700 ;
font-display : swap ;
}
Update Body Font
body {
font-family : 'YourFont' , sans-serif ;
}
Use font-display: swap to prevent invisible text during font loading. The system font shows first, then swaps to custom font.
Modifying Layout
The site uses a centered, vertically-aligned layout with constrained width.
Width Adjustments
body {
width : 70 % ; /* Responsive width */
max-width : 400 px ; /* Maximum width */
}
Narrow Layout
Wide Layout
Full Width
Fixed Width
body {
width : 60 % ;
max-width : 350 px ;
}
body {
width : 85 % ;
max-width : 600 px ;
}
body {
width : 95 % ;
max-width : 1200 px ;
}
body {
width : 450 px ;
max-width : none ;
}
/* Add responsive override */
@media ( max-width : 480 px ) {
body {
width : 90 % ;
}
}
Padding and Spacing
body {
padding : 18 px ; /* Internal spacing */
}
/* Increase padding */
body {
padding : 32 px ;
}
/* Responsive padding */
body {
padding : clamp ( 16 px , 3 vw , 32 px );
}
/* Different padding per side */
body {
padding : 32 px 24 px ; /* top/bottom left/right */
}
Vertical Centering
The current centering approach:
html , body {
height : 100 % ;
}
html {
display : table ;
margin : auto ;
}
body {
display : table-cell ;
vertical-align : middle ;
}
Alternative Centering Methods
Flexbox Method: html {
height : 100 % ;
display : flex ;
align-items : center ;
justify-content : center ;
}
body {
width : 70 % ;
max-width : 400 px ;
}
Grid Method: html {
height : 100 % ;
display : grid ;
place-items : center ;
}
body {
width : 70 % ;
max-width : 400 px ;
}
No Vertical Centering: body {
margin : 0 auto ;
padding : 48 px 18 px ;
width : 70 % ;
max-width : 400 px ;
}
Mobile Responsiveness
Add responsive breakpoints:
/* Tablet */
@media ( max-width : 768 px ) {
body {
width : 80 % ;
max-width : 500 px ;
font-size : 18 px ;
}
}
/* Mobile */
@media ( max-width : 480 px ) {
body {
width : 90 % ;
font-size : 16 px ;
padding : 16 px ;
}
.logo {
width : 10 px ;
height : 10 px ;
}
}
Replacing Logo
The logo is a simple SVG file in the repository root.
Update Existing SVG
Method 1: Replace logo.svg
Design New Logo
Create your logo in any vector editor (Figma, Illustrator, Inkscape)
Export as SVG
Export with these settings:
Format: SVG
Remove unnecessary metadata
Optimize/minify paths
Replace File
Save new SVG as logo.svg in repository root, overwriting old file
Method 2: Use Different Format
<!-- PNG logo -->
< img class = "logo" src = "./logo.png" >
<!-- WebP logo (better compression) -->
< img class = "logo" src = "./logo.webp" >
<!-- Emoji logo -->
< div > 🌀 raster </ div >
Adjust Logo Size
In styles.css :
.logo {
width : 12 px ;
height : 12 px ;
}
/* Larger logo */
.logo {
width : 20 px ;
height : 20 px ;
}
/* Responsive logo */
.logo {
width : clamp ( 10 px , 2 vw , 16 px );
height : clamp ( 10 px , 2 vw , 16 px );
}
Logo Color Customization
For SVG logos, modify the fill attribute:
<!-- Black logo -->
< path fill = "#000000" ... />
<!-- Colored logo -->
< path fill = "#5a4a9f" ... />
<!-- CSS-controlled color -->
< svg class = "logo" ... >
< path fill = "currentColor" ... />
</ svg >
Then in CSS:
.logo {
color : #000000 ; /* Controls fill="currentColor" */
}
.logo:hover {
color : #5a4a9f ;
}
Adding New Links
The links page is a separate HTML file with categorized link collections.
Edit links/index.html
Add New Category:
< h2 > design tools </ h2 >
< p >< a href = "https://www.figma.com/" > figma </ a > (freemium) - collaborative design platform </ p >
< p >< a href = "https://www.sketch.com/" > sketch </ a > (paid) - mac design tool </ p >
< p >< a href = "https://affinity.serif.com/" > affinity designer </ a > (paid) - photoshop alternative </ p >
Add Link to Existing Category:
< h2 > blogging tools </ h2 >
< p >< a href = "https://tilde.club/~april/bloggable/" > bloggable </ a > (free) - free blog tool for neocities </ p >
< p >< a href = "https://bearblog.dev/" > bear blog </ a > (freemium) - no-fluff blogging platform </ p >
<!-- Add new link here -->
< p >< a href = "https://write.as/" > write.as </ a > (freemium) - minimalist blogging platform </ p >
Link to Links Page
The homepage footer already includes the link:
< div style = "font-size: 14px; padding-top: 1rem;" >
< a href = "https://status.cafe/users/raster" class = "ftr" > status </ a >
< a class = "ftr" href = "/links" > links </ a >
</ div >
Add more footer links:
< div style = "font-size: 14px; padding-top: 1rem;" >
< a href = "https://status.cafe/users/raster" class = "ftr" > status </ a >
< a class = "ftr" href = "/links" > links </ a >
< a class = "ftr" href = "/blog" > blog </ a >
< a class = "ftr" href = "mailto:[email protected] " > contact </ a >
</ div >
Customizing Status.cafe Username
The Status.cafe widget displays your current status from the Status.cafe service.
Change Username
In index.html , update the script source:
<!-- Current username: raster -->
< script src = "https://status.cafe/current-status.js?name=raster" defer ></ script >
<!-- Change to your username -->
< script src = "https://status.cafe/current-status.js?name=yourusername" defer ></ script >
< div >
< div id = "statuscafe" >
< div id = "statuscafe-username" ></ div >
< div id = "statuscafe-content" ></ div >
</ div >
</ div >
< script src = "https://status.cafe/current-status.js?name=raster" defer ></ script >
Alternative Status Services
Extending Convex Mutations
The site includes a Convex backend setup for future blog functionality.
Current Mutation
In post-db/convex/posts.ts :
import { v } from "convex/values" ;
import { internalMutation } from "./_generated/server" ;
export const createPost = internalMutation ({
args: {
content: v . string (),
},
handler : async ( ctx , args ) => {
const id = await ctx . db . insert ( "posts" , { content: args . content });
return id ;
},
});
Add More Fields
import { v } from "convex/values" ;
import { internalMutation } from "./_generated/server" ;
export const createPost = internalMutation ({
args: {
title: v . string (),
content: v . string (),
author: v . string (),
tags: v . array ( v . string ()),
published: v . boolean (),
},
handler : async ( ctx , args ) => {
const id = await ctx . db . insert ( "posts" , {
title: args . title ,
content: args . content ,
author: args . author ,
tags: args . tags ,
published: args . published ,
createdAt: Date . now (),
});
return id ;
},
});
Add Query Function
import { v } from "convex/values" ;
import { query , internalMutation } from "./_generated/server" ;
// Get all published posts
export const getPosts = query ({
handler : async ( ctx ) => {
return await ctx . db
. query ( "posts" )
. filter (( q ) => q . eq ( q . field ( "published" ), true ))
. order ( "desc" )
. collect ();
},
});
// Get single post by ID
export const getPost = query ({
args: { postId: v . id ( "posts" ) },
handler : async ( ctx , args ) => {
return await ctx . db . get ( args . postId );
},
});
Add Update/Delete Mutations
// Update post
export const updatePost = internalMutation ({
args: {
postId: v . id ( "posts" ),
title: v . optional ( v . string ()),
content: v . optional ( v . string ()),
published: v . optional ( v . boolean ()),
},
handler : async ( ctx , args ) => {
const { postId , ... updates } = args ;
await ctx . db . patch ( postId , {
... updates ,
updatedAt: Date . now (),
});
},
});
// Delete post
export const deletePost = internalMutation ({
args: { postId: v . id ( "posts" ) },
handler : async ( ctx , args ) => {
await ctx . db . delete ( args . postId );
},
});
These mutations are marked internalMutation, meaning they can only be called from Convex functions, not directly from the browser. For browser access, use mutation instead (but add authentication first!).
Define Schema
Create post-db/convex/schema.ts :
import { defineSchema , defineTable } from "convex/server" ;
import { v } from "convex/values" ;
export default defineSchema ({
posts: defineTable ({
title: v . string (),
content: v . string (),
author: v . string (),
tags: v . array ( v . string ()),
published: v . boolean (),
createdAt: v . number (),
updatedAt: v . optional ( v . number ()),
})
. index ( "by_published" , [ "published" ])
. index ( "by_author" , [ "author" ])
. searchIndex ( "search_content" , {
searchField: "content" ,
filterFields: [ "published" ],
}) ,
}) ;
To actually use Convex:
Integrate with Frontend
< script type = "module" >
import { ConvexHttpClient } from "convex/browser" ;
const client = new ConvexHttpClient ( "https://your-deployment.convex.cloud" );
const posts = await client . query ( "posts:getPosts" );
console . log ( posts );
</ script >