---
title: ""
page-layout: article
toc: false
---
::: {.sidebar-intro}
## Welcome
I'm **Maxime Rivest**, a developer passionate about the about api design, tool making and AI.
::: {.sidebar-links}
[Explore My Writing](#recent-posts){.btn-sidebar-primary}
[About Me](#about){.btn-sidebar-secondary}
:::
:::
::: {.content-section .recent-posts-section}
## Recent Posts {#recent-posts}
```{r}
#| echo: false
#| output: asis
#| warning: false
# Get all posts
posts <- list.files("posts", pattern = "\\.qmd$", full.names = TRUE)
# Function to extract metadata from a post
extract_metadata <- function(post_path) {
lines <- readLines(post_path, warn = FALSE)
# Find YAML boundaries
yaml_start <- which(lines == "---")[1]
yaml_end <- which(lines == "---")[2]
if (!is.na(yaml_start) && !is.na(yaml_end)) {
yaml_content <- lines[(yaml_start + 1):(yaml_end - 1)]
# Extract title
title_line <- grep("^title:", yaml_content, value = TRUE)
title <- gsub("^title:\\s*['\"]?([^'\"]*)['\"]?", "\\1", title_line)
# Extract date
date_line <- grep("^date:", yaml_content, value = TRUE)
date <- gsub("^date:\\s*['\"]?([^'\"]*)['\"]?", "\\1", date_line)
# Extract description
desc_line <- grep("^description:", yaml_content, value = TRUE)
description <- if(length(desc_line) > 0) {
gsub("^description:\\s*['\"]?([^'\"]*)['\"]?", "\\1", desc_line)
} else {
# Try to get first paragraph after YAML
content_start <- yaml_end + 1
while(content_start <= length(lines) && lines[content_start] == "") {
content_start <- content_start + 1
}
if(content_start <= length(lines)) {
substr(lines[content_start], 1, 150)
} else {
"Read more..."
}
}
# Extract categories
cat_line <- grep("^categories:", yaml_content, value = TRUE)
categories <- if(length(cat_line) > 0) {
# Look for array format
cat_start <- which(yaml_content == cat_line)
cats <- c()
i <- cat_start + 1
while(i <= length(yaml_content) && grepl("^\\s*-", yaml_content[i])) {
cats <- c(cats, gsub("^\\s*-\\s*", "", yaml_content[i]))
i <- i + 1
}
cats
} else {
NULL
}
return(list(
title = title,
date = date,
description = description,
categories = categories,
path = post_path
))
}
return(NULL)
}
# Extract metadata from all posts
posts_metadata <- lapply(posts, extract_metadata)
posts_metadata <- posts_metadata[!sapply(posts_metadata, is.null)]
# Filter out posts with [wip] in the title
posts_metadata <- posts_metadata[!sapply(posts_metadata, function(x) grepl("\\[wip\\]", x$title, ignore.case = TRUE))]
# Sort by date (most recent first)
if(length(posts_metadata) > 0) {
dates <- sapply(posts_metadata, function(x) x$date)
posts_metadata <- posts_metadata[order(dates, decreasing = TRUE)]
# Display posts
for(post in posts_metadata[1:min(3, length(posts_metadata))]) {
cat(sprintf('::: {.post-card}\n'))
cat(sprintf('### [%s](%s)\n\n', post$title, gsub("\\.qmd$", ".html", post$path)))
if(!is.null(post$date) && post$date != "") {
cat(sprintf('::: {.post-meta}\n'))
cat(sprintf('<span class="post-date">%s</span>\n', post$date))
if(!is.null(post$categories) && length(post$categories) > 0) {
cat('<span class="post-categories">\n')
for(cat in post$categories) {
cat(sprintf('<span class="category-tag">%s</span>\n', cat))
}
cat('</span>\n')
}
cat(':::\n\n')
}
cat(sprintf('%s\n\n', post$description))
cat(sprintf('[Continue reading →](%s){.read-more}\n', gsub("\\.qmd$", ".html", post$path)))
cat(':::\n\n')
}
if(length(posts_metadata) > 3) {
cat('\n[View all posts →](posts.html){.btn-outline}\n')
}
} else {
cat('::: {.empty-state}\n')
cat('### No posts yet\n\n')
cat('Stay tuned for upcoming content!\n')
cat(':::\n')
}
```
:::
::: {.content-section}
## I write about what I do {#topics}
These days I do those projects:
::: {.topic-grid}
::: {.topic-card}
### Human Computer Interaction
Human computer interaction with voice, hotkeys and the clipboard with [MetaKeyAI](https://github.com/maximerivest/MetaKeyAI)
:::
::: {.topic-card}
### Data Analytics
AI interface for data analytics [Jupyter-Whisper](https://github.com/maximerivest/jupyter-whisper)
:::
::: {.topic-card}
### Developer Tool
General llm funnel; from any file to llm ready content [Attachments](https://github.com/maximerivest/Attachments)
:::
::: {.topic-card}
### API design
API design for building AI agents and AI Software [FunnyDSPy](https://github.com/maximerivest/FunnyDSPy), [OneTokenPy](https://github.com/maximerivest/OneTokenPy-library)
:::
:::
:::
::: {.content-section .about-section}
## About Me {#about}
::: {.about-content}
I'm an Applied AI Engineer with a background in Scientific Computing and Data Analytics.
### Connect With Me
::: {.social-links}
[<i class="bi bi-twitter"></i> X](https://x.com/maximerivest){.social-link}
[<i class="bi bi-github"></i> GitHub](https://github.com/maximerivest){.social-link}
[<i class="bi bi-envelope"></i> Email](mailto:mrive052@gmail.com){.social-link}
:::
:::
:::
<style>
/* Sidebar intro section */
.sidebar-intro {
position: fixed;
right: 2rem;
top: 120px;
width: 280px;
padding: 1.5rem;
background: var(--bs-gray-100, #f8f9fa);
border-radius: 0.5rem;
border: 1px solid var(--bs-gray-200, #e9ecef);
max-height: calc(100vh - 140px);
overflow-y: auto;
}
.sidebar-intro h2 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--bs-primary, #0C85CC);
}
.sidebar-intro p {
font-size: 0.9rem;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.sidebar-links {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 1rem;
}
.btn-sidebar-primary, .btn-sidebar-secondary {
display: inline-block;
padding: 0.375rem 0.75rem;
text-decoration: none;
font-weight: 400;
font-size: 0.8rem;
transition: all 0.2s ease;
color: var(--bs-primary, #0C85CC);
background: transparent;
border: none;
text-align: left;
position: relative;
padding-left: 1.5rem;
}
.btn-sidebar-primary::before, .btn-sidebar-secondary::before {
content: '→';
position: absolute;
left: 0.5rem;
transition: transform 0.2s ease;
}
.btn-sidebar-primary:hover, .btn-sidebar-secondary:hover {
color: var(--bs-secondary, #1DBFE0);
background: transparent;
}
.btn-sidebar-primary:hover::before, .btn-sidebar-secondary:hover::before {
transform: translateX(3px);
}
/* Adjust main content to account for sidebar */
@media (min-width: 1200px) {
.content-section {
margin-right: 320px;
}
}
/* Hide sidebar on mobile */
@media (max-width: 1199px) {
.sidebar-intro {
display: none;
}
.content-section {
margin-right: auto;
}
}
/* Content Sections */
.content-section {
margin: 4rem auto;
max-width: 1200px;
padding: 0 2rem;
}
.content-section h2 {
text-align: center;
margin-bottom: 3rem;
font-size: 2.5rem;
font-weight: 700;
}
/* Topic Grid */
.topic-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 4rem;
}
.topic-card {
padding: 2rem;
background: var(--bs-gray-100, #f8f9fa);
border-radius: 1rem;
transition: all 0.3s ease;
border: 1px solid transparent;
}
.topic-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.1);
border-color: var(--bs-primary, #0C85CC);
}
.topic-card h3 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--bs-primary, #0C85CC);
}
/* Recent Posts */
.post-card {
padding: 2rem;
margin-bottom: 2rem;
background: white;
border-radius: 1rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
border: 1px solid var(--bs-gray-200, #e9ecef);
}
.post-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.post-card h3 {
margin-bottom: 1rem;
}
.post-card h3 a {
color: var(--bs-gray-900, #212529);
text-decoration: none;
font-weight: 700;
}
.post-meta {
display: flex;
gap: 1rem;
align-items: center;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.post-date {
color: var(--bs-gray-600, #6c757d);
font-size: 0.875rem;
}
.category-tag {
background: var(--bs-primary, #0C85CC);
color: white;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.75rem;
font-weight: 500;
}
.read-more {
color: var(--bs-primary, #0C85CC);
font-weight: 600;
text-decoration: none;
}
.read-more:hover {
text-decoration: underline;
}
.btn-outline {
display: inline-block;
margin-top: 1rem;
padding: 0.75rem 2rem;
border: 2px solid var(--bs-primary, #0C85CC);
color: var(--bs-primary, #0C85CC);
border-radius: 2rem;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-outline:hover {
background: var(--bs-primary, #0C85CC);
color: white;
}
/* About Section */
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.social-links {
display: flex;
gap: 1.5rem;
justify-content: center;
margin: 2rem 0;
}
.social-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: var(--bs-gray-100, #f8f9fa);
border-radius: 2rem;
text-decoration: none;
color: var(--bs-gray-700, #495057);
transition: all 0.3s ease;
}
.social-link:hover {
background: var(--bs-primary, #0C85CC);
color: white;
transform: translateY(-2px);
}
/* Newsletter Section */
.newsletter-section {
background: linear-gradient(135deg, rgba(12, 133, 204, 0.05) 0%, rgba(29, 191, 224, 0.05) 100%);
padding: 4rem 2rem;
margin: 4rem -2rem -2rem -2rem;
text-align: center;
}
.newsletter-content h3 {
font-size: 2rem;
margin-bottom: 1rem;
}
.email-form {
display: flex;
gap: 1rem;
max-width: 400px;
margin: 2rem auto;
}
.email-form input {
flex: 1;
padding: 0.75rem 1.5rem;
border: 2px solid var(--bs-gray-300, #dee2e6);
border-radius: 2rem;
font-size: 1rem;
}
.email-form button {
padding: 0.75rem 2rem;
background: var(--bs-primary, #0C85CC);
color: white;
border: none;
border-radius: 2rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.email-form button:hover {
background: var(--bs-secondary, #1DBFE0);
transform: translateY(-2px);
}
/* Dark mode adjustments */
.quarto-dark .sidebar-intro {
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
}
.quarto-dark .sidebar-intro h2 {
color: var(--bs-primary, #0C85CC);
}
.quarto-dark .sidebar-intro p {
color: var(--bs-gray-300, #dee2e6);
}
.quarto-dark .topic-card {
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
}
.quarto-dark .post-card {
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
}
.quarto-dark .post-card h3 a {
color: var(--bs-gray-100, #f8f9fa);
}
.quarto-dark .social-link {
background: rgba(255, 255, 255, 0.1);
color: var(--bs-gray-300, #dee2e6);
}
.quarto-dark .newsletter-section {
background: linear-gradient(135deg, rgba(12, 133, 204, 0.1) 0%, rgba(29, 191, 224, 0.1) 100%);
}
.quarto-dark .email-form input {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.2);
color: white;
}
/* Responsive design */
@media (max-width: 991px) {
.hero-section {
padding: 3rem 1rem;
min-height: auto;
}
.hero-content h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.hero-content p {
font-size: 1.1rem;
margin-bottom: 2rem;
}
.hero-buttons {
flex-direction: column;
gap: 1rem;
align-items: stretch;
}
.btn-hero-primary, .btn-hero-secondary {
width: 100%;
text-align: center;
padding: 1rem;
}
.sidebar-intro {
position: relative;
width: 100%;
margin: 0 0 2rem 0;
max-height: none;
}
.content-section {
padding: 3rem 1rem;
}
.content-section h2 {
font-size: 2rem;
margin-bottom: 0.75rem;
}
.topic-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.post-grid {
grid-template-columns: 1fr;
}
.newsletter-section {
padding: 2rem 1rem;
}
.newsletter-section h2 {
font-size: 1.75rem;
}
.email-form {
flex-direction: column;
max-width: 100%;
}
.email-form input {
width: 100%;
text-align: center;
}
.email-form button {
width: 100%;
}
.social-links {
justify-content: center;
gap: 1rem;
}
}
@media (max-width: 575px) {
.hero-content h1 {
font-size: 2rem;
line-height: 1.2;
}
.hero-content p {
font-size: 1rem;
}
.hero-section {
padding: 2rem 1rem;
}
.content-section {
padding: 2rem 1rem;
}
.content-section h2 {
font-size: 1.75rem;
}
.topic-card {
padding: 1.25rem;
}
.topic-card h3 {
font-size: 1.1rem;
}
.post-card {
padding: 1.25rem;
}
.post-card h3 {
font-size: 1.1rem;
}
.newsletter-section {
padding: 2rem 1rem;
margin: 2rem 0;
}
.newsletter-section h2 {
font-size: 1.5rem;
}
.newsletter-section p {
font-size: 0.95rem;
}
.email-form input {
padding: 0.75rem 1rem;
font-size: 16px; /* Prevents zoom on iOS */
}
.email-form button {
padding: 0.75rem 1.5rem;
}
.social-link {
width: 44px;
height: 44px;
}
}
/* Touch-friendly adjustments */
@media (hover: none) and (pointer: coarse) {
.btn-hero-primary, .btn-hero-secondary {
padding: 1rem 2rem;
}
.topic-card, .post-card {
-webkit-tap-highlight-color: transparent;
}
.social-link {
width: 48px;
height: 48px;
}
}
</style>