riccardo / dev

// Piacenza, Italy · always curious

Hello, human.
I’m Riccardo

Interfaces above.
APIs, data and automation below.

I’m a VAT-registered freelance Full Stack Developer. I work with Node.js, APIs and automation. At Wedoit, I contributed to a MERN and React Native course platform, from the frontend to backend and database support.

developer.tsAnother way to introduce myself
developer.tsread-only
01const developer = {
02  name: "Riccardo Ferri",
03  role: "Full Stack Developer",
04  focus: [
05    "backend",
06    "web interfaces",
07    "automation"
08  ],
09  stack: ["JS/TS", "Python"],
10  lookingFor: "projects + a good team"
11};
New projects and opportunities in a teamRemote · Hybrid · On-site
Node.jsExpressAstroSvelteReactMongoDBGit+ curiosity

// sito-astro · 2025 → 2026

An events website.
More than a homepage.

repo: private

I built the new CESO website in 2025 at comitatoeventisportivioltrepo.it, integrating the previous domain. In 2026, I made functional improvements and proposed a visual redesign with changes to part of the architecture. One concrete example: adding an event edition using a catalogue, shared components and reference validation.

  • Astro
  • Svelte
  • TypeScript
  • IT / EN
Background and full case study ↗
CESO / 2026 redesign proposalFull case study ↗
CESO homepage in the 2026 redesign proposal, with navigation and three featured sports events.

Compare both versions online.

Explore the current website and the 2026 redesign proposal. Links open in new tabs.

  1. before

    The previous website at eventisportivioltrepo.it was managed by another company.

  2. 2025 / create

    New website and integration of the previous domain.

  3. 2026 / iterate

    Features, interface and changes to part of the architecture.

Architecture, validation and technical choices

function composeEventPage()

01 / INPUT

Catalogue + content

Event data, IT/EN copy and shared editorial configuration.

02 / BUILD

Astro + validation

Layouts, reusable components and reference checks.

03 / OUTPUT

HTML + interactivity

Static pages with Svelte components where interaction is needed.

[01]

One source for the data

The previous edition’s title, year and cover image are resolved from the catalogue, avoiding manual updates across multiple pages.

[02]

Errors before publication

Unknown editions, self-references and invalid dates stop the build with an explicit error.

[03]

Deliberate fallbacks

If a cover image is missing, a text card remains available. Content guides and dedicated tests support development.

Open the 2026 visual diff

c9a7594 → bdc120c

− before the redesign / 2026
CESO homepage before the redesign, desktop view.
+ redesign proposal / 2026
CESO homepage redesign proposal, desktop view.

Real screenshots from 25 September 2026, both from the website I built. They may differ from the updated live versions linked above. The reconstruction shared some assets. This comparison does not show the earlier website managed by another company or measured improvements in traffic or conversion. Context and historical archive ↗

// backend & automation

Connect services.
Organise data.

Two projects, two approaches: events and APIs on the server, and interaction with pages in the browser.

01 / backend & integrations

webhook-server.js

Node.js / Express

Incoming events, data operations and external services. An Express server connecting Notion, Google Calendar and email notifications, with scheduled tasks using cron.

  1. 01 / RECEIVEWebhook

    Receive the event and return HTTP 202.

  2. 02 / PROCESSIn-memory queue

    Functions run sequentially.

  3. 03 / INTEGRATEExternal services

    Updates to Notion, calendar and email.

Technical choices and limitations

Separate responsibilities

Routes, services and integration logic are separate modules. Scheduled jobs use the same task queue.

Read beyond the first page

The Notion service traverses results using a cursor, collecting records from subsequent pages too.

The queue trade-off

Failed tasks can be requeued from the admin panel. The queue lives in memory: it does not persist across restarts or guarantee durable delivery.

  • Express
  • Notion API
  • Google Calendar API
  • node-cron
  • Nodemailer

02 / personal automation

universita_helpbot.py

Python / Selenium

A personal browser automation project: collecting and organising questions and answers, saving them in JSON and creating flashcards through web interfaces.

Web pagesSelenium + PythonJSON / flashcard
What’s in the project

Interact with pages

WebDriver, DOM selectors and explicit waits to read content and interact with interfaces.

Reusable data

Information is collected and grouped in JSON files, then reused in flashcard workflows.

Dependence on the interface

Browser automation follows the structure of the pages. Changes to selectors and workflows require maintenance: one of the project’s limitations.

  • Python
  • Selenium WebDriver
  • DOM
  • JSON

// webhook-server · from code to behaviour

