Pricing refonte après rapport 3 (RESEARCH/Hytale/3 Pricing Calibration).
**Décision clé du rapport** : aucun serveur Hytale n'a payé €500+ pour
un plugin single en 2026 (public data). Top server Runeteria = 29 CCU
peak, €200-800/mois gross revenue ceiling. 70-80% du top 30 serveurs
= volunteer/owner-coded, zéro budget externe.
**Nouvelle grille adaptée à la réalité du marché Hytale** :
- Plugin Essentiel 149€ (1 feature, ≤8h, livraison 3-5j)
- Système Sur-Mesure 349€ (GUI in-game, ≤20h, 1-2 sem) [featured]
- Module Flagship 790€ (quote-based, top-30 tier only)
- Retainer Mensuel 450€/mois (~12h/mo)
- Site Gaming 500€
**Ajout** : pricingNote avec mention 45€/h (spot fixes) et flagship CTA.
Ancienne grille (400€/1500€/5000€) filtrait 95% du marché — non viable.
Nouvelle grille capture ~85% de la demande Hytale observée tout en
laissant room upsell pour les 5-8 flagship servers réels.
RESEARCH/Hytale/3 ajouté (rapport complet avec top 30 audit, BBB
scatter analysis, WTP evidence par segment, 3 scénarios projetés).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- REBRAND-01/02/03 commited in f72170b (JSON-LD + 14 i18n keys FR/EN)
- COCON-01 already shipped with M1.1 carry-over (HytaleRecentArticles
live sur /hytale.vue:38, bilingue FR/EN avec filter tag hytale)
M1.2 progress: 4/6 plans (67%). Seule Phase 10 (5 demo plugins Hytale)
reste — user code les plugins en side, Plan 10-03 (HytaleDemoGrid) à
attaquer quand ≥1 plugin shippé sur GitHub.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DEPLOY-02 + DEPLOY-03 validés. Build hang résolu via hook close dans
nuxt.config.ts (nuxt/nuxt#33987). Next: Phase 10 (démos plugins).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Foundation SEO Blog shipped — nuxt-schema-org installed, blog schema extended
with updated field, global Person/WebSite schema.org emitted SSR, sitemap.sources
wired to future Nitro endpoint (07-04).
- variant="default" (listing): cover image conditional (D-03 no fallback),
aspect-[16/9], first tag UBadge, date i18n via Intl.DateTimeFormat,
h2 title, line-clamp-2 description, reading time + extra tags pills,
absolute inset-0 NuxtLink for SEO/a11y (D-02 tags non-clickable)
- variant="compact" (prev/next, D-09/D-10): no image, label row with
UIcon arrow (left/right per direction), h3 title, date mono,
text-right on next / text-left on prev
- Props: article, variant?='default'|'compact', direction?='prev'|'next'
- Slug derived from article.path last segment (locale-agnostic)
- readingMinutes: uses article.minutes (Nitro hook) with useReadingTime
fallback on article.description
- Schema.org BlogPosting markup (headline/description/keywords/url/image/
datePublished) — ready for Phase 7 JSON-LD Article
- a11y aria-label interpolated via t('a11y.blogPrev'|'blogNext', {title})
- Insert { key: 'blog', path: '/blog' } in navLinks computed array
- Position: between hytale and projects (D-15 ordering)
- Template v-for iterations unchanged — new link auto-propagates to
desktop nav + mobile slideover
- Label resolved via t(`nav.${link.key}`) → uses nav.blog key
added in Task 2.1
- Add `draft: true` to frontmatter of both test-kotlin-syntax.md files
so they are excluded from all `queryCollection(...).where('draft', '=', false)`
listings (D-14).
- Articles remain accessible via direct URL (no draft filter on `.path(x).first()`),
keeping them available for internal rendering tests.
- Listings will be empty until real Hytale seed articles land in Phase 8 —
the empty state will render per D-16 ("Hytale articles coming soon" CTA).
- Body content untouched (only frontmatter +1 line each).
- Pure synchronous helper returning minutes (>= 1) from either a pre-computed
word count (number) or raw text (string, tokenized on whitespace).
- Client-side safety net when `article.minutes` isn't yet populated
(e.g., dev hot-reload before the Nitro hook re-parsed). Source of truth
remains the Nitro `content:file:afterParse` hook (D-19).
- Same 200 wpm formula as server-side hook — ensures listing ↔ article parity.
- Auto-imported by Nuxt thanks to `use*` naming convention.
- Register `content:file:afterParse` hook to inject `wordCount` + `minutes`
on every parsed markdown content object (D-19: 200 wpm, floor 1 min).
- Import pure util `countWordsInMinimalBody` from app/utils/countWords.
- Guard against non-`.md` files (defensive — hook fires on all sources).
- Values persist in @nuxt/content SQLite DB and are queryable via
queryCollection thanks to matching Zod fields (content.config.ts).
- Pure AST traversal of @nuxt/content v3 minimal body shape
- Skips code and pre tags (code snippets are not readable prose)
- Zero dependency, zero import, reused by Nitro hook
- Add draft: z.boolean().optional().default(false) to allow .where('draft','=',false)
- Add wordCount + minutes as optional (injected by Nitro hook at parse time)
- Collections blog_fr/blog_en unchanged (schema is referenced by variable)
- content/fr/blog/test-kotlin-syntax.md: FR test article covering all 4 validation criteria
- content/en/blog/test-kotlin-syntax.md: EN version with same slug
- app/pages/test.vue: temporary page at /test for visual checkpoint verification
- Both articles contain: kotlin code block, NuxtImg image, markdown table, 4 callout types
- Introduced a new document outlining the configuration and component patterns for integrating @nuxt/content.
- Included mappings for `nuxt.config.ts`, `content.config.ts`, and new components `ProseImg.vue` and `Alert.vue`.
- Added example markdown content for testing syntax highlighting and layout.
- Documented critical patterns and anti-patterns to follow during implementation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 plans, 2 waves. Plan 01 installe @nuxt/content + typography et
configure Shiki dual-theme + collections bilingues. Plan 02 crée
ProseImg/Alert MDC et articles de test FR/EN avec checkpoint visuel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added a new `/hytale` page with sections for hero, services, and pricing.
- Updated existing components to support Hytale-specific content and i18n.
- Modified site configuration and state to reflect the new focus on Hytale plugin development.
- Enhanced testimonials section to feature relevant client feedback.
- Adjusted navigation to include a link to the new Hytale page.
- Switched from npm to pnpm for dependency management in Dockerfile, improving build efficiency.
- Updated Vue and Vue Router versions in package.json for better compatibility.
- Changed placeholder URLs in site.ts to actual Fiverr links and adjusted review count.
- Removed obsolete sitemap.xml file to streamline the project.
- Added a new rate limiting plugin to manage API request limits for the contact endpoint.
- Deleted several planning documents including config.json, PROJECT.md, REQUIREMENTS.md, ROADMAP.md, STATE.md, and various phase plans.
- These files were no longer relevant to the current project structure and development practices, streamlining the codebase.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deleted several planning documents including ARCHITECTURE.md, CONCERNS.md, CONVENTIONS.md, INTEGRATIONS.md, STACK.md, STRUCTURE.md, and TESTING.md.
- These files were no longer relevant to the current project structure and development practices.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Corrected the name in various files including CLAUDE.md, README.md, and configuration files to reflect the updated branding.
- Ensured consistency in the use of the new name throughout the project, enhancing brand identity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Complete visual overhaul of all pages and components with generous spacing,
bold typography, hover effects, gradient accents, and section differentiation.
Hero features animated terminal mockup and gradient text. Cards use hover
transforms with brand-colored shadows. CTAs use gradient backgrounds.
All i18n keys, data structures, SEO meta, and composable logic preserved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UDrawer (vaul-vue bottom-sheet) rendered content in DOM even when closed,
causing mobile nav to show on desktop. Replaced with USlideover (proper
sidebar panel). Also: backdrop-blur header, UButton for actions, Lucide
icons, brand color active states.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nuxt prefixes components in subdirectories (layout/AppHeader → LayoutAppHeader).
Setting pathPrefix: false allows using <AppHeader>, <HeroSection>, etc. directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Hero with stats (available services count, rating) and profile CTA
- Service cards grid with NuxtImg, price/status badges, order buttons
- FAQSection with UAccordion using homeFAQs data
- Final CTA section linking to Fiverr profile
- Dynamic route /project/[id] with findById composable
- 404 via createError if project not found
- Hero grid: image + info + CTA buttons (demo, source, custom)
- About section with features list (checkmarks)
- Technologies section with TechBadge
- Gallery thumbnails with zoom overlay, opens ProjectGallery modal
- Sidebar: project info card + related projects
- Responsive 2-col layout (main + sidebar)
- SUMMARY.md with 3 tasks, 17 files, 239s duration
- STATE.md advanced to phase 3 plan 1
- ROADMAP.md updated with plan progress
- COMP-01 to COMP-04 marked complete
- Remove PAGE-07 from requirements (formation deleted per D-19)
- No redirect, /formation returns 404 naturally
- Plan 04 now includes full legacy src/ cleanup
- Update success criteria: 7 routes, SMTP instead of EmailJS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Contact form uses server-side nodemailer via Nuxt API route (not EmailJS)
- Formation page removed from Phase 3 scope (was SaaS pricing, not portfolio)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Formation was a SaaS pricing page unrelated to the portfolio.
Removed: page, nav link, locale keys (nav.formation, seo.formation,
pricing.*) in both FR and EN, legacy source files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Introduced a new docker-compose.yml file to define the portfolio service.
- Configured Traefik routing with TLS settings and redirect middleware for non-www to www.
- Set up environment variables and network configuration for the service.
Decisions: 6-section landing, UModal+UCarousel gallery with thumbnails,
3-field contact form with EmailJS+Zod, SSR Docker with runtimeConfig.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 3 TypeScript errors resolved, build passes, server renders.
Phase 2 SSR Shell marked complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@nuxt/ui provides the Vite plugin but tailwindcss package itself
must be installed for @import "tailwindcss" to resolve in CSS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nuxt UI v3 manages Tailwind v4 internally. The old tailwind.config.js
pointed to src/ and used Tailwind v3 format, causing SSR conflicts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These are legacy configs from the Vue SPA. Nuxt manages Vite and
PostCSS internally — external configs cause IPC connection errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@nuxtjs/i18n resolves langDir relative to its own i18n/ directory,
not the project root. Moved fr.json and en.json accordingly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sticky header with z-[1020], desktop nav with locale-aware NuxtLinks
- FR/EN text toggle using useSetLocale, dark/light icon toggle using useColorMode
- Mobile UDrawer with stacked nav links and toggles
- WCAG: min-w-11 min-h-11 touch targets, focus-visible:ring-2, aria-current on active link
- useSeoMeta() with localized title/description/og tags on all 6 pages
- Homepage JSON-LD with Person + ProfessionalService schema
- og:image absolute URL on every page
- Stub templates with max-w-7xl wrapper and h1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- nav, footer, a11y, seo keys from UI-SPEC copywriting contract
- All existing keys migrated from src/locales/fr.ts and en.ts
- Includes home, projects, about, contact, fiverr, faq, pricing, projectData, testimonials, common
- Emojis stripped from translation values for clean rendering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Brand color #85cb85 as CSS @theme with full shade palette
- app.config.ts maps Nuxt UI primary to brand
- colorMode with cookie storage, dark default, no FOUC
- i18n baseUrl and site.url for absolute SEO URLs
- Static og:image placeholder in public/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 4 data files created in app/data/ with proper type imports from shared/types
- 74 WebP images copied to public/images/ (including flowboard gallery)
- All image paths migrated from @/assets/images/ to /images/
- FAQ uses i18n keys instead of direct text
- Mark RESEARCH.md Open Questions as RESOLVED with decisions
- Fix Plan 01-02 Task 1 verify to be independent of Task 2 (file existence + grep check instead of typecheck)
- Strengthen negative criterion: all app/data/ files must NOT contain @/assets/images/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:45:00 +02:00
19 changed files with 47 additions and 819 deletions
title: "GravityFlip: from client brief to a production-grade Hytale plugin"
description: "Lessons learned shipping GravityFlip — how a vague request (\"I want to flip gravity\") became an architected, configurable Hytale plugin that builders can use without touching code."
> **TL;DR** — A client pinged me to "invert gravity in part of my map". Five questions later we were building a **multi-region plugin** with an in-game wand, JSON persistence, and three visualization modes. It's now live in production: [GravityFlip on Modtale](https://modtale.net/mod/gravity-flip).
## The original brief
The Discord message ran two sentences long:
> *"Hi, I'd like a plugin that flips gravity on a zone of my server. It's for an event this weekend, I can pay."*
This is exactly the most dangerous brief shape. Read fast, it sounds clear (*"flip gravity"* + *"zone"* — that's enough to start coding, right?). Read carefully, it says **nothing** specific:
- *"a zone"* — how many? one, configured via YAML? several, managed in-game? server-wide?
- *"for an event this weekend"* — one-off, or a reusable tool for the server's builders later?
- *"I can pay"* — what scope, what budget? Essential plugin at €149 or full system at €349?
I've made it a rule to **never write code until I've exhausted ambiguity**. It feels counter-intuitive when the client is in a hurry, but 30 minutes of questions saves 10 hours of rewrites.
## The five questions that changed everything
### 1. "How many zones, and who defines them?"
Answer: *"At first I thought just one, but actually I'd like my builders to create more without asking me each time."*
Immediate decision: **multi-region system** with persistence. Hardcoded YAML is out (too much friction). We pivot to an **in-game wand** plus `/gravityflip define <name>` commands. Classic Bukkit/Spigot community pattern, ported to Hytale.
### 2. "Who flips? Players only, or everything?"
Answer: *"Players for sure, but flipping dropped items would be sweet too. Mobs I'm not sure."*
Decision: **three booleans per region** — `AffectPlayers`, `AffectItems`, `AffectNpcs`. Default: all on, but the builder can disable mobs on a "jump arena" zone if floating mobs ruin the gameplay. The marginal cost of those three toggles in the JSON codec was zero — optionality offered for free.
### 3. "What happens when a player enters the zone at full free-fall speed?"
Answer (after a pause): *"Uhh... I hadn't thought about it. They shouldn't take fall damage, right?"*
Decision: **configurable `GracePeriodMs` (default 2500ms)**. During the transition, we smooth the gravity flip instead of an instant binary swap that produces brutal acceleration and absurd fall damage. Bonus: a `FallDamage` toggle (default false) for zones where falling should still cost something gameplay-wise.
That's the kind of detail **a written brief never surfaces**. A real conversation does.
### 4. "Do you want to see the zones when you're inside one?"
Answer: *"Yeah in build mode I have to, otherwise I lose track. But in player mode nothing should show."*
-`Particles` — edge-emitting particles (`Torch_Fire` default), more subtle but visible
-`None` — invisible, production mode
Per-region toggle via the `/gravityflip toggle` command. Build and live mode coexist on the same map without re-deploying the plugin.
### 5. "Is this one-shot or are you reusing it?"
Answer: *"One-shot for the event, but if it's well done I'll keep it."*
Pivotal decision: we treat this project as **a production plugin**, not a script. Concretely:
- JSON persistence in `Server/mods/Mythlane_GravityFlip/regions.json` (not memory-only)
- 10 Hz tick loop with concurrent snapshots (lock-free reads)
- Unit tests on pure logic (codec, AABB geometry)
- Auto-seeded demo region on first run for instant onboarding
- Polished EN README, distributable
**Cost vs "quick & dirty"** : about 30 % more time. **Benefit** : the client moved from "I need it by Saturday" to "I still use it, my builders love it". The plugin is now publishable, monetizable, and so it became a shared asset.
## The architecture that emerged
```
Player / NPC / Item
│
▼ (each tick, 10 Hz)
RegionTickLoop ◄─── snapshots from regions.json
│
▼
GravityApplier + FallDamageGuard
│
▼
per-region effect
```
The wand follows its own cycle:
```
Player click → WandSelectionStore
│
▼
/gravityflip define <name>
│
▼
Region registry → regions.json (auto-save)
```
Stack: **Java 25**, official Hytale Plugin API (`com.hypixel.hytale.plugin`), Gradle Shadow to relocate Gson (avoiding stdlib conflicts), JUnit 5 for tests. Source ~2,500 lines, 30 % of which is tests.
### The piece of code that took the most thinking
The **GracePeriodMs**. Not the code itself but the idea behind it: instead of a binary flip, we interpolate the vertical velocity component over a sliding window. Naively:
Three extra lines, but that's what makes the difference between a plugin that's "fun for 30 seconds" and a plugin that players actually use without rage-quitting.
## What this project taught me (or reminded me)
**First**: senior dev value isn't in code-typing speed. It's in the **series of questions** that turn a vague brief into an actionable spec. Without question 3 (free-fall), the client would have shipped the event with absurd fall damage, and the plugin would've been dropped after the weekend.
**Second**: a Hytale plugin that sells isn't a script. It's a **production-grade Java codebase** with persistence, tests, docs, and sub-5-minute onboarding. The client paid €349 (the "Custom System" tier), not €50 Fiverr — and the premium is justified by the quality the client will exploit for months.
**Third**: every plugin I write ends up published. GravityFlip is freely available on [Modtale](https://modtale.net/mod/gravity-flip) and soon on CurseForge. This doesn't dilute the value of paid commissions — it **boosts** my credibility to future prospects looking for a developer who can ship clean code, not just glue StackOverflow snippets.
## Got a Hytale project in mind?
The pattern is always the same: we talk for 30 minutes, I ask the 5-10 questions that kill ambiguity, I send a firm quote, I deliver. Pricing is public on [/hytale](/hytale) — €149 for an essential plugin, €349 for a custom system, €790+ for custom MMO infrastructure.
No Fiverr, no race-to-the-bottom. Just a senior dev shipping code you'll still use six months later.
[Request a quote](/contact) · [See GravityFlip in action](https://modtale.net/mod/gravity-flip) · [See my other plugins](/projects)
title: "GravityFlip : du brief client au plugin Hytale en production"
description: "Retour d'expérience sur le développement de GravityFlip — comment une demande floue (\"je veux inverser la gravité\") devient un plugin Hytale architecturé, configurable, et utilisable par des builders sans toucher au code."
> **TL;DR** — Un client m'a contacté pour "inverser la gravité dans une partie de la map". Cinq questions plus tard, on était sur un plugin de **régions paramétrables** avec wand in-game, persistence JSON, et trois modes de visualisation. Le résultat tourne aujourd'hui en production : [GravityFlip sur Modtale](https://modtale.net/mod/gravity-flip).
## Le brief initial
Le message Discord d'origine tient en deux phrases :
> *"Salut, j'aimerais un plugin qui inverse la gravité sur une zone de mon serveur. C'est pour un event ce week-end, je peux payer."*
C'est exactement la forme de brief la plus dangereuse. Lue rapidement, elle donne l'illusion d'être claire (*"inverser la gravité"* + *"zone"* = ça suffit pour coder, non ?). Lue posément, elle ne dit **rien** de précis :
- *"une zone"* — combien ? une seule, configurée par YAML ? plusieurs, gérées en jeu ? globale au serveur ?
- *"inverser la gravité"* — pour qui ? les joueurs uniquement ? les items qui tombent ? les mobs ? les projectiles ?
- *"pour un event ce week-end"* — usage one-shot ou outil réutilisable par les builders du serveur après ?
- *"je peux payer"* — quel scope, quel budget ? Plugin essentiel à 149€ ou système complet à 349€ ?
J'ai pris l'habitude de **ne jamais coder avant d'avoir épuisé les ambiguïtés**. Ça paraît contre-intuitif quand le client est pressé, mais 30 minutes de questions économisent 10 heures de réécriture.
## Les cinq questions qui ont tout changé
### 1. "Combien de zones, et qui les définit ?"
Réponse : *"Au début je pensais une seule, mais en fait j'aimerais que mes builders puissent en créer plusieurs sans me demander à chaque fois."*
Décision immédiate : **système multi-régions** avec persistence. On exclut le YAML hardcodé (trop friction) et on s'oriente vers un **wand in-game** + commandes `/gravityflip define <name>`. Pattern classique de la communauté Bukkit/Spigot, repris pour Hytale.
### 2. "Pour qui la gravité s'inverse ? Joueurs uniquement, ou tout ?"
Réponse : *"Les joueurs ouais, mais aussi les items dropés ce serait stylé. Les mobs je sais pas."*
Décision : **trois booleans configurables par région** — `AffectPlayers`, `AffectItems`, `AffectNpcs`. Default = tout activé, mais le builder peut désactiver les mobs sur une zone "salle de saut" si les mobs flottants gâchent le gameplay. Le coût marginal de ces 3 toggles dans le codec JSON était nul, l'optionalité a été offerte.
### 3. "Que se passe-t-il quand un joueur entre dans la zone à pleine vitesse en chute libre ?"
Réponse (après une pause) : *"Heu... j'avais pas pensé. Il devrait pas se prendre les dégâts de chute non ?"*
Décision : **`GracePeriodMs` configurable (default 2500ms)**. Pendant la transition, on lisse l'inversion de gravité au lieu d'un flip instantané qui produit une accélération brutale et des dégâts de chute aberrants. En bonus : un toggle `FallDamage` (default false) pour les zones où on veut quand même que tomber ait un coût gameplay.
C'est le genre de détail qu'**un brief écrit ne fait jamais émerger**. Une vraie discussion, oui.
### 4. "Tu veux voir les zones quand tu es dedans ?"
Réponse : *"Oui en build c'est obligé sinon je sais plus où elles sont. Mais en live joueur faut rien voir."*
Décision : **trois modes de visualisation**.
-`Outline` — wireframe couleur configurable (`VisualColor`, default `#00FFFF`), pour le mode build
-`Particles` — bordures émettrices de particules (`Torch_Fire` par défaut), plus discret mais visible
-`None` — invisible, mode production
Toggle par région via la commande `/gravityflip toggle`. Build mode et live mode sur la même map sans rebuild du plugin.
### 5. "C'est un one-shot ou tu réutilises ?"
Réponse : *"One-shot pour l'event, mais si c'est bien fait je le garde."*
Décision déterminante : on traite ce projet comme **un plugin de production**, pas comme un script. Concrètement :
- Persistance JSON dans `Server/mods/Mythlane_GravityFlip/regions.json` (pas mémoire seule)
- Tick loop 10x/sec avec snapshots concurrents (lecture lock-free)
- Tests unitaires sur la logique pure (codec, géométrie AABB)
- Demo region auto-seed au premier démarrage pour onboarding instantané
- Documentation README EN pro, distribuable
**Surcoût vs version "quick & dirty"** : environ 30 % de temps en plus. **Bénéfice** : le client est passé de "j'ai besoin pour samedi" à "je l'utilise toujours, mes builders l'adorent". Le plugin est désormais publiable, monétisable, et donc devenu un actif partagé.
## L'architecture qui en est sortie
```
Player / NPC / Item
│
▼ (chaque tick, 10 Hz)
RegionTickLoop ◄─── snapshots de regions.json
│
▼
GravityApplier + FallDamageGuard
│
▼
effet par région
```
Le wand suit son propre cycle :
```
Player click → WandSelectionStore
│
▼
/gravityflip define <name>
│
▼
Region registry → regions.json (auto-save)
```
Stack technique : **Java 25**, Hytale Plugin API officielle (`com.hypixel.hytale.plugin`), Gradle Shadow pour relocalisation Gson (évite les conflits stdlib), JUnit 5 pour les tests. Code source ~2 500 lignes, dont 30 % de tests.
### Le bout de code qui m'a coûté le plus de réflexion
Le **GracePeriodMs**. Pas du code, mais l'idée derrière : au lieu d'un flip binaire, on interpole la composante verticale de la vélocité sur une fenêtre glissante. Naïvement on écrit :
```java
// version naïve — produit des dégâts de chute aberrants
Trois lignes de plus, mais c'est ce qui fait la différence entre un plugin "marrant 30 secondes" et un plugin que les joueurs utilisent sans rage-quit.
## Ce que ce projet m'a appris (ou rappelé)
**Premièrement** : la valeur du dev senior n'est pas dans la rapidité de code. C'est dans la **série de questions** qui transforme un brief flou en spec actionnable. Si je n'avais pas posé la question 3 (chute libre), le client aurait livré l'event avec des dégâts de chute aberrants, et le plugin aurait été abandonné après le week-end.
**Deuxièmement** : un plugin Hytale qui se vend, ce n'est pas un script. C'est une **codebase Java production-grade** avec persistence, tests, doc, et un onboarding sub-5 minutes. Le client a payé 349€ (tier "Système Sur-Mesure"), pas 50€ Fiverr — et le surcoût est justifié par la qualité que le client va exploiter pendant des mois.
**Troisièmement** : chaque plugin que je code finit publié. GravityFlip est dispo gratuitement sur [Modtale](https://modtale.net/mod/gravity-flip) et bientôt sur CurseForge. Ça ne dilue pas la valeur de la commande client — ça **augmente** ma crédibilité auprès des futurs prospects qui cherchent un dev capable de livrer du code propre, et pas juste de coller des snippets StackOverflow.
## Tu as un projet Hytale en tête ?
Le pattern est toujours le même : on parle 30 minutes, je pose les 5-10 questions qui tuent les ambiguïtés, je te donne un devis ferme, et je livre. Les tarifs sont publics sur [/hytale](/hytale) — entre 149€ pour un plugin essentiel, 349€ pour un système complet, et 790€+ pour une infrastructure MMO custom.
Pas de Fiverr, pas de race-to-the-bottom. Juste un dev senior qui livre du code que tu utilises encore six mois plus tard.
[Demander un devis](/contact) · [Voir GravityFlip en action](https://modtale.net/mod/gravity-flip) · [Voir mes autres plugins](/projects)
"tagline":"Hytale Plugin Developer & Freelance Web Dev. Custom Java plugins, gaming server websites, production-grade Vue/Nuxt apps.",
"navigation":"Quick Links",
"navigation":"Quick Links",
"services":"Services",
"services":"Services",
"legalNotices":"Legal Notices",
"legalNotices":"Legal Notices",
"privacyPolicy":"Privacy Policy",
"privacyPolicy":"Privacy Policy",
"servicesList":{
"servicesList":{
"hytalePlugins":"Hytale Plugins (Java)",
"webDev":"Web Development",
"webDev":"Web Sites & Apps",
"mobileApps":"Mobile Apps",
"retainer":"Monthly Retainer",
"apiBackend":"API Development",
"consulting":"Tech Consulting"
"consulting":"Tech Consulting"
}
}
},
},
@@ -67,20 +66,20 @@
"contact":"Contact me"
"contact":"Contact me"
},
},
"featuredProjects":{
"featuredProjects":{
"title":"Hytale plugins & web apps running in production",
"title":"Web Applications That Deliver Results",
"subtitle":"Portfolio of real projects, in production, used by real players and clients. Java 25 Hytale plugins, Vue/Nuxt apps, SaaS, Discord bots — not proofs-of-concept, actual shipping.",
"subtitle":"Portfolio of real projects that transformed ideas into success. Lightning-fast Vue.js apps, scalable React platforms, robust Node.js APIs.",
"description":"Lightning-fast web apps that convert visitors into customers. Modern SPAs, offline-first PWAs, high-conversion e-commerce. SEO-friendly from day one."
},
"mobileApps":{
"title":"Cost-Effective Cross-Platform Mobile Apps",
"description":"One codebase = iOS + Android + Web. React Native for performant native apps. 60% cost savings vs native development."
},
},
"optimization":{
"optimization":{
"title":"Performance & Technical SEO Optimization",
"title":"Performance & Technical SEO Optimization",
@@ -113,9 +112,6 @@
"subtitle":"Browse my work: custom Hytale plugins, Vue.js applications, React websites, Node.js APIs, Discord bots, and enterprise software.",
"subtitle":"Browse my work: custom Hytale plugins, Vue.js applications, React websites, Node.js APIs, Discord bots, and enterprise software.",
"categories":{
"categories":{
"all":"All Projects",
"all":"All Projects",
"hytaleplugin":"Hytale Plugin",
"hytalelibrary":"Hytale Library",
"minecraftmod":"Minecraft Mod",
"webdevelopment":"Web Development",
"webdevelopment":"Web Development",
"botdevelopment":"Bot Development",
"botdevelopment":"Bot Development",
"opensource":"Open Source",
"opensource":"Open Source",
@@ -253,55 +249,6 @@
}
}
},
},
"projectData":{
"projectData":{
"votepipe":{
"title":"VotePipe — Hytale Vote Rewards SaaS",
"description":"Unified SaaS platform that combines Webhook (V1 RSA, V2 HMAC) and Votifier to handle votes from all 7 major Hytale server lists in a single plugin. Visual reward builder, automatic delivery, no port forwarding needed.",
"longDescription":"The only Hytale plugin that runs Webhook and Votifier through one unified pipeline. Free / Pro / Network tiers with web dashboard (app.votepipe.com), visual reward builder, streaks, milestones, lucky tiers. Stack: Java 25 plugin + TypeScript backend + SaaS dashboard. Outbound-only secure cloud architecture.",
"description":"Hytale plugin that creates custom anti-gravity zones with an in-game wand. Walk on ceilings, floating items, drifting mobs — all configurable without touching files.",
"longDescription":"Wand-based region builder for Hytale servers. Corners are set with left/right click, JSON persistence is automatic, 10x/sec tick loop, configurable vertical force and grace period. Visual modes: outline / particles / hidden. Built on Hytale Plugin API + Java 25 + Gradle Shadow.",
"buttons":{
"modtale":"Modtale",
"curseforge":"CurseForge"
}
},
"async":{
"title":"Async — Coroutines for Hytale's per-world ECS",
"description":"Kotlin coroutine library that replaces the noisy CompletableFuture + world.execute pattern with one suspending call. Player/world/plugin scopes, three dispatchers, suspending ECS DSL.",
"longDescription":"Async solves Hytale's per-world thread model: each world runs on its own thread, touching components from elsewhere throws, and blocking I/O on the world thread freezes players. The library ships dispatchers (World, HytaleIO, Scheduled), scope registries (PlayerScopes, WorldScopes, PluginScopes) with automatic cancellation on disconnect, and a suspending read/modify DSL. Built in Kotlin 2.2, target JVM 24, modular split (core / ecs / binding / dist) so business logic stays testable without a Hytale server.",
"description":"Hytale plugin that fires chain lightning on right-click — bolt jumps to up to 5 nearby enemies within 8 blocks, with damage falloff per hop and a 4-second cooldown.",
"longDescription":"Magical sceptre for Hytale servers. Pure-Java chain resolver decoupled from Hytale via small interfaces (RayCaster, EntitySource, ChainEntity), JUnit 5 tested without a running server. Built on Hytale Plugin API + Java 25 + Gradle Shadow.",
"buttons":{
"modtale":"Modtale",
"curseforge":"CurseForge"
}
},
"playhours":{
"title":"PlayHours — Forge Server Hours Enforcement",
"description":"Forge 1.20.1 mod that enforces per-day open windows, blocks logins outside hours, warns at 15/10/5/1 min, auto-kicks at close, handles holidays, whitelist/blacklist, force modes, LuckPerms integration.",
"longDescription":"Minecraft server mod for time-gated access: per-day schedules, midnight-spanning, date exceptions, dynamic MOTD, multi-language (EN/FR), LuckPerms or vanilla ops permissions. Perfect for educational servers, family servers, or maintenance windows.",
"buttons":{
"curseforge":"CurseForge",
"repository":"Repository"
}
},
"virtual-tour":{
"virtual-tour":{
"title":"Virtual Tour - Interactive 360° Experience",
"title":"Virtual Tour - Interactive 360° Experience",
"description":"My high school teacher and me had an idea to create a Virtual tour with 360° videos to allow everyone to visit the school from the web.",
"description":"My high school teacher and me had an idea to create a Virtual tour with 360° videos to allow everyone to visit the school from the web.",
"flagshipCta":"Flagship: custom quote after a 30-minute scoping call."
"flagshipCta":"Flagship: custom quote after a 30-minute scoping call."
},
},
"demos":{
"label":"// live-demos",
"title":"Live plugins, production-grade code",
"subtitle":"No marketing promises. These are the Hytale plugins I publicly maintain — usable today on any Hytale server.",
"featured":"Featured",
"viewSite":"View site",
"footnote":"Every plugin is built in-house, production-tested, and ships with full documentation.",
"votepipe":{
"title":"VotePipe — Vote Rewards SaaS",
"tagline":"Hytale plugin + SaaS dashboard that unifies Webhook and Votifier across the 7 major vote lists. No port forwarding, automatic delivery, visual reward builder."
},
"gravity-flip":{
"title":"GravityFlip Region",
"tagline":"Drop a wand, set 2 corners, gravity flips inside the zone. Ceiling-walking and floating items live in 5 minutes of setup."
},
"chain-lightning":{
"title":"ChainLightning Sceptre",
"tagline":"Right-click a mob and the bolt jumps to up to 5 nearby enemies within 8 blocks. Damage falls off per hop, JUnit-tested chain resolver."
},
"async":{
"title":"Async — Kotlin coroutines for Hytale ECS",
"tagline":"One suspending call replaces CompletableFuture + world.execute boilerplate. Player/world/plugin scopes, three dispatchers, automatic cancellation on disconnect."
}
},
"recentArticles":{
"recentArticles":{
"title":"Recent articles",
"title":"Recent articles",
"subtitle":"Latest writing on Hytale plugin development",
"subtitle":"Latest writing on Hytale plugin development",
"tagline":"Hytale Plugin Developer & Dev Web Freelance. Plugins Java sur-mesure, sites pour serveurs gaming, applications Vue/Nuxt en production.",
"navigation":"Liens Rapides",
"navigation":"Liens Rapides",
"services":"Services",
"services":"Services",
"legalNotices":"Mentions Légales",
"legalNotices":"Mentions Légales",
"privacyPolicy":"Politique de Confidentialité",
"privacyPolicy":"Politique de Confidentialité",
"servicesList":{
"servicesList":{
"hytalePlugins":"Plugins Hytale (Java)",
"webDev":"Développement Web",
"webDev":"Sites & Apps Web",
"mobileApps":"Applications Mobiles",
"retainer":"Retainer Mensuel",
"apiBackend":"Développement API",
"consulting":"Conseil Tech"
"consulting":"Consulting Tech"
}
}
},
},
"a11y":{
"a11y":{
@@ -67,20 +66,20 @@
"contact":"Me contacter"
"contact":"Me contacter"
},
},
"featuredProjects":{
"featuredProjects":{
"title":"Plugins Hytale & Apps Web qui tournent en prod",
"title":"Applications Web Qui Cartonnent",
"subtitle":"Portfolio de projets réels, en production, utilisés par de vrais joueurs et clients. Plugins Hytale Java 25, applications Vue.js/Nuxt, SaaS, bots Discord — pas du proof-of-concept, du shipping.",
"subtitle":"Portfolio de projets réels qui ont transformé des idées en succès. Applications Vue.js ultra-rapides, plateformes React scalables, API Node.js robustes.",
"viewAll":"Explorer Tous les Projets"
"viewAll":"Explorer Tous les Projets"
},
},
"services":{
"services":{
"title":"Services Premium Hytale & Web",
"title":"Services Premium de Développement Web",
"subtitle":"Plugins Hytale custom, applications web haute performance, SaaS gaming. Stack Java 25 + Vue/Nuxt + Node.js. Tarifs transparents (149€-790€), devis sous 24h.",
"subtitle":"Solutions clés en main qui boostent votre croissance. Technologies de pointe + méthodologie éprouvée = succès garanti pour votre projet digital.",
"hytalePlugins":{
"title":"Plugins Hytale Custom (Java)",
"description":"Du plugin essentiel au système MMO complet. Wand-based regions, votes & rewards, économie, quêtes, mini-jeux. Stack Java 25 + Hytale Plugin API + Gradle Shadow."
},
"webDev":{
"webDev":{
"title":"Applications Web Vue.js / Nuxt / React",
"title":"Applications Web Vue.js/React Sur-Mesure",
"description":"Sites pour serveurs gaming, SaaS, e-commerce. SSR Nuxt 4 SEO-optimisé, dashboards admin, intégrations Tebex/Discord. Lighthouse 95+, chargement <2s."
"description":"Création d'applications web lightning-fast qui convertissent. SPA modernes, PWA offline-first, e-commerce haute conversion. SEO-friendly dès la conception."
},
"mobileApps":{
"title":"Apps Mobiles Cross-Platform Rentables",
"description":"Une seule codebase = iOS + Android + Web. React Native pour des apps natives performantes. 60% d'économie vs développement natif."
},
},
"optimization":{
"optimization":{
"title":"Optimisation Performance & SEO Technique",
"title":"Optimisation Performance & SEO Technique",
@@ -113,9 +112,6 @@
"subtitle":"Parcourez mes projets : plugins Hytale, applications Vue.js, sites React, API Node.js, bots Discord et solutions d'entreprise.",
"subtitle":"Parcourez mes projets : plugins Hytale, applications Vue.js, sites React, API Node.js, bots Discord et solutions d'entreprise.",
"categories":{
"categories":{
"all":"Tous les Projets",
"all":"Tous les Projets",
"hytaleplugin":"Plugin Hytale",
"hytalelibrary":"Librairie Hytale",
"minecraftmod":"Mod Minecraft",
"webdevelopment":"Développement Web",
"webdevelopment":"Développement Web",
"botdevelopment":"Développement de Bot",
"botdevelopment":"Développement de Bot",
"opensource":"Open Source",
"opensource":"Open Source",
@@ -253,55 +249,6 @@
}
}
},
},
"projectData":{
"projectData":{
"votepipe":{
"title":"VotePipe — SaaS Vote Rewards Hytale",
"description":"Plateforme SaaS unifiée qui combine Webhook (V1 RSA, V2 HMAC) et Votifier pour récupérer les votes des 7 grandes listes Hytale en un seul plugin. Visual reward builder, livraison automatique, aucun port à ouvrir.",
"longDescription":"Le seul plugin Hytale qui fait passer Webhook et Votifier dans un pipeline unifié. Tarifs Free / Pro / Network avec dashboard web (app.votepipe.com), reward builder visuel, streaks, milestones, lucky tiers. Stack : Java 25 plugin + backend TypeScript + dashboard SaaS. Architecture cloud sécurisée — outbound-only.",
"description":"Plugin Hytale qui crée des zones d'anti-gravité custom avec un wand in-game. Marche sur le plafond, items qui flottent, mobs flottants — tout configurable sans toucher aux fichiers.",
"longDescription":"Wand-based region builder pour serveurs Hytale. Les corners se définissent en clic gauche/droit, persistance JSON automatique, tick loop 10x/sec, force verticale et grace period configurables. Mode visuel outline / particles / hidden. Construit sur Hytale Plugin API + Java 25 + Gradle Shadow.",
"buttons":{
"modtale":"Modtale",
"curseforge":"CurseForge"
}
},
"async":{
"title":"Async — Coroutines pour l'ECS per-world de Hytale",
"description":"Bibliothèque Kotlin qui remplace le pattern CompletableFuture + world.execute par un seul appel suspending. Scopes player/world/plugin, trois dispatchers, DSL ECS suspending.",
"longDescription":"Async résout le modèle thread per-world de Hytale : chaque monde tourne sur son thread, toucher un composant ailleurs throw, et un I/O bloquant sur le thread world freeze tous les joueurs. La lib expose des dispatchers (World, HytaleIO, Scheduled), des registres de scopes (PlayerScopes, WorldScopes, PluginScopes) avec annulation automatique au disconnect, et un DSL read/modify suspending. Construit en Kotlin 2.2, cible JVM 24, split modulaire (core / ecs / binding / dist) pour garder la logique testable sans serveur Hytale.",
"description":"Plugin Hytale qui lance un éclair en chaîne au clic droit — le bolt rebondit sur jusqu'à 5 ennemis proches dans un rayon de 8 blocs, avec damage falloff par hop et un cooldown de 4 secondes.",
"longDescription":"Sceptre magique pour serveurs Hytale. Chain resolver pur Java découplé de Hytale via petites interfaces (RayCaster, EntitySource, ChainEntity), testé en JUnit 5 sans serveur. Construit sur Hytale Plugin API + Java 25 + Gradle Shadow.",
"buttons":{
"modtale":"Modtale",
"curseforge":"CurseForge"
}
},
"playhours":{
"title":"PlayHours — Forge Server Hours Enforcement",
"description":"Mod Forge 1.20.1 qui force des horaires d'ouverture par jour, blocage de connexion hors heures, warns 15/10/5/1 min, auto-kick à la fermeture, gestion des jours fériés, whitelist/blacklist, force modes, intégration LuckPerms.",
"longDescription":"Mod serveur Minecraft pour gérer l'accès aux horaires : schedules per-day, midnight-spanning, exceptions de dates, MOTD dynamique, multi-langues (EN/FR), permissions LuckPerms ou ops vanilla. Parfait pour serveurs scolaires, familiaux, ou avec maintenance windows.",
"description":"Mon professeur de lycée et moi avons eu l'idée de créer une visite virtuelle avec des vidéos 360° pour permettre à tous de visiter l'école depuis le web.",
"description":"Mon professeur de lycée et moi avons eu l'idée de créer une visite virtuelle avec des vidéos 360° pour permettre à tous de visiter l'école depuis le web.",
"flagshipCta":"Flagship : sur devis après cadrage de 30 minutes."
"flagshipCta":"Flagship : sur devis après cadrage de 30 minutes."
},
},
"demos":{
"label":"// live-demos",
"title":"Plugins live, code en production",
"subtitle":"Pas de promesses marketing. Voici les plugins Hytale que je maintiens publiquement, utilisables aujourd'hui sur n'importe quel serveur Hytale.",
"featured":"À la une",
"viewSite":"Voir le site",
"footnote":"Chaque plugin est build maison, testé en production, et livré avec sa documentation.",
"votepipe":{
"title":"VotePipe — SaaS Vote Rewards",
"tagline":"Plugin Hytale + dashboard SaaS qui unifie Webhook et Votifier sur les 7 grandes listes de votes. Sans port à ouvrir, livraison automatique, reward builder visuel."
},
"gravity-flip":{
"title":"GravityFlip Region",
"tagline":"Pose un wand, définis 2 corners, gravité inversée dans la zone. Marche-au-plafond et items qui flottent en 5 minutes de setup."
},
"chain-lightning":{
"title":"ChainLightning Sceptre",
"tagline":"Clic droit sur un mob et l'éclair rebondit sur jusqu'à 5 ennemis dans un rayon de 8 blocs. Damage falloff par hop, chain resolver JUnit-testé."
},
"async":{
"title":"Async — Coroutines Kotlin pour l'ECS Hytale",
"tagline":"Un seul appel suspending remplace le boilerplate CompletableFuture + world.execute. Scopes player/world/plugin, trois dispatchers, annulation auto au disconnect."
}
},
"recentArticles":{
"recentArticles":{
"title":"Articles récents",
"title":"Articles récents",
"subtitle":"Les dernières publications sur le développement de plugins Hytale",
"subtitle":"Les dernières publications sur le développement de plugins Hytale",
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.