One event.
A workflow to follow.

Local demo · sample data

A record changes, the server accepts the event and the work enters a queue. This simulation makes waiting, completion and error recovery visible. You can send several events and process them one at a time.

The interactive demo requires JavaScript. The workflow and technical decisions are also described below.

Event log
  1. Waiting for events.
Demo decisions, limitations and code

What comes from the project

A 202 response from dedicated routes, sequential execution and the option to manually requeue failed tasks at the end. The source separates routes, the queue and external services.

The key limitation

The queue lives in memory: restarting loses its state. Retrying reruns the task and does not guarantee freedom from duplicates. Persistence and idempotency would need to be designed as future improvements.

How to read this demo

A standalone simulation written for the portfolio, limited to six events. The simulated service becomes available on the second attempt. Private backend code is neither executed nor distributed.

Read the demo code ↓

// the experimental side

Code for
curiosity.

Games, 3D worlds and networked interactions.
Twelve learning projects, from tutorial foundations to my own adaptations. Plus two small pieces you can try here.

Live fragment / Three.js

From my 3D portfolio.

A surface that moves and changes colour under the pointer. Taken from my-portfolio, adapted to this small space.

It only animates when you activate it.
01Games & interactionMovement, collisions and game systems6 projects
Real Fight screenshot: two pixel art fighters in an arena, with health bars and a timer.

Featured / JavaScript + Canvas

Fight.

fight · two players, keyboard or touch

A fighting game built from a Chris Courses tutorial, which I continued to improve.

In this version
Double jump, wall jump, friction and hit reactions.
Inside the code
Fighter states, animated sprites and attack collisions.
60-second rounds · 2 local players
Based on Chris Courses ↗

JavaScript / Canvas / Camera

js_vertical_platformer

A platformer with gravity, collisions, platforms and a camera that follows the character on both axes. A prototype exploring the relationship between world coordinates, movement and framing.

Tutorial ↗

Three.js / JavaScript

js_threejs_game

Keyboard movement, gravity, collisions and progressively spawning enemies. A prototype exploring the update loop of a 3D game.

Tutorial ↗
023D graphics & shadersGeometry, light and mouse interaction5 projects

Three.js / Raycaster / GSAP

my-portfolio

My first 3D portfolio experiment: an animated triangulated surface, vertex colours that react to the mouse and adjustable parameters using dat.GUI. A playground for geometry and interaction.

Tutorial ↗

GLSL / Uniforms / Varyings

intro_to_GLSL

Experiments with vertex and fragment shaders, time passed through uniforms and wave deformations. The source also includes my own formula experiments.

Tutorial ↗

Three.js / OrbitControls / GSAP

three_crash_course_n12

Scene, camera and lights; orbit controls, resize handling and colour changes driven by the mouse.

Tutorial ↗
03Multiplayer & networkingShared state, synchronisation and latency1 project

Node.js / Express / Socket.IO

multiplayer_game

Server-managed player state, movement synchronisation, client interpolation, projectiles and a leaderboard. An exercise exploring the relationship between networking and gameplay.

Tutorial ↗
Client inputServer stateClient interpolation

Real screenshots from local copies; remote fonts are replaced with local fonts in the previews. Links credit the original foundations, while the cards describe my own adaptations. Tutorial assets belong to their respective authors.

// one edge case beats three buzzwords

What if something is missing?

An interactive example of the rules for linking a previous edition: valid references, incomplete content and data that needs fixing. Sample data, running in your browser.

event.demo.jsoninput
{
  "slug": "evento-2026",
  "lastEdition": "evento-2025",
  "previousCover": "cover.jpg"
}
OK / VALID REFERENCE

The previous edition exists.

The catalogue resolves the title, year and cover image. The page can be built.

→ card with title + year + cover image

Another way
to get to know me.

Try help, whoami or coffee.
This shell only runs on this page.

visitor@riccardo:~portfolio-shell

Welcome to the developer side.

Type help for the list of commands. Tab and Enter work as you would expect.

// no ticket needed to say hello

Let’s start a
conversation.

VAT-registered freelancer, available for new projects.
Interested in joining a team: remote, hybrid or on-site.

rikiferri999@gmail.com ↗

Playground / playable demo

Fight.

Two players on the same keyboard, or use the buttons below. Press jump again while airborne to double jump. Esc to exit.

01 / SamuraiA · D · Space · J
02 / Kenji← · → · ↑ · Delete

From my repository fight · based on Chris Courses ↗, extended with my own changes.

Go to…

Tab to choose · Enter to open · Esc to close